Ejemplo n.º 1
0
        protected TicketCard ConvertTicket(Ticket ticket)
        {
            var card = new TicketCard()
            {
                Title               = ticket.Title,
                Description         = ticket.Description,
                UrgencyLevel        = string.Format(SharedStrings.Urgency, ticket.Urgency.ToLocalizedString()),
                State               = string.Format(SharedStrings.TicketState, ticket.State.ToLocalizedString()),
                OpenedTime          = string.Format(SharedStrings.OpenedAt, ticket.OpenedTime.ToString()),
                Id                  = string.Format(SharedStrings.ID, ticket.Id),
                ResolvedReason      = ticket.ResolvedReason,
                Speak               = ticket.Description,
                Number              = string.Format(SharedStrings.TicketNumber, ticket.Number),
                ActionUpdateTitle   = SharedStrings.TicketActionUpdateTitle,
                ActionUpdateValue   = string.Format(SharedStrings.TicketActionUpdateValue, ticket.Number),
                ProviderDisplayText = string.Format(SharedStrings.PoweredBy, ticket.Provider),
            };

            if (ticket.State != TicketState.Closed)
            {
                card.ActionCloseTitle = SharedStrings.TicketActionCloseTitle;
                card.ActionCloseValue = string.Format(SharedStrings.TicketActionCloseValue, ticket.Number);
            }

            return(card);
        }
        /// <summary>
        /// Handle when a message is addressed to the bot in personal scope.
        /// </summary>
        /// <param name="message">Message activity of bot.</param>
        /// <param name="turnContext">The turn context.</param>
        /// <param name="telemetryClient">The Application Insights telemetry client. </param>
        /// <param name="logger">Sends logs to the Application Insights service.</param>
        /// <param name="cardConfigurationStorageProvider">Provider to search card configuration details in Azure Table Storage.</param>
        /// <param name="environment">Hosting environment.</param>
        /// <param name="ticketGenerateStorageProvider">Provider to get ticket id to Azure Table Storage.</param>
        /// <param name="ticketDetailStorageProvider">Provider to store ticket details to Azure Table Storage.</param>
        /// <param name="microsoftAppCredentials">Microsoft Application credentials for Bot/ME.</param>
        /// <param name="appBaseUrl">Represents the Application base Uri.</param>
        /// <param name="localizer">The current cultures' string localizer.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns> A task that represents the work queued to execute for user message activity to bot.</returns>
        internal static async Task OnMessageActivityInPersonalChatAsync(
            IMessageActivity message,
            ITurnContext <IMessageActivity> turnContext,
            TelemetryClient telemetryClient,
            ILogger <RemoteSupportActivityHandler> logger,
            ICardConfigurationStorageProvider cardConfigurationStorageProvider,
            IHostingEnvironment environment,
            ITicketIdGeneratorStorageProvider ticketGenerateStorageProvider,
            ITicketDetailStorageProvider ticketDetailStorageProvider,
            MicrosoftAppCredentials microsoftAppCredentials,
            string appBaseUrl,
            IStringLocalizer <Strings> localizer,
            CancellationToken cancellationToken)
        {
            if (!string.IsNullOrEmpty(message.ReplyToId) && message.Value != null && ((JObject)message.Value).HasValues)
            {
                telemetryClient.TrackTrace("Card submitted in 1:1 chat.");
                await OnAdaptiveCardSubmitInPersonalChatAsync(message: message, turnContext : turnContext, ticketGenerateStorageProvider : ticketGenerateStorageProvider, ticketDetailStorageProvider : ticketDetailStorageProvider, cardConfigurationStorageProvider : cardConfigurationStorageProvider, microsoftAppCredentials : microsoftAppCredentials, logger : logger, appBaseUrl : appBaseUrl, environment : environment, localizer : localizer, cancellationToken : cancellationToken);

                return;
            }

            string text = (turnContext.Activity.Text ?? string.Empty).Trim().ToUpperInvariant();

            switch (text)
            {
            case Constants.NewRequestAction:
                logger.LogInformation("New request action called.");
                CardConfigurationEntity cardTemplateJson = await cardConfigurationStorageProvider.GetConfigurationAsync();

                IMessageActivity newTicketActivity = MessageFactory.Attachment(TicketCard.GetNewTicketCard(cardTemplateJson, localizer));
                await turnContext.SendActivityAsync(newTicketActivity);

                break;

            case Constants.NoCommand:
                return;

            default:
                if (turnContext.Activity.Attachments == null || turnContext.Activity.Attachments.Count == 0)
                {
                    // In case of ME when user clicks on closed or active requests the bot posts adaptive card of request details we don't have to consider this as invalid command.
                    logger.LogInformation("Unrecognized input in End User.");
                    await turnContext.SendActivityAsync(MessageFactory.Attachment(WelcomeCard.GetCard(appBaseUrl, localizer)));
                }

                break;
            }
        }
