/// <summary>
        /// Add a new suggestion in company response entity in Microsoft Azure Table storage.
        /// </summary>
        /// <param name="turnContext">Context object containing information cached for a single turn of conversation with a user.</param>
        /// <param name="userRequestDetails">User response new request details object used to send new request data.</param>
        /// <param name="customAPIAuthenticationToken">Generate JWT token used by client application to authenticate HTTP calls with API.</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 <MessagingExtensionActionResponse> AddNewSuggestionResultAsync(
            ITurnContext <IInvokeActivity> turnContext,
            AddUserResponseRequestDetail userRequestDetails,
            string customAPIAuthenticationToken,
            CancellationToken cancellationToken)
        {
            var activity = turnContext.Activity;
            var companyResponseEntity = await this.companyStorageHelper.AddNewSuggestionAsync(activity, userRequestDetails);

            // Parse team channel deep link URL and get team id.
            var teamId = AdaptiveCardHelper.ParseTeamIdFromDeepLink(this.botSetting.Value.TeamIdDeepLink);

            if (string.IsNullOrEmpty(teamId))
            {
                throw new NullReferenceException("Provided team details seems to incorrect, please reach out to the Admin.");
            }

            var isAddSuggestionSuccess = await this.companyResponseStorageProvider.UpsertConverationStateAsync(companyResponseEntity);

            if (isAddSuggestionSuccess)
            {
                // Tracking for company response suggested request.
                this.RecordEvent(RecordSuggestCompanyResponse, turnContext);
                var attachment       = AdminCard.GetNewResponseRequestCard(companyResponseEntity, localizer: this.localizer);
                var resourceResponse = await this.SendCardToTeamAsync(turnContext, attachment, teamId, cancellationToken);

                companyResponseEntity.ActivityId = resourceResponse.ActivityId;
                await this.companyResponseStorageProvider.UpsertConverationStateAsync(companyResponseEntity);

                return(new MessagingExtensionActionResponse
                {
                    Task = new TaskModuleContinueResponse
                    {
                        Value = new TaskModuleTaskInfo
                        {
                            Url = $"{this.options.Value.AppBaseUri}/response-message?token={customAPIAuthenticationToken}&status=addSuccess&isCompanyResponse=true&message={this.localizer.GetString("AddNewSuggestionSuccessMessage")}&telemetry=${this.telemetrySettings.Value.InstrumentationKey}&theme=" + "{theme}&locale=" + "{locale}",
                            Height = TaskModuleHeight,
                            Width = TaskModuleWidth,
                            Title = this.localizer.GetString("ManageYourResponsesTitleText"),
                        },
                    },
                });
            }
            else
            {
                return(new MessagingExtensionActionResponse
                {
                    Task = new TaskModuleContinueResponse
                    {
                        Value = new TaskModuleTaskInfo
                        {
                            Url = $"{this.options.Value.AppBaseUri}/response-message?token={customAPIAuthenticationToken}&status=editFailed&isCompanyResponse=true&message={this.localizer.GetString("AddNewSuggestionFailedMessage")}&theme=" + "{theme}&locale=" + "{locale}",
                            Height = TaskModuleHeight,
                            Width = TaskModuleWidth,
                            Title = this.localizer.GetString("ManageYourResponsesTitleText"),
                        },
                    },
                });
            }
        }
