Ejemplo n.º 1
0
        /// <summary>
        /// Delete company response details data in Microsoft Azure Table storage.
        /// </summary>
        /// <param name="entity">Holds company response detail entity data.</param>
        /// <returns>A task that represents company response entity data is deleted.</returns>
        public async Task <bool> DeleteEntityAsync(CompanyResponseEntity entity)
        {
            await this.EnsureInitializedAsync();

            TableOperation deleteOperation = TableOperation.Delete(entity);
            var            result          = await this.ResponsesCloudTable.ExecuteAsync(deleteOperation);

            return(result.HttpStatusCode == (int)HttpStatusCode.NoContent);
        }
Ejemplo n.º 2
0
 /// <summary>
 /// Show reject adaptive card on new response request card.
 /// </summary>
 /// <param name="userRequestDetails">User request details object.</param>
 /// <param name="localizer">The current cultures' string localizer.</param>
 /// <returns>An reject card to show on new response request card.</returns>
 private static AdaptiveCard GetRejectCard(CompanyResponseEntity userRequestDetails, IStringLocalizer <Strings> localizer)
 {
     return(new AdaptiveCard(new AdaptiveSchemaVersion(1, 2))
     {
         Body = new List <AdaptiveElement>
         {
             new AdaptiveContainer
             {
                 Items = new List <AdaptiveElement>
                 {
                     new AdaptiveColumnSet
                     {
                         Columns = new List <AdaptiveColumn>
                         {
                             new AdaptiveColumn
                             {
                                 Items = new List <AdaptiveElement>
                                 {
                                     new AdaptiveTextBlock
                                     {
                                         Text = localizer.GetString("RejectToggleCardRemarkTitle"),
                                         Wrap = true,
                                     },
                                     new AdaptiveTextInput
                                     {
                                         Id = "approvalremark",
                                         Placeholder = localizer.GetString("RejectToggleCardRemarkPlaceholder"),
                                         IsMultiline = true,
                                         MaxLength = RejectToggleCardCommentFieldMaxLimit,
                                     },
                                 },
                             },
                         },
                     },
                 },
             },
         },
         Actions = new List <AdaptiveAction>
         {
             new AdaptiveSubmitAction
             {
                 Title = localizer.GetString("RejectToggleCardSubmitButtonTitle"),
                 Data = new AdaptiveSubmitActionData
                 {
                     AdaptiveCardActions = new CardAction
                     {
                         Type = ActionTypes.MessageBack,
                         Text = Constants.RejectCommand,
                     },
                     ResponseId = userRequestDetails.ResponseId,
                     ApprovalStatus = RejectedRequestStatus,
                 },
             },
         },
     });
 }
Ejemplo n.º 3
0
        /// <summary>
        /// Stores or update company response details data in Microsoft Azure Table storage.
        /// </summary>
        /// <param name="entity">Holds company response detail entity data.</param>
        /// <returns>A task that represents a company response data that is saved or updated.</returns>
        private async Task <TableResult> StoreOrUpdateEntityAsync(CompanyResponseEntity entity)
        {
            try
            {
                await this.EnsureInitializedAsync();

                TableOperation addOrUpdateOperation = TableOperation.InsertOrReplace(entity);
                return(await this.ResponsesCloudTable.ExecuteAsync(addOrUpdateOperation));
            }
            catch (Exception)
            {
                throw;
            }
        }
        public async Task <IActionResult> DeleteAsync([FromBody] CompanyResponseEntity companyResponseEntity)
        {
            try
            {
                if (string.IsNullOrEmpty(companyResponseEntity?.UserId) || string.IsNullOrEmpty(companyResponseEntity.ResponseId))
                {
                    this.logger.LogError("Error while deleting company response details data in Microsoft Azure Table storage.");
                    return(this.GetErrorResponse(StatusCodes.Status400BadRequest, "Error while deleting company response details data in Microsoft Azure Table storage."));
                }

                this.RecordEvent(RecordCompanyHTTPDeleteCall, companyResponseEntity.UserId);
                return(this.Ok(await this.companyResponseStorageProvider.DeleteEntityAsync(companyResponseEntity)));
            }
            catch (Exception ex)
            {
                this.logger.LogError(ex, "Error while making call to company response service.");
                throw;
            }
        }
        public async Task <IActionResult> PostAsync([FromBody] CompanyResponseEntity companyResponseEntity)
        {
            try
            {
                if (string.IsNullOrEmpty(companyResponseEntity?.UserId))
                {
                    this.logger.LogError("Error while creating company response details data in Microsoft Azure Table storage.");
                    return(this.GetErrorResponse(StatusCodes.Status400BadRequest, "Error while creating company response details data in Microsoft Azure Table storage."));
                }

                var claims = this.GetUserClaims();
                this.RecordEvent(RecordCompanyHTTPPostCall, claims.FromId);
                return(this.Ok(await this.companyResponseStorageProvider.UpsertConverationStateAsync(companyResponseEntity)));
            }
            catch (Exception ex)
            {
                this.logger.LogError(ex, "Error while making call to company response service.");
                throw;
            }
        }
