/// <summary> /// Fetches the roster with the new paginated calls to handles larger teams. /// https://docs.microsoft.com/en-us/microsoftteams/platform/bots/how-to/get-teams-context?tabs=dotnet#fetching-the-roster-or-user-profile. /// </summary> /// <param name="turnContext">The context object for this turn.</param> /// <param name="cancellationToken">A cancellation token that can be used by other objects.</param> /// <returns>The roster fetched by calling the new paginated SDK API.</returns> private async Task <IEnumerable <TeamsChannelAccount> > GetMembersAsync( ITurnContext turnContext, CancellationToken cancellationToken) { var members = new List <TeamsChannelAccount>(); string continuationToken = null; const int pageSize = 500; do { var currentPage = await TeamsInfo.GetPagedMembersAsync( turnContext, pageSize, continuationToken, cancellationToken); continuationToken = currentPage.ContinuationToken; // Skip Guest users. var membersWithoutGuests = currentPage.Members.Where(member => !member.UserPrincipalName.ToLower().Contains("#ext#")); members.AddRange(membersWithoutGuests); }while (continuationToken != null && !cancellationToken.IsCancellationRequested); return(members); }
/// <inheritdoc/> public override async Task <DialogTurnResult> BeginDialogAsync(DialogContext dc, object options = null, CancellationToken cancellationToken = default) { if (options is CancellationToken) { throw new ArgumentException($"{nameof(options)} cannot be a cancellation token"); } if (Disabled != null && Disabled.GetValue(dc.State)) { return(await dc.EndDialogAsync(cancellationToken : cancellationToken).ConfigureAwait(false)); } if (dc.Context.Activity.ChannelId != Channels.Msteams) { throw new InvalidOperationException($"{Kind} works only on the Teams channel."); } string continuationToken = ContinuationToken.GetValueOrNull(dc.State); int? pageSize = PageSize.GetValueOrNull(dc.State); var result = await TeamsInfo.GetPagedMembersAsync(dc.Context, pageSize, continuationToken, cancellationToken : cancellationToken).ConfigureAwait(false); if (Property != null) { dc.State.SetValue(Property.GetValue(dc.State), result); } return(await dc.EndDialogAsync(result, cancellationToken : cancellationToken).ConfigureAwait(false)); }
/// <summary> /// Get scrum details adaptive card response. /// </summary> /// <param name="scrumMembers">Members who are part of the scrum.</param> /// <param name="scrumTeamConfigId">Unique identifier for scrum team configuration details.</param> /// <param name="scrumStartActivityId">Scrum start card activity Id.</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>Returns scrum details card to be displayed in task module.</returns> public async Task <TaskModuleResponse> GetScrumDetailsCardResponseAsync(string scrumMembers, string scrumTeamConfigId, string scrumStartActivityId, ITurnContext <IInvokeActivity> turnContext, CancellationToken cancellationToken) { turnContext = turnContext ?? throw new ArgumentNullException(nameof(turnContext)); var activity = turnContext.Activity; this.logger.LogInformation($"Getting information about scrum with summaryCardId: {scrumStartActivityId}"); string aadGroupId = await this.activityHelper.GetTeamAadGroupIdAsync(turnContext, cancellationToken); var scrumSummary = (await this.scrumStorageProvider.GetScrumsByScrumStartActivityIdAsync(scrumStartActivityId, aadGroupId)).FirstOrDefault(); if (scrumSummary == null) { this.logger.LogInformation($"Value obtained from storage for scrum summary is null."); return(this.GetTaskModuleErrorResponse(string.Format(CultureInfo.CurrentCulture, this.localizer.GetString("ErrorScrumDoesNotExist"), activity.From.Name), this.localizer.GetString("ScrumDetailsTitle"))); } this.logger.LogInformation($"Received information about scrum with scrumId: {scrumSummary.ScrumId}"); var scrumStatusDetails = await this.scrumStatusStorageProvider.GetScrumStatusBySummaryCardIdAsync(scrumSummary.ScrumStartCardResponseId, aadGroupId); var membersActivityIdMap = JsonConvert.DeserializeObject <Dictionary <string, string> >(scrumMembers); var updatedScrumSummary = await this.scrumHelper.GetScrumSummaryAsync(scrumTeamConfigId, aadGroupId, scrumSummary.ScrumStartCardResponseId, membersActivityIdMap); if (scrumStatusDetails == null || updatedScrumSummary == null) { this.logger.LogInformation($"Value obtained from storage for scrum is null."); return(this.GetTaskModuleErrorResponse(string.Format(CultureInfo.CurrentCulture, this.localizer.GetString("ErrorScrumDoesNotExist"), activity.From.Name), this.localizer.GetString("ScrumDetailsTitle"))); } var scrumConfigurationDetails = await this.scrumConfigurationStorageProvider.GetScrumConfigurationDetailByScrumTeamConfigIdAsync(scrumSummary.ScrumTeamConfigId, scrumSummary.AadGroupId); activity.Conversation.Id = scrumConfigurationDetails.TeamId; var validScrumMembers = new List <TeamsChannelAccount>(); string continuationToken = null; do { var currentPage = await TeamsInfo.GetPagedMembersAsync(turnContext, 100, continuationToken, cancellationToken); continuationToken = currentPage.ContinuationToken; validScrumMembers.AddRange(currentPage.Members.Where(member => membersActivityIdMap.ContainsKey(member.Id))); }while (continuationToken != null); return(new TaskModuleResponse { Task = new TaskModuleContinueResponse { Value = new TaskModuleTaskInfo() { Card = ScrumCard.GetScrumDetailsCard(scrumStatusDetails, updatedScrumSummary, validScrumMembers, this.appBaseUri, this.localizer, scrumConfigurationDetails.TimeZone), Height = TaskModuleHeight, Width = TaskModuleWidth, Title = this.localizer.GetString("ScrumDetailsTitle"), }, }, }); }
public async Task <IActionResult> GetTeamDetailsAsync(string teamId) { try { var userClaims = this.GetUserClaims(); var teamsChannelAccounts = new List <TeamsChannelAccount>(); IEnumerable <ChannelInfo> teamsChannelInfo = new List <ChannelInfo>(); var conversationReference = new ConversationReference { ChannelId = teamId, ServiceUrl = userClaims.ServiceUrl, Bot = new ChannelAccount() { Id = this.appId }, Conversation = new ConversationAccount() { ConversationType = Constants.ConversationType, IsGroup = true, Id = teamId, TenantId = this.options.Value.TenantId }, }; await this.botAdapter.ContinueConversationAsync( this.appId, conversationReference, async (context, token) => { string continuationToken = null; do { var currentPage = await TeamsInfo.GetPagedMembersAsync(context, 100, continuationToken, CancellationToken.None); continuationToken = currentPage.ContinuationToken; teamsChannelAccounts.AddRange(currentPage.Members); }while (continuationToken != null); teamsChannelInfo = await TeamsInfo.GetTeamChannelsAsync(context, teamId, CancellationToken.None); }, default); this.logger.LogInformation("GET call for fetching team members and channels from team roster is successful"); teamsChannelInfo.First(channel => channel.Name == null).Name = Constants.GeneralChannel; var teamDetails = new { TeamMembers = teamsChannelAccounts.Select(member => new { content = member.Email, header = member.Name, aadobjectid = member.AadObjectId }), Channels = teamsChannelInfo.Select(member => new { ChannelId = member.Id, header = member.Name }), }; return(this.Ok(teamDetails)); } catch (Exception ex) { this.logger.LogError(ex, "Error occurred while getting team member list."); throw; } }
private async Task GetPagedMembers(ITurnContext <IMessageActivity> turnContext, CancellationToken cancellationToken) { var members = await TeamsInfo.GetPagedMembersAsync(turnContext, 1, null, cancellationToken).ConfigureAwait(false); var text = $"There are {members.Members.Count} people in the group."; foreach (var member in members.Members) { text += $" {member.Name}."; } await turnContext.SendActivityAsync(MessageFactory.Text(text), cancellationToken).ConfigureAwait(false); }
private static async Task <List <TeamsChannelAccount> > GetPagedMembers(ITurnContext <IMessageActivity> turnContext, CancellationToken cancellationToken) { var members = new List <TeamsChannelAccount>(); string continuationToken = null; do { var currentPage = await TeamsInfo.GetPagedMembersAsync(turnContext, 100, continuationToken, cancellationToken); continuationToken = currentPage.ContinuationToken; members = members.Concat(currentPage.Members).ToList(); }while (continuationToken != null); return(members); }
/// <summary> /// Get valid members in scrum and compares whether those members exist in the channel. /// </summary> /// <param name="turnContext">Context object containing information cached for a single turn of conversation with a user.</param> /// <param name="scrumMaster">Scrum master details.</param> /// <param name="cancellationToken">Propagates notification that operations should be canceled.</param> /// <returns>Returns list of valid members in scrum.</returns> public async Task <IEnumerable <TeamsChannelAccount> > GetValidMembersInScrumAsync(ITurnContext turnContext, ScrumMaster scrumMaster, CancellationToken cancellationToken) { var teamsChannelAccounts = new List <TeamsChannelAccount>(); string continuationToken = null; do { var currentPage = await TeamsInfo.GetPagedMembersAsync(turnContext, 100, continuationToken, cancellationToken); continuationToken = currentPage.ContinuationToken; teamsChannelAccounts.AddRange(currentPage.Members); }while (continuationToken != null); var validusers = scrumMaster?.UserPrincipalNames.Split(',').Where(email => !string.IsNullOrEmpty(email)); return(teamsChannelAccounts.Where(member => validusers.Any(user => user.Equals(member.UserPrincipalName, StringComparison.OrdinalIgnoreCase))).ToList()); }
/// <inheritdoc/> public async Task <IEnumerable <Member> > GetCourseMembersAsync(TeamInfo teamInfo, ITurnContext turnContext, CancellationToken cancellationToken) { // Note: We do not filter guest users. var members = new List <TeamsChannelAccount>(); string continuationToken = null; do { var currentPage = await TeamsInfo.GetPagedMembersAsync(turnContext, 500 /*pageSize*/, continuationToken, cancellationToken); continuationToken = currentPage.ContinuationToken; members = members.Concat(currentPage.Members).ToList(); }while (continuationToken != null); var owners = await this.teamInfoService.GetTeamOwnersIdsAsync(teamInfo.AadGroupId); return(members .Select(member => this.ConvertToMember(member, owners.ToHashSet()))); }
public static async Task <bool> IsBotAddedToTheConversationAsync(this ITurnContext context) { try { // https://docs.microsoft.com/en-us/microsoftteams/platform/resources/messaging-extension-v3/create-extensions?tabs=typescript#request-to-install-your-conversational-bot // https://docs.microsoft.com/en-us/microsoftteams/platform/bots/how-to/get-teams-context?tabs=dotnet#fetching-the-roster-or-user-profile // https://stackoverflow.com/questions/58866100/operation-returned-an-invalid-status-code-forbidden-when-calling-getconversati await TeamsInfo.GetPagedMembersAsync(context); return(true); } catch (HttpOperationException ex) { if (ex.Response.StatusCode == System.Net.HttpStatusCode.Forbidden) { return(false); } throw; } }
/// <summary> /// Fetches the roster with the new paginated calls to handles larger teams. /// https://docs.microsoft.com/en-us/microsoftteams/platform/bots/how-to/get-teams-context?tabs=dotnet#fetching-the-roster-or-user-profile. /// </summary> /// <param name="turnContext">The context object for this turn.</param> /// <param name="cancellationToken">A cancellation token that can be used by other objects.</param> /// <returns>The roster fetched by calling the new paginated SDK API.</returns> private async Task <IEnumerable <TeamsChannelAccount> > GetMembersAsync( ITurnContext turnContext, CancellationToken cancellationToken) { var members = new List <TeamsChannelAccount>(); string continuationToken = null; const int pageSize = 500; do { var currentPage = await TeamsInfo.GetPagedMembersAsync( turnContext, pageSize, continuationToken, cancellationToken); continuationToken = currentPage.ContinuationToken; members.AddRange(currentPage.Members); }while (continuationToken != null && !cancellationToken.IsCancellationRequested); return(members); }
/// <summary> /// Get list of members present in the team. /// </summary> /// <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>Returns list of members present in the team.</returns> public async Task <IEnumerable <TeamsChannelAccount> > GetMembersInTeamAsync(ITurnContext turnContext, CancellationToken cancellationToken) { try { var teamsChannelAccounts = new List <TeamsChannelAccount>(); string continuationToken = null; do { var currentPage = await TeamsInfo.GetPagedMembersAsync(turnContext, 100, continuationToken, cancellationToken); continuationToken = currentPage.ContinuationToken; teamsChannelAccounts.AddRange(currentPage.Members); }while (continuationToken != null); return(teamsChannelAccounts); } catch (Exception ex) { this.logger.LogError(ex, "Error while obtaining team members of the team."); throw; } }
protected override async Task <MessagingExtensionActionResponse> OnTeamsMessagingExtensionFetchTaskAsync(ITurnContext <IInvokeActivity> turnContext, MessagingExtensionAction action, CancellationToken cancellationToken) { try { string continuationToken = null; var currentPage = await TeamsInfo.GetPagedMembersAsync(turnContext, 100, continuationToken, cancellationToken); return(new MessagingExtensionActionResponse { Task = new TaskModuleContinueResponse { Value = new TaskModuleTaskInfo { Card = CreateAdaptiveCardAttachment(), Height = 200, Width = 400, Title = "Adaptive Card: Inputs", }, }, }); } catch (Exception) { return(new MessagingExtensionActionResponse { Task = new TaskModuleContinueResponse { Value = new TaskModuleTaskInfo { Card = GetInstallationPage(), Height = 200, Width = 400, Title = "Adaptive Card: Inputs", }, }, }); } }
// 1. Will be called when user triggers messaging extension which then calls CreateTaskModuleCommand protected override async Task <MessagingExtensionActionResponse> OnTeamsMessagingExtensionFetchTaskAsync(ITurnContext <IInvokeActivity> turnContext, MessagingExtensionAction action, CancellationToken cancellationToken) { // Check if the bot has been installed in the team by getting the team rooster try { var teamsMembers = await TeamsInfo.GetMembersAsync(turnContext); } catch { // if not installed we will send out the card instructing the user to install the bot string jitCardPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Cards", "jitCard.json"); var jitCard = File.ReadAllText(jitCardPath, Encoding.UTF8); string jitCardJson = jitCard; var jitCardTeams = AdaptiveCard.FromJson(jitCardJson); return(await Task.FromResult(new MessagingExtensionActionResponse { Task = new TaskModuleContinueResponse { Value = new TaskModuleTaskInfo { Card = new Attachment { Content = jitCardTeams.Card, ContentType = AdaptiveCard.ContentType, }, Height = 300, Width = 600, Title = "Install bot", }, }, })); } var magicCode = string.Empty; var state = (turnContext.Activity.Value as Newtonsoft.Json.Linq.JObject).Value <string>("state"); if (!string.IsNullOrEmpty(state)) { int parsed = 0; if (int.TryParse(state, out parsed)) { magicCode = parsed.ToString(); } } var tokenResponse = await(turnContext.Adapter as IUserTokenProvider).GetUserTokenAsync(turnContext, _connectionName, magicCode, cancellationToken: cancellationToken); if (tokenResponse == null || string.IsNullOrEmpty(tokenResponse.Token)) { // There is no token, so the user has not signed in yet. // Retrieve the OAuth Sign in Link to use in the MessagingExtensionResult Suggested Actions var signInLink = await(turnContext.Adapter as IUserTokenProvider).GetOauthSignInLinkAsync(turnContext, _connectionName, cancellationToken); return(new MessagingExtensionActionResponse { ComposeExtension = new MessagingExtensionResult { Type = "auth", SuggestedActions = new MessagingExtensionSuggestedAction { Actions = new List <CardAction> { new CardAction { Type = ActionTypes.OpenUrl, Value = signInLink, Title = "Sign in Please", }, }, }, }, }); } var accessToken = tokenResponse.Token; if (accessToken != null || !string.IsNullOrEmpty(accessToken)) { // Create Graph Client var client = new SimpleGraphClient(accessToken); // Get Group details var channel = turnContext.Activity.TeamsGetChannelId(); if (channel != null) { var members = new List <TeamsChannelAccount>(); string continuationToken = null; do { var currentPage = await TeamsInfo.GetPagedMembersAsync(turnContext, 100, continuationToken, cancellationToken); continuationToken = currentPage.ContinuationToken; members = members.Concat(currentPage.Members).ToList(); }while (continuationToken != null); TeamDetails teamDetails = await TeamsInfo.GetTeamDetailsAsync(turnContext, turnContext.Activity.TeamsGetTeamInfo().Id, cancellationToken); if (teamDetails != null) { var groupId = teamDetails.AadGroupId; plannerGroupId = groupId; //Get Plans var currentGroupPlan = await client.GetCurrentPlan(groupId); var favoritePlans = await client.GetFavoritePlans(); // Fill Adaptive Card data var exampleData = new ExampleData(); exampleData.MultiSelect = "false"; if (currentGroupPlan.CurrentPage.Count == 0) { exampleData.Option1 = favoritePlans.CurrentPage[4].Title; exampleData.Option1Value = favoritePlans.CurrentPage[4].Id; } else { exampleData.Option1 = currentGroupPlan.CurrentPage[0].Title; exampleData.Option1Value = currentGroupPlan.CurrentPage[0].Id; } exampleData.Option2 = favoritePlans.CurrentPage[0].Title; exampleData.Option3 = favoritePlans.CurrentPage[1].Title; exampleData.Option4 = favoritePlans.CurrentPage[2].Title; exampleData.Option2Value = favoritePlans.CurrentPage[0].Id; exampleData.Option3Value = favoritePlans.CurrentPage[1].Id; exampleData.Option4Value = favoritePlans.CurrentPage[2].Id; // Create and return card var adaptiveCardEditor = AdaptiveCardHelper.CreateAdaptiveCardEditor(exampleData); //var adaptiveCardEditor = CreateAdaptiveCard(); return(await Task.FromResult(new MessagingExtensionActionResponse { Task = new TaskModuleContinueResponse { Value = new TaskModuleTaskInfo { Card = new Microsoft.Bot.Schema.Attachment { Content = adaptiveCardEditor, ContentType = AdaptiveCard.ContentType, }, Height = 600, Width = 600, Title = "Task creation", }, }, })); } } else { // Return only favorite plans without current plan as in 1:1 or group chat var favoritePlans = await client.GetFavoritePlans(); // Fill Adaptive Card data var exampleData = new ExampleData(); exampleData.MultiSelect = "false"; exampleData.Option1 = favoritePlans.CurrentPage[0].Title; exampleData.Option2 = favoritePlans.CurrentPage[1].Title; exampleData.Option3 = favoritePlans.CurrentPage[2].Title; exampleData.Option1Value = favoritePlans.CurrentPage[0].Id; exampleData.Option3Value = favoritePlans.CurrentPage[1].Id; exampleData.Option4Value = favoritePlans.CurrentPage[2].Id; // Create and return card var adaptiveCardEditor = AdaptiveCardHelper.CreateAdaptiveCardEditor(exampleData); //var adaptiveCardEditor = CreateAdaptiveCard(); return(await Task.FromResult(new MessagingExtensionActionResponse { Task = new TaskModuleContinueResponse { Value = new TaskModuleTaskInfo { Card = new Microsoft.Bot.Schema.Attachment { Content = adaptiveCardEditor, ContentType = AdaptiveCard.ContentType, }, Height = 600, Width = 600, Title = "Task creation", }, }, })); } } //Needs to be replaced with OAuth Prompt return(null); }
/// <summary> /// Invoked when an invoke activity is received from the connector. /// </summary> /// <param name="turnContext">The turn context.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>A task that represents the work queued to execute.</returns> protected override async Task <InvokeResponse> OnInvokeActivityAsync(ITurnContext <IInvokeActivity> turnContext, CancellationToken cancellationToken) { if (turnContext.Activity.Name == "adaptiveCard/action") { var data = JsonConvert.DeserializeObject <InitialSequentialCard>(turnContext.Activity.Value.ToString()); string verb = data.action.verb; AdaptiveCardInvokeResponse adaptiveCardResponse; string cardJson; JObject response; switch (verb) { case "initialRefresh": string[] initialCard = { ".", "Cards", "RequestCard.json" }; adaptiveCardResponse = GetNextActionCard(initialCard, data); return(CreateInvokeResponse(adaptiveCardResponse)); case "requestCard": string[] firstCard = { ".", "Cards", "RequestDetailsCardForUser.json" }; var assigneeInfo = await TeamsInfo.GetMemberAsync(turnContext, data.action.data.AssignedTo, cancellationToken); data.action.data.UserMRI = assigneeInfo.Id; data.action.data.CreatedById = turnContext.Activity.From.Id; data.action.data.AssignedToName = assigneeInfo.Name; var members = new List <TeamsChannelAccount>(); string continuationToken = null; do { var currentPage = await TeamsInfo.GetPagedMembersAsync(turnContext, 100, continuationToken, cancellationToken); continuationToken = currentPage.ContinuationToken; members.AddRange(currentPage.Members); }while (continuationToken != null); foreach (var member in members) { if (member.AadObjectId != turnContext.Activity.From.AadObjectId) { var newMemberInfo = member.Id; memberDetails.Add(newMemberInfo); } } data.action.data.UserId = memberDetails; var responseAttachment = GetResponseAttachment(firstCard, data, out cardJson); Activity pendingActivity = new Activity(); pendingActivity.Type = "message"; pendingActivity.Id = turnContext.Activity.ReplyToId; pendingActivity.Attachments = new List <Attachment> { responseAttachment }; await turnContext.UpdateActivityAsync(pendingActivity); response = JObject.Parse(cardJson); adaptiveCardResponse = new AdaptiveCardInvokeResponse() { StatusCode = 200, Type = "application/vnd.microsoft.card.adaptive", Value = response }; return(CreateInvokeResponse(adaptiveCardResponse)); case "refresh": if (turnContext.Activity.From.Id == data.action.data.UserMRI) { string[] assignedToCard = { ".", "Cards", "AssignedToCard.json" }; adaptiveCardResponse = GetNextActionCard(assignedToCard, data); return(CreateInvokeResponse(adaptiveCardResponse)); } else { string[] othersCard = { ".", "Cards", "OtherMembersCard.json" }; adaptiveCardResponse = GetNextActionCard(othersCard, data); return(CreateInvokeResponse(adaptiveCardResponse)); } case "cancelCard": string[] cancelCard = { ".", "Cards", "CancelCard.json" }; var cancelCardResponse = GetResponseAttachment(cancelCard, data, out cardJson); Activity canceledActivity = new Activity(); canceledActivity.Type = "message"; canceledActivity.Id = turnContext.Activity.ReplyToId; canceledActivity.Attachments = new List <Attachment> { cancelCardResponse }; await turnContext.UpdateActivityAsync(canceledActivity); response = JObject.Parse(cardJson); adaptiveCardResponse = new AdaptiveCardInvokeResponse() { StatusCode = 200, Type = "application/vnd.microsoft.card.adaptive", Value = response }; return(CreateInvokeResponse(adaptiveCardResponse)); case "approved": string[] approvedCard = { ".", "Cards", "ApprovedCard.json" }; var approvedAttachment = GetResponseAttachment(approvedCard, data, out cardJson); Activity approvedActivity = new Activity(); approvedActivity.Type = "message"; approvedActivity.Id = turnContext.Activity.ReplyToId; approvedActivity.Attachments = new List <Attachment> { approvedAttachment }; await turnContext.UpdateActivityAsync(approvedActivity); response = JObject.Parse(cardJson); adaptiveCardResponse = new AdaptiveCardInvokeResponse() { StatusCode = 200, Type = "application/vnd.microsoft.card.adaptive", Value = response }; return(CreateInvokeResponse(adaptiveCardResponse)); case "rejected": string[] rejectedCard = { ".", "Cards", "RejectedCard.json" }; var rejectedAttachment = GetResponseAttachment(rejectedCard, data, out cardJson); Activity rejectedActivity = new Activity(); rejectedActivity.Type = "message"; rejectedActivity.Id = turnContext.Activity.ReplyToId; rejectedActivity.Attachments = new List <Attachment> { rejectedAttachment }; await turnContext.UpdateActivityAsync(rejectedActivity); response = JObject.Parse(cardJson); adaptiveCardResponse = new AdaptiveCardInvokeResponse() { StatusCode = 200, Type = "application/vnd.microsoft.card.adaptive", Value = response }; return(CreateInvokeResponse(adaptiveCardResponse)); } } return(null); }
/// <summary> /// To fetch members of all LnD teams /// Return null if the members not found in team id or either of the information is incorrect. /// Caller should handle null value to throw unauthorized if required /// </summary> /// <returns>The LnD team members</returns> public async Task <List <TeamsChannelAccount> > GetAllLnDTeamMembersAsync() { var cachedMembers = this.cache.Get("all-team-members"); if (cachedMembers != null) { return(cachedMembers as List <TeamsChannelAccount>); } List <TeamsChannelAccount> allLnDTeamMembers = null; try { var lnDTeams = await this.teamConfigurationRepository.GetTeamsAsync(); if (lnDTeams.IsNullOrEmpty()) { return(allLnDTeamMembers); } allLnDTeamMembers = new List <TeamsChannelAccount>(); foreach (var teamDetails in lnDTeams) { try { await this.retryPolicy.ExecuteAsync(async() => { if (teamDetails == null) { this.logger.LogError($"GetAllLnDTeamMembersAsync- The team details are not available for team {teamDetails.TeamId}"); return; } string serviceUrl = teamDetails.ServiceUrl; var conversationReference = new ConversationReference() { ChannelId = Constants.TeamsBotFrameworkChannelId, Bot = new ChannelAccount() { Id = this.microsoftAppCredentials.MicrosoftAppId }, ServiceUrl = serviceUrl, Conversation = new ConversationAccount() { ConversationType = ConversationTypes.Channel, IsGroup = true, Id = teamDetails.TeamId }, }; await((BotFrameworkAdapter)this.botAdapter).ContinueConversationAsync( this.microsoftAppCredentials.MicrosoftAppId, conversationReference, async(context, token) => { var members = new List <TeamsChannelAccount>(); string continuationToken = null; do { var currentPage = await TeamsInfo.GetPagedMembersAsync(context, 100, continuationToken, token); continuationToken = currentPage.ContinuationToken; members.AddRange(currentPage.Members); }while (continuationToken != null); allLnDTeamMembers.AddRange(members); }, default); }); } #pragma warning disable CA1031 // Catching general exception to continue the execution catch (Exception ex) #pragma warning restore CA1031 // Catching general exception to continue the execution { this.logger.LogError(ex, $"Error while getting team members for team {teamDetails.TeamId}"); } } } #pragma warning disable CA1031 // Catching general exceptions to log exception details in telemetry client. catch (Exception ex) #pragma warning restore CA1031 // Catching general exceptions to log exception details in telemetry client. { this.logger.LogError(ex, $"Error occurred while fetching LnD teams' members for one or multiple teams"); return(allLnDTeamMembers); } this.cache.Set("all-team-members", allLnDTeamMembers.Count == 0 ? null : allLnDTeamMembers, TimeSpan.FromMinutes(30)); return(allLnDTeamMembers); }
protected override async Task <InvokeResponse> OnInvokeActivityAsync(ITurnContext <IInvokeActivity> turnContext, CancellationToken cancellationToken) { List <IncidentDetails> currentIncidentList = new List <IncidentDetails>(); incidentDetailsList.TryGetValue("incidentList", out currentIncidentList); if (turnContext.Activity.Name == "composeExtension/submitAction") { var asJobject = JObject.FromObject(turnContext.Activity.Value); var data = (object)asJobject.ToObject <CardTaskFetchValue <object> >()?.Data; var botInstalled = (object)JObject.Parse(data.ToString()).ToObject <CardTaskFetchValue <object> >()?.MsTeams; if (botInstalled != null) { return(GetIncientListFromMEAction(currentIncidentList)); } else { var incidentId = (string)JObject.Parse(data.ToString()).ToObject <CardTaskFetchValue <string> >()?.IncidentId; var incidentDetail = currentIncidentList.FirstOrDefault(incident => incident.IncidentId.ToString() == incidentId); await turnContext.SendActivityAsync(MessageFactory.Attachment(CardHelper.GetIncidentReviewCard(incidentDetail))); return(CreateInvokeResponse()); } } if (turnContext.Activity.Name == "composeExtension/fetchTask") { try { // Check if your app is installed by fetching member information. var member = await TeamsInfo.GetMemberAsync(turnContext, turnContext.Activity.From.Id, cancellationToken); return(GetIncientListFromMEAction(currentIncidentList)); } catch (ErrorResponseException ex) { if (ex.Body.Error.Code == "BotNotInConversationRoster") { string[] paths = { ".", "Resources", "justInTimeInstall.json" }; var adaptiveCardJson = File.ReadAllText(Path.Combine(paths)); var adaptiveCardAttachment = new Attachment() { ContentType = AdaptiveCard.ContentType, Content = JsonConvert.DeserializeObject(adaptiveCardJson), }; return(CreateInvokeResponse(new MessagingExtensionActionResponse { Task = new TaskModuleContinueResponse { Value = new TaskModuleTaskInfo { Card = adaptiveCardAttachment, Height = 200, Width = 400, Title = "Bot is not installed", }, }, })); } } } if (turnContext.Activity.Name == "adaptiveCard/action") { var data = JsonConvert.DeserializeObject <InitialSequentialCard>(turnContext.Activity.Value.ToString()); string verb = data.action.verb; AdaptiveCardInvokeResponse adaptiveCardResponse; string cardJson; JObject response; switch (verb) { case "initialRefresh": string[] initialCard = { ".", "Resources", "firstCard.json" }; var members = new List <TeamsChannelAccount>(); string continuationToken = null; do { var currentPage = await TeamsInfo.GetPagedMembersAsync(turnContext, 100, continuationToken, cancellationToken); continuationToken = currentPage.ContinuationToken; members.AddRange(currentPage.Members); }while (continuationToken != null); foreach (var member in members) { if (member.AadObjectId != turnContext.Activity.From.AadObjectId) { var newMemberInfo = new Info { value = member.AadObjectId, title = member.Name }; memberDetails.Add(newMemberInfo); } } adaptiveCardResponse = GetNextActionCard(initialCard, data); return(CreateInvokeResponse(adaptiveCardResponse)); case "firstCard": string[] firstCard = { ".", "Resources", "secondCard.json" }; var assigneeInfo = await TeamsInfo.GetMemberAsync(turnContext, data.action.data.AssignedTo, cancellationToken); data.action.data.UserMRI = assigneeInfo.Id; adaptiveCardResponse = GetNextActionCard(firstCard, data); return(CreateInvokeResponse(adaptiveCardResponse)); case "secondCard": string[] secondCard = { ".", "Resources", "thirdCard.json" }; if (data.action.data.Category == "Software") { adaptiveCardResponse = GetNextActionCard(secondCard, data, Constants.Software); } else { adaptiveCardResponse = GetNextActionCard(secondCard, data, Constants.Hardware); } return(CreateInvokeResponse(adaptiveCardResponse)); case "thirdCard": var initiator = await TeamsInfo.GetMemberAsync(turnContext, data.action.data.AssignedTo, cancellationToken); data.action.data.AssignedToName = initiator.Name; var incidentDetail = new IncidentDetails { IncidentId = Guid.NewGuid(), CreatedBy = turnContext.Activity.From.Name, AssignedToMRI = data.action.data.UserMRI, AssignedToName = data.action.data.AssignedToName, Category = data.action.data.Category, IncidentTitle = data.action.data.IncidentTitle, SubCategory = data.action.data.SubCategory }; data.action.data.IncidentId = incidentDetail.IncidentId; string[] thirdCard = { ".", "Resources", "reviewCard.json" }; var responseAttachment = CardHelper.GetResponseAttachment(thirdCard, data, out cardJson); Activity pendingActivity = new Activity(); pendingActivity.Type = "message"; pendingActivity.Id = turnContext.Activity.ReplyToId; pendingActivity.Attachments = new List <Attachment> { responseAttachment }; await turnContext.UpdateActivityAsync(pendingActivity); response = JObject.Parse(cardJson); adaptiveCardResponse = new AdaptiveCardInvokeResponse() { StatusCode = 200, Type = AdaptiveCard.ContentType, Value = response }; if (currentIncidentList == null) { currentIncidentList = new List <IncidentDetails> { incidentDetail }; } else { List <IncidentDetails> incidentList = new List <IncidentDetails>(); incidentList = currentIncidentList; incidentList.Add(incidentDetail); currentIncidentList = incidentList; } incidentDetailsList.AddOrUpdate("incidentList", currentIncidentList, (key, value) => currentIncidentList); return(CreateInvokeResponse(adaptiveCardResponse)); case "refresh": string[] assignedToCard = { ".", "Resources", "assignedToCard.json" }; adaptiveCardResponse = GetNextActionCard(assignedToCard, data); return(CreateInvokeResponse(adaptiveCardResponse)); case "approved": string[] approvedCard = { ".", "Resources", "approvedCard.json" }; var approvedAttachment = CardHelper.GetResponseAttachment(approvedCard, data, out cardJson); Activity approvedActivity = new Activity(); approvedActivity.Type = "message"; approvedActivity.Id = turnContext.Activity.ReplyToId; approvedActivity.Attachments = new List <Attachment> { approvedAttachment }; await turnContext.UpdateActivityAsync(approvedActivity); response = JObject.Parse(cardJson); adaptiveCardResponse = new AdaptiveCardInvokeResponse() { StatusCode = 200, Type = AdaptiveCard.ContentType, Value = response }; return(CreateInvokeResponse(adaptiveCardResponse)); case "rejected": string[] rejectedCard = { ".", "Resources", "rejectedCard.json" }; var rejectedAttachment = CardHelper.GetResponseAttachment(rejectedCard, data, out cardJson); Activity rejectedActivity = new Activity(); rejectedActivity.Type = "message"; rejectedActivity.Id = turnContext.Activity.ReplyToId; rejectedActivity.Attachments = new List <Attachment> { rejectedAttachment }; await turnContext.UpdateActivityAsync(rejectedActivity); response = JObject.Parse(cardJson); adaptiveCardResponse = new AdaptiveCardInvokeResponse() { StatusCode = 200, Type = AdaptiveCard.ContentType, Value = response }; return(CreateInvokeResponse(adaptiveCardResponse)); } } return(null); }
protected override async Task <InvokeResponse> OnInvokeActivityAsync(ITurnContext <IInvokeActivity> turnContext, CancellationToken cancellationToken) { if (AdaptiveCardInvokeValidator.IsAdaptiveCardAction(turnContext) && (turnContext.Activity.Name == "adaptiveCard/action")) { var userSA = _userState.CreateProperty <User>(nameof(User)); var user = await userSA.GetAsync(turnContext, () => new User() { Id = turnContext.Activity.From.Id }); try { AdaptiveCardInvoke request = AdaptiveCardInvokeValidator.ValidateRequest(turnContext); if (request.Action.Verb == "initialRefresh") { var members = new List <TeamsChannelAccount>(); string continuationToken = null; do { var currentPage = await TeamsInfo.GetPagedMembersAsync(turnContext, 100, continuationToken, cancellationToken); continuationToken = currentPage.ContinuationToken; members.AddRange(currentPage.Members); }while (continuationToken != null); foreach (var member in members) { if (member.AadObjectId != turnContext.Activity.From.AadObjectId) { var newMemberInfo = new MemberDetails { value = member.Id, title = member.Name }; memberDetails.Add(newMemberInfo); } } var cardOptions = AdaptiveCardInvokeValidator.ValidateAction <InitialCardOptions>(request); var responseBody = await ProcessCreateIncident(cardOptions, turnContext); return(CreateInvokeResponse(responseBody)); } else if (request.Action.Verb == "createIncident") { var cardOptions = AdaptiveCardInvokeValidator.ValidateAction <CreateIncidentCardOptions>(request); var responseBody = await ProcessReviewIncident(cardOptions, turnContext); return(CreateInvokeResponse(responseBody)); } else if (request.Action.Verb == "editOrResolveIncident") { var cardOptions = AdaptiveCardInvokeValidator.ValidateAction <ReviewIncidentCardOptions>(request); if (cardOptions.createdByUserID == turnContext.Activity.From.Id) { var responseBody = await ProcessCancelOrResolveIncident("CancelIncident.json", cardOptions, turnContext); return(CreateInvokeResponse(responseBody)); } else if (cardOptions.assignedToUserID == turnContext.Activity.From.Id) { var responseBody = await ProcessCancelOrResolveIncident("ResolveIncident.json", cardOptions, turnContext); return(CreateInvokeResponse(responseBody)); } } else if (request.Action.Verb == "cancelIncident" || request.Action.Verb == "resolveIncident") { var cardOptions = AdaptiveCardInvokeValidator.ValidateAction <CancelOrResolveIncidentOptions>(request); var responseBody = await CloseIncident(request.Action.Verb, cardOptions, turnContext); return(CreateInvokeResponse(responseBody)); } else { AdaptiveCardActionException.VerbNotSupported(request.Action.Type); } } catch (AdaptiveCardActionException e) { return(CreateInvokeResponse(HttpStatusCode.OK, e.Response)); } } return(null); }