From aa690630d903a18e824242cbcc14492319adccce Mon Sep 17 00:00:00 2001 From: Daniel Pastoor Date: Wed, 5 Jul 2023 11:19:07 +0200 Subject: [PATCH 1/2] Added creation options so we can create team site with the graph api for application and delegated permissions --- .../Public/Options/GraphGroupOptions.cs | 5 + .../Core/Internal/SiteCollectionCreator.cs | 199 +++++++----------- 2 files changed, 78 insertions(+), 126 deletions(-) diff --git a/src/sdk/PnP.Core.Admin/Model/Microsoft365/Public/Options/GraphGroupOptions.cs b/src/sdk/PnP.Core.Admin/Model/Microsoft365/Public/Options/GraphGroupOptions.cs index 848ed3744a..d61fab3601 100644 --- a/src/sdk/PnP.Core.Admin/Model/Microsoft365/Public/Options/GraphGroupOptions.cs +++ b/src/sdk/PnP.Core.Admin/Model/Microsoft365/Public/Options/GraphGroupOptions.cs @@ -70,5 +70,10 @@ public class GraphGroupOptions /// See https://learn.microsoft.com/en-us/graph/group-set-options#configure-groups /// public List ResourceBehaviorOptions { get; set; } + + /// + /// Allows defining creation options for SharePoint Site Creation + /// + public List CreationOptions { get; set; } } } diff --git a/src/sdk/PnP.Core.Admin/Model/SharePoint/Core/Internal/SiteCollectionCreator.cs b/src/sdk/PnP.Core.Admin/Model/SharePoint/Core/Internal/SiteCollectionCreator.cs index 6317dc0e99..a4fc59dbd4 100644 --- a/src/sdk/PnP.Core.Admin/Model/SharePoint/Core/Internal/SiteCollectionCreator.cs +++ b/src/sdk/PnP.Core.Admin/Model/SharePoint/Core/Internal/SiteCollectionCreator.cs @@ -187,149 +187,96 @@ private static async Task CreateCommonNoGroupSiteAsync(PnPContext co private static async Task CreateTeamSiteAsync(PnPContext context, TeamSiteOptions siteToCreate, SiteCreationOptions creationOptions) { - // If we're using application permissions we use Microsoft Graph to create the site - if (creationOptions.UsingApplicationPermissions.Value) + var newGroup = new GraphGroupOptions + { + DisplayName = siteToCreate.DisplayName, + MailNickname = siteToCreate.Alias, + MailEnabled = true, + Visibility = siteToCreate.IsPublic ? GroupVisibility.Public.ToString() : GroupVisibility.Private.ToString(), + GroupTypes = new List { "Unified" }, + Owners = siteToCreate.Owners, + Members = siteToCreate.Members, + ResourceBehaviorOptions = new List(), + CreationOptions = new List(), + }; + + if (!string.IsNullOrEmpty(siteToCreate.Description)) { - var newGroup = new GraphGroupOptions - { - DisplayName = siteToCreate.DisplayName, - MailNickname = siteToCreate.Alias, - MailEnabled = true, - Visibility = siteToCreate.IsPublic ? GroupVisibility.Public.ToString() : GroupVisibility.Private.ToString(), - GroupTypes = new List { "Unified" }, - Owners = siteToCreate.Owners, - Members = siteToCreate.Members, - ResourceBehaviorOptions = new List() - }; + newGroup.Description = siteToCreate.Description; + } - if (!string.IsNullOrEmpty(siteToCreate.Description)) - { - newGroup.Description = siteToCreate.Description; - } - - if (siteToCreate.AllowOnlyMembersToPost.GetValueOrDefault(false)) - { - newGroup.ResourceBehaviorOptions.Add("AllowOnlyMembersToPost"); - } + if (siteToCreate.AllowOnlyMembersToPost.GetValueOrDefault(false)) + { + newGroup.ResourceBehaviorOptions.Add("AllowOnlyMembersToPost"); + } - if (siteToCreate.CalendarMemberReadOnly.GetValueOrDefault(false)) - { - newGroup.ResourceBehaviorOptions.Add("CalendarMemberReadOnly"); - } + if (siteToCreate.CalendarMemberReadOnly.GetValueOrDefault(false)) + { + newGroup.ResourceBehaviorOptions.Add("CalendarMemberReadOnly"); + } - if (siteToCreate.ConnectorsDisabled.GetValueOrDefault(false)) - { - newGroup.ResourceBehaviorOptions.Add("ConnectorsDisabled"); - } + if (siteToCreate.ConnectorsDisabled.GetValueOrDefault(false)) + { + newGroup.ResourceBehaviorOptions.Add("ConnectorsDisabled"); + } - if (siteToCreate.HideGroupInOutlook.GetValueOrDefault(false)) - { - newGroup.ResourceBehaviorOptions.Add("HideGroupInOutlook"); - } + if (siteToCreate.HideGroupInOutlook.GetValueOrDefault(false)) + { + newGroup.ResourceBehaviorOptions.Add("HideGroupInOutlook"); + } - if (siteToCreate.SubscribeMembersToCalendarEventsDisabled.GetValueOrDefault(false)) - { - newGroup.ResourceBehaviorOptions.Add("SubscribeMembersToCalendarEventsDisabled"); - } + if (siteToCreate.SubscribeMembersToCalendarEventsDisabled.GetValueOrDefault(false)) + { + newGroup.ResourceBehaviorOptions.Add("SubscribeMembersToCalendarEventsDisabled"); + } - if (siteToCreate.SubscribeNewGroupMembers.GetValueOrDefault(false)) - { - newGroup.ResourceBehaviorOptions.Add("SubscribeNewGroupMembers"); - } + if (siteToCreate.SubscribeNewGroupMembers.GetValueOrDefault(false)) + { + newGroup.ResourceBehaviorOptions.Add("SubscribeNewGroupMembers"); + } - if (siteToCreate.WelcomeEmailDisabled.GetValueOrDefault(false)) - { - newGroup.ResourceBehaviorOptions.Add("WelcomeEmailDisabled"); - } + if (siteToCreate.WelcomeEmailDisabled.GetValueOrDefault(false)) + { + newGroup.ResourceBehaviorOptions.Add("WelcomeEmailDisabled"); + } - if (siteToCreate.PreferredDataLocation.HasValue) - { - newGroup.PreferredDataLocation = siteToCreate.PreferredDataLocation.Value.ToString(); - } + if (siteToCreate.PreferredDataLocation.HasValue) + { + newGroup.PreferredDataLocation = siteToCreate.PreferredDataLocation.Value.ToString(); + } - if (!string.IsNullOrEmpty(siteToCreate.Classification)) - { - newGroup.Classification = siteToCreate.Classification; - } + if (!string.IsNullOrEmpty(siteToCreate.Classification)) + { + newGroup.Classification = siteToCreate.Classification; + } - Microsoft365.CreationOptions groupCreationOptions = new Microsoft365.CreationOptions - { - MaxStatusChecks = creationOptions.MaxStatusChecks, - WaitAfterStatusCheck = creationOptions.WaitAfterStatusCheck, - }; + if (siteToCreate.SensitivityLabelId != Guid.Empty) + { + newGroup.CreationOptions.Add($"SensitivityLabel:{siteToCreate.SensitivityLabelId}"); + } - return await context.GetMicrosoft365Admin().CreateGroupAsync(newGroup, groupCreationOptions).ConfigureAwait(false); + if (siteToCreate.SiteDesignId.HasValue) + { + newGroup.CreationOptions.Add($"implicit_formula_292aa8a00786498a87a5ca52d9f4214a_{siteToCreate.SiteDesignId.Value.ToString("D").ToLower()}"); } - else + if (siteToCreate.Language != Language.Default) { - var creationOptionsValues = new List(); - Dictionary payload = new Dictionary - { - { "displayName", siteToCreate.DisplayName }, - { "alias", NormalizeSiteAlias(siteToCreate.Alias) }, - { "isPublic", siteToCreate.IsPublic } - }; - - var optionalParams = new Dictionary - { - { "Description", siteToCreate.Description ?? "" } - }; - - // Sensitivity labels have replaced classification (see https://docs.microsoft.com/en-us/microsoft-365/compliance/sensitivity-labels-teams-groups-sites?view=o365-worldwide#classic-azure-ad-group-classification) - // once enabled. Therefore we prefer setting a sensitivity label id over classification when specified. Also note that for setting sensitivity labels on - // group connected sites one needs to have at least one Azure AD P1 license. See https://docs.microsoft.com/en-us/azure/active-directory/enterprise-users/groups-assign-sensitivity-labels - if (siteToCreate.SensitivityLabelId != Guid.Empty) - { - creationOptionsValues.Add($"SensitivityLabel:{siteToCreate.SensitivityLabelId}"); - } - else - { - optionalParams.Add("Classification", siteToCreate.Classification ?? ""); - } - - if (siteToCreate.SiteDesignId.HasValue) - { - creationOptionsValues.Add($"implicit_formula_292aa8a00786498a87a5ca52d9f4214a_{siteToCreate.SiteDesignId.Value.ToString("D").ToLower()}"); - } - if (siteToCreate.Language != Language.Default) - { - creationOptionsValues.Add($"SPSiteLanguage:{(int)siteToCreate.Language}"); - } - if (!string.IsNullOrEmpty(siteToCreate.SiteAlias)) - { - creationOptionsValues.Add($"SiteAlias:{siteToCreate.SiteAlias}"); - } - creationOptionsValues.Add($"HubSiteId:{siteToCreate.HubSiteId}"); - - if (siteToCreate.Owners != null && siteToCreate.Owners.Length > 0) - { - var ownersBody = new - { - __metadata = new { type = "Collection(Edm.String)" }, - results = siteToCreate.Owners - }.AsExpando(); - optionalParams.Add("Owners", ownersBody); - } - if (siteToCreate.PreferredDataLocation.HasValue) - { - optionalParams.Add("PreferredDataLocation", siteToCreate.PreferredDataLocation.Value.ToString()); - } + newGroup.CreationOptions.Add($"SPSiteLanguage:{(int)siteToCreate.Language}"); + } + if (!string.IsNullOrEmpty(siteToCreate.SiteAlias)) + { + newGroup.CreationOptions.Add($"SiteAlias:{siteToCreate.SiteAlias}"); + } - if (creationOptionsValues.Any()) - { - var creationOptionsValuesBody = new - { - __metadata = new { type = "Collection(Edm.String)" }, - results = creationOptionsValues - }.AsExpando(); - optionalParams.Add("CreationOptions", creationOptionsValuesBody); - } + newGroup.CreationOptions.Add($"HubSiteId:{siteToCreate.HubSiteId}"); - payload.Add("optionalParams", optionalParams); + Microsoft365.CreationOptions groupCreationOptions = new Microsoft365.CreationOptions + { + MaxStatusChecks = creationOptions.MaxStatusChecks, + WaitAfterStatusCheck = creationOptions.WaitAfterStatusCheck, + }; - // Delegated permissions can use the SharePoint endpoints for site collection creation - return await CreateSiteUsingSpoRestImplementationAsync(context, SiteCreationModel.GroupSiteManagerCreateGroupEx, payload, creationOptions).ConfigureAwait(false); - } + return await context.GetMicrosoft365Admin().CreateGroupAsync(newGroup, groupCreationOptions).ConfigureAwait(false); } private static async Task CreateClassicSiteAsync(PnPContext context, ClassicSiteOptions siteToCreate, SiteCreationOptions creationOptions, VanityUrlOptions vanityUrlOptions) From 5c9552e6a85d2e4dfbc0d22d0d27c0914ff85525 Mon Sep 17 00:00:00 2001 From: Daniel Pastoor Date: Wed, 5 Jul 2023 11:52:26 +0200 Subject: [PATCH 2/2] Changed documentation by removing the not supported options for creating a Team Site With group because it is supported now --- docs/using-the-sdk/admin-sharepoint-sites.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/using-the-sdk/admin-sharepoint-sites.md b/docs/using-the-sdk/admin-sharepoint-sites.md index 39d36662dd..90b91fb495 100644 --- a/docs/using-the-sdk/admin-sharepoint-sites.md +++ b/docs/using-the-sdk/admin-sharepoint-sites.md @@ -98,7 +98,7 @@ It's highly recommended to use one of the "modern" site collections as these off Category | Delegated permissions | Application permissions ---------|-----------------------|------------------------ Modern, no group | Use `CommunicationSiteOptions` or `TeamSiteWithoutGroupOptions` | Use `CommunicationSiteOptions` or `TeamSiteWithoutGroupOptions`. The `Owner` property must be set. -Modern, with group | Use `TeamSiteOptions`. The `AllowOnlyMembersToPost`, `CalendarMemberReadOnly`, `ConnectorsDisabled`, `HideGroupInOutlook`, `SubscribeMembersToCalendarEventsDisabled`, `SubscribeNewGroupMembers`, `WelcomeEmailDisabled` and `Members` properties are not applicable here. | Use `TeamSiteOptions`. The `Owners` property must be set, properties `Language`, `SiteDesignId`, `HubSiteId`, `SensitivityLabelId` and `SiteAlias` are not applicable here. +Modern, with group | Use `TeamSiteOptions`. The Owners property must be set. | Use `TeamSiteOptions`. The `Owners` property must be set. Classic site | Use `ClassicSiteOptions` | Use `ClassicSiteOptions` All provisioning flows will only return once the site collection is done, for the modern sites this is a matter of seconds, for classic sites this can take up to 10-15 minutes.