Ejemplo n.º 6
0
        /// <summary>
        /// Store user suggestion to Microsoft Azure Table storage.
        /// </summary>
        /// <param name="activity">Represents activity for current turn of bot.</param>
        /// <param name="userSuggestionDetails">New suggestion detail.</param>
        /// <returns>Represent a task queued for operation.</returns>
        public async Task <CompanyResponseEntity> AddNewSuggestionAsync(IInvokeActivity activity, AddUserResponseRequestDetail userSuggestionDetails)
        {
            userSuggestionDetails = userSuggestionDetails ?? throw new ArgumentNullException(nameof(userSuggestionDetails));
            activity = activity ?? throw new ArgumentNullException(nameof(activity));

            var userResponse = new CompanyResponseEntity()
            {
                QuestionLabel          = userSuggestionDetails.Label,
                QuestionText           = userSuggestionDetails.Question,
                ResponseText           = userSuggestionDetails.Response,
                ResponseId             = Guid.NewGuid().ToString(),
                UserId                 = activity.From.AadObjectId,
                LastUpdatedDate        = DateTime.UtcNow,
                CreatedDate            = DateTime.UtcNow,
                ApprovalStatus         = PendingRequestStatus,
                CreatedBy              = activity.From.Name,
                ApprovedOrRejectedDate = DateTime.UtcNow,
                UserPrincipalName      = userSuggestionDetails.UPN,
            };

            await this.companyResponseStorageProvider.UpsertConverationStateAsync(userResponse);

            return(userResponse);
        }
