Skip to content

Commit a01d9b9

Browse files
committed
Fixes an issue where adding members during group creation can fail with message 'Resource Not Found: groupKey [404]' (#7)
Fixes an issue where an Exported-change-not-reimported error occurs after deleting the last alias (#8)
1 parent 2fd7d6b commit a01d9b9

File tree

7 files changed

+127
-13
lines changed

7 files changed

+127
-13
lines changed

src/Lithnet.GoogleApps.MA.Setup/Product.wxs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<Product Id="*"
44
Name="Lithnet GoogleApps Management Agent"
55
Language="1033"
6-
Version="1.1.6090"
6+
Version="1.1.6093"
77
Manufacturer="Lithnet"
88
UpgradeCode="3410d571b358426281edb2990ae57cae" >
99

src/Lithnet.GoogleApps.MA.UnitTests/GroupTests.cs

Lines changed: 78 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,7 @@ public void Update()
235235
}
236236
}
237237
}
238-
238+
239239
[TestMethod]
240240
public void Delete()
241241
{
@@ -628,6 +628,80 @@ public void ReplaceAliases()
628628

629629
}
630630

631+
[TestMethod]
632+
public void AddGroupWithMembers()
633+
{
634+
string dn = $"{Guid.NewGuid()}@{UnitTestControl.TestParameters.Domain}";
635+
636+
CSEntryChange cs = CSEntryChange.Create();
637+
cs.ObjectModificationType = ObjectModificationType.Add;
638+
cs.DN = dn;
639+
cs.ObjectType = SchemaConstants.Group;
640+
cs.AttributeChanges.Add(AttributeChange.CreateAttributeAdd("name", Guid.NewGuid().ToString()));
641+
642+
Group group1;
643+
Group group2;
644+
string member1 = this.CreateGroup(out group1);
645+
string member2 = this.CreateGroup(out group2);
646+
string member3 = $"{Guid.NewGuid()}@{UnitTestControl.TestParameters.Domain}";
647+
648+
ManagedObjects.User e = new ManagedObjects.User
649+
{
650+
PrimaryEmail = member3,
651+
Password = Guid.NewGuid().ToString(),
652+
Name =
653+
{
654+
GivenName = "test",
655+
FamilyName = "test"
656+
}
657+
};
658+
659+
e = UserRequestFactory.Add(e);
660+
661+
cs.AttributeChanges.Add(AttributeChange.CreateAttributeAdd("member", new List<object>() { member1, member2 }));
662+
cs.AttributeChanges.Add(AttributeChange.CreateAttributeAdd("owner", new List<object>() { member3 }));
663+
664+
CSEntryChangeResult result = null;
665+
666+
try
667+
{
668+
result = ExportProcessor.PutCSEntryChange(cs, UnitTestControl.Schema.GetSchema().Types[SchemaConstants.Group]);
669+
670+
if (result.ErrorCode != MAExportError.Success)
671+
{
672+
Assert.Fail(result.ErrorName);
673+
}
674+
675+
System.Threading.Thread.Sleep(10000);
676+
677+
CollectionAssert.AreEquivalent(new string[] { member1, member2 }, GroupMemberRequestFactory.GetMembership(cs.DN).Members.ToArray());
678+
}
679+
finally
680+
{
681+
string id = result?.AnchorAttributes.FirstOrDefault()?.GetValueAdd<string>();
682+
683+
if (id != null)
684+
{
685+
GroupRequestFactory.Delete(id);
686+
}
687+
688+
if (group1?.Id != null)
689+
{
690+
GroupRequestFactory.Delete(group1.Id);
691+
}
692+
693+
if (group2?.Id != null)
694+
{
695+
GroupRequestFactory.Delete(group2.Id);
696+
}
697+
698+
if (e?.Id != null)
699+
{
700+
UserRequestFactory.Delete(e.Id);
701+
}
702+
}
703+
}
704+
631705
[TestMethod]
632706
public void AddMembers()
633707
{
@@ -668,6 +742,9 @@ public void AddMembers()
668742
{
669743
GroupRequestFactory.Delete(id);
670744
}
745+
746+
GroupRequestFactory.Delete(member1);
747+
GroupRequestFactory.Delete(member2);
671748
}
672749

673750
}

