/// <summary>
        /// Converts JSON property to adaptive card TextBlock element.
        /// </summary>
        /// <param name="cardElementTemplate">TextBlock item element json property.</param>
        /// <param name="showDateValidation">true if need to show validation message else false.</param>
        /// <returns>Returns adaptive card TextBlock item element.</returns>
        public static AdaptiveTextBlock ConvertToAdaptiveTextBlock(string cardElementTemplate, bool showDateValidation = false)
        {
            var  result    = JsonConvert.DeserializeObject <Dictionary <string, string> >(cardElementTemplate);
            bool isVisible = true;

            if (!string.IsNullOrEmpty(CardHelper.TryParseTicketDetailsKeyValuePair(result, "isVisible")))
            {
                bool status = bool.TryParse(CardHelper.TryParseTicketDetailsKeyValuePair(result, "isVisible"), out isVisible);
            }

            string color = CardHelper.TryParseTicketDetailsKeyValuePair(result, "color");

            return(new AdaptiveTextBlock()
            {
                Id = CardHelper.TryParseTicketDetailsKeyValuePair(result, "id"),
                Text = CardHelper.TryParseTicketDetailsKeyValuePair(result, "text"),
                IsVisible = isVisible,
                Color = string.IsNullOrEmpty(color) ? AdaptiveTextColor.Default : (AdaptiveTextColor)Enum.Parse(typeof(AdaptiveTextColor), color),
            });
        }
Beispiel #2
0
        /// <summary>
        /// Handle members added conversationUpdate event in team.
        /// </summary>
        /// <param name="membersAdded">Channel account information needed to route a message.</param>
        /// <param name="turnContext">Context object containing information cached for a single turn of conversation with a user.</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 represents the work queued to execute.</returns>
        internal static async Task OnMembersAddedToTeamAsync(
            IList <ChannelAccount> membersAdded,
            ITurnContext <IConversationUpdateActivity> turnContext,
            MicrosoftAppCredentials microsoftAppCredentials,
            ILogger logger,
            string appBaseUrl,
            IStringLocalizer <Strings> localizer,
            CancellationToken cancellationToken)
        {
            turnContext = turnContext ?? throw new ArgumentNullException(nameof(turnContext));
            var activity = turnContext.Activity;

            if (membersAdded.Any(channelAccount => channelAccount.Id == activity.Recipient.Id))
            {
                // Bot was added to a team
                logger.LogInformation($"Bot added to team {activity.Conversation.Id}");
                var teamDetails = ((JObject)turnContext.Activity.ChannelData).ToObject <TeamsChannelData>();
                var teamWelcomeCardAttachment = WelcomeTeamCard.GetCard(appBaseUrl, localizer);
                await CardHelper.SendCardToTeamAsync(turnContext, teamWelcomeCardAttachment, teamDetails.Team.Id, microsoftAppCredentials, cancellationToken);
            }
        }
Beispiel #3
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;
            }
        }
