/// <summary> /// Actual implementation of extracting configuration from existing site. /// </summary> /// <param name="web"></param> /// <param name="creationInfo"></param> /// <returns></returns> internal ProvisioningTemplate GetRemoteTemplate(Web web, ProvisioningTemplateCreationInformation creationInfo) { Log.Info(Constants.LOGGING_SOURCE_FRAMEWORK_PROVISIONING, CoreResources.Provisioning_ObjectHandlers_StartExtraction); ProvisioningProgressDelegate progressDelegate = null; ProvisioningMessagesDelegate messagesDelegate = null; if (creationInfo != null) { progressDelegate = creationInfo.ProgressDelegate; messagesDelegate = creationInfo.MessagesDelegate; } // Create empty object ProvisioningTemplate template = new ProvisioningTemplate(); // Hookup connector, is handy when the generated template object is used to apply to another site template.Connector = creationInfo.FileConnector; List <ObjectHandlerBase> objectHandlers = new List <ObjectHandlerBase>(); objectHandlers.Add(new ObjectSitePolicy()); objectHandlers.Add(new ObjectSiteSecurity()); objectHandlers.Add(new ObjectTermGroups()); objectHandlers.Add(new ObjectField()); objectHandlers.Add(new ObjectContentType()); objectHandlers.Add(new ObjectListInstance()); objectHandlers.Add(new ObjectCustomActions()); objectHandlers.Add(new ObjectFeatures()); objectHandlers.Add(new ObjectComposedLook()); objectHandlers.Add(new ObjectFiles()); objectHandlers.Add(new ObjectPages()); objectHandlers.Add(new ObjectPropertyBagEntry()); objectHandlers.Add(new ObjectRetrieveTemplateInfo()); int step = 1; var count = objectHandlers.Count(o => o.ReportProgress && o.WillExtract(web, template, creationInfo)); foreach (var handler in objectHandlers) { if (handler.WillExtract(web, template, creationInfo)) { if (messagesDelegate != null) { handler.MessagesDelegate = messagesDelegate; } if (handler.ReportProgress && progressDelegate != null) { progressDelegate(handler.Name, step, count); step++; } template = handler.ExtractObjects(web, template, creationInfo); } } Log.Info(Constants.LOGGING_SOURCE_FRAMEWORK_PROVISIONING, CoreResources.Provisioning_ObjectHandlers_FinishExtraction); return(template); }
/// <summary> /// Actual implementation of the apply templates /// </summary> /// <param name="web"></param> /// <param name="template"></param> /// <param name="provisioningInfo"></param> internal void ApplyRemoteTemplate(Web web, ProvisioningTemplate template, ProvisioningTemplateApplyingInformation provisioningInfo) { ProvisioningProgressDelegate progressDelegate = null; ProvisioningMessagesDelegate messagesDelegate = null; if (provisioningInfo != null) { progressDelegate = provisioningInfo.ProgressDelegate; messagesDelegate = provisioningInfo.MessageDelegate; } Log.Info(Constants.LOGGING_SOURCE_FRAMEWORK_PROVISIONING, CoreResources.Provisioning_ObjectHandlers_StartProvisioning); List <ObjectHandlerBase> objectHandlers = new List <ObjectHandlerBase>(); objectHandlers.Add(new ObjectSitePolicy()); objectHandlers.Add(new ObjectSiteSecurity()); objectHandlers.Add(new ObjectFeatures()); objectHandlers.Add(new ObjectTermGroups()); objectHandlers.Add(new ObjectField()); objectHandlers.Add(new ObjectContentType()); objectHandlers.Add(new ObjectListInstance()); objectHandlers.Add(new ObjectLookupFields()); objectHandlers.Add(new ObjectListInstanceDataRows()); objectHandlers.Add(new ObjectFiles()); objectHandlers.Add(new ObjectPages()); objectHandlers.Add(new ObjectCustomActions()); objectHandlers.Add(new ObjectComposedLook()); objectHandlers.Add(new ObjectPropertyBagEntry()); objectHandlers.Add(new ObjectExtensibilityProviders()); objectHandlers.Add(new ObjectPersistTemplateInfo()); TokenParser.Initialize(web, template); int step = 1; var count = objectHandlers.Count(o => o.ReportProgress && o.WillProvision(web, template)); foreach (var handler in objectHandlers) { if (handler.WillProvision(web, template)) { if (messagesDelegate != null) { handler.MessagesDelegate = messagesDelegate; } if (handler.ReportProgress && progressDelegate != null) { progressDelegate(handler.Name, step, count); step++; } handler.ProvisionObjects(web, template, provisioningInfo); } } Log.Info(Constants.LOGGING_SOURCE_FRAMEWORK_PROVISIONING, CoreResources.Provisioning_ObjectHandlers_FinishProvisioning); }
public static TokenParser ProcessSharingSettings(Tenant tenant, ProvisioningTenant provisioningTenant, TokenParser parser, PnPMonitoredScope scope, ProvisioningMessagesDelegate messagesDelegate) { var sharingSettings = provisioningTenant.SharingSettings; if (sharingSettings != null) { // Set general setting of Sharing Capability tenant.SharingCapability = (Microsoft.Online.SharePoint.TenantManagement.SharingCapabilities)Enum.Parse(typeof(Microsoft.Online.SharePoint.TenantManagement.SharingCapabilities), sharingSettings.SharingCapability.ToString()); if (sharingSettings.SharingCapability != SharingCapability.Disabled) { // Configure the number of days for anonymous links expiration tenant.RequireAnonymousLinksExpireInDays = sharingSettings.RequireAnonymousLinksExpireInDays; // Configure the default anonymous link type for files tenant.FileAnonymousLinkType = (Microsoft.SharePoint.Client.AnonymousLinkType)Enum.Parse(typeof(Microsoft.SharePoint.Client.AnonymousLinkType), sharingSettings.FileAnonymousLinkType.ToString()); // Configure the default anonymous link type for folders tenant.FolderAnonymousLinkType = (Microsoft.SharePoint.Client.AnonymousLinkType)Enum.Parse(typeof(Microsoft.SharePoint.Client.AnonymousLinkType), sharingSettings.FolderAnonymousLinkType.ToString()); // Configure the default sharing link type tenant.DefaultSharingLinkType = (Microsoft.Online.SharePoint.TenantManagement.SharingLinkType)Enum.Parse(typeof(Microsoft.Online.SharePoint.TenantManagement.SharingLinkType), sharingSettings.DefaultSharingLinkType.ToString()); // Configure whether external users are prevented from re-sharing shared content tenant.PreventExternalUsersFromResharing = sharingSettings.PreventExternalUsersFromResharing; // Configure if the the guest account must match the invited account tenant.RequireAcceptingAccountMatchInvitedAccount = sharingSettings.RequireAcceptingAccountMatchInvitedAccount; // Configure the domain restriction mode tenant.SharingDomainRestrictionMode = (Microsoft.Online.SharePoint.TenantManagement.SharingDomainRestrictionModes)Enum.Parse(typeof(Microsoft.Online.SharePoint.TenantManagement.SharingDomainRestrictionModes), sharingSettings.SharingDomainRestrictionMode.ToString()); if (sharingSettings.SharingDomainRestrictionMode == SharingDomainRestrictionMode.AllowList) { // Configure the list of allowed domains tenant.SharingAllowedDomainList = sharingSettings.AllowedDomainList.Aggregate(string.Empty, (acc, next) => acc += $" {next}").Trim(); } else if (sharingSettings.SharingDomainRestrictionMode == SharingDomainRestrictionMode.BlockList) { // Configure the list of blocked domains tenant.SharingBlockedDomainList = sharingSettings.BlockedDomainList.Aggregate(string.Empty, (acc, next) => acc += $" {next}").Trim(); } } // Save the new settings tenant.Context.ExecuteQueryRetry(); } return(parser); }
public static TokenParser ProcessUserProfiles(Tenant tenant, ProvisioningTenant provisioningTenant, TokenParser parser, PnPMonitoredScope scope, ProvisioningMessagesDelegate messagesDelegate) { if (provisioningTenant.SPUsersProfiles != null && provisioningTenant.SPUsersProfiles.Any()) { messagesDelegate?.Invoke("Processing User Profiles", ProvisioningMessageType.Progress); foreach (var profile in provisioningTenant.SPUsersProfiles) { string parsedUser; if (!string.IsNullOrEmpty(profile.TargetUser)) { parsedUser = parser.ParseString(profile.TargetUser); } else { parsedUser = parser.ParseString(profile.TargetGroup); } PeopleManager peopleManager = new PeopleManager(tenant.Context); try { // Currently only supports setting Single Valued property // We don't have a way at the moment to set Multi-valued property foreach (var props in profile.Properties) { peopleManager.SetSingleValueProfileProperty($"i:0#.f|membership|{parsedUser}", props.Key, parser.ParseString(props.Value)); } tenant.Context.ExecuteQueryRetry(); } catch (Exception ex) { scope.LogError($"Error processing user profile for {parsedUser}. Skipped due to error: ${ex.Message}"); } } } return(parser); }
public static TokenParser ProcessThemes(Tenant tenant, ProvisioningTenant provisioningTenant, TokenParser parser, PnPMonitoredScope scope, ProvisioningMessagesDelegate messagesDelegate) { if (provisioningTenant.Themes != null && provisioningTenant.Themes.Any()) { foreach (var theme in provisioningTenant.Themes) { var parsedName = parser.ParseString(theme.Name); var parsedPalette = parser.ParseString(theme.Palette); messagesDelegate?.Invoke($"Processing theme {parsedName}", ProvisioningMessageType.Progress); var palette = JsonConvert.DeserializeObject <Dictionary <string, string> >(parsedPalette); var tenantTheme = new TenantTheme() { Name = parsedName, Palette = palette, IsInverted = theme.IsInverted }; tenant.UpdateTenantTheme(parsedName, JsonConvert.SerializeObject(tenantTheme)); tenant.Context.ExecuteQueryRetry(); } } return(parser); }
public static TokenParser ProcessWebApiPermissions(Tenant tenant, ProvisioningTenant provisioningTenant, TokenParser parser, PnPMonitoredScope scope, ProvisioningMessagesDelegate messagesDelegate) { if (provisioningTenant.WebApiPermissions != null && provisioningTenant.WebApiPermissions.Any()) { messagesDelegate?.Invoke("Processing WebApiPermissions", ProvisioningMessageType.Progress); var servicePrincipal = new SPOWebAppServicePrincipal(tenant.Context); //var requests = servicePrincipal.PermissionRequests; var requestsEnumerable = tenant.Context.LoadQuery(servicePrincipal.PermissionRequests); var grantsEnumerable = tenant.Context.LoadQuery(servicePrincipal.PermissionGrants); tenant.Context.ExecuteQueryRetry(); var requests = requestsEnumerable.ToList(); foreach (var permission in provisioningTenant.WebApiPermissions) { var parsedScope = parser.ParseString(permission.Scope); var parsedResource = parser.ParseString(permission.Resource); var request = requests.FirstOrDefault(r => r.Scope.Equals(parsedScope, StringComparison.InvariantCultureIgnoreCase) && r.Resource.Equals(parsedResource, StringComparison.InvariantCultureIgnoreCase)); while (request != null) { if (grantsEnumerable.FirstOrDefault(g => g.Resource.Equals(parsedResource, StringComparison.InvariantCultureIgnoreCase) && g.Scope.ToLower().Contains(parsedScope.ToLower())) == null) { var requestToApprove = servicePrincipal.PermissionRequests.GetById(request.Id); tenant.Context.Load(requestToApprove); tenant.Context.ExecuteQueryRetry(); try { requestToApprove.Approve(); tenant.Context.ExecuteQueryRetry(); } catch (Exception ex) { messagesDelegate?.Invoke(ex.Message, ProvisioningMessageType.Warning); } } requests.Remove(request); request = requests.FirstOrDefault(r => r.Scope.Equals(parsedScope, StringComparison.InvariantCultureIgnoreCase) && r.Resource.Equals(parsedResource, StringComparison.InvariantCultureIgnoreCase)); } } } return(parser); }
public static TokenParser ProcessApps(Tenant tenant, ProvisioningTenant provisioningTenant, FileConnectorBase connector, TokenParser parser, PnPMonitoredScope scope, ProvisioningTemplateApplyingInformation applyingInformation, ProvisioningMessagesDelegate messagesDelegate) { if (provisioningTenant.AppCatalog != null && provisioningTenant.AppCatalog.Packages.Count > 0) { var rootSiteUrl = tenant.GetRootSiteUrl(); tenant.Context.ExecuteQueryRetry(); using (var context = ((ClientContext)tenant.Context).Clone(rootSiteUrl.Value, applyingInformation.AccessTokens)) { var web = context.Web; Uri appCatalogUri = null; try { appCatalogUri = web.GetAppCatalog(); } catch (System.Net.WebException ex) { if (ex.Response != null) { var httpResponse = ex.Response as System.Net.HttpWebResponse; if (httpResponse != null && httpResponse.StatusCode == HttpStatusCode.Unauthorized) { // Ignore any security exception and simply keep // the AppCatalog URI null } else { throw ex; } } else { throw ex; } } if (appCatalogUri != null) { var manager = new AppManager(context); foreach (var app in provisioningTenant.AppCatalog.Packages) { AppMetadata appMetadata = null; if (app.Action == PackageAction.Upload || app.Action == PackageAction.UploadAndPublish) { var appSrc = parser.ParseString(app.Src); var appBytes = ConnectorFileHelper.GetFileBytes(connector, appSrc); var hash = string.Empty; using (var memoryStream = new MemoryStream(appBytes)) { hash = CalculateHash(memoryStream); } var exists = false; var appId = Guid.Empty; using (var appCatalogContext = ((ClientContext)tenant.Context).Clone(appCatalogUri, applyingInformation.AccessTokens)) { // check if the app already is present var appList = appCatalogContext.Web.GetListByUrl("AppCatalog"); var camlQuery = new CamlQuery { ViewXml = string.Format(appExistsQuery, hash) }; var items = appList.GetItems(camlQuery); appCatalogContext.Load(items, i => i.IncludeWithDefaultProperties()); appCatalogContext.ExecuteQueryRetry(); if (items.Count > 0) { exists = true; appId = Guid.Parse(items[0].FieldValues["UniqueId"].ToString()); } } var appFilename = appSrc.Substring(appSrc.LastIndexOf('\\') + 1); if (!exists) { messagesDelegate?.Invoke($"Processing solution {app.Src}", ProvisioningMessageType.Progress); appMetadata = manager.Add(appBytes, appFilename, app.Overwrite, timeoutSeconds: 500); } else { messagesDelegate?.Invoke($"Skipping existing solution {app.Src}", ProvisioningMessageType.Progress); appMetadata = manager.GetAvailable().FirstOrDefault(a => a.Id == appId); } if (appMetadata != null) { parser.AddToken(new AppPackageIdToken(web, appFilename, appMetadata.Id)); parser.AddToken(new AppPackageIdToken(web, appMetadata.Title, appMetadata.Id)); } } if (app.Action == PackageAction.Publish || app.Action == PackageAction.UploadAndPublish) { if (appMetadata == null) { appMetadata = manager.GetAvailable() .FirstOrDefault(a => a.Id == Guid.Parse(parser.ParseString(app.PackageId))); } if (appMetadata != null) { manager.Deploy(appMetadata, app.SkipFeatureDeployment); } else { scope.LogError("Referenced App Package {0} not available", app.PackageId); throw new Exception($"Referenced App Package {app.PackageId} not available"); } } if (app.Action == PackageAction.Remove) { var appId = Guid.Parse(parser.ParseString(app.PackageId)); // Get the apps already installed in the site var appExists = manager.GetAvailable()?.Any(a => a.Id == appId); if (appExists.HasValue && appExists.Value) { manager.Remove(appId); } else { messagesDelegate?.Invoke($"App Package with ID {appId} does not exist in the AppCatalog and cannot be removed!", ProvisioningMessageType.Warning); } } } } else { messagesDelegate?.Invoke($"Tenant app catalog doesn't exist. ALM step will be skipped!", ProvisioningMessageType.Warning); } } } return(parser); }
internal static TokenParser ProcessSiteScripts(Tenant tenant, ProvisioningTenant provisioningTenant, FileConnectorBase connector, TokenParser parser, PnPMonitoredScope scope, ProvisioningMessagesDelegate messagesDelegate) { if (provisioningTenant.SiteScripts != null && provisioningTenant.SiteScripts.Any()) { var existingScripts = tenant.GetSiteScripts(); tenant.Context.Load(existingScripts); tenant.Context.ExecuteQueryRetry(); foreach (var siteScript in provisioningTenant.SiteScripts) { var parsedTitle = parser.ParseString(siteScript.Title); var parsedDescription = parser.ParseString(siteScript.Description); var parsedContent = parser.ParseString(System.Text.Encoding.UTF8.GetString(ConnectorFileHelper.GetFileBytes(connector, parser.ParseString(siteScript.JsonFilePath)))); var existingScript = existingScripts.FirstOrDefault(s => s.Title == parsedTitle); messagesDelegate?.Invoke($"Processing site script {parsedTitle}", ProvisioningMessageType.Progress); if (existingScript == null) { TenantSiteScriptCreationInfo siteScriptCreationInfo = new TenantSiteScriptCreationInfo { Title = parsedTitle, Description = parsedDescription, Content = parsedContent }; var script = tenant.CreateSiteScript(siteScriptCreationInfo); tenant.Context.Load(script); tenant.Context.ExecuteQueryRetry(); parser.AddToken(new SiteScriptIdToken(null, parsedTitle, script.Id)); } else { if (siteScript.Overwrite) { var existingId = existingScript.Id; existingScript = Tenant.GetSiteScript(tenant.Context, existingId); tenant.Context.ExecuteQueryRetry(); existingScript.Content = parsedContent; existingScript.Title = parsedTitle; existingScript.Description = parsedDescription; tenant.UpdateSiteScript(existingScript); tenant.Context.ExecuteQueryRetry(); var existingToken = parser.Tokens.OfType <SiteScriptIdToken>().FirstOrDefault(t => t.GetReplaceValue() == existingId.ToString()); if (existingToken != null) { parser.Tokens.Remove(existingToken); } parser.AddToken(new SiteScriptIdToken(null, parsedTitle, existingId)); } } } } return(parser); }
internal static TokenParser ProcessStorageEntities(Tenant tenant, ProvisioningTenant provisioningTenant, TokenParser parser, PnPMonitoredScope scope, ProvisioningTemplateApplyingInformation applyingInformation, ProvisioningMessagesDelegate messagesDelegate) { if (provisioningTenant.StorageEntities != null && provisioningTenant.StorageEntities.Any()) { using (var context = ((ClientContext)tenant.Context).Clone(tenant.RootSiteUrl, applyingInformation.AccessTokens)) { var web = context.Web; var appCatalogUri = web.GetAppCatalog(); using (var appCatalogContext = context.Clone(appCatalogUri, applyingInformation.AccessTokens)) { foreach (var entity in provisioningTenant.StorageEntities) { var key = parser.ParseString(entity.Key); var value = parser.ParseString(entity.Value); var description = parser.ParseString(entity.Description); var comment = parser.ParseString(entity.Comment); appCatalogContext.Web.SetStorageEntity(key, value, description, comment); } appCatalogContext.Web.Update(); appCatalogContext.ExecuteQueryRetry(); } } } return(parser); }
/// <summary> /// Actual implementation of the apply templates /// </summary> /// <param name="web"></param> /// <param name="template"></param> /// <param name="provisioningInfo"></param> internal void ApplyRemoteTemplate(Web web, ProvisioningTemplate template, ProvisioningTemplateApplyingInformation provisioningInfo) { using (var scope = new PnPMonitoredScope(CoreResources.Provisioning_ObjectHandlers_Provisioning)) { ProvisioningProgressDelegate progressDelegate = null; ProvisioningMessagesDelegate messagesDelegate = null; if (provisioningInfo != null) { if (provisioningInfo.OverwriteSystemPropertyBagValues == true) { scope.LogInfo(CoreResources.SiteToTemplateConversion_ApplyRemoteTemplate_OverwriteSystemPropertyBagValues_is_to_true); } progressDelegate = provisioningInfo.ProgressDelegate; if (provisioningInfo.ProgressDelegate != null) { scope.LogInfo(CoreResources.SiteToTemplateConversion_ProgressDelegate_registered); } messagesDelegate = provisioningInfo.MessagesDelegate; if (provisioningInfo.MessagesDelegate != null) { scope.LogInfo(CoreResources.SiteToTemplateConversion_MessagesDelegate_registered); } } else { // When no provisioning info was passed then we want to execute all handlers provisioningInfo = new ProvisioningTemplateApplyingInformation(); provisioningInfo.HandlersToProcess = Handlers.All; } // Check if the target site shares the same base template with the template's source site var targetSiteTemplateId = web.GetBaseTemplateId(); if (!String.IsNullOrEmpty(targetSiteTemplateId) && !String.IsNullOrEmpty(template.BaseSiteTemplate)) { if (!targetSiteTemplateId.Equals(template.BaseSiteTemplate, StringComparison.InvariantCultureIgnoreCase)) { var templatesNotMatchingWarning = String.Format(CoreResources.Provisioning_Asymmetric_Base_Templates, template.BaseSiteTemplate, targetSiteTemplateId); scope.LogWarning(templatesNotMatchingWarning); if (provisioningInfo.MessagesDelegate != null) { provisioningInfo.MessagesDelegate(templatesNotMatchingWarning, ProvisioningMessageType.Warning); } } } // Always ensure the Url property is loaded. In the tokens we need this and we don't want to call ExecuteQuery as this can // impact delta scenarions (calling ExecuteQuery before the planned update is called) web.EnsureProperty(w => w.Url); List <ObjectHandlerBase> objectHandlers = new List <ObjectHandlerBase>(); if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.RegionalSettings)) { objectHandlers.Add(new ObjectRegionalSettings()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.SupportedUILanguages)) { objectHandlers.Add(new ObjectSupportedUILanguages()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.AuditSettings)) { objectHandlers.Add(new ObjectAuditSettings()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.SitePolicy)) { objectHandlers.Add(new ObjectSitePolicy()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.SiteSecurity)) { objectHandlers.Add(new ObjectSiteSecurity()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.Features)) { objectHandlers.Add(new ObjectFeatures()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.TermGroups)) { objectHandlers.Add(new ObjectTermGroups()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.Fields) || provisioningInfo.HandlersToProcess.HasFlag(Handlers.Lists)) { objectHandlers.Add(new ObjectField()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.ContentTypes)) { objectHandlers.Add(new ObjectContentType()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.Lists)) { objectHandlers.Add(new ObjectListInstance()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.Fields) || provisioningInfo.HandlersToProcess.HasFlag(Handlers.Lists)) { objectHandlers.Add(new ObjectLookupFields()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.Fields) || provisioningInfo.HandlersToProcess.HasFlag(Handlers.Lists)) { objectHandlers.Add(new ObjectListInstanceDataRows()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.Workflows)) { objectHandlers.Add(new ObjectWorkflows()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.Publishing)) { objectHandlers.Add(new ObjectPublishing()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.Files)) { objectHandlers.Add(new ObjectFiles()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.Pages)) { objectHandlers.Add(new ObjectPages()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.PageContents)) { objectHandlers.Add(new ObjectPageContents()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.CustomActions)) { objectHandlers.Add(new ObjectCustomActions()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.ComposedLook)) { objectHandlers.Add(new ObjectComposedLook()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.SearchSettings)) { objectHandlers.Add(new ObjectSearchSettings()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.PropertyBagEntries)) { objectHandlers.Add(new ObjectPropertyBagEntry()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.WebSettings)) { objectHandlers.Add(new ObjectWebSettings()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.Navigation)) { objectHandlers.Add(new ObjectNavigation()); } objectHandlers.Add(new ObjectLocalization()); // Always add this one, check is done in the handler if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.ExtensibilityProviders)) { objectHandlers.Add(new ObjectExtensibilityHandlers()); } // Only persist template information in case this flag is set: this will allow the engine to // work with lesser permissions if (provisioningInfo.PersistTemplateInfo) { objectHandlers.Add(new ObjectPersistTemplateInfo()); } var tokenParser = new TokenParser(web, template); if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.ExtensibilityProviders)) { var extensibilityHandler = objectHandlers.OfType <ObjectExtensibilityHandlers>().First(); extensibilityHandler.AddExtendedTokens(web, template, tokenParser, provisioningInfo); } int step = 1; var count = objectHandlers.Count(o => o.ReportProgress && o.WillProvision(web, template)); foreach (var handler in objectHandlers) { if (handler.WillProvision(web, template)) { if (messagesDelegate != null) { handler.MessagesDelegate = messagesDelegate; } if (handler.ReportProgress && progressDelegate != null) { progressDelegate(handler.Name, step, count); step++; } tokenParser = handler.ProvisionObjects(web, template, tokenParser, provisioningInfo); } } } }
/// <summary> /// Actual implementation of the apply templates /// </summary> /// <param name="web"></param> /// <param name="template"></param> /// <param name="provisioningInfo"></param> internal void ApplyRemoteTemplate(Web web, ProvisioningTemplate template, ProvisioningTemplateApplyingInformation provisioningInfo) { using (var scope = new PnPMonitoredScope(CoreResources.Provisioning_ObjectHandlers_Provisioning)) { ProvisioningProgressDelegate progressDelegate = null; ProvisioningMessagesDelegate messagesDelegate = null; if (provisioningInfo != null) { if (provisioningInfo.OverwriteSystemPropertyBagValues == true) { scope.LogInfo(CoreResources.SiteToTemplateConversion_ApplyRemoteTemplate_OverwriteSystemPropertyBagValues_is_to_true); } progressDelegate = provisioningInfo.ProgressDelegate; if (provisioningInfo.ProgressDelegate != null) { scope.LogInfo(CoreResources.SiteToTemplateConversion_ProgressDelegate_registered); } messagesDelegate = provisioningInfo.MessagesDelegate; if (provisioningInfo.MessagesDelegate != null) { scope.LogInfo(CoreResources.SiteToTemplateConversion_MessagesDelegate_registered); } } else { // When no provisioning info was passed then we want to execute all handlers provisioningInfo = new ProvisioningTemplateApplyingInformation(); provisioningInfo.HandlersToProcess = Handlers.All; } List <ObjectHandlerBase> objectHandlers = new List <ObjectHandlerBase>(); if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.RegionalSettings)) { objectHandlers.Add(new ObjectRegionalSettings()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.SupportedUILanguages)) { objectHandlers.Add(new ObjectSupportedUILanguages()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.AuditSettings)) { objectHandlers.Add(new ObjectAuditSettings()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.SitePolicy)) { objectHandlers.Add(new ObjectSitePolicy()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.SiteSecurity)) { objectHandlers.Add(new ObjectSiteSecurity()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.Features)) { objectHandlers.Add(new ObjectFeatures()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.TermGroups)) { objectHandlers.Add(new ObjectTermGroups()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.Fields) || provisioningInfo.HandlersToProcess.HasFlag(Handlers.Lists)) { objectHandlers.Add(new ObjectField()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.ContentTypes)) { objectHandlers.Add(new ObjectContentType()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.Lists)) { objectHandlers.Add(new ObjectListInstance()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.Fields) || provisioningInfo.HandlersToProcess.HasFlag(Handlers.Lists)) { objectHandlers.Add(new ObjectLookupFields()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.Fields) || provisioningInfo.HandlersToProcess.HasFlag(Handlers.Lists)) { objectHandlers.Add(new ObjectListInstanceDataRows()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.Files)) { objectHandlers.Add(new ObjectFiles()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.Pages)) { objectHandlers.Add(new ObjectPages()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.PageContents)) { objectHandlers.Add(new ObjectPageContents()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.CustomActions)) { objectHandlers.Add(new ObjectCustomActions()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.Publishing)) { objectHandlers.Add(new ObjectPublishing()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.ComposedLook)) { objectHandlers.Add(new ObjectComposedLook()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.SearchSettings)) { objectHandlers.Add(new ObjectSearchSettings()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.Workflows)) { objectHandlers.Add(new ObjectWorkflows()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.PropertyBagEntries)) { objectHandlers.Add(new ObjectPropertyBagEntry()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.WebSettings)) { objectHandlers.Add(new ObjectWebSettings()); } objectHandlers.Add(new ObjectLocalization()); // Always add this one, check is done in the handler if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.ExtensibilityProviders)) { objectHandlers.Add(new ObjectExtensibilityHandlers()); } // Only persist template information in case this flag is set: this will allow the engine to // work with lesser permissions if (provisioningInfo.PersistTemplateInfo) { objectHandlers.Add(new ObjectPersistTemplateInfo()); } var tokenParser = new TokenParser(web, template); if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.ExtensibilityProviders)) { var extensibilityHandler = objectHandlers.OfType <ObjectExtensibilityHandlers>().First(); extensibilityHandler.AddExtendedTokens(web, template, tokenParser, provisioningInfo); } int step = 1; var count = objectHandlers.Count(o => o.ReportProgress && o.WillProvision(web, template)); foreach (var handler in objectHandlers) { if (handler.WillProvision(web, template)) { if (messagesDelegate != null) { handler.MessagesDelegate = messagesDelegate; } if (handler.ReportProgress && progressDelegate != null) { progressDelegate(handler.Name, step, count); step++; } tokenParser = handler.ProvisionObjects(web, template, tokenParser, provisioningInfo); } } } }
/// <summary> /// Actual implementation of extracting configuration from existing site. /// </summary> /// <param name="web"></param> /// <param name="creationInfo"></param> /// <returns></returns> internal ProvisioningTemplate GetRemoteTemplate(Web web, ProvisioningTemplateCreationInformation creationInfo) { using (var scope = new PnPMonitoredScope(CoreResources.Provisioning_ObjectHandlers_Extraction)) { ProvisioningProgressDelegate progressDelegate = null; ProvisioningMessagesDelegate messagesDelegate = null; if (creationInfo != null) { if (creationInfo.BaseTemplate != null) { scope.LogDebug(CoreResources.SiteToTemplateConversion_Base_template_available___0_, creationInfo.BaseTemplate.Id); } progressDelegate = creationInfo.ProgressDelegate; if (creationInfo.ProgressDelegate != null) { scope.LogDebug(CoreResources.SiteToTemplateConversion_ProgressDelegate_registered); } messagesDelegate = creationInfo.MessagesDelegate; if (creationInfo.MessagesDelegate != null) { scope.LogDebug(CoreResources.SiteToTemplateConversion_MessagesDelegate_registered); } if (creationInfo.IncludeAllTermGroups) { scope.LogDebug(CoreResources.SiteToTemplateConversion_IncludeAllTermGroups_is_set_to_true); } if (creationInfo.IncludeSiteCollectionTermGroup) { scope.LogDebug(CoreResources.SiteToTemplateConversion_IncludeSiteCollectionTermGroup_is_set_to_true); } if (creationInfo.PersistComposedLookFiles) { scope.LogDebug(CoreResources.SiteToTemplateConversion_PersistComposedLookFiles_is_set_to_true); } } // Create empty object ProvisioningTemplate template = new ProvisioningTemplate(); // Hookup connector, is handy when the generated template object is used to apply to another site template.Connector = creationInfo.FileConnector; List <ObjectHandlerBase> objectHandlers = new List <ObjectHandlerBase>(); objectHandlers.Add(new ObjectRegionalSettings()); objectHandlers.Add(new ObjectSupportedUILanguages()); objectHandlers.Add(new ObjectAuditSettings()); objectHandlers.Add(new ObjectSitePolicy()); objectHandlers.Add(new ObjectSiteSecurity()); objectHandlers.Add(new ObjectTermGroups()); objectHandlers.Add(new ObjectField()); objectHandlers.Add(new ObjectContentType()); objectHandlers.Add(new ObjectListInstance()); objectHandlers.Add(new ObjectCustomActions()); objectHandlers.Add(new ObjectFeatures()); objectHandlers.Add(new ObjectComposedLook()); objectHandlers.Add(new ObjectSearchSettings()); objectHandlers.Add(new ObjectFiles()); objectHandlers.Add(new ObjectPages()); objectHandlers.Add(new ObjectPropertyBagEntry()); objectHandlers.Add(new ObjectPublishing()); objectHandlers.Add(new ObjectWorkflows()); objectHandlers.Add(new ObjectRetrieveTemplateInfo()); int step = 1; var count = objectHandlers.Count(o => o.ReportProgress && o.WillExtract(web, template, creationInfo)); foreach (var handler in objectHandlers) { if (handler.WillExtract(web, template, creationInfo)) { if (messagesDelegate != null) { handler.MessagesDelegate = messagesDelegate; } if (handler.ReportProgress && progressDelegate != null) { progressDelegate(handler.Name, step, count); step++; } template = handler.ExtractObjects(web, template, creationInfo); } } return(template); } }
/// <summary> /// Actual implementation of the apply templates /// </summary> /// <param name="web"></param> /// <param name="template"></param> /// <param name="provisioningInfo"></param> internal void ApplyRemoteTemplate(Web web, ProvisioningTemplate template, ProvisioningTemplateApplyingInformation provisioningInfo) { using (var scope = new PnPMonitoredScope(CoreResources.Provisioning_ObjectHandlers_Provisioning)) { ProvisioningProgressDelegate progressDelegate = null; ProvisioningMessagesDelegate messagesDelegate = null; if (provisioningInfo != null) { if (provisioningInfo.OverwriteSystemPropertyBagValues == true) { scope.LogInfo(CoreResources.SiteToTemplateConversion_ApplyRemoteTemplate_OverwriteSystemPropertyBagValues_is_to_true); } progressDelegate = provisioningInfo.ProgressDelegate; if (provisioningInfo.ProgressDelegate != null) { scope.LogInfo(CoreResources.SiteToTemplateConversion_ProgressDelegate_registered); } messagesDelegate = provisioningInfo.MessagesDelegate; if (provisioningInfo.MessagesDelegate != null) { scope.LogInfo(CoreResources.SiteToTemplateConversion_MessagesDelegate_registered); } } List <ObjectHandlerBase> objectHandlers = new List <ObjectHandlerBase>(); objectHandlers.Add(new ObjectRegionalSettings()); objectHandlers.Add(new ObjectSupportedUILanguages()); objectHandlers.Add(new ObjectAuditSettings()); objectHandlers.Add(new ObjectSitePolicy()); objectHandlers.Add(new ObjectSiteSecurity()); objectHandlers.Add(new ObjectFeatures()); objectHandlers.Add(new ObjectTermGroups()); objectHandlers.Add(new ObjectField()); objectHandlers.Add(new ObjectContentType()); objectHandlers.Add(new ObjectListInstance()); objectHandlers.Add(new ObjectLookupFields()); objectHandlers.Add(new ObjectListInstanceDataRows()); objectHandlers.Add(new ObjectFiles()); objectHandlers.Add(new ObjectPages()); objectHandlers.Add(new ObjectCustomActions()); objectHandlers.Add(new ObjectPublishing()); objectHandlers.Add(new ObjectComposedLook()); objectHandlers.Add(new ObjectSearchSettings()); objectHandlers.Add(new ObjectWorkflows()); objectHandlers.Add(new ObjectPropertyBagEntry()); objectHandlers.Add(new ObjectExtensibilityProviders()); objectHandlers.Add(new ObjectPersistTemplateInfo()); var tokenParser = new TokenParser(web, template); int step = 1; var count = objectHandlers.Count(o => o.ReportProgress && o.WillProvision(web, template)); foreach (var handler in objectHandlers) { if (handler.WillProvision(web, template)) { if (messagesDelegate != null) { handler.MessagesDelegate = messagesDelegate; } if (handler.ReportProgress && progressDelegate != null) { progressDelegate(handler.Name, step, count); step++; } tokenParser = handler.ProvisionObjects(web, template, tokenParser, provisioningInfo); } } } }
private static IEnumerable <Model.RoleAssignment> CheckForAndRemoveNonExistingPrincipals(IEnumerable <Model.RoleAssignment> RoleAssignments, TokenParser parser, IEnumerable <Microsoft.SharePoint.Client.Group> groups, ClientContext context, ProvisioningMessagesDelegate MessageDelegate) { var result = new List <Model.RoleAssignment>(); foreach (var roleAssignment in RoleAssignments) { var roleAssignmentPrincipal = parser.ParseString(roleAssignment.Principal); Principal principal = TryGetGroupPrincipal(groups, roleAssignmentPrincipal); if (principal == null) { try { context.Web.EnsureUser(roleAssignmentPrincipal); context.ExecuteQueryRetry(); } catch (ServerException ex) { // catch user not found if (ex.ServerErrorCode == -2146232832 && ex.ServerErrorTypeName.Equals("Microsoft.SharePoint.SPException", StringComparison.InvariantCultureIgnoreCase)) { MessageDelegate($"Cannot find principal '{roleAssignmentPrincipal}', cannot grant permissions", ProvisioningMessageType.Warning); continue; } } } result.Add(roleAssignment); } return(result); }
public static void SetSecurity(this SecurableObject securable, TokenParser parser, ObjectSecurity security, ProvisioningMessagesDelegate MessageDelegate) { // If there's no role assignments we're returning if (security.RoleAssignments.Count == 0) { return; } var context = securable.Context as ClientContext; var groups = context.LoadQuery(context.Web.SiteGroups.Include(g => g.LoginName, g => g.Id)); var webRoleDefinitions = context.LoadQuery(context.Web.RoleDefinitions); securable.BreakRoleInheritance(security.CopyRoleAssignments, security.ClearSubscopes); var securableRoleAssignments = context.LoadQuery(securable.RoleAssignments); context.ExecuteQueryRetry(); IEnumerable <Model.RoleAssignment> roleAssignmentsToHandle = security.RoleAssignments; // try to apply the security in two steps: step one assumes all principals from the template exist and can be granted permission at once try { // note that this step fails if there is one principal that doesn't exist ApplySecurity(securable, parser, context, groups, webRoleDefinitions, securableRoleAssignments, roleAssignmentsToHandle); context.ExecuteQueryRetry(); } catch (ServerException ex) { // catch user not found; enter step 2: check each and every principal for existence before granting security for those that exist if (ex.ServerErrorCode == -2146232832 && ex.ServerErrorTypeName.Equals("Microsoft.SharePoint.SPException", StringComparison.InvariantCultureIgnoreCase)) { roleAssignmentsToHandle = CheckForAndRemoveNonExistingPrincipals(roleAssignmentsToHandle, parser, groups, context, MessageDelegate); ApplySecurity(securable, parser, context, groups, webRoleDefinitions, securableRoleAssignments, roleAssignmentsToHandle); // if it fails this time we just let it fail context.ExecuteQueryRetry(); } } }
public static TokenParser ProcessO365GroupSettings(Tenant tenant, ProvisioningTenant provisioningTenant, TokenParser parser, PnPMonitoredScope scope, ProvisioningMessagesDelegate messagesDelegate) { if (provisioningTenant.Office365GroupsSettings != null && provisioningTenant.Office365GroupsSettings.Properties.Any()) { messagesDelegate?.Invoke("Processing Office 365 Group Settings", ProvisioningMessageType.Progress); bool siteClassificationSettingsExists = false; if (PnPProvisioningContext.Current != null) { string accessToken = string.Empty; try { // Get a fresh Access Token for every request accessToken = PnPProvisioningContext.Current.AcquireToken(GraphHelper.MicrosoftGraphBaseURI, "Directory.ReadWrite.All"); if (accessToken != null) { try { var siteClassificationSettings = tenant.GetSiteClassificationsSettings(accessToken); siteClassificationSettingsExists = true; } catch (Exception ex) { // Tenant classification doesn't exist, just swallow the exception. } if (siteClassificationSettingsExists) { // Tenant classification exists, update the necessary values for Group Settings. try { string directorySettingTemplatesUrl = $"{GraphHttpClient.MicrosoftGraphV1BaseUri}groupSettings"; var directorySettingTemplatesJson = GraphHttpClient.MakeGetRequestForString(directorySettingTemplatesUrl, accessToken); var directorySettingTemplates = JsonConvert.DeserializeObject <DirectorySettingTemplates>(directorySettingTemplatesJson); // Retrieve the setinngs for "Group.Unified" var unifiedGroupSetting = directorySettingTemplates.Templates.FirstOrDefault(t => t.DisplayName == "Group.Unified"); if (unifiedGroupSetting != null) { var props = provisioningTenant.Office365GroupsSettings.Properties; foreach (var v in unifiedGroupSetting.SettingValues) { var item = props.Where(p => p.Key == v.Name).FirstOrDefault(); if (!string.IsNullOrEmpty(item.Key)) { v.Value = parser.ParseString(item.Value); } } string updateDirectorySettingUrl = $"{GraphHttpClient.MicrosoftGraphV1BaseUri}groupSettings/{unifiedGroupSetting.Id}"; var updateDirectorySettingResult = GraphHttpClient.MakePatchRequestForString( updateDirectorySettingUrl, content: new { templateId = unifiedGroupSetting.Id, values = from v in unifiedGroupSetting.SettingValues select new { name = v.Name, value = v.Value }, }, contentType: "application/json", accessToken: accessToken); } else { throw new ApplicationException("Missing DirectorySettingTemplate for \"Group.Unified\""); } } catch (Exception ex) { scope.LogError($"Error occurred processing O365 Group settings ${ex.Message}"); } } else { // Tenant classification doesn't exist, create the necessary template for Group Settings. try { string directorySettingTemplatesUrl = $"{GraphHttpClient.MicrosoftGraphV1BaseUri}groupSettingTemplates"; var directorySettingTemplatesJson = GraphHttpClient.MakeGetRequestForString(directorySettingTemplatesUrl, accessToken); var directorySettingTemplates = JsonConvert.DeserializeObject <DirectorySettingTemplates>(directorySettingTemplatesJson); // Retrieve the setinngs for "Group.Unified" var unifiedGroupSetting = directorySettingTemplates.Templates.FirstOrDefault(t => t.DisplayName == "Group.Unified"); if (unifiedGroupSetting != null) { var props = provisioningTenant.Office365GroupsSettings.Properties; foreach (var v in unifiedGroupSetting.SettingValues) { var item = props.Where(p => p.Key == v.Name).FirstOrDefault(); if (!string.IsNullOrEmpty(item.Key)) { v.Value = parser.ParseString(item.Value); } else { // Set default value because null is not supported // It only accepts entire collection and not individual properties v.Value = v.DefaultValue; } } string updateDirectorySettingUrl = $"{GraphHttpClient.MicrosoftGraphV1BaseUri}groupSettings"; var updateDirectorySettingResult = GraphHttpClient.MakePostRequestForString( updateDirectorySettingUrl, content: new { templateId = unifiedGroupSetting.Id, values = from v in unifiedGroupSetting.SettingValues select new { name = v.Name, value = v.Value }, }, contentType: "application/json", accessToken: accessToken); } else { throw new ApplicationException("Missing DirectorySettingTemplate for \"Group.Unified\""); } } catch (Exception ex) { scope.LogError($"Error occurred processing O365 Group settings ${ex.Message}"); } } } } catch (Exception ex) { scope.LogError($"Error occurred processing O365 Group settings ${ex.Message}"); } } } return(parser); }
internal static TokenParser ProcessStorageEntities(Tenant tenant, ProvisioningTenant provisioningTenant, TokenParser parser, PnPMonitoredScope scope, ProvisioningTemplateApplyingInformation applyingInformation, ProvisioningMessagesDelegate messagesDelegate) { if (provisioningTenant.StorageEntities != null && provisioningTenant.StorageEntities.Any()) { var rootSiteUrl = tenant.GetRootSiteUrl(); tenant.Context.ExecuteQueryRetry(); using (var context = ((ClientContext)tenant.Context).Clone(rootSiteUrl.Value, applyingInformation.AccessTokens)) { var web = context.Web; Uri appCatalogUri = null; try { appCatalogUri = web.GetAppCatalog(); } catch (System.Net.WebException ex) { if (ex.Response != null) { var httpResponse = ex.Response as System.Net.HttpWebResponse; if (httpResponse != null && httpResponse.StatusCode == HttpStatusCode.Unauthorized) { // Ignore any security exception and simply keep // the AppCatalog URI null } else { throw ex; } } else { throw ex; } } if (appCatalogUri != null) { using (var appCatalogContext = context.Clone(appCatalogUri, applyingInformation.AccessTokens)) { foreach (var entity in provisioningTenant.StorageEntities) { var key = parser.ParseString(entity.Key); var value = parser.ParseString(entity.Value); var description = parser.ParseString(entity.Description); var comment = parser.ParseString(entity.Comment); appCatalogContext.Web.SetStorageEntity(key, value, description, comment); } appCatalogContext.Web.Update(); appCatalogContext.ExecuteQueryRetry(); } } else { messagesDelegate?.Invoke($"Tenant app catalog doesn't exist. Provisioning of storage entities will be skipped!", ProvisioningMessageType.Warning); } } } return(parser); }
internal void ApplyTenantTemplate(Tenant tenant, PnP.Framework.Provisioning.Model.ProvisioningHierarchy hierarchy, string sequenceId, ApplyConfiguration configuration) { using (var scope = new PnPMonitoredScope(CoreResources.Provisioning_ObjectHandlers_Provisioning)) { ProvisioningProgressDelegate progressDelegate = null; ProvisioningMessagesDelegate messagesDelegate = null; if (configuration == null) { // When no provisioning info was passed then we want to execute all handlers configuration = new ApplyConfiguration(); } else { progressDelegate = configuration.ProgressDelegate; if (configuration.ProgressDelegate != null) { scope.LogInfo(CoreResources.SiteToTemplateConversion_ProgressDelegate_registered); } messagesDelegate = configuration.MessagesDelegate; if (configuration.MessagesDelegate != null) { scope.LogInfo(CoreResources.SiteToTemplateConversion_MessagesDelegate_registered); } } List <ObjectHierarchyHandlerBase> objectHandlers = new List <ObjectHierarchyHandlerBase> { new ObjectHierarchyTenant(), new ObjectHierarchySequenceTermGroups(), new ObjectHierarchySequenceSites(), new ObjectTeams(), new ObjectAzureActiveDirectory(), }; var count = objectHandlers.Count(o => o.ReportProgress && o.WillProvision(tenant, hierarchy, sequenceId, configuration)) + 1; progressDelegate?.Invoke("Initializing engine", 1, count); // handlers + initializing message) int step = 2; TokenParser sequenceTokenParser = new TokenParser(tenant, hierarchy); CallWebHooks(hierarchy.Templates.FirstOrDefault(), sequenceTokenParser, ProvisioningTemplateWebhookKind.ProvisioningStarted); foreach (var handler in objectHandlers) { if (handler.WillProvision(tenant, hierarchy, sequenceId, configuration)) { if (messagesDelegate != null) { handler.MessagesDelegate = messagesDelegate; } if (handler.ReportProgress && progressDelegate != null) { progressDelegate(handler.Name, step, count); step++; } try { sequenceTokenParser = handler.ProvisionObjects(tenant, hierarchy, sequenceId, sequenceTokenParser, configuration); } catch (Exception ex) { CallWebHooks(hierarchy.Templates.FirstOrDefault(), sequenceTokenParser, ProvisioningTemplateWebhookKind.ProvisioningExceptionOccurred, handler.Name, ex); throw; } } } CallWebHooks(hierarchy.Templates.FirstOrDefault(), sequenceTokenParser, ProvisioningTemplateWebhookKind.ProvisioningCompleted); } }
public static TokenParser ProcessSiteDesigns(Tenant tenant, ProvisioningTenant provisioningTenant, TokenParser parser, PnPMonitoredScope scope, ProvisioningMessagesDelegate messagesDelegate) { if (provisioningTenant.SiteDesigns != null && provisioningTenant.SiteDesigns.Any()) { var existingDesigns = tenant.GetSiteDesigns(); tenant.Context.Load(existingDesigns); tenant.Context.ExecuteQueryRetry(); foreach (var siteDesign in provisioningTenant.SiteDesigns) { var parsedTitle = parser.ParseString(siteDesign.Title); var parsedDescription = parser.ParseString(siteDesign.Description); var parsedPreviewImageUrl = parser.ParseString(siteDesign.PreviewImageUrl); var parsedPreviewImageAltText = parser.ParseString(siteDesign.PreviewImageAltText); messagesDelegate?.Invoke($"Processing site design {parsedTitle}", ProvisioningMessageType.Progress); var existingSiteDesign = existingDesigns.FirstOrDefault(d => d.Title == parsedTitle); if (existingSiteDesign == null) { TenantSiteDesignCreationInfo siteDesignCreationInfo = new TenantSiteDesignCreationInfo() { Title = parsedTitle, Description = parsedDescription, PreviewImageUrl = parsedPreviewImageUrl, PreviewImageAltText = parsedPreviewImageAltText, IsDefault = siteDesign.IsDefault, }; switch ((int)siteDesign.WebTemplate) { case 0: { siteDesignCreationInfo.WebTemplate = "64"; break; } case 1: { siteDesignCreationInfo.WebTemplate = "68"; break; } } if (siteDesign.SiteScripts != null && siteDesign.SiteScripts.Any()) { List <Guid> ids = new List <Guid>(); foreach (var siteScriptRef in siteDesign.SiteScripts) { ids.Add(Guid.Parse(parser.ParseString(siteScriptRef))); } siteDesignCreationInfo.SiteScriptIds = ids.ToArray(); } var design = tenant.CreateSiteDesign(siteDesignCreationInfo); tenant.Context.Load(design); tenant.Context.ExecuteQueryRetry(); if (siteDesign.Grants != null && siteDesign.Grants.Any()) { foreach (var grant in siteDesign.Grants) { var rights = (TenantSiteDesignPrincipalRights)Enum.Parse(typeof(TenantSiteDesignPrincipalRights), grant.Right.ToString()); tenant.GrantSiteDesignRights(design.Id, new[] { grant.Principal }, rights); } tenant.Context.ExecuteQueryRetry(); } parser.AddToken(new SiteDesignIdToken(null, design.Title, design.Id)); } else { if (siteDesign.Overwrite) { var existingId = existingSiteDesign.Id; existingSiteDesign = Tenant.GetSiteDesign(tenant.Context, existingId); tenant.Context.ExecuteQueryRetry(); existingSiteDesign.Title = parsedTitle; existingSiteDesign.Description = parsedDescription; existingSiteDesign.PreviewImageUrl = parsedPreviewImageUrl; existingSiteDesign.PreviewImageAltText = parsedPreviewImageAltText; existingSiteDesign.IsDefault = siteDesign.IsDefault; switch ((int)siteDesign.WebTemplate) { case 0: { existingSiteDesign.WebTemplate = "64"; break; } case 1: { existingSiteDesign.WebTemplate = "68"; break; } } tenant.UpdateSiteDesign(existingSiteDesign); tenant.Context.ExecuteQueryRetry(); var existingToken = parser.Tokens.OfType <SiteDesignIdToken>().FirstOrDefault(t => t.GetReplaceValue() == existingId.ToString()); if (existingToken != null) { parser.Tokens.Remove(existingToken); } parser.AddToken(new SiteScriptIdToken(null, parsedTitle, existingId)); if (siteDesign.Grants != null && siteDesign.Grants.Any()) { var existingRights = Tenant.GetSiteDesignRights(tenant.Context, existingId); tenant.Context.Load(existingRights); tenant.Context.ExecuteQueryRetry(); foreach (var existingRight in existingRights) { Tenant.RevokeSiteDesignRights(tenant.Context, existingId, new[] { existingRight.PrincipalName }); } foreach (var grant in siteDesign.Grants) { var rights = (TenantSiteDesignPrincipalRights)Enum.Parse(typeof(TenantSiteDesignPrincipalRights), grant.Right.ToString()); tenant.GrantSiteDesignRights(existingId, new[] { parser.ParseString(grant.Principal) }, rights); } tenant.Context.ExecuteQueryRetry(); } } } } } return(parser); }
/// <summary> /// Actual implementation of extracting configuration from existing site. /// </summary> /// <param name="web"></param> /// <param name="creationInfo"></param> /// <returns></returns> internal ProvisioningTemplate GetRemoteTemplate(Web web, ProvisioningTemplateCreationInformation creationInfo) { using (var scope = new PnPMonitoredScope(CoreResources.Provisioning_ObjectHandlers_Extraction)) { #if !ONPREMISES || SP2016 || SP2019 web.Context.DisableReturnValueCache = true; #endif ProvisioningProgressDelegate progressDelegate = null; ProvisioningMessagesDelegate messagesDelegate = null; if (creationInfo != null) { if (creationInfo.BaseTemplate != null) { scope.LogDebug(CoreResources.SiteToTemplateConversion_Base_template_available___0_, creationInfo.BaseTemplate.Id); } progressDelegate = creationInfo.ProgressDelegate; if (creationInfo.ProgressDelegate != null) { scope.LogDebug(CoreResources.SiteToTemplateConversion_ProgressDelegate_registered); } messagesDelegate = creationInfo.MessagesDelegate; if (creationInfo.MessagesDelegate != null) { scope.LogDebug(CoreResources.SiteToTemplateConversion_MessagesDelegate_registered); } if (creationInfo.IncludeAllTermGroups) { scope.LogDebug(CoreResources.SiteToTemplateConversion_IncludeAllTermGroups_is_set_to_true); } if (creationInfo.IncludeSiteCollectionTermGroup) { scope.LogDebug(CoreResources.SiteToTemplateConversion_IncludeSiteCollectionTermGroup_is_set_to_true); } if (creationInfo.PersistBrandingFiles) { scope.LogDebug(CoreResources.SiteToTemplateConversion_PersistBrandingFiles_is_set_to_true); } } else { // When no provisioning info was passed then we want to execute all handlers creationInfo = new ProvisioningTemplateCreationInformation(web); creationInfo.HandlersToProcess = Handlers.All; } // Create empty object ProvisioningTemplate template = new ProvisioningTemplate(); // Hookup connector, is handy when the generated template object is used to apply to another site template.Connector = creationInfo.FileConnector; List <ObjectHandlerBase> objectHandlers = new List <ObjectHandlerBase>(); if (creationInfo.HandlersToProcess.HasFlag(Handlers.RegionalSettings)) { objectHandlers.Add(new ObjectRegionalSettings()); } if (creationInfo.HandlersToProcess.HasFlag(Handlers.SupportedUILanguages)) { objectHandlers.Add(new ObjectSupportedUILanguages()); } if (creationInfo.HandlersToProcess.HasFlag(Handlers.AuditSettings)) { objectHandlers.Add(new ObjectAuditSettings()); } if (creationInfo.HandlersToProcess.HasFlag(Handlers.SitePolicy)) { objectHandlers.Add(new ObjectSitePolicy()); } if (creationInfo.HandlersToProcess.HasFlag(Handlers.SiteSecurity)) { objectHandlers.Add(new ObjectSiteSecurity()); } if (creationInfo.HandlersToProcess.HasFlag(Handlers.TermGroups)) { objectHandlers.Add(new ObjectTermGroups()); } if (creationInfo.HandlersToProcess.HasFlag(Handlers.Fields)) { objectHandlers.Add(new ObjectField(FieldAndListProvisioningStepHelper.Step.Export)); } if (creationInfo.HandlersToProcess.HasFlag(Handlers.ContentTypes)) { objectHandlers.Add(new ObjectContentType(FieldAndListProvisioningStepHelper.Step.Export)); } if (creationInfo.HandlersToProcess.HasFlag(Handlers.Lists)) { objectHandlers.Add(new ObjectListInstance(FieldAndListProvisioningStepHelper.Step.Export)); } if (creationInfo.HandlersToProcess.HasFlag(Handlers.CustomActions)) { objectHandlers.Add(new ObjectCustomActions()); } if (creationInfo.HandlersToProcess.HasFlag(Handlers.Features)) { objectHandlers.Add(new ObjectFeatures()); } if (creationInfo.HandlersToProcess.HasFlag(Handlers.ComposedLook)) { objectHandlers.Add(new ObjectComposedLook()); } if (creationInfo.HandlersToProcess.HasFlag(Handlers.SearchSettings)) { objectHandlers.Add(new ObjectSearchSettings()); } if (creationInfo.HandlersToProcess.HasFlag(Handlers.Files)) { objectHandlers.Add(new ObjectFiles()); } if (creationInfo.HandlersToProcess.HasFlag(Handlers.Pages)) { objectHandlers.Add(new ObjectPages()); } if (creationInfo.HandlersToProcess.HasFlag(Handlers.PageContents)) { objectHandlers.Add(new ObjectPageContents()); } #if !ONPREMISES if (creationInfo.HandlersToProcess.HasFlag(Handlers.PageContents)) { objectHandlers.Add(new ObjectClientSidePageContents()); } if (creationInfo.HandlersToProcess.HasFlag(Handlers.SiteHeader)) { objectHandlers.Add(new ObjectSiteHeaderSettings()); } if (creationInfo.HandlersToProcess.HasFlag(Handlers.SiteFooter)) { objectHandlers.Add(new ObjectSiteFooterSettings()); } #endif if (creationInfo.HandlersToProcess.HasFlag(Handlers.PropertyBagEntries)) { objectHandlers.Add(new ObjectPropertyBagEntry()); } if (creationInfo.HandlersToProcess.HasFlag(Handlers.Publishing)) { objectHandlers.Add(new ObjectPublishing()); } if (creationInfo.HandlersToProcess.HasFlag(Handlers.Workflows)) { objectHandlers.Add(new ObjectWorkflows()); } if (creationInfo.HandlersToProcess.HasFlag(Handlers.WebSettings)) { objectHandlers.Add(new ObjectWebSettings()); } if (creationInfo.HandlersToProcess.HasFlag(Handlers.Theme)) { objectHandlers.Add(new ObjectTheme()); } if (creationInfo.HandlersToProcess.HasFlag(Handlers.Navigation)) { objectHandlers.Add(new ObjectNavigation()); } if (creationInfo.HandlersToProcess.HasFlag(Handlers.ImageRenditions)) { objectHandlers.Add(new ObjectImageRenditions()); } objectHandlers.Add(new ObjectLocalization()); // Always add this one, check is done in the handler #if !ONPREMISES if (creationInfo.HandlersToProcess.HasFlag(Handlers.Tenant)) { objectHandlers.Add(new ObjectTenant()); } if (creationInfo.HandlersToProcess.HasFlag(Handlers.ApplicationLifecycleManagement)) { objectHandlers.Add(new ObjectApplicationLifecycleManagement()); } #endif if (creationInfo.HandlersToProcess.HasFlag(Handlers.ExtensibilityProviders)) { objectHandlers.Add(new ObjectExtensibilityHandlers()); } objectHandlers.Add(new ObjectRetrieveTemplateInfo()); int step = 1; var count = objectHandlers.Count(o => o.ReportProgress && o.WillExtract(web, template, creationInfo)); web.EnsureProperty(w => w.Url); foreach (var handler in objectHandlers) { if (handler.WillExtract(web, template, creationInfo)) { if (messagesDelegate != null) { handler.MessagesDelegate = messagesDelegate; } if (handler.ReportProgress && progressDelegate != null) { progressDelegate(handler.Name, step, count); step++; } using (var handlerContext = web.Context.Clone(web.Url)) { template = handler.ExtractObjects(handlerContext.Web, template, creationInfo); } } } return(template); } }
public static TokenParser ProcessThemes(Tenant tenant, ProvisioningTenant provisioningTenant, TokenParser parser, PnPMonitoredScope scope, ProvisioningMessagesDelegate messagesDelegate) { if (provisioningTenant.Themes != null && provisioningTenant.Themes.Any()) { var themes = tenant.GetAllTenantThemes(); tenant.Context.Load(themes); tenant.Context.ExecuteQueryRetry(); foreach (var theme in provisioningTenant.Themes) { var parsedName = parser.ParseString(theme.Name); if (themes.FirstOrDefault(t => t.Name == parsedName) != null) { if (theme.Overwrite) { var parsedPalette = parser.ParseString(theme.Palette); messagesDelegate?.Invoke($"Overwriting existing theme {parsedName}", ProvisioningMessageType.Progress); var palette = JsonConvert.DeserializeObject <Dictionary <string, string> >(parsedPalette); var tenantTheme = new TenantTheme() { Name = parsedName, Palette = palette, IsInverted = theme.IsInverted }; tenant.UpdateTenantTheme(parsedName, JsonConvert.SerializeObject(tenantTheme)); tenant.Context.ExecuteQueryRetry(); } else { messagesDelegate?.Invoke($"Skipped processing theme {parsedName} as it already exists and Overwrite is set to false", ProvisioningMessageType.Progress); } } else { var parsedPalette = parser.ParseString(theme.Palette); messagesDelegate?.Invoke($"Processing theme {parsedName}", ProvisioningMessageType.Progress); var palette = JsonConvert.DeserializeObject <Dictionary <string, string> >(parsedPalette); var tenantTheme = new TenantTheme() { Name = parsedName, Palette = palette, IsInverted = theme.IsInverted }; tenant.AddTenantTheme(parsedName, JsonConvert.SerializeObject(tenantTheme)); tenant.Context.ExecuteQueryRetry(); } } } return(parser); }
internal void ApplyProvisioningHierarchy(Tenant tenant, OfficeDevPnP.Core.Framework.Provisioning.Model.ProvisioningHierarchy hierarchy, string sequenceId, ProvisioningTemplateApplyingInformation provisioningInfo) { using (var scope = new PnPMonitoredScope(CoreResources.Provisioning_ObjectHandlers_Provisioning)) { ProvisioningProgressDelegate progressDelegate = null; ProvisioningMessagesDelegate messagesDelegate = null; if (provisioningInfo == null) { // When no provisioning info was passed then we want to execute all handlers provisioningInfo = new ProvisioningTemplateApplyingInformation(); provisioningInfo.HandlersToProcess = Handlers.All; } else { progressDelegate = provisioningInfo.ProgressDelegate; if (provisioningInfo.ProgressDelegate != null) { scope.LogInfo(CoreResources.SiteToTemplateConversion_ProgressDelegate_registered); } messagesDelegate = provisioningInfo.MessagesDelegate; if (provisioningInfo.MessagesDelegate != null) { scope.LogInfo(CoreResources.SiteToTemplateConversion_MessagesDelegate_registered); } if (provisioningInfo.HandlersToProcess == default(Handlers)) { provisioningInfo.HandlersToProcess = Handlers.All; } } List <ObjectHierarchyHandlerBase> objectHandlers = new List <ObjectHierarchyHandlerBase> { new ObjectHierarchyTenant(), new ObjectHierarchySequenceTermGroups(), new ObjectHierarchySequenceSites(), new ObjectTeams(), new ObjectAzureActiveDirectory(), }; var count = objectHandlers.Count(o => o.ReportProgress && o.WillProvision(tenant, hierarchy, sequenceId, provisioningInfo)) + 1; progressDelegate?.Invoke("Initializing engine", 1, count); // handlers + initializing message) int step = 2; TokenParser sequenceTokenParser = new TokenParser(tenant, hierarchy); foreach (var handler in objectHandlers) { if (handler.WillProvision(tenant, hierarchy, sequenceId, provisioningInfo)) { if (messagesDelegate != null) { handler.MessagesDelegate = messagesDelegate; } if (handler.ReportProgress && progressDelegate != null) { progressDelegate(handler.Name, step, count); step++; } sequenceTokenParser = handler.ProvisionObjects(tenant, hierarchy, sequenceId, sequenceTokenParser, provisioningInfo); } } } }
/// <summary> /// Retrieves a file as a byte array from the connector. If the file name contains special characters (e.g. "%20") and cannot be retrieved, a workaround will be performed /// </summary> internal static void ProcessCdns(Tenant tenant, ProvisioningTenant provisioningTenant, TokenParser parser, PnPMonitoredScope scope, ProvisioningMessagesDelegate messagesDelegate) { if (provisioningTenant.ContentDeliveryNetwork != null) { if (provisioningTenant.ContentDeliveryNetwork.PublicCdn != null || provisioningTenant.ContentDeliveryNetwork.PrivateCdn != null) { var publicCdnEnabled = tenant.GetTenantCdnEnabled(SPOTenantCdnType.Public); var privateCdnEnabled = tenant.GetTenantCdnEnabled(SPOTenantCdnType.Private); tenant.Context.ExecuteQueryRetry(); var publicCdn = provisioningTenant.ContentDeliveryNetwork.PublicCdn; if (publicCdn != null) { if (publicCdnEnabled.Value != publicCdn.Enabled) { scope.LogInfo($"Public CDN is set to {(publicCdn.Enabled ? "Enabled" : "Disabled")}"); tenant.SetTenantCdnEnabled(SPOTenantCdnType.Public, publicCdn.Enabled); tenant.Context.ExecuteQueryRetry(); } if (publicCdn.Enabled) { if (!publicCdn.NoDefaultOrigins) { tenant.CreateTenantCdnDefaultOrigins(SPOTenantCdnType.Public); tenant.Context.ExecuteQueryRetry(); } ProcessOrigins(tenant, publicCdn, SPOTenantCdnType.Public, parser, scope); ProcessPolicies(tenant, publicCdn, SPOTenantCdnType.Public, parser, scope); } } var privateCdn = provisioningTenant.ContentDeliveryNetwork.PrivateCdn; if (privateCdn != null) { if (privateCdnEnabled.Value != privateCdn.Enabled) { scope.LogInfo($"Private CDN is set to {(privateCdn.Enabled ? "Enabled" : "Disabled")}"); tenant.SetTenantCdnEnabled(SPOTenantCdnType.Private, privateCdn.Enabled); tenant.Context.ExecuteQueryRetry(); } if (privateCdn.Enabled) { if (!privateCdn.NoDefaultOrigins) { tenant.CreateTenantCdnDefaultOrigins(SPOTenantCdnType.Private); tenant.Context.ExecuteQueryRetry(); } ProcessOrigins(tenant, privateCdn, SPOTenantCdnType.Private, parser, scope); ProcessPolicies(tenant, privateCdn, SPOTenantCdnType.Private, parser, scope); } } } } }
/// <summary> /// Actual implementation of the apply templates /// </summary> /// <param name="web"></param> /// <param name="template"></param> /// <param name="provisioningInfo"></param> /// <param name="calledFromHierarchy"></param> /// <param name="tokenParser"></param> internal void ApplyRemoteTemplate(Web web, ProvisioningTemplate template, ProvisioningTemplateApplyingInformation provisioningInfo, bool calledFromHierarchy = false, TokenParser tokenParser = null) { using (var scope = new PnPMonitoredScope(CoreResources.Provisioning_ObjectHandlers_Provisioning)) { #if !ONPREMISES || SP2016 || SP2019 web.Context.DisableReturnValueCache = true; #endif ProvisioningProgressDelegate progressDelegate = null; ProvisioningMessagesDelegate messagesDelegate = null; ProvisioningSiteProvisionedDelegate siteProvisionedDelegate = null; if (provisioningInfo != null) { if (provisioningInfo.OverwriteSystemPropertyBagValues == true) { scope.LogInfo(CoreResources.SiteToTemplateConversion_ApplyRemoteTemplate_OverwriteSystemPropertyBagValues_is_to_true); } progressDelegate = provisioningInfo.ProgressDelegate; if (provisioningInfo.ProgressDelegate != null) { scope.LogInfo(CoreResources.SiteToTemplateConversion_ProgressDelegate_registered); } messagesDelegate = provisioningInfo.MessagesDelegate; if (provisioningInfo.MessagesDelegate != null) { scope.LogInfo(CoreResources.SiteToTemplateConversion_MessagesDelegate_registered); } siteProvisionedDelegate = provisioningInfo.SiteProvisionedDelegate; } else { // When no provisioning info was passed then we want to execute all handlers provisioningInfo = new ProvisioningTemplateApplyingInformation(); provisioningInfo.HandlersToProcess = Handlers.All; } // Check if scope is present and if so, matches the current site. When scope was not set the returned value will be ProvisioningTemplateScope.Undefined if (template.Scope == ProvisioningTemplateScope.RootSite) { if (web.IsSubSite()) { scope.LogError(CoreResources.SiteToTemplateConversion_ScopeOfTemplateDoesNotMatchTarget); throw new Exception(CoreResources.SiteToTemplateConversion_ScopeOfTemplateDoesNotMatchTarget); } } var currentCultureInfoValue = System.Threading.Thread.CurrentThread.CurrentCulture.LCID; if (!string.IsNullOrEmpty(template.TemplateCultureInfo)) { int cultureInfoValue = System.Threading.Thread.CurrentThread.CurrentCulture.LCID; if (int.TryParse(template.TemplateCultureInfo, out cultureInfoValue)) { System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo(cultureInfoValue); } else { System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo(template.TemplateCultureInfo); } } // Check if the target site shares the same base template with the template's source site var targetSiteTemplateId = web.GetBaseTemplateId(); if (!String.IsNullOrEmpty(targetSiteTemplateId) && !String.IsNullOrEmpty(template.BaseSiteTemplate)) { if (!targetSiteTemplateId.Equals(template.BaseSiteTemplate, StringComparison.InvariantCultureIgnoreCase)) { var templatesNotMatchingWarning = String.Format(CoreResources.Provisioning_Asymmetric_Base_Templates, template.BaseSiteTemplate, targetSiteTemplateId); scope.LogWarning(templatesNotMatchingWarning); messagesDelegate?.Invoke(templatesNotMatchingWarning, ProvisioningMessageType.Warning); } } // Always ensure the Url property is loaded. In the tokens we need this and we don't want to call ExecuteQuery as this can // impact delta scenarions (calling ExecuteQuery before the planned update is called) web.EnsureProperty(w => w.Url); List <ObjectHandlerBase> objectHandlers = new List <ObjectHandlerBase>(); if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.RegionalSettings)) { objectHandlers.Add(new ObjectRegionalSettings()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.SupportedUILanguages)) { objectHandlers.Add(new ObjectSupportedUILanguages()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.AuditSettings)) { objectHandlers.Add(new ObjectAuditSettings()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.SitePolicy)) { objectHandlers.Add(new ObjectSitePolicy()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.SiteSecurity)) { objectHandlers.Add(new ObjectSiteSecurity()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.Features)) { objectHandlers.Add(new ObjectFeatures()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.TermGroups)) { objectHandlers.Add(new ObjectTermGroups()); } // Process 3 times these providers to handle proper ordering of artefact creation when dealing with lookup fields // 1st. create fields, content and list without lookup fields if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.Fields) || provisioningInfo.HandlersToProcess.HasFlag(Handlers.Lists)) { objectHandlers.Add(new ObjectField(FieldAndListProvisioningStepHelper.Step.ListAndStandardFields)); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.ContentTypes)) { objectHandlers.Add(new ObjectContentType(FieldAndListProvisioningStepHelper.Step.ListAndStandardFields)); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.Lists)) { objectHandlers.Add(new ObjectListInstance(FieldAndListProvisioningStepHelper.Step.ListAndStandardFields)); } // 2nd. create lookup fields (which requires lists to be present if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.Fields) || provisioningInfo.HandlersToProcess.HasFlag(Handlers.Lists)) { objectHandlers.Add(new ObjectField(FieldAndListProvisioningStepHelper.Step.LookupFields)); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.ContentTypes)) { objectHandlers.Add(new ObjectContentType(FieldAndListProvisioningStepHelper.Step.LookupFields)); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.Lists)) { objectHandlers.Add(new ObjectListInstance(FieldAndListProvisioningStepHelper.Step.LookupFields)); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.Files)) { objectHandlers.Add(new ObjectFiles()); } // 3rd. Create remaining objects in lists (views, user custom actions, ...) if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.Lists)) { objectHandlers.Add(new ObjectListInstance(FieldAndListProvisioningStepHelper.Step.ListSettings)); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.Fields) || provisioningInfo.HandlersToProcess.HasFlag(Handlers.Lists)) { objectHandlers.Add(new ObjectListInstanceDataRows()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.Workflows)) { objectHandlers.Add(new ObjectWorkflows()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.Pages)) { objectHandlers.Add(new ObjectPages()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.PageContents)) { objectHandlers.Add(new ObjectPageContents()); } #if !ONPREMISES if (!calledFromHierarchy && provisioningInfo.HandlersToProcess.HasFlag(Handlers.Tenant)) { objectHandlers.Add(new ObjectTenant()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.ApplicationLifecycleManagement)) { objectHandlers.Add(new ObjectApplicationLifecycleManagement()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.Pages)) { objectHandlers.Add(new ObjectClientSidePages()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.SiteHeader)) { objectHandlers.Add(new ObjectSiteHeaderSettings()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.SiteFooter)) { objectHandlers.Add(new ObjectSiteFooterSettings()); } #endif if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.CustomActions)) { objectHandlers.Add(new ObjectCustomActions()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.Publishing)) { objectHandlers.Add(new ObjectPublishing()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.ComposedLook)) { objectHandlers.Add(new ObjectComposedLook()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.SearchSettings)) { objectHandlers.Add(new ObjectSearchSettings()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.PropertyBagEntries)) { objectHandlers.Add(new ObjectPropertyBagEntry()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.WebSettings)) { objectHandlers.Add(new ObjectWebSettings()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.Theme)) { objectHandlers.Add(new ObjectTheme()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.Navigation)) { objectHandlers.Add(new ObjectNavigation()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.ImageRenditions)) { objectHandlers.Add(new ObjectImageRenditions()); } objectHandlers.Add(new ObjectLocalization()); // Always add this one, check is done in the handler if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.ExtensibilityProviders)) { objectHandlers.Add(new ObjectExtensibilityHandlers()); } // Only persist template information in case this flag is set: this will allow the engine to // work with lesser permissions if (provisioningInfo.PersistTemplateInfo) { objectHandlers.Add(new ObjectPersistTemplateInfo()); } var count = objectHandlers.Count(o => o.ReportProgress && o.WillProvision(web, template, provisioningInfo)) + 1; progressDelegate?.Invoke("Initializing engine", 1, count); // handlers + initializing message) if (tokenParser == null) { tokenParser = new TokenParser(web, template); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.ExtensibilityProviders)) { var extensibilityHandler = objectHandlers.OfType <ObjectExtensibilityHandlers>().First(); extensibilityHandler.AddExtendedTokens(web, template, tokenParser, provisioningInfo); } int step = 2; // Remove potentially unsupported artifacts var cleaner = new NoScriptTemplateCleaner(web); if (messagesDelegate != null) { cleaner.MessagesDelegate = messagesDelegate; } template = cleaner.CleanUpBeforeProvisioning(template); CallWebHooks(template, tokenParser, ProvisioningTemplateWebhookKind.ProvisioningStarted); foreach (var handler in objectHandlers) { if (handler.WillProvision(web, template, provisioningInfo)) { if (messagesDelegate != null) { handler.MessagesDelegate = messagesDelegate; } if (handler.ReportProgress && progressDelegate != null) { progressDelegate(handler.Name, step, count); step++; } CallWebHooks(template, tokenParser, ProvisioningTemplateWebhookKind.ObjectHandlerProvisioningStarted, handler); tokenParser = handler.ProvisionObjects(web, template, tokenParser, provisioningInfo); CallWebHooks(template, tokenParser, ProvisioningTemplateWebhookKind.ObjectHandlerProvisioningCompleted, handler); } } // Notify the completed provisioning of the site web.EnsureProperties(w => w.Title, w => w.Url); siteProvisionedDelegate?.Invoke(web.Title, web.Url); CallWebHooks(template, tokenParser, ProvisioningTemplateWebhookKind.ProvisioningCompleted); System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo(currentCultureInfoValue); } }