src/Lithnet.GoogleApps.MA/ApiInterfaces/ApiInterfaceGroup.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,9 @@ public IList<AttributeChange> ApplyChanges(CSEntryChange csentry, SchemaType typ
8888
{
8989
result.Group = GroupRequestFactory.Add(group.Group);
9090
group.Group = result.Group;
91+
92+
// Group membership operations fail on newly created groups if processed too quickly
93+
System.Threading.Thread.Sleep(1000);
9194
}
9295
else if (csentry.ObjectModificationType == ObjectModificationType.Replace || csentry.ObjectModificationType == ObjectModificationType.Update)
9396
{
@@ -111,7 +114,7 @@ public IList<AttributeChange> ApplyChanges(CSEntryChange csentry, SchemaType typ
111114

112115
changes.AddRange(this.GetLocalChanges(csentry.DN, csentry.ObjectModificationType, type, result));
113116
}
114-
117+
115118
foreach (IApiInterface i in ApiInterfaceGroup.internalInterfaces)
116119
{
117120
foreach (AttributeChange c in i.ApplyChanges(csentry, type, ref target, patch))

src/Lithnet.GoogleApps.MA/ApiInterfaces/ApiInterfaceGroupAliases.cs

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -51,11 +51,12 @@ public IList<AttributeChange> GetChanges(string dn, ObjectModificationType modTy
5151
return attributeChanges;
5252
}
5353

54-
private static void GetGroupAliasChanges(CSEntryChange csentry, Group group, out IList<string> aliasAdds, out IList<string> aliasDeletes)
54+
private static void GetGroupAliasChanges(CSEntryChange csentry, out IList<string> aliasAdds, out IList<string> aliasDeletes, out bool deletingAll)
5555
{
5656
aliasAdds = new List<string>();
5757
aliasDeletes = new List<string>();
5858
AttributeChange change = csentry.AttributeChanges.FirstOrDefault(t => t.Name == "aliases");
59+
deletingAll = false;
5960

6061
if (csentry.ObjectModificationType == ObjectModificationType.Replace)
6162
{
@@ -87,6 +88,8 @@ private static void GetGroupAliasChanges(CSEntryChange csentry, Group group, out
8788
{
8889
aliasDeletes.Add(alias);
8990
}
91+
92+
deletingAll = true;
9093
break;
9194

9295
case AttributeModificationType.Replace:
@@ -113,8 +116,9 @@ private static AttributeChange ApplyGroupAliasChanges(CSEntryChange csentry, Gro
113116
{
114117
IList<string> aliasAdds;
115118
IList<string> aliasDeletes;
119+
bool deletingAll;
116120

117-
ApiInterfaceGroupAliases.GetGroupAliasChanges(csentry, group, out aliasAdds, out aliasDeletes);
121+
ApiInterfaceGroupAliases.GetGroupAliasChanges(csentry, out aliasAdds, out aliasDeletes, out deletingAll);
118122

119123
if (aliasAdds.Count == 0 && aliasDeletes.Count == 0)
120124
{
@@ -157,7 +161,14 @@ private static AttributeChange ApplyGroupAliasChanges(CSEntryChange csentry, Gro
157161
{
158162
if (csentry.ObjectModificationType == ObjectModificationType.Update)
159163
{
160-
change = AttributeChange.CreateAttributeUpdate("aliases", valueChanges);
164+
if (deletingAll && valueChanges.Count == aliasDeletes?.Count)
165+
{
166+
change = AttributeChange.CreateAttributeDelete("aliases");
167+
}
168+
else
169+
{
170+
change = AttributeChange.CreateAttributeUpdate("aliases", valueChanges);
171+
}
161172
}
162173
else
163174
{
@@ -169,5 +180,4 @@ private static AttributeChange ApplyGroupAliasChanges(CSEntryChange csentry, Gro
169180
return change;
170181
}
171182
}
172-
}
173-
183+
}

src/Lithnet.GoogleApps.MA/ApiInterfaces/ApiInterfaceGroupMembership.cs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,12 @@ public IList<AttributeChange> ApplyChanges(CSEntryChange csentry, SchemaType typ
5555
}
5656
catch (AggregateGroupUpdateException ex)
5757
{
58+
Logger.WriteLine("The following member removals failed");
59+
foreach (Exception e in ex.Exceptions)
60+
{
61+
Logger.WriteException(e);
62+
}
63+
5864
ApiInterfaceGroupMembership.AddAttributeChange("member", modificationType, membershipToDelete.Members.Except(ex.FailedMembers).ToValueChange(ValueModificationType.Delete), changes);
5965
ApiInterfaceGroupMembership.AddAttributeChange("externalMember", modificationType, membershipToDelete.ExternalMembers.Except(ex.FailedMembers).ToValueChange(ValueModificationType.Delete), changes);
6066
ApiInterfaceGroupMembership.AddAttributeChange("manager", modificationType, membershipToDelete.Managers.Except(ex.FailedMembers).ToValueChange(ValueModificationType.Delete), changes);
@@ -94,6 +100,12 @@ public IList<AttributeChange> ApplyChanges(CSEntryChange csentry, SchemaType typ
94100
}
95101
catch (AggregateGroupUpdateException ex)
96102
{
103+
Logger.WriteLine("The following member additions failed");
104+
foreach(Exception e in ex.Exceptions)
105+
{
106+
Logger.WriteException(e);
107+
}
108+
97109
ApiInterfaceGroupMembership.AddAttributeChange("member", modificationType, membershipToAdd.Members.Except(ex.FailedMembers).ToValueChange(ValueModificationType.Add), changes);
98110
ApiInterfaceGroupMembership.AddAttributeChange("externalMember", modificationType, membershipToAdd.ExternalMembers.Except(ex.FailedMembers).ToValueChange(ValueModificationType.Add), changes);
99111
ApiInterfaceGroupMembership.AddAttributeChange("manager", modificationType, membershipToAdd.Managers.Except(ex.FailedMembers).ToValueChange(ValueModificationType.Add), changes);
@@ -228,7 +240,7 @@ private static void GetMemberChangesFromCSEntryChange(CSEntryChange csentry, out
228240
{
229241
adds = new GroupMembership();
230242
deletes = new GroupMembership();
231-
GroupMembership existingGroupMembership = null;
243+
GroupMembership existingGroupMembership;
232244

233245
if (ApiInterfaceGroupMembership.ExistingMembershipRequiredForUpdate(csentry) | replacing)
234246
{

src/Lithnet.GoogleApps.MA/ApiInterfaces/ApiInterfaceUserAliases.cs

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,12 @@ public IList<AttributeChange> GetChanges(string dn, ObjectModificationType modTy
4343
return attributeChanges;
4444
}
4545

46-
private static void GetUserAliasChanges(CSEntryChange csentry, User user, out IList<string> aliasAdds, out IList<string> aliasDeletes)
46+
private static void GetUserAliasChanges(CSEntryChange csentry, out IList<string> aliasAdds, out IList<string> aliasDeletes, out bool deletingAll)
4747
{
4848
aliasAdds = new List<string>();
4949
aliasDeletes = new List<string>();
5050
AttributeChange change = csentry.AttributeChanges.FirstOrDefault(t => t.Name == "aliases");
51+
deletingAll = false;
5152

5253
if (csentry.ObjectModificationType == ObjectModificationType.Replace)
5354
{
@@ -79,6 +80,8 @@ private static void GetUserAliasChanges(CSEntryChange csentry, User user, out IL
7980
{
8081
aliasDeletes.Add(alias);
8182
}
83+
84+
deletingAll = true;
8285
break;
8386

8487
case AttributeModificationType.Replace:
@@ -105,8 +108,9 @@ private static AttributeChange ApplyUserAliasChanges(CSEntryChange csentry, User
105108
{
106109
IList<string> aliasAdds;
107110
IList<string> aliasDeletes;
111+
bool deletingAll;
108112

109-
ApiInterfaceUserAliases.GetUserAliasChanges(csentry, user, out aliasAdds, out aliasDeletes);
113+
ApiInterfaceUserAliases.GetUserAliasChanges(csentry, out aliasAdds, out aliasDeletes, out deletingAll);
110114

111115
if (aliasAdds.Count == 0 && aliasDeletes.Count == 0)
112116
{
@@ -165,7 +169,14 @@ private static AttributeChange ApplyUserAliasChanges(CSEntryChange csentry, User
165169
{
166170
if (csentry.ObjectModificationType == ObjectModificationType.Update)
167171
{
168-
change = AttributeChange.CreateAttributeUpdate("aliases", valueChanges);
172+
if (deletingAll && valueChanges.Count == aliasDeletes?.Count)
173+
{
174+
change = AttributeChange.CreateAttributeDelete("aliases");
175+
}
176+
else
177+
{
178+
change = AttributeChange.CreateAttributeUpdate("aliases", valueChanges);
179+
}
169180
}
170181
else
171182
{
@@ -177,4 +188,4 @@ private static AttributeChange ApplyUserAliasChanges(CSEntryChange csentry, User
177188
return change;
178189
}
179190
}
180-
}
191+
}

src/Lithnet.GoogleApps.MA/Lithnet.GoogleApps.MA.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@
109109
</ItemGroup>
110110
<ItemGroup>
111111
<None Include="app.config" />
112+
<None Include="ClassDiagram1.cd" />
112113
<None Include="packages.config" />
113114
</ItemGroup>
114115
<ItemGroup>

0 commit comments

Comments
 (0)