Exemplo n.º 1
0
        private async Task CreateChannelCSEntryChanges(string groupid, SchemaType schemaType)
        {
            if (!this.context.Types.Types.Contains("channel"))
            {
                return;
            }

            var channels = await GraphHelperTeams.GetChannels(this.betaClient, groupid, this.token);

            foreach (var channel in channels)
            {
                var members = await GraphHelperTeams.GetChannelMembers(this.betaClient, groupid, channel.Id, this.token);

                CSEntryChange c = CSEntryChange.Create();
                c.ObjectType             = "channel";
                c.ObjectModificationType = ObjectModificationType.Add;
                c.AnchorAttributes.Add(AnchorAttribute.Create("id", channel.Id));
                c.DN = channel.Id;

                c.AttributeChanges.Add(AttributeChange.CreateAttributeAdd("displayName", channel.DisplayName));

                if (!string.IsNullOrWhiteSpace(channel.Description))
                {
                    c.AttributeChanges.Add(AttributeChange.CreateAttributeAdd("description", channel.Description));
                }

                if (members.Count > 0)
                {
                    c.AttributeChanges.Add(AttributeChange.CreateAttributeAdd("member", members.Select(t => t.Id).ToList <object>()));
                }

                this.context.ImportItems.Add(c, this.token);
            }
        }
        private async Task PutMemberChanges(CSEntryChange csentry, string teamid, string channelid)
        {
            if (!csentry.HasAttributeChange("member") && !csentry.HasAttributeChange("owner"))
            {
                return;
            }

            IList <string> memberAdds    = csentry.GetValueAdds <string>("member");
            IList <string> memberDeletes = csentry.GetValueDeletes <string>("member");
            IList <string> ownerAdds     = csentry.GetValueAdds <string>("owner");
            IList <string> ownerDeletes  = csentry.GetValueDeletes <string>("owner");

            if (csentry.ObjectModificationType == ObjectModificationType.Add)
            {
                if (ownerAdds.Count > 0)
                {
                    ownerAdds.RemoveAt(0);
                }
            }

            if (csentry.HasAttributeChangeDelete("member") || csentry.HasAttributeChangeDelete("owner"))
            {
                var existingMembership = await GraphHelperTeams.GetChannelMembers(this.betaClient, teamid, channelid, this.token);

                if (csentry.HasAttributeChangeDelete("member"))
                {
                    memberDeletes = existingMembership.Where(t => !this.userFilter.ShouldExclude(t.Id, this.token) && (t.Roles == null || !t.Roles.Any(u => string.Equals(u, "owner", StringComparison.OrdinalIgnoreCase)))).Select(t => t.Id).ToList();
                }

                if (csentry.HasAttributeChangeDelete("owner"))
                {
                    ownerDeletes = existingMembership.Where(t => !this.userFilter.ShouldExclude(t.Id, this.token) && t.Roles != null && t.Roles.Any(u => string.Equals(u, "owner", StringComparison.OrdinalIgnoreCase))).Select(t => t.Id).ToList();
                }
            }

            var memberUpgradesToOwners = memberDeletes.Intersect(ownerAdds).ToList();

            foreach (var m in memberUpgradesToOwners)
            {
                memberDeletes.Remove(m);
                ownerAdds.Remove(m);
            }

            var ownerDowngradeToMembers = ownerDeletes.Intersect(memberAdds).ToList();

            foreach (var m in ownerDowngradeToMembers)
            {
                memberAdds.Remove(m);
                ownerDeletes.Remove(m);
            }

            List <Beta.AadUserConversationMember> cmToAdd    = new List <Beta.AadUserConversationMember>();
            List <Beta.AadUserConversationMember> cmToDelete = new List <Beta.AadUserConversationMember>();
            List <Beta.AadUserConversationMember> cmToUpdate = new List <Beta.AadUserConversationMember>();

            foreach (var m in memberDeletes)
            {
                cmToDelete.Add(GraphHelperTeams.CreateAadUserConversationMember(m));
            }

            // If we try to delete the last owner on a channel, the operation will fail. If we are swapping out the full set of owners (eg an add/delete of 100 owners), this will never succeed if we do a 'delete' operation first.
            // If we do an 'add' operation first, and the channel already has the maximum number of owners, the call will fail.
            // So the order of events should be to
            //    1) Process all membership removals except for one owner (100-99 = 1 owner)
            //    2) Process all membership adds except for one owner (1 + 99 = 100 owners)
            //    3) Remove the final owner (100 - 1 = 99 owners)
            //    4) Add the final owner (99 + 1 = 100 owners)

            string lastOwnerToRemove = null;

            if (ownerDeletes.Count > 0)
            {
                lastOwnerToRemove = ownerDeletes[0];
                ownerDeletes.RemoveAt(0);
            }

            string lastOwnerToAdd = null;

            if (ownerAdds.Count > 0)
            {
                lastOwnerToAdd = ownerAdds[0];
                ownerAdds.RemoveAt(0);
            }

            foreach (var m in ownerDeletes)
            {
                cmToDelete.Add(GraphHelperTeams.CreateAadUserConversationMember(m));
            }

            foreach (var m in memberAdds)
            {
                cmToAdd.Add(GraphHelperTeams.CreateAadUserConversationMember(m));
            }

            foreach (var m in ownerAdds)
            {
                cmToAdd.Add(GraphHelperTeams.CreateAadUserConversationMember(m, "owner"));
            }

            foreach (var m in memberUpgradesToOwners)
            {
                cmToUpdate.Add(GraphHelperTeams.CreateAadUserConversationMember(m, "owner"));
            }

            foreach (var m in ownerDowngradeToMembers)
            {
                cmToUpdate.Add(GraphHelperTeams.CreateAadUserConversationMember(m, (string[])null));
            }

            await GraphHelperTeams.RemoveChannelMembers(this.betaClient, teamid, channelid, cmToDelete, true, this.token);

            await GraphHelperTeams.UpdateChannelMembers(this.betaClient, teamid, channelid, cmToUpdate, this.token);

            await GraphHelperTeams.AddChannelMembers(this.betaClient, teamid, channelid, cmToAdd, true, this.token);

            if (lastOwnerToRemove != null)
            {
                cmToDelete.Clear();
                cmToDelete.Add(GraphHelperTeams.CreateAadUserConversationMember(lastOwnerToRemove));
                await GraphHelperTeams.RemoveChannelMembers(this.betaClient, teamid, channelid, cmToDelete, true, this.token);
            }

            if (lastOwnerToAdd != null)
            {
                cmToAdd.Clear();
                cmToAdd.Add(GraphHelperTeams.CreateAadUserConversationMember(lastOwnerToAdd, "owner"));
                await GraphHelperTeams.AddChannelMembers(this.betaClient, teamid, channelid, cmToAdd, true, this.token);
            }

            logger.Info($"Membership modification for channel {teamid}:{channelid} completed. Members added: {memberAdds.Count}, members removed: {memberDeletes.Count}, owners added: {ownerAdds.Count}, owners removed: {ownerDeletes.Count}, owners downgraded to members: {ownerDowngradeToMembers.Count}, members upgraded to owners: {memberUpgradesToOwners.Count}");
        }
        private async Task CreateChannelCSEntryChanges(string groupid)
        {
            if (!this.context.Types.Types.Contains("publicChannel") && !this.context.Types.Types.Contains("privateChannel"))
            {
                return;
            }

            var channels = await GraphHelperTeams.GetChannels(this.betaClient, groupid, this.token);

            Regex regex = null;

            if (!string.IsNullOrWhiteSpace(this.context.ConfigParameters[ConfigParameterNames.ChannelNameFilter].Value))
            {
                regex = new Regex(this.context.ConfigParameters[ConfigParameterNames.ChannelNameFilter].Value, RegexOptions.ExplicitCapture | RegexOptions.IgnoreCase);
            }

            foreach (var channel in channels)
            {
                string objectType;

                if (channel.MembershipType.HasValue)
                {
                    if (channel.MembershipType == Beta.ChannelMembershipType.UnknownFutureValue)
                    {
                        logger.Warn($"Ignoring unknown channel {channel.Id} of unknown type");
                        continue;
                    }
                    else
                    {
                        objectType = channel.MembershipType == Beta.ChannelMembershipType.Standard ? "publicChannel" : "privateChannel";
                    }
                }
                else
                {
                    objectType = "publicChannel";
                }

                if (!this.context.Types.Types.Contains(objectType))
                {
                    continue;
                }

                if (regex != null)
                {
                    if (!regex.IsMatch(channel.DisplayName))
                    {
                        logger.Trace($"Dropping channel {channel.Id} with display name {channel.DisplayName} as it did not match the regular expression filter");
                        continue;
                    }
                }

                CSEntryChange c = CSEntryChange.Create();

                c.ObjectModificationType = ObjectModificationType.Add;
                c.AnchorAttributes.Add(AnchorAttribute.Create("id", channel.Id));
                c.AnchorAttributes.Add(AnchorAttribute.Create("teamid", groupid));
                c.DN         = channel.Id;
                c.ObjectType = objectType;
                c.CreateAttributeAdd("team", groupid);

                SchemaType schemaType = this.context.Types.Types[objectType];

                if (schemaType.HasAttribute("displayName"))
                {
                    c.CreateAttributeAdd("displayName", channel.DisplayName);
                }

                if (schemaType.HasAttribute("description") && !string.IsNullOrWhiteSpace(channel.Description))
                {
                    c.CreateAttributeAdd("description", channel.Description);
                }

                if (schemaType.HasAttribute("email") && !string.IsNullOrWhiteSpace(channel.Email))
                {
                    c.CreateAttributeAdd("email", channel.Email);
                }

                if (schemaType.HasAttribute("webUrl") && !string.IsNullOrWhiteSpace(channel.WebUrl))
                {
                    c.CreateAttributeAdd("webUrl", channel.WebUrl);
                }

                if (schemaType.HasAttribute("isFavoriteByDefault"))
                {
                    c.CreateAttributeAdd("isFavoriteByDefault", channel.IsFavoriteByDefault ?? false);
                }

                if (channel.MembershipType == Beta.ChannelMembershipType.Private && (schemaType.HasAttribute("member") || schemaType.HasAttribute("owner")))
                {
                    List <Beta.AadUserConversationMember> members = await GraphHelperTeams.GetChannelMembers(this.betaClient, groupid, channel.Id, this.token);

                    if (members.Count > 0)
                    {
                        List <object> memberList = new List <object>();
                        List <object> ownerList  = new List <object>();

                        foreach (Beta.ConversationMember member in members)
                        {
                            string memberValue;

                            if (member is Beta.AadUserConversationMember conMember)
                            {
                                memberValue = conMember.UserId;
                            }
                            else
                            {
                                if (member.AdditionalData == null)
                                {
                                    logger.Warn("Member has no additional data and therefore no userId\r\n" + JsonConvert.SerializeObject(member));
                                    continue;
                                }

                                if (!member.AdditionalData.ContainsKey("userId"))
                                {
                                    logger.Warn("Member does not have userId\r\n" + JsonConvert.SerializeObject(member));
                                    continue;
                                }

                                memberValue = member.AdditionalData["userId"] as string;
                            }

                            if (memberValue == null)
                            {
                                logger.Warn("Member userId was null\r\n" + JsonConvert.SerializeObject(member));
                                continue;
                            }

                            if (this.userFilter.ShouldExclude(memberValue, this.token))
                            {
                                continue;
                            }

                            if (member.Roles.Contains("owner", StringComparer.OrdinalIgnoreCase))
                            {
                                ownerList.Add(memberValue);
                            }
                            else
                            {
                                memberList.Add(memberValue);
                            }
                        }

                        if (memberList.Count > 0 && schemaType.HasAttribute("member"))
                        {
                            c.CreateAttributeAdd("member", memberList);
                        }

                        if (ownerList.Count > 0 && schemaType.HasAttribute("owner"))
                        {
                            c.CreateAttributeAdd("owner", ownerList);
                        }
                    }
                }

                this.context.ImportItems.Add(c, this.token);
            }
        }