Ejemplo n.º 7
0
        /// <summary>
        /// Get new response request card to create new response.
        /// </summary>
        /// <param name="userRequestDetails">User request details object.</param>
        /// <param name="localizer">The current cultures' string localizer.</param>
        /// <param name="emptyApproveField">Show error message if SME has missed to fill any field while approving the response.</param>
        /// <returns>An new response request card attachment.</returns>
        public static Attachment GetNewResponseRequestCard(CompanyResponseEntity userRequestDetails, IStringLocalizer <Strings> localizer, bool emptyApproveField = false)
        {
            if (userRequestDetails == null)
            {
                throw new ArgumentNullException(nameof(userRequestDetails));
            }

            AdaptiveCard card = new AdaptiveCard(new AdaptiveSchemaVersion(1, 2))
            {
                Body = new List <AdaptiveElement>
                {
                    new AdaptiveContainer
                    {
                        Items = new List <AdaptiveElement>
                        {
                            new AdaptiveColumnSet
                            {
                                Columns = new List <AdaptiveColumn>
                                {
                                    new AdaptiveColumn
                                    {
                                        Items = new List <AdaptiveElement>
                                        {
                                            new AdaptiveTextBlock
                                            {
                                                Text = localizer.GetString("NotificationRequestCardContentText"),
                                                Wrap = true,
                                            },
                                            new AdaptiveTextBlock
                                            {
                                                Text = string.Format(CultureInfo.InvariantCulture, localizer.GetString("NotificationCardRequestText"), userRequestDetails.CreatedBy),
                                                Wrap = true,
                                            },
                                        },
                                    },
                                },
                            },
                        },
                    },
                    new AdaptiveContainer
                    {
                        Items = new List <AdaptiveElement>
                        {
                            new AdaptiveColumnSet
                            {
                                Columns = new List <AdaptiveColumn>
                                {
                                    new AdaptiveColumn
                                    {
                                        Items = new List <AdaptiveElement>
                                        {
                                            new AdaptiveTextBlock
                                            {
                                                Text = localizer.GetString("NotificationCardLabelText"),
                                                Wrap = true,
                                            },
                                            new AdaptiveTextBlock
                                            {
                                                Text = userRequestDetails.QuestionLabel,
                                                Wrap = true,
                                            },
                                            new AdaptiveTextBlock
                                            {
                                                Text = localizer.GetString("NotificationCardQuestion"),
                                                Wrap = true,
                                            },
                                            new AdaptiveTextBlock
                                            {
                                                Text = userRequestDetails.QuestionText,
                                                Wrap = true,
                                            },
                                            new AdaptiveTextBlock
                                            {
                                                Text = localizer.GetString("NotificationCardResponse"),
                                                Wrap = true,
                                            },
                                            new AdaptiveTextBlock
                                            {
                                                Text = userRequestDetails.ResponseText,
                                                Wrap = true,
                                            },
                                        },
                                        Style = AdaptiveContainerStyle.Emphasis,
                                    },
                                },
                            },
                        },
                    },
                    new AdaptiveContainer
                    {
                        Items = new List <AdaptiveElement>
                        {
                            new AdaptiveTextBlock
                            {
                                Text      = localizer.GetString("ErrorMessageOnApprove"),
                                Wrap      = true,
                                IsVisible = emptyApproveField,
                                Color     = AdaptiveTextColor.Attention,
                            },
                        },
                    },
                },
                Actions = new List <AdaptiveAction>
                {
                    new AdaptiveShowCardAction
                    {
                        Title = localizer.GetString("ApproveButtonTitle"),
                        Card  = GetApproveCard(userRequestDetails, localizer: localizer),
                    },
                    new AdaptiveShowCardAction
                    {
                        Title = localizer.GetString("RejectButtonTitle"),
                        Card  = GetRejectCard(userRequestDetails, localizer: localizer),
                    },
                    new AdaptiveOpenUrlAction
                    {
                        Title     = string.Format(CultureInfo.InvariantCulture, localizer.GetString("ChatTextButton"), userRequestDetails.CreatedBy),
                        UrlString = $"https://teams.microsoft.com/l/chat/0/0?users={Uri.EscapeDataString(userRequestDetails.UserPrincipalName)}",
                    },
                },
            };
            var adaptiveCardAttachment = new Attachment()
            {
                ContentType = AdaptiveCard.ContentType,
                Content     = card,
            };

            return(adaptiveCardAttachment);
        }
