/// <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));
        }
示例#3
0
        /// <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"),
                    },
                },
            });
        }
示例#4
0
        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;
            }
        }
示例#5
0
        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);
        }
示例#6
0
        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);
        }
示例#7
0
        /// <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());
        }
示例#8
0
        /// <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())));
        }
示例#9
0
        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;
            }
        }
示例#10
0
        /// <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);
        }
示例#11
0
        /// <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",
                        },
                    },
                });
            }
        }
示例#13
0
        // 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);
        }
示例#14
0
        /// <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);
        }
示例#15
0
        /// <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);
        }
示例#16
0
        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);
        }
示例#17
0
        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);
        }