Ejemplo n.º 3
0
        protected TicketCard ConvertTicket(Ticket ticket)
        {
            var card = new TicketCard()
            {
                Description    = ticket.Description,
                UrgencyLevel   = $"{SharedStrings.Urgency}{ticket.Urgency.ToLocalizedString()}",
                State          = $"{SharedStrings.TicketState}{ticket.State.ToLocalizedString()}",
                OpenedTime     = $"{SharedStrings.OpenedAt}{ticket.OpenedTime.ToString()}",
                Id             = $"{SharedStrings.ID}{ticket.Id}",
                ResolvedReason = ticket.ResolvedReason,
                Speak          = ticket.Description,
                Number         = $"{SharedStrings.TicketNumber}{ticket.Number}",
            };

            return(card);
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Handle when a message is addressed to the bot in personal scope.
        /// </summary>
        /// <param name="message">Message activity of bot.</param>
        /// <param name="turnContext">The turn context.</param>
        /// <param name="logger">Sends logs to the Application Insights service.</param>
        /// <param name="cardConfigurationStorageProvider">Provider to search card configuration details in Azure Table Storage.</param>
        /// <param name="ticketGenerateStorageProvider">Provider to get ticket id to Azure Table Storage.</param>
        /// <param name="ticketDetailStorageProvider">Provider to store ticket details to Azure Table Storage.</param>
        /// <param name="microsoftAppCredentials">Microsoft Application credentials for Bot/ME.</param>
        /// <param name="appBaseUrl">Represents the Application base Uri.</param>
        /// <param name="localizer">The current cultures' string localizer.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns> A task that represents the work queued to execute for user message activity to bot.</returns>
        internal static async Task OnMessageActivityInPersonalChatAsync(
            IMessageActivity message,
            ITurnContext <IMessageActivity> turnContext,
            ILogger logger,
            ICardConfigurationStorageProvider cardConfigurationStorageProvider,
            ITicketIdGeneratorStorageProvider ticketGenerateStorageProvider,
            ITicketDetailStorageProvider ticketDetailStorageProvider,
            MicrosoftAppCredentials microsoftAppCredentials,
            string appBaseUrl,
            IStringLocalizer <Strings> localizer,
            CancellationToken cancellationToken)
        {
            if (!string.IsNullOrEmpty(message.ReplyToId) && message.Value != null && ((JObject)message.Value).HasValues)
            {
                logger.LogInformation("Card submitted in 1:1 chat.");
                await OnAdaptiveCardSubmitInPersonalChatAsync(message, turnContext, ticketGenerateStorageProvider, ticketDetailStorageProvider, cardConfigurationStorageProvider, microsoftAppCredentials, logger, appBaseUrl, localizer, cancellationToken);

                return;
            }

            string text = (turnContext.Activity.Text ?? string.Empty).Trim().ToUpperInvariant();

            if (text.Equals(localizer.GetString("BotCommandNewRequest"), StringComparison.CurrentCultureIgnoreCase))
            {
                logger.LogInformation("New request action called.");
                CardConfigurationEntity cardTemplateJson = await cardConfigurationStorageProvider.GetConfigurationAsync();

                IMessageActivity newTicketActivity = MessageFactory.Attachment(TicketCard.GetNewTicketCard(cardTemplateJson, localizer));
                await turnContext.SendActivityAsync(newTicketActivity);
            }
            else if (text.Equals(localizer.GetString("No").ToString(), StringComparison.CurrentCultureIgnoreCase))
            {
                return;
            }
            else
            {
                if (turnContext.Activity.Attachments == null || turnContext.Activity.Attachments.Count == 0)
                {
                    // In case of ME when user clicks on closed or active requests the bot posts adaptive card of request details we don't have to consider this as invalid command.
                    logger.LogInformation("Unrecognized input in End User.");
                    await turnContext.SendActivityAsync(MessageFactory.Attachment(WelcomeCard.GetCard(appBaseUrl, localizer)));
                }
            }
        }
Ejemplo n.º 5
0
        /// <summary>
        /// Method Handle adaptive card submit in 1:1 chat and Send new ticket details to SME team.
        /// </summary>
        /// <param name="message">Message activity of bot.</param>
        /// <param name="turnContext">Context object containing information cached for a single turn of conversation with a user.</param>
        /// <param name="ticketGenerateStorageProvider">Provider to get ticket id to Azure Table Storage.</param>
        /// <param name="ticketDetailStorageProvider">Provider to store ticket details to Azure Table Storage.</param>
        /// <param name="cardConfigurationStorageProvider">Provider to search card configuration details in Azure Table Storage.</param>
        /// <param name="microsoftAppCredentials">Microsoft Application credentials for Bot/ME.</param>
        /// <param name="logger">Sends logs to the Application Insights service.</param>
        /// <param name="appBaseUrl">Represents the Application base Uri.</param>
        /// <param name="localizer">The current cultures' string localizer.</param>
        /// <param name="cancellationToken">Propagates notification that operations should be canceled.</param>
        /// <returns>A task that handles submit action in 1:1 chat.</returns>
        internal static async Task OnAdaptiveCardSubmitInPersonalChatAsync(
            IMessageActivity message,
            ITurnContext <IMessageActivity> turnContext,
            ITicketIdGeneratorStorageProvider ticketGenerateStorageProvider,
            ITicketDetailStorageProvider ticketDetailStorageProvider,
            ICardConfigurationStorageProvider cardConfigurationStorageProvider,
            MicrosoftAppCredentials microsoftAppCredentials,
            ILogger logger,
            string appBaseUrl,
            IStringLocalizer <Strings> localizer,
            CancellationToken cancellationToken)
        {
            IMessageActivity endUserUpdateCard;

            switch (message.Text.ToUpperInvariant())
            {
            case Constants.SendRequestAction:
                TicketDetail newTicketDetail = JsonConvert.DeserializeObject <TicketDetail>(message.Value?.ToString());
                if (TicketHelper.ValidateRequestDetail(newTicketDetail))
                {
                    AdaptiveCardAction cardDetail = ((JObject)message.Value).ToObject <AdaptiveCardAction>();
                    logger.LogInformation("Adding new request with additional details.");
                    var ticketTd = await ticketGenerateStorageProvider.GetTicketIdAsync();

                    // Update new request with additional details.
                    var userDetails = await GetUserDetailsInPersonalChatAsync(turnContext, cancellationToken);

                    newTicketDetail.TicketId = ticketTd.ToString(CultureInfo.InvariantCulture);
                    newTicketDetail          = TicketHelper.GetNewTicketDetails(turnContext: turnContext, ticketDetail: newTicketDetail, ticketAdditionalDetails: message.Value?.ToString(), cardId: cardDetail.CardId, member: userDetails);
                    bool result = await ticketDetailStorageProvider.UpsertTicketAsync(newTicketDetail);

                    if (!result)
                    {
                        logger.LogError("Error in storing new ticket details in table storage.");
                        await turnContext.SendActivityAsync(localizer.GetString("AzureStorageErrorText"));

                        return;
                    }

                    logger.LogInformation("New request created with ticket Id:" + newTicketDetail.TicketId);

                    // Get card item element mappings
                    var carditemElementMapping = await cardConfigurationStorageProvider.GetCardItemElementMappingAsync(cardDetail?.CardId);

                    endUserUpdateCard = MessageFactory.Attachment(TicketCard.GetTicketDetailsForPersonalChatCard(carditemElementMapping, newTicketDetail, localizer, false));
                    await CardHelper.SendRequestCardToSMEChannelAsync(turnContext : turnContext, ticketDetail : newTicketDetail, logger : logger, ticketDetailStorageProvider : ticketDetailStorageProvider, applicationBasePath : appBaseUrl, cardElementMapping : carditemElementMapping, localizer, teamId : cardDetail?.TeamId, microsoftAppCredentials : microsoftAppCredentials, cancellationToken : cancellationToken);

                    await CardHelper.UpdateRequestCardForEndUserAsync(turnContext, endUserUpdateCard);

                    await turnContext.SendActivityAsync(MessageFactory.Text(localizer.GetString("EndUserNotificationText", newTicketDetail.TicketId)));
                }
                else
                {
                    // Update card with validation message.
                    newTicketDetail.AdditionalProperties = CardHelper.ValidateAdditionalTicketDetails(message.Value?.ToString(), timeSpan: turnContext.Activity.LocalTimestamp.Value.Offset);
                    CardConfigurationEntity cardTemplateJson = await cardConfigurationStorageProvider.GetConfigurationAsync();

                    endUserUpdateCard = MessageFactory.Attachment(TicketCard.GetNewTicketCard(cardConfiguration: cardTemplateJson, localizer: localizer, showValidationMessage: true, ticketDetail: newTicketDetail));
                    await CardHelper.UpdateRequestCardForEndUserAsync(turnContext, endUserUpdateCard);
                }

                break;

            case Constants.WithdrawRequestAction:
                var payload = ((JObject)message.Value).ToObject <AdaptiveCardAction>();
                endUserUpdateCard = MessageFactory.Attachment(WithdrawCard.GetCard(payload.PostedValues, localizer));

                // Get the ticket from the data store.
                TicketDetail ticketDetail = await ticketDetailStorageProvider.GetTicketAsync(payload.PostedValues);

                if (ticketDetail.TicketStatus == (int)TicketState.Kapatılmış)
                {
                    await turnContext.SendActivityAsync(localizer.GetString("WithdrawErrorMessage"));

                    return;
                }

                ticketDetail.LastModifiedByName     = message.From.Name;
                ticketDetail.LastModifiedByObjectId = message.From.AadObjectId;
                ticketDetail.TicketStatus           = (int)TicketState.Vazgeçilmiş;
                bool success = await ticketDetailStorageProvider.UpsertTicketAsync(ticketDetail);

                if (!success)
                {
                    logger.LogError("Error in updating ticket details in table storage.");
                    await turnContext.SendActivityAsync(localizer.GetString("AzureStorageErrorText"));

                    return;
                }

                logger.LogInformation("Withdrawn the ticket:" + ticketDetail.TicketId);
                IMessageActivity smeWithdrawNotification = MessageFactory.Text(localizer.GetString("SmeWithdrawNotificationText", ticketDetail.RequesterName));
                var itemElementMapping = await cardConfigurationStorageProvider.GetCardItemElementMappingAsync(ticketDetail?.CardId);

                await CardHelper.UpdateSMECardAsync(turnContext, ticketDetail, smeWithdrawNotification, appBaseUrl, itemElementMapping, localizer, logger, cancellationToken);

                await CardHelper.UpdateRequestCardForEndUserAsync(turnContext, endUserUpdateCard);

                break;
            }
        }
        /// <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)
        {
            turnContext = turnContext ?? throw new ArgumentNullException(nameof(turnContext));
            var activity = (Activity)turnContext.Activity;

            this.RecordEvent(nameof(this.OnTeamsTaskModuleFetchAsync), turnContext);
            var valuesforTaskModule = JsonConvert.DeserializeObject <AdaptiveCardAction>(((JObject)activity.Value).GetValue("data", StringComparison.OrdinalIgnoreCase)?.ToString());
            var editTicketDetail    = JsonConvert.DeserializeObject <TicketDetail>(((JObject)activity.Value).GetValue("data", StringComparison.OrdinalIgnoreCase)?.ToString());

            switch (valuesforTaskModule.Command.ToUpperInvariant())
            {
            case Constants.UpdateRequestAction:
                var ticketDetail = await this.ticketDetailStorageProvider.GetTicketAsync(valuesforTaskModule.TicketId);

                if (TicketHelper.ValidateRequestDetail(editTicketDetail))
                {
                    ticketDetail.AdditionalProperties = CardHelper.ValidateAdditionalTicketDetails(((JObject)activity.Value).GetValue("data", StringComparison.OrdinalIgnoreCase)?.ToString(), turnContext.Activity.Timestamp.Value.Offset);

                    // Update request card with user entered values.
                    ticketDetail = TicketHelper.GetUpdatedTicketDetails(turnContext, ticketDetail, editTicketDetail);
                    bool result = await this.ticketDetailStorageProvider.UpsertTicketAsync(ticketDetail);

                    if (!result)
                    {
                        this.logger.LogError("Error in storing new ticket details in table storage.");
                        await turnContext.SendActivityAsync(this.localizer.GetString("AzureStorageErrorText"));

                        return(null);
                    }

                    // Send update audit trail message and request details card in personal chat and SME team.
                    this.logger.LogInformation($"Edited the ticket:{ticketDetail.TicketId}");
                    IMessageActivity smeEditNotification = MessageFactory.Text(string.Format(CultureInfo.InvariantCulture, this.localizer.GetString("SmeEditNotificationText"), ticketDetail.LastModifiedByName));

                    // Get card item element mappings
                    var cardElementMapping = await this.cardConfigurationStorageProvider.GetCardItemElementMappingAsync(ticketDetail.CardId);

                    IMessageActivity ticketDetailActivity = MessageFactory.Attachment(TicketCard.GetTicketDetailsForPersonalChatCard(cardElementMapping, ticketDetail, this.localizer, true));
                    ticketDetailActivity.Conversation = turnContext.Activity.Conversation;
                    ticketDetailActivity.Id           = ticketDetail.RequesterTicketActivityId;
                    await turnContext.UpdateActivityAsync(ticketDetailActivity);

                    await CardHelper.UpdateSMECardAsync(turnContext, ticketDetail, smeEditNotification, this.appBaseUrl, cardElementMapping, this.localizer, this.logger, cancellationToken);
                }
                else
                {
                    editTicketDetail.AdditionalProperties = CardHelper.ValidateAdditionalTicketDetails(additionalDetails: ((JObject)activity.Value).GetValue("data", StringComparison.OrdinalIgnoreCase)?.ToString(), timeSpan: turnContext.Activity.Timestamp.Value.Offset);
                    return(CardHelper.GetEditTicketAdaptiveCard(cardConfigurationStorageProvider: this.cardConfigurationStorageProvider, ticketDetail: editTicketDetail, localizer: this.localizer, existingTicketDetail: ticketDetail));
                }

                break;

            case Constants.UpdateExpertListAction:
                var teamsChannelData = ((JObject)turnContext.Activity.ChannelData).ToObject <TeamsChannelData>();
                var expertChannelId  = teamsChannelData.Team == null ? this.teamId : teamsChannelData.Team.Id;
                if (expertChannelId != this.teamId)
                {
                    this.logger.LogInformation("Invalid team. Bot is not installed in this team.");
                    await turnContext.SendActivityAsync(this.localizer.GetString("InvalidTeamText"));

                    return(null);
                }

                var onCallExpertsDetail = JsonConvert.DeserializeObject <OnCallExpertsDetail>(JObject.Parse(taskModuleRequest?.Data?.ToString())?.ToString());
                await CardHelper.UpdateManageExpertsCardInTeamAsync(turnContext, onCallExpertsDetail, this.onCallSupportDetailSearchService, this.onCallSupportDetailStorageProvider, this.localizer);

                await ActivityHelper.SendMentionActivityAsync(onCallExpertsEmails : onCallExpertsDetail.OnCallExperts, turnContext : turnContext, logger : this.logger, localizer : this.localizer, cancellationToken : cancellationToken);

                this.logger.LogInformation("Expert List has been updated");
                return(null);

            case Constants.CancelCommand:
                return(null);
            }

            return(null);
        }