Ejemplo n.º 8
0
 /// <summary>
 /// Show approve adaptive card on new response request card.
 /// </summary>
 /// <param name="userRequestDetails">User request details object.</param>
 /// <param name="localizer">The current cultures' string localizer.</param>
 /// <returns>An approve card to show on new response request card.</returns>
 private static AdaptiveCard GetApproveCard(CompanyResponseEntity userRequestDetails, IStringLocalizer <Strings> localizer)
 {
     return(new AdaptiveCard(new AdaptiveSchemaVersion(1, 2))
     {
         Body = new List <AdaptiveElement>
         {
             new AdaptiveContainer
             {
                 Items = new List <AdaptiveElement>
                 {
                     new AdaptiveColumnSet
                     {
                         Columns = new List <AdaptiveColumn>
                         {
                             new AdaptiveColumn
                             {
                                 Items = new List <AdaptiveElement>
                                 {
                                     new AdaptiveTextBlock
                                     {
                                         Text = localizer.GetString("ApproveToggleCardCategoryTitle"),
                                         Wrap = true,
                                     },
                                     new AdaptiveTextInput
                                     {
                                         Id = "updatedquestioncategory",
                                         Value = userRequestDetails.QuestionLabel,
                                         Placeholder = localizer.GetString("ApproveToggleCardLabelPlaceholder"),
                                         MaxLength = ApproveToggleCardCategoryFieldMaxLimit,
                                     },
                                     new AdaptiveTextBlock
                                     {
                                         Text = localizer.GetString("ApproveToggleCardQuestionsTitle"),
                                         Wrap = true,
                                     },
                                     new AdaptiveTextInput
                                     {
                                         Id = "updatedquestiontext",
                                         Value = userRequestDetails.QuestionText,
                                         Placeholder = localizer.GetString("ApproveToggleCardQuestionsPlaceholder"),
                                         MaxLength = ApproveToggleCardQuestionFieldMaxLimit,
                                     },
                                     new AdaptiveTextBlock
                                     {
                                         Text = localizer.GetString("ApproveToggleCardQuestionsPlaceholder"),
                                         Wrap = true,
                                         HorizontalAlignment = AdaptiveHorizontalAlignment.Right,
                                     },
                                     new AdaptiveTextBlock
                                     {
                                         Text = localizer.GetString("ApproveToggleCardResponseTitle"),
                                         Wrap = true,
                                     },
                                     new AdaptiveTextInput
                                     {
                                         Id = "updatedresponsetext",
                                         Value = userRequestDetails.ResponseText,
                                         Placeholder = localizer.GetString("ApproveToggleCardResponsePlaceholder"),
                                         MaxLength = ApproveToggleCardResponseFieldMaxLimit,
                                         IsMultiline = true,
                                     },
                                 },
                             },
                         },
                     },
                 },
             },
         },
         Actions = new List <AdaptiveAction>
         {
             new AdaptiveSubmitAction
             {
                 Title = localizer.GetString("ApproveToggleCardSubmitButtonTitle"),
                 Data = new AdaptiveSubmitActionData
                 {
                     AdaptiveCardActions = new CardAction
                     {
                         Type = ActionTypes.MessageBack,
                         Text = Constants.ApproveCommand,
                     },
                     ResponseId = userRequestDetails.ResponseId,
                     ApprovalStatus = ApprovedRequestStatus,
                 },
             },
         },
     });
 }
