/// <summary> /// Send the nomination reminder notification to specified team. /// </summary> /// <param name="rewardCycleEntity">Reward cycle model object.</param> /// <returns>A task that sends notification card in channel.</returns> private async Task SendCardToTeamAsync(RewardCycleEntity rewardCycleEntity) { rewardCycleEntity = rewardCycleEntity ?? throw new ArgumentNullException(nameof(rewardCycleEntity)); var awardsList = await this.awardsStorageProvider.GetAwardsAsync(rewardCycleEntity.TeamId); var valuesFromTaskModule = new TaskModuleResponseDetails() { RewardCycleStartDate = rewardCycleEntity.RewardCycleStartDate, RewardCycleEndDate = rewardCycleEntity.RewardCycleEndDate, RewardCycleId = rewardCycleEntity.CycleId, }; var teamDetails = await this.teamStorageProvider.GetTeamDetailAsync(rewardCycleEntity.TeamId); string serviceUrl = teamDetails.ServiceUrl; MicrosoftAppCredentials.TrustServiceUrl(serviceUrl); string teamGeneralChannelId = rewardCycleEntity.TeamId; this.logger.LogInformation($"sending notification to channel id - {teamGeneralChannelId}"); await retryPolicy.ExecuteAsync(async() => { try { var conversationParameters = new ConversationParameters() { ChannelData = new TeamsChannelData() { Channel = new ChannelInfo() { Id = rewardCycleEntity.TeamId } }, Activity = (Activity)MessageFactory.Carousel(NominateCarouselCard.GetAwardNominationCards(this.options.Value.AppBaseUri, awardsList, this.localizer, valuesFromTaskModule)), }; Activity mentionActivity = MessageFactory.Text(this.localizer.GetString("NominationReminderNotificationText")); await((BotFrameworkAdapter)this.adapter).CreateConversationAsync( Constants.TeamsBotFrameworkChannelId, serviceUrl, this.microsoftAppCredentials, conversationParameters, async(conversationTurnContext, conversationCancellationToken) => { await conversationTurnContext.SendActivityAsync(mentionActivity, conversationCancellationToken); }, default); } catch (Exception ex) { this.logger.LogError(ex, "Error while sending mention card notification to channel."); throw; } }); }
/// <summary> /// This method will construct admin card with corresponding details. /// </summary> /// <param name="localizer">The current cultures' string localizer.</param> /// <param name="adminDetails">Admin details to show in card.</param> /// <returns>User welcome card.</returns> public static Attachment GetAdminCard(IStringLocalizer <Strings> localizer, TaskModuleResponseDetails adminDetails) { AdaptiveCard card = new AdaptiveCard(new AdaptiveSchemaVersion(Constants.AdaptiveCardVersion)) { Body = new List <AdaptiveElement> { new AdaptiveTextBlock { Text = localizer.GetString("AdminHeaderText"), Weight = AdaptiveTextWeight.Bolder, Size = AdaptiveTextSize.Large, }, new AdaptiveTextBlock { Text = localizer.GetString("AdminSubheaderText"), Spacing = AdaptiveSpacing.None, }, new AdaptiveTextBlock { Text = localizer.GetString("AdminName", adminDetails?.AdminName, adminDetails.AdminPrincipalName), Wrap = true, Spacing = AdaptiveSpacing.Default, }, new AdaptiveTextBlock { Text = localizer.GetString("NoteForTeamText", adminDetails.NoteForTeam), Wrap = true, Spacing = AdaptiveSpacing.Default, IsVisible = !string.IsNullOrEmpty(adminDetails.NoteForTeam), }, }, Actions = new List <AdaptiveAction> { new AdaptiveOpenUrlAction { Title = localizer.GetString("ManageRewardTitle"), Url = new System.Uri($"{GoToLink}threadId={adminDetails.TeamId}&ctx=channel"), }, }, }; return(new Attachment { ContentType = AdaptiveCard.ContentType, Content = card, }); }
/// <summary> /// This method will construct admin card with corresponding details. /// </summary> /// <param name="localizer">The current cultures' string localizer.</param> /// <param name="adminDetails">Admin details to show in card.</param> /// <returns>User welcome card.</returns> public static Attachment GetAdminCard(IStringLocalizer <Strings> localizer, TaskModuleResponseDetails adminDetails) { adminDetails = adminDetails ?? throw new ArgumentNullException(nameof(adminDetails)); AdaptiveCard card = new AdaptiveCard(new AdaptiveSchemaVersion(Constants.AdaptiveCardVersion)) { Body = new List <AdaptiveElement> { new AdaptiveTextBlock { Text = localizer.GetString("AdminHeaderText"), Weight = AdaptiveTextWeight.Bolder, Size = AdaptiveTextSize.Large, }, new AdaptiveTextBlock { Text = localizer.GetString("AdminSubheaderText", adminDetails.AdminName, adminDetails.AdminUserPrincipalName), Spacing = AdaptiveSpacing.None, }, new AdaptiveTextBlock { Text = localizer.GetString("NoteForTeamText", adminDetails.NoteForTeam), Wrap = true, Spacing = AdaptiveSpacing.Default, IsVisible = !string.IsNullOrEmpty(adminDetails.NoteForTeam), }, new AdaptiveTextBlock { Text = localizer.GetString("AdminTabNavigationText", adminDetails.NoteForTeam), Wrap = true, Spacing = AdaptiveSpacing.Large, Size = AdaptiveTextSize.Medium, Weight = AdaptiveTextWeight.Bolder, }, }, }; return(new Attachment { ContentType = AdaptiveCard.ContentType, Content = card, }); }
/// <summary> /// This method will construct admin card with corresponding details. /// </summary> /// <param name="localizer">The current cultures' string localizer.</param> /// <param name="adminDetails">Admin details to show in card.</param> /// <param name="manifestId">Unique id of manifest.</param> /// <returns>User welcome card.</returns> public static Attachment GetAdminCard(IStringLocalizer <Strings> localizer, TaskModuleResponseDetails adminDetails, string manifestId) { string context = HttpUtility.UrlEncode(JsonConvert.SerializeObject(new { channelId = adminDetails?.TeamId })); AdaptiveCard card = new AdaptiveCard(new AdaptiveSchemaVersion(Constants.AdaptiveCardVersion)) { Body = new List <AdaptiveElement> { new AdaptiveTextBlock { Text = localizer.GetString("AdminHeaderText"), Weight = AdaptiveTextWeight.Bolder, Size = AdaptiveTextSize.Large, }, new AdaptiveTextBlock { Text = localizer.GetString("AdminSubheaderText", adminDetails?.AdminName, adminDetails.AdminPrincipalName), Spacing = AdaptiveSpacing.None, }, new AdaptiveTextBlock { Text = localizer.GetString("NoteForTeamText", adminDetails.NoteForTeam), Wrap = true, Spacing = AdaptiveSpacing.Default, IsVisible = !string.IsNullOrEmpty(adminDetails.NoteForTeam), }, }, Actions = new List <AdaptiveAction> { new AdaptiveOpenUrlAction { Title = localizer.GetString("ManageRewardTitle"), Url = new System.Uri(string.Format(CultureInfo.InvariantCulture, Constants.TabDeepLink, manifestId, context)), }, }, }; return(new Attachment { ContentType = AdaptiveCard.ContentType, Content = card, }); }
/// <summary> /// Render the set of attachments that comprise carousel. /// </summary> /// <param name="applicationBasePath">Application base URL.</param> /// <param name="awards">award details.</param> /// <param name="localizer">The current cultures' string localizer.</param> /// <param name="details">Details to show in card.</param> /// <returns>The cards that comprise nominations.</returns> public static IEnumerable <Attachment> GetAwardsCard(string applicationBasePath, IEnumerable <AwardEntity> awards, IStringLocalizer <Strings> localizer, TaskModuleResponseDetails details) { var attachments = new List <Attachment>(); var startCycleDate = "{{DATE(" + details?.RewardCycleStartDate.ToString(Constants.Rfc3339DateTimeFormat, CultureInfo.InvariantCulture) + ", SHORT)}}"; var endCycleDate = "{{DATE(" + details?.RewardCycleEndDate.ToString(Constants.Rfc3339DateTimeFormat, CultureInfo.InvariantCulture) + ", SHORT)}}"; foreach (var award in awards) { AdaptiveCard carouselCard = new AdaptiveCard(new AdaptiveSchemaVersion(Constants.AdaptiveCardVersion)) { Body = new List <AdaptiveElement> { new AdaptiveTextBlock { Text = localizer.GetString("RewardTitle"), Weight = AdaptiveTextWeight.Bolder, Size = AdaptiveTextSize.Large, }, new AdaptiveImage { Url = string.IsNullOrEmpty(award.AwardLink) ? new Uri(string.Format(CultureInfo.InvariantCulture, "{0}/Content/DefaultAwardImage.png", applicationBasePath?.Trim('/'))) : new Uri(award.AwardLink), PixelWidth = PixelWidth, PixelHeight = PixelHeight, Size = AdaptiveImageSize.Auto, Style = AdaptiveImageStyle.Default, }, new AdaptiveTextBlock { Text = $"**{award.AwardName.Trim()}**", Size = AdaptiveTextSize.Large, Weight = AdaptiveTextWeight.Bolder, Spacing = AdaptiveSpacing.Small, Wrap = true, }, new AdaptiveTextBlock { Text = localizer.GetString("RewardCycleHeader", startCycleDate, endCycleDate), Size = AdaptiveTextSize.Small, Spacing = AdaptiveSpacing.Small, Wrap = true, }, new AdaptiveTextBlock { Text = award.AwardDescription, Size = AdaptiveTextSize.Small, Spacing = AdaptiveSpacing.Small, Wrap = true, }, }, Actions = new List <AdaptiveAction> { new AdaptiveSubmitAction { Title = localizer.GetString("NominateButtonText"), Data = new AdaptiveCardAction { MsteamsCardAction = new CardAction { Type = Constants.FetchActionType, }, Command = Constants.NominateAction, AwardId = award.AwardId, RewardCycleId = details.RewardCycleId, }, }, }, }; attachments.Add(new Attachment { ContentType = AdaptiveCard.ContentType, Content = carouselCard, }); } return(attachments); }
/// <summary> /// Render the set of attachments that comprise carousel. /// </summary> /// <param name="awards">award details.</param> /// <param name="localizer">The current cultures' string localizer.</param> /// <param name="details">Details to show in card.</param> /// <returns>The cards that comprise nominations.</returns> public static IEnumerable <Attachment> GetAwardsCard(IEnumerable <AwardEntity> awards, IStringLocalizer <Strings> localizer, TaskModuleResponseDetails details) { var attachments = new List <Attachment>(); var startCycleDate = "{{DATE(" + details?.RewardCycleStartDate.ToString(Constants.Rfc3339DateTimeFormat, CultureInfo.InvariantCulture) + ", SHORT)}}"; var endCycleDate = "{{DATE(" + details?.RewardCycleEndDate.ToString(Constants.Rfc3339DateTimeFormat, CultureInfo.InvariantCulture) + ", SHORT)}}"; foreach (var award in awards) { AdaptiveCard carouselCard = new AdaptiveCard(new AdaptiveSchemaVersion(Constants.AdaptiveCardVersion)) { Body = new List <AdaptiveElement> { new AdaptiveTextBlock { Text = localizer.GetString("RewardTitle"), Weight = AdaptiveTextWeight.Bolder, Size = AdaptiveTextSize.Large, }, new AdaptiveImage { Url = string.IsNullOrEmpty(award.AwardLink) ? default : new Uri(award.AwardLink), PixelWidth = PixelWidth, PixelHeight = PixelHeight, Size = AdaptiveImageSize.Auto, Style = AdaptiveImageStyle.Default, },
/// <summary> /// This method will construct endorse card with corresponding details. /// </summary> /// <param name="localizer">The current cultures' string localizer.</param> /// <param name="nominatedDetails">Nominated details to show in card.</param> /// <returns>Endorse card with nominated details.</returns> public static Attachment GetEndorseCard(IStringLocalizer <Strings> localizer, TaskModuleResponseDetails nominatedDetails) { AdaptiveCard card = new AdaptiveCard(new AdaptiveSchemaVersion(Constants.AdaptiveCardVersion)) { Body = new List <AdaptiveElement> { new AdaptiveColumnSet { Columns = new List <AdaptiveColumn> { new AdaptiveColumn { Width = "50", Items = new List <AdaptiveElement> { new AdaptiveTextBlock { Text = nominatedDetails?.AwardName, Wrap = true, HorizontalAlignment = AdaptiveHorizontalAlignment.Left, Weight = AdaptiveTextWeight.Bolder, Size = AdaptiveTextSize.Large, }, }, }, new AdaptiveColumn { Width = "100", Items = new List <AdaptiveElement> { new AdaptiveImage { Url = string.IsNullOrEmpty(nominatedDetails.AwardLink) ? default : new Uri(nominatedDetails.AwardLink), HorizontalAlignment = AdaptiveHorizontalAlignment.Right, PixelHeight = PixelHeight, PixelWidth = PixelWidth, }, }, }, }, },
/// <summary> /// This method will construct endorse card with corresponding details. /// </summary> /// <param name="applicationBasePath">Application base URL.</param> /// <param name="localizer">The current cultures' string localizer.</param> /// <param name="nominatedDetails">Nominated details to show in card.</param> /// <returns>Endorse card with nominated details.</returns> public static Attachment GetEndorseCard(string applicationBasePath, IStringLocalizer <Strings> localizer, TaskModuleResponseDetails nominatedDetails) { AdaptiveCard card = new AdaptiveCard(new AdaptiveSchemaVersion(Constants.AdaptiveCardVersion)) { Body = new List <AdaptiveElement> { new AdaptiveColumnSet { Columns = new List <AdaptiveColumn> { new AdaptiveColumn { Width = AdaptiveColumnWidth.Stretch, Items = new List <AdaptiveElement> { new AdaptiveTextBlock { Text = nominatedDetails?.AwardName, Wrap = true, HorizontalAlignment = AdaptiveHorizontalAlignment.Left, Weight = AdaptiveTextWeight.Bolder, Size = AdaptiveTextSize.Large, }, }, }, new AdaptiveColumn { Width = AdaptiveColumnWidth.Auto, Items = new List <AdaptiveElement> { new AdaptiveImage { Url = string.IsNullOrEmpty(nominatedDetails.AwardLink) ? new Uri(string.Format(CultureInfo.InvariantCulture, "{0}/Content/DefaultAwardImage.png", applicationBasePath?.Trim('/'))) : new Uri(nominatedDetails.AwardLink), HorizontalAlignment = AdaptiveHorizontalAlignment.Right, PixelHeight = PixelHeight, PixelWidth = PixelWidth, }, }, }, }, }, new AdaptiveTextBlock { Text = nominatedDetails.NominatedToName, Wrap = true, HorizontalAlignment = AdaptiveHorizontalAlignment.Left, Weight = AdaptiveTextWeight.Bolder, Spacing = AdaptiveSpacing.Large, }, new AdaptiveTextBlock { Text = localizer.GetString("NominatedByText", nominatedDetails.NominatedByName), Wrap = true, HorizontalAlignment = AdaptiveHorizontalAlignment.Left, Spacing = AdaptiveSpacing.Default, }, new AdaptiveTextBlock { Text = nominatedDetails.ReasonForNomination, Wrap = true, HorizontalAlignment = AdaptiveHorizontalAlignment.Left, Spacing = AdaptiveSpacing.Default, }, }, Actions = new List <AdaptiveAction> { new AdaptiveSubmitAction { Title = localizer.GetString("EndorseButtonText"), Data = new AdaptiveCardAction { MsteamsCardAction = new CardAction { Type = Constants.FetchActionType, }, Command = Constants.EndorseAction, NominatedToPrincipalName = nominatedDetails.NominatedToPrincipalName, AwardName = nominatedDetails.AwardName, NominatedToName = nominatedDetails.NominatedToName, NominatedToObjectId = nominatedDetails.NominatedToObjectId, AwardId = nominatedDetails.AwardId, RewardCycleId = nominatedDetails.RewardCycleId, }, }, }, }; return(new Attachment { ContentType = AdaptiveCard.ContentType, Content = card, }); }
/// <summary> /// This method will construct endorse card with corresponding details. /// </summary> /// <param name="applicationBasePath">Application base URL.</param> /// <param name="localizer">The current cultures' string localizer.</param> /// <param name="nominatedDetails">Nominated details to show in card.</param> /// <returns>Endorse card with nominated details.</returns> public static Attachment GetEndorseCard(string applicationBasePath, IStringLocalizer <Strings> localizer, TaskModuleResponseDetails nominatedDetails) { nominatedDetails = nominatedDetails ?? throw new ArgumentNullException(nameof(nominatedDetails)); AdaptiveCard card = new AdaptiveCard(new AdaptiveSchemaVersion(Constants.AdaptiveCardVersion)) { Body = new List <AdaptiveElement> { new AdaptiveColumnSet { Columns = new List <AdaptiveColumn> { new AdaptiveColumn { Width = AdaptiveColumnWidth.Stretch, Items = new List <AdaptiveElement> { new AdaptiveTextBlock { Text = nominatedDetails.AwardName, Wrap = true, HorizontalAlignment = AdaptiveHorizontalAlignment.Left, Weight = AdaptiveTextWeight.Bolder, Size = AdaptiveTextSize.Large, }, }, }, new AdaptiveColumn { Width = AdaptiveColumnWidth.Auto, Items = new List <AdaptiveElement> { new AdaptiveImage { Url = string.IsNullOrEmpty(nominatedDetails.AwardLink) ? new Uri(string.Format(CultureInfo.InvariantCulture, "{0}/Content/DefaultAwardImage.png", applicationBasePath)) : new Uri(nominatedDetails.AwardLink), HorizontalAlignment = AdaptiveHorizontalAlignment.Right, PixelHeight = AwardImagePixelHeight, PixelWidth = AwardImagePixelWidth, }, }, }, }, }, new AdaptiveTextBlock { Text = string.Join(", ", JsonConvert.DeserializeObject <List <string> >(nominatedDetails.GroupName)), Wrap = true, HorizontalAlignment = AdaptiveHorizontalAlignment.Left, Weight = AdaptiveTextWeight.Bolder, Spacing = AdaptiveSpacing.Large, }, new AdaptiveTextBlock { Text = localizer.GetString("NominatedByText", nominatedDetails.NominatedByName), Wrap = true, HorizontalAlignment = AdaptiveHorizontalAlignment.Left, Spacing = AdaptiveSpacing.Default, }, new AdaptiveTextBlock { Text = nominatedDetails.ReasonForNomination, Wrap = true, HorizontalAlignment = AdaptiveHorizontalAlignment.Left, Spacing = AdaptiveSpacing.Default, }, }, }; return(new Attachment { ContentType = AdaptiveCard.ContentType, Content = card, }); }
/// <summary> /// Send the given attachment to the specified team. /// </summary> /// <param name="rewardCycleEntity">Reward cycle model object.</param> /// <returns>A task that sends notification card in channel.</returns> private async Task SendCardToTeamAsync(RewardCycleEntity rewardCycleEntity) { try { var awardsList = await this.awardsStorageProvider.GetAwardsAsync(rewardCycleEntity.TeamId); var valuesfromTaskModule = new TaskModuleResponseDetails() { RewardCycleStartDate = rewardCycleEntity.RewardCycleStartDate, RewardCycleEndDate = rewardCycleEntity.RewardCycleEndDate, RewardCycleId = rewardCycleEntity.CycleId, }; var teamDetails = await this.teamStorageProvider.GetTeamDetailAsync(rewardCycleEntity.TeamId); string serviceUrl = teamDetails.ServiceUrl; MicrosoftAppCredentials.TrustServiceUrl(serviceUrl); string teamsChannelId = rewardCycleEntity.TeamId; var conversationReference = new ConversationReference() { ChannelId = Channel, Bot = new ChannelAccount() { Id = this.microsoftAppCredentials.MicrosoftAppId }, ServiceUrl = serviceUrl, Conversation = new ConversationAccount() { ConversationType = ChannelConversationType, IsGroup = true, Id = teamsChannelId, TenantId = teamsChannelId }, }; this.logger.LogInformation($"sending notification to channelId- {teamsChannelId}"); await retryPolicy.ExecuteAsync(async() => { try { var conversationParameters = new ConversationParameters() { ChannelData = new TeamsChannelData() { Team = new TeamInfo() { Id = rewardCycleEntity.TeamId }, Channel = new ChannelInfo() { Id = rewardCycleEntity.TeamId } }, Activity = (Activity)MessageFactory.Carousel(NominateCarouselCard.GetAwardsCard(this.options.Value.AppBaseUri, awardsList, this.localizer, valuesfromTaskModule)), Bot = new ChannelAccount() { Id = this.microsoftAppCredentials.MicrosoftAppId }, IsGroup = true, TenantId = this.options.Value.TenantId, }; await((BotFrameworkAdapter)this.adapter).CreateConversationAsync( Channel, serviceUrl, this.microsoftAppCredentials, conversationParameters, async(conversationTurnContext, conversationCancellationToken) => { Activity mentionActivity = MessageFactory.Text(this.localizer.GetString("NominationReminderNotificationText")); await((BotFrameworkAdapter)this.adapter).ContinueConversationAsync( this.microsoftAppCredentials.MicrosoftAppId, conversationTurnContext.Activity.GetConversationReference(), async(continueConversationTurnContext, continueConversationCancellationToken) => { mentionActivity.ApplyConversationReference(conversationTurnContext.Activity.GetConversationReference()); await continueConversationTurnContext.SendActivityAsync(mentionActivity, continueConversationCancellationToken); }, conversationCancellationToken); }, default); } catch (Exception ex) { this.logger.LogError(ex, "Error while performing retry logic to send notification to channel."); throw; } }); } catch (Exception ex) { this.logger.LogError(ex, "Error while sending notification to channel from background service."); } }