Beispiel #4
0
        /// <summary>
        /// Get result for messaging extension tab.
        /// </summary>
        /// <param name="searchServiceResults">List of tickets from Azure search service.</param>
        /// <param name="localizer">The current cultures' string localizer.</param>
        /// <param name="commandId">Command id to determine which tab in message extension has been invoked.</param>
        /// <param name="onCallSMEUsers">OncallSMEUsers to give support from group-chat or on-call.</param>
        /// <returns><see cref="Task"/> Returns MessagingExtensionResult which will be shown in messaging extension tab.</returns>
        public static MessagingExtensionResult GetMessagingExtensionResult(
            IList <TicketDetail> searchServiceResults,
            IStringLocalizer <Strings> localizer,
            string commandId      = "",
            string onCallSMEUsers = "")
        {
            MessagingExtensionResult composeExtensionResult = new MessagingExtensionResult
            {
                Type             = "result",
                AttachmentLayout = AttachmentLayoutTypes.List,
                Attachments      = new List <MessagingExtensionAttachment>(),
            };

            if (searchServiceResults != null)
            {
                foreach (var ticket in searchServiceResults)
                {
                    var dynamicElements = new List <AdaptiveElement>
                    {
                        CardHelper.GetAdaptiveCardColumnSet(localizer.GetString("RequestNumberText"), $"#{ticket.TicketId}"),
                        CardHelper.GetAdaptiveCardColumnSet(localizer.GetString("TitleDisplayText"), ticket.Title),
                        CardHelper.GetAdaptiveCardColumnSet(localizer.GetString("DescriptionText"), ticket.Description),
                        CardHelper.GetAdaptiveCardColumnSet(localizer.GetString("CreatedOnText"), ticket.CreatedOn.ToString(CultureInfo.InvariantCulture)),
                    };

                    AdaptiveCard commandIdCard = new AdaptiveCard(Constants.AdaptiveCardVersion)
                    {
                        Body    = dynamicElements,
                        Actions = new List <AdaptiveAction>(),
                    };

                    if (commandId == Constants.ActiveCommandId && !string.IsNullOrEmpty(onCallSMEUsers))
                    {
                        commandIdCard.Actions.Add(
                            new AdaptiveOpenUrlAction
                        {
                            Title = localizer.GetString("EscalateButtonText"),
                            Url   = new Uri(CreateGroupChat(onCallSMEUsers, ticket.TicketId, ticket.RequesterName, localizer)),
                        });
                    }
                    else if ((commandId == Constants.UrgentCommandId || commandId == Constants.AssignedCommandId || commandId == Constants.UnassignedCommandId) && ticket.SmeConversationId != null)
                    {
                        commandIdCard.Actions.Add(
                            new AdaptiveOpenUrlAction
                        {
                            Title = localizer.GetString("GoToOriginalThreadButtonText"),
                            Url   = new Uri(CreateDeepLinkToThread(ticket.SmeConversationId)),
                        });
                    }

                    ThumbnailCard previewCard = new ThumbnailCard
                    {
                        Title                          = $"<b>{HttpUtility.HtmlEncode(ticket.Title)} | {HttpUtility.HtmlEncode(ticket.Severity == (int)TicketSeverity.Acil ? localizer.GetString("UrgentText") : localizer.GetString("NormalText"))}</b>",
                        Subtitle                       = ticket.Description.Length <= TruncateDescriptionLength?HttpUtility.HtmlEncode(ticket.Description) : HttpUtility.HtmlEncode(ticket.Description.Substring(0, 45)) + Ellipsis,
                                                  Text = ticket.RequesterName,
                    };
                    composeExtensionResult.Attachments.Add(new Attachment
                    {
                        ContentType = AdaptiveCard.ContentType,
                        Content     = commandIdCard,
                    }.ToMessagingExtensionAttachment(previewCard.ToAttachment()));
                }
            }

            return(composeExtensionResult);
        }
        /// <summary>
        /// Converts JSON property to adaptive card DateInput element.
        /// </summary>
        /// <param name="cardElementTemplate">DateInput item element json property.</param>
        /// <returns>Returns adaptive card DateInput item element.</returns>
        public static AdaptiveDateInput ConvertToAdaptiveDateInput(string cardElementTemplate)
        {
            var result = JsonConvert.DeserializeObject <Dictionary <string, string> >(cardElementTemplate);

            return(new AdaptiveDateInput()
            {
                Id = CardHelper.TryParseTicketDetailsKeyValuePair(result, "id"),
                Placeholder = CardHelper.TryParseTicketDetailsKeyValuePair(result, "placeholder"),
                Value = string.IsNullOrEmpty(CardHelper.TryParseTicketDetailsKeyValuePair(result, "value")) ? DateTime.Now.ToString(CultureInfo.InvariantCulture) : CardHelper.TryParseTicketDetailsKeyValuePair(result, "value"),
                Max = CardHelper.TryParseTicketDetailsKeyValuePair(result, "max"),
                Min = CardHelper.TryParseTicketDetailsKeyValuePair(result, "min"),
            });
        }