Ejemplo n.º 9
0
        /// <summary>
        ///  Get refreshed card for rejected request.
        /// </summary>
        /// <param name="userRequestDetails">User request details object.</param>
        /// <param name="rejectedBy">User name who approved the request.</param>
        /// <param name="localizer">The current cultures' string localizer.</param>
        /// <returns>An attachment.</returns>
        public static Attachment GetRefreshedCardForRejectedRequest(CompanyResponseEntity userRequestDetails, string rejectedBy, IStringLocalizer <Strings> localizer)
        {
            if (userRequestDetails == null)
            {
                throw new ArgumentNullException(nameof(userRequestDetails));
            }

            bool   showRemarkField   = !string.IsNullOrEmpty(userRequestDetails.ApprovalRemark);
            var    formattedDateTime = userRequestDetails.ApprovedOrRejectedDate.ToString(Constants.Rfc3339DateTimeFormat, CultureInfo.InvariantCulture);
            string dateString        = string.Format(CultureInfo.InvariantCulture, localizer.GetString("DateFormat"), "{{DATE(" + formattedDateTime + ", COMPACT)}}", "{{TIME(" + formattedDateTime + ")}}");

            AdaptiveCard card = new AdaptiveCard(new AdaptiveSchemaVersion(1, 2))
            {
                Body = new List <AdaptiveElement>
                {
                    new AdaptiveContainer
                    {
                        Items = new List <AdaptiveElement>
                        {
                            new AdaptiveColumnSet
                            {
                                Columns = new List <AdaptiveColumn>
                                {
                                    new AdaptiveColumn
                                    {
                                        Items = new List <AdaptiveElement>
                                        {
                                            new AdaptiveTextBlock
                                            {
                                                Text = localizer.GetString("NotificationCardRequestReject"),
                                                Wrap = true,
                                            },
                                            new AdaptiveTextBlock
                                            {
                                                Text = string.Format(CultureInfo.InvariantCulture, localizer.GetString("RefreshedNotificationCardRequestText"), userRequestDetails.CreatedBy),
                                                Wrap = true,
                                            },
                                        },
                                    },
                                },
                            },
                        },
                    },
                    new AdaptiveContainer
                    {
                        Items = new List <AdaptiveElement>
                        {
                            new AdaptiveColumnSet
                            {
                                Columns = new List <AdaptiveColumn>
                                {
                                    new AdaptiveColumn
                                    {
                                        Items = new List <AdaptiveElement>
                                        {
                                            new AdaptiveTextBlock
                                            {
                                                Text = localizer.GetString("NotificationCardLabelText"),
                                                Wrap = true,
                                            },
                                            new AdaptiveTextBlock
                                            {
                                                Text = userRequestDetails.QuestionLabel,
                                                Wrap = true,
                                            },
                                            new AdaptiveTextBlock
                                            {
                                                Text = localizer.GetString("NotificationCardQuestion"),
                                                Wrap = true,
                                            },
                                            new AdaptiveTextBlock
                                            {
                                                Text = userRequestDetails.QuestionText,
                                                Wrap = true,
                                            },
                                            new AdaptiveTextBlock
                                            {
                                                Text = localizer.GetString("NotificationCardResponse"),
                                                Wrap = true,
                                            },
                                            new AdaptiveTextBlock
                                            {
                                                Text = userRequestDetails.ResponseText,
                                                Wrap = true,
                                            },
                                        },
                                        Style = AdaptiveContainerStyle.Emphasis,
                                    },
                                },
                            },
                        },
                    },
                    new AdaptiveContainer
                    {
                        Items = new List <AdaptiveElement>
                        {
                            new AdaptiveColumnSet
                            {
                                Columns = new List <AdaptiveColumn>
                                {
                                    new AdaptiveColumn
                                    {
                                        Items = new List <AdaptiveElement>
                                        {
                                            new AdaptiveTextBlock
                                            {
                                                Text      = localizer.GetString("NotificationCardRemark"),
                                                Wrap      = true,
                                                IsVisible = showRemarkField,
                                            },
                                            new AdaptiveTextBlock
                                            {
                                                Text      = userRequestDetails.ApprovalRemark,
                                                Wrap      = true,
                                                IsVisible = showRemarkField,
                                            },
                                            new AdaptiveTextBlock
                                            {
                                                Text = string.Format(CultureInfo.InvariantCulture, localizer.GetString("RejectedAdminCardLabelText"), dateString, rejectedBy),
                                                Wrap = true,
                                            },
                                        },
                                    },
                                },
                            },
                        },
                    },
                },
            };
            var adaptiveCardAttachment = new Attachment()
            {
                ContentType = AdaptiveCard.ContentType,
                Content     = card,
            };

            return(adaptiveCardAttachment);
        }
Ejemplo n.º 10
0
        /// <summary>
        /// Stores or update company response data in Microsoft Azure Table storage.
        /// </summary>
        /// <param name="companyResponseEntity">Holds company response detail entity data.</param>
        /// <returns>A task that represents company response entity data is saved or updated.</returns>
        public async Task <bool> UpsertConverationStateAsync(CompanyResponseEntity companyResponseEntity)
        {
            var result = await this.StoreOrUpdateEntityAsync(companyResponseEntity);

            return(result.HttpStatusCode == (int)HttpStatusCode.NoContent);
        }
        /// <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;
            }
        }
