Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Start trying to remove graph api sdk dependency #1003

Open
wants to merge 76 commits into
base: dev
Choose a base branch
from
Open
Changes from 1 commit
Commits
Show all changes
76 commits
Select commit Hold shift + click to select a range
2fbaeb4
Switch caught exception usage
quails4Eva Apr 1, 2024
9626e86
Replace graph api sdk usage with http client usage
quails4Eva Apr 1, 2024
d3867f1
Update version of System.Text.Json used
quails4Eva May 15, 2024
22297cc
Replace Newtonsoft.Json with system.text.json
quails4Eva May 15, 2024
280db1d
Update Microsoft.Bcl.AsyncInterfaces
quails4Eva May 15, 2024
5c1b2ff
Re-use existing item group
quails4Eva May 15, 2024
c0098e4
Replace some graph api exception usage
quails4Eva May 15, 2024
6c45fdf
Add async version of MakeHttpRequest
quails4Eva May 15, 2024
c137c80
Replace a delete group usage
quails4Eva May 15, 2024
014dd41
Throw more specific exception when http error
quails4Eva May 15, 2024
68c6983
Replace delete call
quails4Eva May 15, 2024
c7f922f
CreateSubscription to use http client
quails4Eva May 27, 2024
d6a3e24
Update patch
quails4Eva May 27, 2024
5e8d822
Update delete
quails4Eva May 27, 2024
32e7b28
Update ListSubscriptions
quails4Eva May 27, 2024
f2cc5f7
Implement range selection
quails4Eva May 27, 2024
6c7acc9
Remove unused async -> sync
quails4Eva May 27, 2024
e30cd74
Add todo
quails4Eva May 27, 2024
d8d503c
Replace graph api usage
quails4Eva Jun 1, 2024
1484fbc
fix build issue
quails4Eva Jun 1, 2024
4cffde9
Fix build issue
quails4Eva Jun 1, 2024
8d979cf
.
quails4Eva Jun 1, 2024
a1b75ba
Remove some graph api usage
quails4Eva Jun 1, 2024
62fbf58
Remove graph api usage from Delete Group
quails4Eva Jun 1, 2024
4a1baaa
Remove unused code
quails4Eva Jun 1, 2024
cd6f09d
Maintain stack info
quails4Eva Jun 1, 2024
f9e6df3
Fix exception type
quails4Eva Jun 1, 2024
3a6104e
Update InviteGuestUser to not use graph nuget
quails4Eva Jun 1, 2024
f174b41
Remove unused task.run
quails4Eva Jun 1, 2024
e50af31
Tidy exception handling
quails4Eva Jun 8, 2024
a35d919
Replace graph api usage
quails4Eva Jun 8, 2024
54f6f4b
Rename group
quails4Eva Jul 20, 2024
321fc21
Update GetUnifiedGroup to not use grapn api sdk
quails4Eva Jul 20, 2024
2ea945c
Replace GetGroups graph api sdk usage
quails4Eva Jul 20, 2024
b03a32a
Replace Graph SDK in Create Group
quails4Eva Sep 29, 2024
476a0b8
Fix exception handling
quails4Eva Sep 29, 2024
5ce9af3
Don't use Graph SDK for RemoveGroupMembers
quails4Eva Sep 29, 2024
e2b4910
Remove unused code
quails4Eva Sep 29, 2024
e4aaf0a
Remove Graph SDK from RemoveGroupOwners
quails4Eva Sep 29, 2024
8b3e3ef
change naming
quails4Eva Sep 29, 2024
05403d5
Fix UpdateGroup setup
quails4Eva Sep 29, 2024
ad6ef23
Start updating UpdateMembers to use less Graph SDK
quails4Eva Sep 29, 2024
2435d06
Reduce Graph SDK use in UpdateOwners
quails4Eva Sep 29, 2024
a634d10
Remove direct use of Graph SDK from UpdateGroup
quails4Eva Sep 29, 2024
e95beaa
Replace direct Graph SDK usage in UpdateGroup
quails4Eva Sep 29, 2024
4b0fd00
Add helper method for reading paged data
quails4Eva Nov 17, 2024
769b909
Iterate paged owners and members without graph api sdk
quails4Eva Nov 17, 2024
62939e2
Remove unused ref to graph client and update exception type
quails4Eva Nov 17, 2024
12e30fe
Remaining GroupsUtility code to not use Graph SDK, allow custom deser…
quails4Eva Nov 17, 2024
301d6e7
Tidy async and tasks
quails4Eva Nov 17, 2024
ffc0d5e
Remove unused consts
quails4Eva Nov 17, 2024
cf619ed
Copy some methods from GroupsUtility to UnifiedGroupsUtility
quails4Eva Nov 17, 2024
25783a5
Copy some code from Group to UnifiedGroup utility
quails4Eva Nov 17, 2024
29bfccb
Get user ids without graph api sdk
quails4Eva Nov 23, 2024
2994cb9
Convert UpdateUnifiedGroup to not use Graph Api SDK
quails4Eva Nov 23, 2024
60293ae
Add missing content type
quails4Eva Nov 23, 2024
c2dcfcc
Use const for json content type
quails4Eva Nov 23, 2024
ac75bbd
Update Renew to not use Graph Api SDK
quails4Eva Nov 23, 2024
cac4566
Update CreateUnifiedGroup to not use Graph Api SDK
quails4Eva Nov 23, 2024
f373293
ListUnifiedGroups to not use Graph Api SDK
quails4Eva Nov 23, 2024
bb97d36
GetUnifiedGroups to not use Graph Api SDK
quails4Eva Nov 23, 2024
7ed9e96
GetUnifiedGroupMembers to not us MS Graph SDK
quails4Eva Dec 7, 2024
af15c73
Same for owners
quails4Eva Dec 7, 2024
6f99942
Remove unused code
quails4Eva Dec 7, 2024
ebbae7a
Update GetNestedUnifiedGroupMembers
quails4Eva Dec 7, 2024
6099479
Remove unused code
quails4Eva Dec 7, 2024
3cdc1a1
ListUsers to not use MS Graph Api SDK
quails4Eva Dec 7, 2024
6df9841
Fix start and end index
quails4Eva Dec 7, 2024
5355b6f
Replace use of MS Graph Api SDK
quails4Eva Dec 7, 2024
6a3d2e9
Remove PnPHttpProvider
quails4Eva Dec 7, 2024
b0ceb5c
Re-use json options
quails4Eva Dec 7, 2024
2372b67
Merge
quails4Eva Dec 7, 2024
a5d6613
Remove extra package added
quails4Eva Dec 7, 2024
81db6cc
Remove Microsoft.Graph package
quails4Eva Jan 11, 2025
47a75b0
Minor updates
quails4Eva Jan 11, 2025
281de1f
Remove Microsoft.Graph.Core
quails4Eva Jan 11, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Update CreateUnifiedGroup to not use Graph Api SDK
quails4Eva committed Nov 23, 2024
commit cac456655a3e1e30d3044f93927b8908eb210335
20 changes: 20 additions & 0 deletions src/lib/PnP.Framework/Graph/Model/GroupExtended.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using Newtonsoft.Json;
using System.Collections.Generic;