Example #2
0
        /// <summary>
        /// When OnTurn method receives a submit invoke activity on bot turn, it calls this method.
        /// </summary>
        /// <param name="turnContext">Context object containing information cached for a single turn of conversation with a user.</param>
        /// <param name="taskModuleRequest">Task module invoke request value payload.</param>
        /// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
        /// <returns>A task that represents a task module response.</returns>
        protected override async Task <TaskModuleResponse> OnTeamsTaskModuleSubmitAsync(ITurnContext <IInvokeActivity> turnContext, TaskModuleRequest taskModuleRequest, CancellationToken cancellationToken)
        {
            try
            {
                turnContext = turnContext ?? throw new ArgumentNullException(nameof(turnContext));

                var activity = (Activity)turnContext.Activity;
                this.RecordEvent(nameof(this.OnTeamsTaskModuleFetchAsync), turnContext);
                IMessageActivity notificationCard;
                Activity         mentionActivity;
                var valuesfromTaskModule = JsonConvert.DeserializeObject <TaskModuleResponseDetails>(((JObject)activity.Value).GetValue("data", StringComparison.OrdinalIgnoreCase)?.ToString());
                switch (valuesfromTaskModule.Command.ToUpperInvariant())
                {
                case Constants.SaveAdminDetailsAction:
                    mentionActivity = await CardHelper.GetMentionActivityAsync(valuesfromTaskModule.AdminPrincipalName.Split(",").ToList(), turnContext.Activity.From.AadObjectId, valuesfromTaskModule.TeamId, turnContext, this.localizer, this.logger, MentionActivityType.SetAdmin, cancellationToken);

                    var cardDetail = (Activity)MessageFactory.Attachment(AdminCard.GetAdminCard(this.localizer, valuesfromTaskModule, this.options.Value.ManifestId));
                    await this.SendMentionedCardAsync(turnContext, cardDetail, mentionActivity);

                    this.logger.LogInformation("R&R admin has been configured");
                    break;

                case Constants.CancelCommand:
                    break;

                case Constants.UpdateAdminDetailCommand:
                    mentionActivity = await CardHelper.GetMentionActivityAsync(valuesfromTaskModule.AdminPrincipalName.Split(",").ToList(), turnContext.Activity.From.AadObjectId, valuesfromTaskModule.TeamId, turnContext, this.localizer, this.logger, MentionActivityType.SetAdmin, cancellationToken);

                    notificationCard              = MessageFactory.Attachment(AdminCard.GetAdminCard(this.localizer, valuesfromTaskModule, this.options.Value.ManifestId));
                    notificationCard.Id           = turnContext.Activity.Conversation.Id.Split(';')[1].Split("=")[1];
                    notificationCard.Conversation = turnContext.Activity.Conversation;
                    await turnContext.UpdateActivityAsync(notificationCard);

                    await turnContext.SendActivityAsync(mentionActivity);

                    this.logger.LogInformation("Card is updated.");
                    break;

                case Constants.NominateAction:
                    var awardsList = await this.awardsStorageProvider.GetAwardsAsync(valuesfromTaskModule.TeamId);

                    await turnContext.SendActivityAsync(MessageFactory.Carousel(NominateCarouselCard.GetAwardsCard(this.appBaseUrl, awardsList, this.localizer, valuesfromTaskModule)));

                    break;

                case Constants.SaveNominatedDetailsAction:
                    turnContext.Activity.Conversation.Id = valuesfromTaskModule.TeamId;
                    var result = (Activity)MessageFactory.Attachment(EndorseCard.GetEndorseCard(this.appBaseUrl, this.localizer, valuesfromTaskModule));
                    mentionActivity = await CardHelper.GetMentionActivityAsync(valuesfromTaskModule.NominatedToPrincipalName.Split(",").Select(row => row.Trim()).ToList(), turnContext.Activity.From.AadObjectId, valuesfromTaskModule.TeamId, turnContext, this.localizer, this.logger, MentionActivityType.Nomination, cancellationToken);

                    await this.SendMentionedCardAsync(turnContext, result, mentionActivity);

                    this.logger.LogInformation("Nominated an award");
                    break;

                case Constants.OkCommand:
                    return(null);

                default:
                    this.logger.LogInformation($"Invalid command for task module submit activity.Command is : {valuesfromTaskModule.Command} ");
                    await turnContext.SendActivityAsync(this.localizer.GetString("ErrorMessage"));

                    break;
                }

                return(null);
            }
            catch (Exception ex)
            {
                this.logger.LogError(ex, $"Error at OnTeamsTaskModuleSubmitAsync(): {ex.Message}", SeverityLevel.Error);
                await turnContext.SendActivityAsync(this.localizer.GetString("ErrorMessage"));

                throw;
            }
        }
        /// <summary>
        /// Handle message activity in channel.
        /// </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 OnMessageActivityInChannelAsync(
            IMessageActivity message,
            ITurnContext <IMessageActivity> turnContext,
            CancellationToken cancellationToken)
        {
            try
            {
                if (message.Value == null)
                {
                    await turnContext.SendActivityAsync(this.localizer.GetString("ErrorWhenMessageInChannel"));

                    return;
                }

                IMessageActivity      userNotification      = null;
                CompanyResponseEntity companyResponseEntity = null;
                var cardPostedData = ((JObject)message.Value).ToObject <AdaptiveSubmitActionData>();
                var text           = cardPostedData.AdaptiveCardActions.Text;
                var activity       = turnContext.Activity;

                switch (text)
                {
                case Constants.ApproveCommand:

                    if (string.IsNullOrEmpty(cardPostedData.UpdatedQuestionCategory) || string.IsNullOrEmpty(cardPostedData.UpdatedQuestionText) || string.IsNullOrEmpty(cardPostedData.UpdatedResponseText))
                    {
                        companyResponseEntity = this.companyResponseStorageProvider.GetCompanyResponseEntityAsync(cardPostedData.ResponseId).GetAwaiter().GetResult();
                        var attachment = AdminCard.GetNewResponseRequestCard(companyResponseEntity, localizer: this.localizer, emptyApproveField: true);
                        await AdaptiveCardHelper.RefreshCardAsync(turnContext, companyResponseEntity.ActivityId, attachment);

                        return;
                    }

                    companyResponseEntity = this.companyStorageHelper.AddApprovedData(cardPostedData, activity.From.Name, activity.From.AadObjectId);
                    var approveRequestResult = this.companyResponseStorageProvider.UpsertConverationStateAsync(companyResponseEntity).GetAwaiter().GetResult();

                    if (approveRequestResult)
                    {
                        // Refresh the approved card in channel.
                        var attachment = AdminCard.GetRefreshedCardForApprovedRequest(companyResponseEntity, activity.From.Name, localizer: this.localizer);
                        await AdaptiveCardHelper.RefreshCardAsync(turnContext, companyResponseEntity.ActivityId, attachment);

                        // Get user notification attachment and send it to user for approved request.
                        userNotification = MessageFactory.Attachment(UserCard.GetNotificationCardForApprovedRequest(companyResponseEntity, localizer: this.localizer));

                        var result = await this.conversationStorageProvider.GetConversationEntityAsync(companyResponseEntity.UserId);

                        if (result != null)
                        {
                            await AdaptiveCardHelper.SendNotificationCardAsync(turnContext, userNotification, result.ConversationId, cancellationToken);

                            // Tracking for number of requests approved.
                            this.RecordEvent(ApprovedRequestEventName, turnContext);
                        }
                        else
                        {
                            this.logger.LogInformation("Unable to send notification card for approved request because conversation id is null.");
                        }
                    }
                    else
                    {
                        this.logger.LogInformation("Unable to approve the request.");
                    }

                    break;

                case Constants.RejectCommand:

                    companyResponseEntity = this.companyStorageHelper.AddRejectedData(cardPostedData, activity.From.Name, activity.From.AadObjectId);
                    var rejectRequestResult = this.companyResponseStorageProvider.UpsertConverationStateAsync(companyResponseEntity).GetAwaiter().GetResult();

                    if (rejectRequestResult)
                    {
                        // Get user notification rejected card attachment.
                        var attachment = AdminCard.GetRefreshedCardForRejectedRequest(companyResponseEntity, activity.From.Name, localizer: this.localizer);
                        await AdaptiveCardHelper.RefreshCardAsync(turnContext, companyResponseEntity.ActivityId, attachment);

                        // Send end user notification for approved request.
                        userNotification = MessageFactory.Attachment(UserCard.GetNotificationCardForRejectedRequest(companyResponseEntity, localizer: this.localizer));

                        var result = await this.conversationStorageProvider.GetConversationEntityAsync(companyResponseEntity.UserId);

                        if (result != null)
                        {
                            await AdaptiveCardHelper.SendNotificationCardAsync(turnContext, userNotification, result.ConversationId, cancellationToken);

                            // Tracking for number of requests rejected.
                            this.RecordEvent(RejectedRequestEventName, turnContext);
                        }
                        else
                        {
                            this.logger.LogInformation("Unable to send notification card for rejected request because conversation id is null.");
                        }
                    }
                    else
                    {
                        this.logger.LogInformation("Unable to reject the request.");
                    }

                    return;

                default:
                    this.logger.LogInformation("Unrecognized input in channel");
                    break;
                }
            }
            catch (Exception ex)
            {
                this.logger.LogError(ex, $"Error processing message: {ex.Message}", SeverityLevel.Error);
                throw;
            }
        }