Ejemplo n.º 12
0
        /// <summary>
        /// Get notification card for approved request.
        /// </summary>
        /// <param name="userRequestDetails">User request details object.</param>
        /// <param name="localizer">The current cultures' string localizer.</param>
        /// <returns>An attachment card for approved request.</returns>
        public static Attachment GetNotificationCardForApprovedRequest(CompanyResponseEntity userRequestDetails, IStringLocalizer <Strings> localizer)
        {
            if (userRequestDetails == null)
            {
                throw new ArgumentNullException(nameof(userRequestDetails));
            }

            var    formattedDateTime = userRequestDetails.ApprovedOrRejectedDate.ToString(Constants.Rfc3339DateTimeFormat, CultureInfo.InvariantCulture);
            string dateString        = string.Format(CultureInfo.InvariantCulture, localizer.GetString("DateFormat"), "{{DATE(" + formattedDateTime + ", COMPACT)}}", "{{TIME(" + formattedDateTime + ")}}");

            AdaptiveCard card = new AdaptiveCard(new AdaptiveSchemaVersion(1, 2))
            {
                Body = new List <AdaptiveElement>
                {
                    new AdaptiveContainer
                    {
                        Items = new List <AdaptiveElement>
                        {
                            new AdaptiveColumnSet
                            {
                                Columns = new List <AdaptiveColumn>
                                {
                                    new AdaptiveColumn
                                    {
                                        Items = new List <AdaptiveElement>
                                        {
                                            new AdaptiveTextBlock
                                            {
                                                Text = localizer.GetString("NotificationCardApprovedOrRejectedTitle"),
                                                Wrap = true,
                                            },
                                            new AdaptiveTextBlock
                                            {
                                                Text  = string.Format(CultureInfo.InvariantCulture, localizer.GetString("NotificationCardStatusText"), localizer.GetString("ApprovedRequestStatusText")),
                                                Wrap  = true,
                                                Color = AdaptiveTextColor.Good,
                                            },
                                        },
                                    },
                                },
                            },
                        },
                    },
                    new AdaptiveContainer
                    {
                        Items = new List <AdaptiveElement>
                        {
                            new AdaptiveColumnSet
                            {
                                Columns = new List <AdaptiveColumn>
                                {
                                    new AdaptiveColumn
                                    {
                                        Items = new List <AdaptiveElement>
                                        {
                                            new AdaptiveTextBlock
                                            {
                                                Text = localizer.GetString("NotificationCardLabelText"),
                                                Wrap = true,
                                            },
                                            new AdaptiveTextBlock
                                            {
                                                Text = userRequestDetails.QuestionLabel,
                                                Wrap = true,
                                            },
                                            new AdaptiveTextBlock
                                            {
                                                Text = localizer.GetString("NotificationCardQuestion"),
                                                Wrap = true,
                                            },
                                            new AdaptiveTextBlock
                                            {
                                                Text = userRequestDetails.QuestionText,
                                                Wrap = true,
                                            },
                                            new AdaptiveTextBlock
                                            {
                                                Text = localizer.GetString("NotificationCardResponse"),
                                                Wrap = true,
                                            },
                                            new AdaptiveTextBlock
                                            {
                                                Text = userRequestDetails.ResponseText,
                                                Wrap = true,
                                            },
                                        },
                                        Style = AdaptiveContainerStyle.Emphasis,
                                    },
                                },
                            },
                        },
                    },
                    new AdaptiveContainer
                    {
                        Items = new List <AdaptiveElement>
                        {
                            new AdaptiveColumnSet
                            {
                                Columns = new List <AdaptiveColumn>
                                {
                                    new AdaptiveColumn
                                    {
                                        Items = new List <AdaptiveElement>
                                        {
                                            new AdaptiveTextBlock
                                            {
                                                Text = string.Format(CultureInfo.InvariantCulture, localizer.GetString("ApprovedCardLabelText"), dateString),
                                                Wrap = true,
                                            },
                                        },
                                    },
                                },
                            },
                        },
                    },
                },
            };
            var adaptiveCardAttachment = new Attachment()
            {
                ContentType = AdaptiveCard.ContentType,
                Content     = card,
            };

            return(adaptiveCardAttachment);
        }