namespace PnP.Framework.Graph.Model
{
internal class GroupExtended : Group
{
#pragma warning disable CA1819
[JsonProperty("owners@odata.bind", NullValueHandling = NullValueHandling.Ignore)]
public string[] OwnersODataBind { get; set; }
[JsonProperty("members@odata.bind", NullValueHandling = NullValueHandling.Ignore)]
public string[] MembersODataBind { get; set; }
#pragma warning restore CA1819

public List<GroupLabel> AssignedLabels { get; set; }
public string PreferredDataLocation { get; set; }

public Dictionary<string, object> AdditionalData { get; set; }
}
}
8 changes: 8 additions & 0 deletions src/lib/PnP.Framework/Graph/Model/GroupLabel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@

namespace PnP.Framework.Graph.Model
{
public class GroupLabel
{
public string LabelId { get; set; }
}
}
235 changes: 109 additions & 126 deletions src/lib/PnP.Framework/Graph/UnifiedGroupsUtility.cs
Original file line number Diff line number Diff line change
@@ -15,15 +15,6 @@

namespace PnP.Framework.Graph
{
public class GroupExtended : Group
{
#pragma warning disable CA1819
[JsonProperty("owners@odata.bind", NullValueHandling = NullValueHandling.Ignore)]
public string[] OwnersODataBind { get; set; }
[JsonProperty("members@odata.bind", NullValueHandling = NullValueHandling.Ignore)]
public string[] MembersODataBind { get; set; }
#pragma warning restore CA1819
}
/// <summary>
/// Class that deals with Unified group CRUD operations.
/// </summary>
@@ -124,8 +115,6 @@ public static UnifiedGroupEntity CreateUnifiedGroup(string displayName, string d
bool isPrivate = false, bool createTeam = false, int retryCount = 10, int delay = 500, AzureEnvironment azureEnvironment = AzureEnvironment.Production,
Enums.Office365Geography? preferredDataLocation = null, Guid[] assignedLabels = null, bool welcomeEmailDisabled = false)
{
UnifiedGroupEntity result = null;

if (string.IsNullOrEmpty(displayName))
{
throw new ArgumentNullException(nameof(displayName));
@@ -141,14 +130,14 @@ public static UnifiedGroupEntity CreateUnifiedGroup(string displayName, string d
throw new ArgumentNullException(nameof(accessToken));
}

var labels = new List<AssignedLabel>();
var labels = new List<Model.GroupLabel>();
if (assignedLabels != null)
{
foreach (var label in assignedLabels)
{
if (!Guid.Empty.Equals(label))
{
labels.Add(new AssignedLabel
labels.Add(new Model.GroupLabel
{
LabelId = label.ToString()
});
@@ -159,161 +148,155 @@ public static UnifiedGroupEntity CreateUnifiedGroup(string displayName, string d

try
{
// Use a synchronous model to invoke the asynchronous process
result = Task.Run(async () =>
var group = new UnifiedGroupEntity();

// Prepare the group resource object
var newGroup = new Model.GroupExtended
{
var group = new UnifiedGroupEntity();
DisplayName = displayName,
Description = string.IsNullOrEmpty(description) ? null : description,
MailNickname = mailNickname,
MailEnabled = true,
SecurityEnabled = false,
Visibility = isPrivate == true ? "Private" : "Public",
GroupTypes = new string[] { "Unified" }
};

var graphClient = CreateGraphClient(accessToken, retryCount, delay, azureEnvironment);
if (labels.Any())
{
newGroup.AssignedLabels = labels;
}

// Prepare the group resource object
var newGroup = new GroupExtended
{
DisplayName = displayName,
Description = string.IsNullOrEmpty(description) ? null : description,
MailNickname = mailNickname,
MailEnabled = true,
SecurityEnabled = false,
Visibility = isPrivate == true ? "Private" : "Public",
GroupTypes = new List<string> { "Unified" }
};
if (preferredDataLocation.HasValue)
{
newGroup.PreferredDataLocation = preferredDataLocation.Value.ToString();
}

if (labels.Any())
if (owners != null && owners.Length > 0)
{
var users = GetUserIds(accessToken, owners, retryCount, delay, azureEnvironment);
if (users != null && users.Count > 0)
{
newGroup.AssignedLabels = labels;
newGroup.OwnersODataBind = users.Select(u => $"https://{AuthenticationManager.GetGraphEndPoint(azureEnvironment)}/v1.0/users/{u}").ToArray();
}
}

if (preferredDataLocation.HasValue)
if (members != null && members.Length > 0)
{
var users = GetUserIds(accessToken, owners, retryCount, delay, azureEnvironment);
if (users != null && users.Count > 0)
{
newGroup.PreferredDataLocation = preferredDataLocation.Value.ToString();
newGroup.MembersODataBind = users.Select(u => $"https://{AuthenticationManager.GetGraphEndPoint(azureEnvironment)}/v1.0/users/{u}").ToArray();
}
}

if (owners != null && owners.Length > 0)
if (welcomeEmailDisabled)
{
if (newGroup.AdditionalData == null)
{
var users = GetUserIds(accessToken, owners, retryCount,delay, azureEnvironment);
if (users != null && users.Count > 0)
{
newGroup.OwnersODataBind = users.Select(u => $"https://{AuthenticationManager.GetGraphEndPoint(azureEnvironment)}/v1.0/users/{u}").ToArray();
}
newGroup.AdditionalData = new Dictionary<string, object>();
}
newGroup.AdditionalData.Add("resourceBehaviorOptions", new string[] { "WelcomeEmailDisabled" });
}

if (members != null && members.Length > 0)
{
var users = GetUserIds(accessToken, owners, retryCount, delay, azureEnvironment);
if (users != null && users.Count > 0)
{
newGroup.MembersODataBind = users.Select(u => $"https://{AuthenticationManager.GetGraphEndPoint(azureEnvironment)}/v1.0/users/{u}").ToArray();
}
}
//Microsoft.Graph.Group addedGroup = null;
string modernSiteUrl = null;

if (welcomeEmailDisabled)
{
if (newGroup.AdditionalData == null)
{
newGroup.AdditionalData = new Dictionary<string, object>();
}
newGroup.AdditionalData.Add("resourceBehaviorOptions", new string[] { "WelcomeEmailDisabled" });
}
// Add the group to the collection of groups (if it does not exist)
var groupRequestUrl = $"{GraphHttpClient.GetGraphEndPointUrl(azureEnvironment)}groups";
var responseAsString = HttpHelper.MakePostRequestForString(groupRequestUrl, newGroup, HttpHelper.JsonContentType, accessToken, retryCount: retryCount, delay: delay);
var addedGroup = JsonConvert.DeserializeObject<Model.GroupExtended>(responseAsString);

Microsoft.Graph.Group addedGroup = null;
string modernSiteUrl = null;
if (addedGroup != null)
{
group.DisplayName = addedGroup.DisplayName;
group.Description = addedGroup.Description;
group.GroupId = addedGroup.GroupId;
group.Mail = addedGroup.Mail;
group.MailNickname = addedGroup.MailNickname;

// Add the group to the collection of groups (if it does not exist)
if (addedGroup == null)
{
addedGroup = await graphClient.Groups.Request().AddAsync(newGroup);
int imageRetryCount = retryCount;

if (addedGroup != null)
if (groupLogo != null)
{
using (var memGroupLogo = new MemoryStream())
{
group.DisplayName = addedGroup.DisplayName;
group.Description = addedGroup.Description;
group.GroupId = addedGroup.Id;
group.Mail = addedGroup.Mail;
group.MailNickname = addedGroup.MailNickname;
groupLogo.CopyTo(memGroupLogo);

int imageRetryCount = retryCount;

if (groupLogo != null)
while (imageRetryCount > 0)
{
using (var memGroupLogo = new MemoryStream())
bool groupLogoUpdated = false;
memGroupLogo.Position = 0;

using (var tempGroupLogo = new MemoryStream())
{
groupLogo.CopyTo(memGroupLogo);
memGroupLogo.CopyTo(tempGroupLogo);
tempGroupLogo.Position = 0;

while (imageRetryCount > 0)
try
{
groupLogoUpdated = UpdateUnifiedGroup(addedGroup.GroupId, accessToken, groupLogo: tempGroupLogo, azureEnvironment: azureEnvironment);
}
catch
{
bool groupLogoUpdated = false;
memGroupLogo.Position = 0;

using (var tempGroupLogo = new MemoryStream())
{
memGroupLogo.CopyTo(tempGroupLogo);
tempGroupLogo.Position = 0;

try
{
groupLogoUpdated = UpdateUnifiedGroup(addedGroup.Id, accessToken, groupLogo: tempGroupLogo, azureEnvironment: azureEnvironment);
}
catch
{
// Skip any exception and simply retry
}
}

// In case of failure retry up to 10 times, with 500ms delay in between
if (!groupLogoUpdated)
{
// Pop up the delay for the group image
await Task.Delay(delay * (retryCount - imageRetryCount));
imageRetryCount--;
}
else
{
break;
}
// Skip any exception and simply retry
}
}
}

int driveRetryCount = retryCount;

while (driveRetryCount > 0 && string.IsNullOrEmpty(modernSiteUrl))
{
try
// In case of failure retry up to 10 times, with 500ms delay in between
if (!groupLogoUpdated)
{
modernSiteUrl = GetUnifiedGroupSiteUrl(addedGroup.Id, accessToken, azureEnvironment: azureEnvironment);
// Pop up the delay for the group image
Task.Delay(delay * (retryCount - imageRetryCount)).GetAwaiter().GetResult();
imageRetryCount--;
}
catch
else
{
// Skip any exception and simply retry
}

// In case of failure retry up to 10 times, with 500ms delay in between
if (string.IsNullOrEmpty(modernSiteUrl))
{
await Task.Delay(delay * (retryCount - driveRetryCount));
driveRetryCount--;
break;
}
}

group.SiteUrl = modernSiteUrl;
}
}

if (createTeam)
int driveRetryCount = retryCount;

while (driveRetryCount > 0 && string.IsNullOrEmpty(modernSiteUrl))
{
await CreateTeam(group.GroupId, accessToken, azureEnvironment: azureEnvironment);
try
{
modernSiteUrl = GetUnifiedGroupSiteUrl(addedGroup.GroupId, accessToken, azureEnvironment: azureEnvironment);
}
catch
{
// Skip any exception and simply retry
}

// In case of failure retry up to 10 times, with 500ms delay in between
if (string.IsNullOrEmpty(modernSiteUrl))
{
Task.Delay(delay * (retryCount - driveRetryCount)).GetAwaiter().GetResult();
driveRetryCount--;
}
}

return (group);
group.SiteUrl = modernSiteUrl;
}

}).GetAwaiter().GetResult();
if (createTeam)
{
Task.Run(async () =>
{
await CreateTeam(group.GroupId, accessToken, azureEnvironment: azureEnvironment);
}).GetAwaiter().GetResult();
}

return group;
}
catch (ServiceException ex)
catch (HttpResponseException ex)
{
Log.Error(Constants.LOGGING_SOURCE, CoreResources.GraphExtensions_ErrorOccured, ex.Error.Message);
Log.Error(Constants.LOGGING_SOURCE, CoreResources.GraphExtensions_ErrorOccured, ex.Message);
throw;
}
return (result);
}

/// <summary>