Example #4
0
        /// <summary>
        /// When OnTurn method receives a submit invoke activity on bot turn, it calls this method.
        /// </summary>
        /// <param name="turnContext">Context object containing information cached for a single turn of conversation with a user.</param>
        /// <param name="taskModuleRequest">Task module invoke request value payload.</param>
        /// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
        /// <returns>A task that represents a task module response.</returns>
        protected override async Task <TaskModuleResponse> OnTeamsTaskModuleSubmitAsync(ITurnContext <IInvokeActivity> turnContext, TaskModuleRequest taskModuleRequest, CancellationToken cancellationToken)
        {
            try
            {
                turnContext = turnContext ?? throw new ArgumentNullException(nameof(turnContext));

                var activity = (Activity)turnContext.Activity;
                this.RecordEvent(nameof(this.OnTeamsTaskModuleFetchAsync), turnContext);
                Activity mentionActivity;
                var      valuesFromTaskModule = JsonConvert.DeserializeObject <TaskModuleResponseDetails>(((JObject)activity.Value).GetValue("data", StringComparison.OrdinalIgnoreCase)?.ToString());
                switch (valuesFromTaskModule.Command.ToUpperInvariant())
                {
                // Command to send award admin card on save admin action.
                case Constants.SaveAdminDetailsAction:
                    mentionActivity = await CardHelper.GetMentionActivityAsync(
                        valuesFromTaskModule.AdminUserPrincipalName.Split(",").ToList(),
                        turnContext.Activity.From.AadObjectId,
                        valuesFromTaskModule.TeamId,
                        turnContext,
                        this.localizer,
                        this.logger,
                        MentionActivityType.SetAdmin,
                        cancellationToken);

                    var cardDetail = AdminCard.GetAdminCard(this.localizer, valuesFromTaskModule);
                    await this.SendCardAndMentionsAsync(turnContext, cardDetail, mentionActivity);

                    this.logger.LogInformation("Admin has been configured successfully.");

                    break;

                // Command to update award admin card
                case Constants.UpdateAdminDetailCommand:
                    mentionActivity = await CardHelper.GetMentionActivityAsync(
                        valuesFromTaskModule.AdminUserPrincipalName.Split(",").ToList(),
                        turnContext.Activity.From.AadObjectId,
                        valuesFromTaskModule.TeamId,
                        turnContext,
                        this.localizer,
                        this.logger,
                        MentionActivityType.SetAdmin,
                        cancellationToken);

                    var notificationCard = (Activity)MessageFactory.Attachment(AdminCard.GetAdminCard(this.localizer, valuesFromTaskModule));

                    // Split here extracts the activity id from turn context conversation
                    notificationCard.Id           = turnContext.Activity.Conversation.Id.Split(';')[1].Split("=")[1];
                    notificationCard.Conversation = turnContext.Activity.Conversation;
                    await turnContext.UpdateActivityAsync(notificationCard);

                    await turnContext.SendActivityAsync(mentionActivity);

                    this.logger.LogInformation("Admin card is updated successfully.");
                    break;

                // Command to show list of awards ready for nomination
                case Constants.NominateAction:
                    var awardsList = await this.awardsStorageProvider.GetAwardsAsync(valuesFromTaskModule.TeamId);

                    await turnContext.SendActivityAsync(MessageFactory.Carousel(NominateCarouselCard.GetAwardNominationCards(this.options.Value.AppBaseUri, awardsList, this.localizer, valuesFromTaskModule)));

                    this.logger.LogInformation("Nomination carousel card is sent successfully.");
                    break;

                // Command to save nominated user details
                case Constants.SaveNominatedDetailsAction:
                    turnContext.Activity.Conversation.Id = valuesFromTaskModule.TeamId;
                    var endorsementCard = EndorseCard.GetEndorseCard(this.options.Value.AppBaseUri, this.localizer, valuesFromTaskModule);
                    mentionActivity = await CardHelper.GetMentionActivityAsync(
                        valuesFromTaskModule.NomineeUserPrincipalNames.Split(",").Select(row => row.Trim()).ToList(),
                        turnContext.Activity.From.AadObjectId,
                        valuesFromTaskModule.TeamId,
                        turnContext,
                        this.localizer,
                        this.logger,
                        MentionActivityType.Nomination,
                        cancellationToken);

                    await this.SendCardAndMentionsAsync(turnContext, endorsementCard, mentionActivity);

                    this.logger.LogInformation("Award nomination for user sent successfully");
                    break;

                // Commands to close task modules
                case Constants.OkCommand:
                case Constants.CancelCommand:
                    this.logger.LogInformation($"{valuesFromTaskModule.Command.ToUpperInvariant()} is called. [note] - no actions are performed.");
                    break;

                default:
                    this.logger.LogInformation($"Invalid command for task module submit activity.Command is : {valuesFromTaskModule.Command} ");
                    await turnContext.SendActivityAsync(this.localizer.GetString("ErrorMessage"));

                    break;
                }

                return(null);
            }
            catch (Exception ex)
            {
                this.logger.LogError(ex, $"Error at OnTeamsTaskModuleSubmitAsync(): {ex.Message}");
                throw;
            }
        }