private async Task PutGroupMembersMailNickname(CSEntryChange csentry, string teamID) { if (csentry.HasAttributeChange("mailNickname")) { Group group = new Group(); group.MailNickname = csentry.GetValueAdd <string>("mailNickname"); try { await GraphHelperGroups.UpdateGroup(this.client, teamID, group, this.token); logger.Info($"{csentry.DN}: Updated group {teamID}"); } catch (ServiceException ex) { if (MicrosoftTeamsMAConfigSection.Configuration.DeleteAddConflictingGroup && ex.StatusCode == HttpStatusCode.BadRequest && ex.Message.IndexOf("mailNickname", 0, StringComparison.Ordinal) > 0) { string mailNickname = csentry.GetValueAdd <string>("mailNickname"); logger.Warn($"{csentry.DN}: Deleting group with conflicting mailNickname '{mailNickname}'"); string existingGroup = await GraphHelperGroups.GetGroupIdByMailNickname(this.client, mailNickname, this.token); await GraphHelperGroups.DeleteGroup(this.client, existingGroup, this.token); await Task.Delay(TimeSpan.FromSeconds(MicrosoftTeamsMAConfigSection.Configuration.PostGroupCreateDelay), this.token); await GraphHelperGroups.UpdateGroup(this.client, teamID, group, this.token); logger.Info($"{csentry.DN}: Updated group {group.Id}"); } else { throw; } } } IList <string> members = csentry.GetValueAdds <string>("member") ?? new List <string>(); IList <string> owners = csentry.GetValueAdds <string>("owner") ?? new List <string>(); if (owners.Count > 0) { // Remove the first owner, as we already added them during team creation string initialOwner = owners[0]; owners.RemoveAt(0); // Teams API unhelpfully adds the initial owner as a member as well, so we need to undo that. await GraphHelperGroups.RemoveGroupMembers(this.client, teamID, new List <string> { initialOwner }, false, this.token); } if (owners.Count > 100) { throw new UnsupportedAttributeModificationException($"The group creation request {csentry.DN} contained more than 100 owners"); } await this.ApplyMembership(teamID, teamID, members, owners); }
private async Task <CSEntryChangeResult> PutCSEntryChangeAdd(CSEntryChange csentry) { string teamid = null; try { IList <string> owners = csentry.GetValueAdds <string>("owner") ?? new List <string>(); if (owners.Count == 0) { throw new InvalidProvisioningStateException("At least one owner is required to create a team"); } teamid = await this.CreateTeam(csentry, this.betaClient, owners.First()); await this.PutGroupMembersMailNickname(csentry, teamid); } catch { try { if (teamid != null) { logger.Error($"{csentry.DN}: An exception occurred while creating the team, rolling back by deleting it"); await Task.Delay(TimeSpan.FromSeconds(MicrosoftTeamsMAConfigSection.Configuration.PostGroupCreateDelay), this.token); await GraphHelperGroups.DeleteGroup(this.client, teamid, CancellationToken.None); logger.Info($"{csentry.DN}: The group was deleted"); } } catch (Exception ex2) { logger.Error(ex2, $"{csentry.DN}: An exception occurred while rolling back the team"); } throw; } List <AttributeChange> anchorChanges = new List <AttributeChange>(); anchorChanges.Add(AttributeChange.CreateAttributeAdd("id", teamid)); return(CSEntryChangeResult.Create(csentry.Identifier, anchorChanges, MAExportError.Success)); }
private async Task <CSEntryChangeResult> PutCSEntryChangeDelete(CSEntryChange csentry) { try { await GraphHelperGroups.DeleteGroup(this.client, csentry.DN, this.token); } catch (ServiceException ex) { if (ex.StatusCode == HttpStatusCode.NotFound) { logger.Warn($"The request to delete the group {csentry.DN} failed because the group doesn't exist"); } else { throw; } } return(CSEntryChangeResult.Create(csentry.Identifier, null, MAExportError.Success)); }
private async Task <CSEntryChangeResult> PutCSEntryChangeAdd(CSEntryChange csentry) { Group result = null; try { result = await this.CreateGroup(csentry); await this.CreateTeam(csentry, result.Id); } catch { try { if (result != null) { logger.Error($"{csentry.DN}: An exception occurred while creating the team, rolling back the group by deleting it"); await Task.Delay(TimeSpan.FromSeconds(MicrosoftTeamsMAConfigSection.Configuration.PostGroupCreateDelay)); await GraphHelperGroups.DeleteGroup(this.client, result.Id, CancellationToken.None); logger.Info($"{csentry.DN}: The group was deleted"); } } catch (Exception ex2) { logger.Error(ex2, $"{csentry.DN}: An exception occurred while rolling back the team"); } throw; } List <AttributeChange> anchorChanges = new List <AttributeChange>(); anchorChanges.Add(AttributeChange.CreateAttributeAdd("id", result.Id)); return(CSEntryChangeResult.Create(csentry.Identifier, anchorChanges, MAExportError.Success)); }
private async Task <CSEntryChangeResult> PutCSEntryChangeDelete(CSEntryChange csentry) { try { string teamid = csentry.GetAnchorValueOrDefault <string>("id"); await GraphHelperGroups.DeleteGroup(this.client, teamid, this.token); logger.Info($"The team {teamid} was deleted"); } catch (ServiceException ex) { if (ex.StatusCode == HttpStatusCode.NotFound) { logger.Warn($"The request to delete the team {csentry.DN} failed because the group doesn't exist"); } else { throw; } } return(CSEntryChangeResult.Create(csentry.Identifier, null, MAExportError.Success)); }
private async Task <Group> CreateGroup(CSEntryChange csentry) { Group group = new Group(); group.DisplayName = csentry.GetValueAdd <string>("displayName") ?? throw new UnexpectedDataException("The group must have a displayName"); group.GroupTypes = new[] { "Unified" }; group.MailEnabled = true; group.Description = csentry.GetValueAdd <string>("description"); group.MailNickname = csentry.GetValueAdd <string>("mailNickname") ?? throw new UnexpectedDataException("The group must have a mailNickname"); group.SecurityEnabled = false; group.AdditionalData = new Dictionary <string, object>(); group.Id = csentry.DN; group.Visibility = csentry.GetValueAdd <string>("visibility"); IList <string> members = csentry.GetValueAdds <string>("member") ?? new List <string>(); IList <string> owners = csentry.GetValueAdds <string>("owner") ?? new List <string>(); IList <string> deferredMembers = new List <string>(); IList <string> createOpMembers = new List <string>(); IList <string> deferredOwners = new List <string>(); IList <string> createOpOwners = new List <string>(); int memberCount = 0; if (owners.Count > 100) { throw new UnexpectedDataException($"The group creation request {csentry.DN} contained more than 100 owners"); } foreach (string owner in owners) { if (memberCount >= MaxReferencesPerCreateRequest) { deferredOwners.Add(owner); } else { createOpOwners.Add($"https://graph.microsoft.com/v1.0/users/{owner}"); memberCount++; } } foreach (string member in members) { if (memberCount >= MaxReferencesPerCreateRequest) { deferredMembers.Add(member); } else { createOpMembers.Add($"https://graph.microsoft.com/v1.0/users/{member}"); memberCount++; } } if (createOpMembers.Count > 0) { group.AdditionalData.Add("*****@*****.**", createOpMembers.ToArray()); } if (createOpOwners.Count > 0) { group.AdditionalData.Add("*****@*****.**", createOpOwners.ToArray()); } logger.Trace($"{csentry.DN}: Creating group {group.MailNickname} with {createOpMembers.Count} members and {createOpOwners.Count} owners (Deferring {deferredMembers.Count} members and {deferredOwners.Count} owners until after group creation)"); logger.Trace($"{csentry.DN}: Group data: {JsonConvert.SerializeObject(group)}"); Group result; try { result = await GraphHelperGroups.CreateGroup(this.client, group, this.token); } catch (ServiceException ex) { if (MicrosoftTeamsMAConfigSection.Configuration.DeleteAddConflictingGroup && ex.StatusCode == HttpStatusCode.BadRequest && ex.Message.IndexOf("mailNickname", 0, StringComparison.Ordinal) > 0) { string mailNickname = csentry.GetValueAdd <string>("mailNickname"); logger.Warn($"{csentry.DN}: Delete/Adding conflicting group with mailNickname '{mailNickname}'"); string existingGroup = await GraphHelperGroups.GetGroupIdByMailNickname(this.client, mailNickname, this.token); await GraphHelperGroups.DeleteGroup(this.client, existingGroup, this.token); await Task.Delay(TimeSpan.FromSeconds(MicrosoftTeamsMAConfigSection.Configuration.PostGroupCreateDelay)); result = await GraphHelperGroups.CreateGroup(this.client, group, this.token); } else { throw; } } logger.Info($"{csentry.DN}: Created group {group.Id}"); await Task.Delay(TimeSpan.FromSeconds(MicrosoftTeamsMAConfigSection.Configuration.PostGroupCreateDelay), this.token); try { await this.ProcessDeferredMembership(deferredMembers, result, deferredOwners, csentry.DN); } catch (Exception ex) { logger.Error(ex, $"{csentry.DN}: An exception occurred while modifying the membership, rolling back the group by deleting it"); await Task.Delay(TimeSpan.FromSeconds(5), this.token); await GraphHelperGroups.DeleteGroup(this.client, csentry.DN, CancellationToken.None); logger.Info($"{csentry.DN}: The group was deleted"); throw; } return(result); }