public override TokenParser ProvisionObjects(Web web, ProvisioningTemplate template, TokenParser parser, ProvisioningTemplateApplyingInformation applyingInformation) { using (var scope = new PnPMonitoredScope(this.Name)) { var context = web.Context as ClientContext; var site = context.Site; // Check if this is not a noscript site as we're not allowed to update some properties bool isNoScriptSite = web.IsNoScriptSite(); // if this is a sub site then we're not enabling the site collection scoped custom actions if (!web.IsSubSite()) { var siteCustomActions = template.CustomActions.SiteCustomActions; ProvisionCustomActionImplementation(site, siteCustomActions, parser, scope, isNoScriptSite); } var webCustomActions = template.CustomActions.WebCustomActions; ProvisionCustomActionImplementation(web, webCustomActions, parser, scope, isNoScriptSite); // Switch parser context back to it's original context parser.Rebase(web); } return(parser); }
public override TokenParser ProvisionObjects(Web web, ProvisioningTemplate template, TokenParser parser, ProvisioningTemplateApplyingInformation applyingInformation) { using (var scope = new PnPMonitoredScope(this.Name)) { if (template.ApplicationLifecycleManagement != null) { var manager = new AppManager(web.Context as ClientContext); // The ALM API do not support the local Site Collection App Catalog // Thus, so far we skip the AppCatalog section // NOOP if (template.ApplicationLifecycleManagement.Apps != null && template.ApplicationLifecycleManagement.Apps.Count > 0) { //Get tenant app catalog var appCatalogUri = web.GetAppCatalog(); if (appCatalogUri != null) { // Get the apps already installed in the site var siteApps = manager.GetAvailable()?.Where(a => a.InstalledVersion != null)?.ToList(); foreach (var app in template.ApplicationLifecycleManagement.Apps) { var appId = Guid.Parse(parser.ParseString(app.AppId)); var alreadyExists = siteApps.Any(a => a.Id == appId); var working = false; if (app.Action == AppAction.Install && !alreadyExists) { manager.Install(appId); working = true; } else if (app.Action == AppAction.Install && alreadyExists) { WriteMessage($"App with ID {appId} already exists in the target site and will be skipped", ProvisioningMessageType.Warning); } else if (app.Action == AppAction.Uninstall && alreadyExists) { manager.Uninstall(appId); working = true; } else if (app.Action == AppAction.Uninstall && !alreadyExists) { WriteMessage($"App with ID {appId} does not exist in the target site and cannot be uninstalled", ProvisioningMessageType.Warning); } else if (app.Action == AppAction.Update && alreadyExists) { manager.Upgrade(appId); working = true; } else if (app.Action == AppAction.Update && !alreadyExists) { WriteMessage($"App with ID {appId} does not exist in the target site and cannot be updated", ProvisioningMessageType.Warning); } if (app.SyncMode == SyncMode.Synchronously && working) { // We need to wait for the app management // to be completed before proceeding switch (app.Action) { case AppAction.Install: case AppAction.Update: { PollforAppInstalled(manager, appId); break; } case AppAction.Uninstall: { PollforAppUninstalled(manager, appId); break; } } } } } else { WriteMessage($"Tenant app catalog doesn't exist. ALM step will be skipped.", ProvisioningMessageType.Warning); } } } } return(parser); }
public override bool WillProvision(Web web, ProvisioningTemplate template, ProvisioningTemplateApplyingInformation applyingInformation) { return(template.Publishing != null); }
public override TokenParser ProvisionObjects(Web web, ProvisioningTemplate template, TokenParser parser, ProvisioningTemplateApplyingInformation applyingInformation) { using (var scope = new PnPMonitoredScope(this.Name)) { // Check if this is not a noscript site as we're not allowed to write to the web property bag is that one bool isNoScriptSite = web.IsNoScriptSite(); web.EnsureProperties(w => w.ServerRelativeUrl, w => w.Url); // Build on the fly the list of additional files coming from the Directories var directoryFiles = new List <Model.File>(); foreach (var directory in template.Directories) { var metadataProperties = directory.GetMetadataProperties(); directoryFiles.AddRange(directory.GetDirectoryFiles(metadataProperties)); } var filesToProcess = template.Files.Union(directoryFiles).ToArray(); var siteAssetsFiles = filesToProcess.Where(f => f.Folder.ToLower().Contains("siteassets")).FirstOrDefault(); if (siteAssetsFiles != null) { // Need this so that we dont have access denied error during the first time upload, especially for modern sites web.Lists.EnsureSiteAssetsLibrary(); web.Context.ExecuteQueryRetry(); } var currentFileIndex = 0; var originalWeb = web; // Used to store and re-store context in case files are deployed to masterpage gallery foreach (var file in filesToProcess) { file.Src = parser.ParseString(file.Src); var targetFileName = parser.ParseString( !String.IsNullOrEmpty(file.TargetFileName) ? file.TargetFileName : template.Connector.GetFilenamePart(file.Src) ); currentFileIndex++; WriteSubProgress("File", targetFileName, currentFileIndex, filesToProcess.Length); var folderName = parser.ParseString(file.Folder); if (folderName.ToLower().Contains("/_catalogs/")) { // Edge case where you have files in the template which should be provisioned to the site collection // master page gallery and not to a connected subsite web = web.Context.GetSiteCollectionContext().Web; web.EnsureProperties(w => w.ServerRelativeUrl, w => w.Url); } if (folderName.ToLower().StartsWith((web.ServerRelativeUrl.ToLower()))) { folderName = folderName.Substring(web.ServerRelativeUrl.Length); } if (SkipFile(isNoScriptSite, targetFileName, folderName)) { // add log message scope.LogWarning(CoreResources.Provisioning_ObjectHandlers_Files_SkipFileUpload, targetFileName, folderName); continue; } var folder = web.EnsureFolderPath(folderName); folder.EnsureProperties(p => p.UniqueId, p => p.ServerRelativeUrl); parser.AddToken(new FileUniqueIdToken(web, folder.ServerRelativeUrl.Substring(web.ServerRelativeUrl.Length).TrimStart("/".ToCharArray()), folder.UniqueId)); parser.AddToken(new FileUniqueIdEncodedToken(web, folder.ServerRelativeUrl.Substring(web.ServerRelativeUrl.Length).TrimStart("/".ToCharArray()), folder.UniqueId)); var checkedOut = false; var targetFile = folder.GetFile(template.Connector.GetFilenamePart(targetFileName)); if (targetFile != null) { if (file.Overwrite) { scope.LogDebug(CoreResources.Provisioning_ObjectHandlers_Files_Uploading_and_overwriting_existing_file__0_, targetFileName); checkedOut = CheckOutIfNeeded(web, targetFile); using (var stream = FileUtilities.GetFileStream(template, file)) { targetFile = UploadFile(folder, stream, targetFileName, file.Overwrite); } } else { checkedOut = CheckOutIfNeeded(web, targetFile); } } else { using (var stream = FileUtilities.GetFileStream(template, file)) { if (stream == null) { throw new FileNotFoundException($"File {file.Src} does not exist"); } else { scope.LogDebug(CoreResources.Provisioning_ObjectHandlers_Files_Uploading_file__0_, targetFileName); targetFile = UploadFile(folder, stream, targetFileName, file.Overwrite); } } checkedOut = CheckOutIfNeeded(web, targetFile); } if (targetFile != null) { // Add the fileuniqueid tokens targetFile.EnsureProperties(p => p.UniqueId, p => p.ServerRelativePath); parser.AddToken(new FileUniqueIdToken(web, targetFile.ServerRelativePath.DecodedUrl.Substring(web.ServerRelativeUrl.Length).TrimStart("/".ToCharArray()), targetFile.UniqueId)); parser.AddToken(new FileUniqueIdEncodedToken(web, targetFile.ServerRelativePath.DecodedUrl.Substring(web.ServerRelativeUrl.Length).TrimStart("/".ToCharArray()), targetFile.UniqueId)); bool webPartsNeedLocalization = false; if (file.WebParts != null && file.WebParts.Any()) { targetFile.EnsureProperties(f => f.ServerRelativePath); var existingWebParts = web.GetWebParts(targetFile.ServerRelativePath.DecodedUrl).ToList(); foreach (var webPart in file.WebParts) { // check if the webpart is already set on the page if (existingWebParts.FirstOrDefault(w => w.WebPart.Title == parser.ParseString(webPart.Title)) == null) { scope.LogDebug(CoreResources.Provisioning_ObjectHandlers_Files_Adding_webpart___0___to_page, webPart.Title); var wpEntity = new WebPartEntity { WebPartTitle = parser.ParseString(webPart.Title), WebPartXml = parser.ParseXmlString(webPart.Contents).Trim(new[] { '\n', ' ' }), WebPartZone = webPart.Zone, WebPartIndex = (int)webPart.Order }; var wpd = web.AddWebPartToWebPartPage(targetFile.ServerRelativePath.DecodedUrl, wpEntity); if (webPart.Title.ContainsResourceToken()) { // update data based on where it was added - needed in order to localize wp title wpd.EnsureProperties(w => w.ZoneId, w => w.WebPart, w => w.WebPart.Properties); webPart.Zone = wpd.ZoneId; webPart.Order = (uint)wpd.WebPart.ZoneIndex; webPartsNeedLocalization = true; } } } } if (webPartsNeedLocalization) { file.LocalizeWebParts(web, parser, targetFile, scope); } //Set Properties before Checkin if (file.Properties != null && file.Properties.Any()) { Dictionary <string, string> transformedProperties = file.Properties.ToDictionary(property => property.Key, property => parser.ParseString(property.Value)); SetFileProperties(targetFile, transformedProperties, parser, false); } switch (file.Level) { case Model.FileLevel.Published: { targetFile.PublishFileToLevel(Microsoft.SharePoint.Client.FileLevel.Published); break; } case Model.FileLevel.Draft: { targetFile.PublishFileToLevel(Microsoft.SharePoint.Client.FileLevel.Draft); break; } default: { if (checkedOut) { targetFile.CheckIn("", CheckinType.MajorCheckIn); web.Context.ExecuteQueryRetry(); } break; } } // Don't set security when nothing is defined. This otherwise breaks on files set outside of a list if (file.Security != null && (file.Security.ClearSubscopes == true || file.Security.CopyRoleAssignments == true || file.Security.RoleAssignments.Count > 0)) { targetFile.ListItemAllFields.SetSecurity(parser, file.Security, WriteMessage); } } web = originalWeb; // restore context in case files are provisioned to the master page gallery #1059 } } WriteMessage("Done processing files", ProvisioningMessageType.Completed); return(parser); }
public override TokenParser ProvisionObjects(Web web, ProvisioningTemplate template, TokenParser parser, ProvisioningTemplateApplyingInformation applyingInformation) { using (var scope = new PnPMonitoredScope(this.Name)) { var site = (web.Context as ClientContext).Site; // Check if this is not a noscript site as publishing features are not supported if (web.IsNoScriptSite()) { scope.LogWarning(CoreResources.Provisioning_ObjectHandlers_Publishing_SkipProvisioning); return(parser); } var webFeatureActive = web.IsFeatureActive(Constants.FeatureId_Web_Publishing); var siteFeatureActive = site.IsFeatureActive(Constants.FeatureId_Site_Publishing); if (template.Publishing.AutoCheckRequirements == AutoCheckRequirementsOptions.SkipIfNotCompliant && !webFeatureActive) { scope.LogDebug("Publishing Feature (Web Scoped) not active. Skipping provisioning of Publishing settings"); return(parser); } else if (template.Publishing.AutoCheckRequirements == AutoCheckRequirementsOptions.MakeCompliant) { if (!siteFeatureActive) { scope.LogDebug("Making site compliant for publishing"); site.ActivateFeature(Constants.FeatureId_Site_Publishing); web.ActivateFeature(Constants.FeatureId_Web_Publishing); } else { if (!web.IsFeatureActive(Constants.FeatureId_Web_Publishing)) { scope.LogDebug("Making site compliant for publishing"); web.ActivateFeature(Constants.FeatureId_Web_Publishing); } } } else if (!webFeatureActive) { throw new Exception("Publishing Feature not active. Provisioning failed"); } // Set allowed web templates var availableWebTemplates = template.Publishing.AvailableWebTemplates.Select(t => new WebTemplateEntity() { LanguageCode = t.LanguageCode.ToString(), TemplateName = t.TemplateName }).ToList(); if (availableWebTemplates.Any()) { web.SetAvailableWebTemplates(availableWebTemplates); } if (template.Publishing.DesignPackage != null) { var package = template.Publishing.DesignPackage; var tempFileName = Path.Combine(Path.GetTempPath(), template.Connector.GetFilenamePart(package.DesignPackagePath)); scope.LogDebug("Saving {0} to temporary file: {1}", package.DesignPackagePath, tempFileName); using (var stream = template.Connector.GetFileStream(package.DesignPackagePath)) { using (var outstream = System.IO.File.Create(tempFileName)) { stream.CopyTo(outstream); } } scope.LogDebug("Installing design package"); site.InstallSolution(package.PackageGuid, tempFileName, package.MajorVersion, package.MinorVersion); System.IO.File.Delete(tempFileName); } // Set allowed page layouts var availablePageLayouts = template.Publishing.PageLayouts.Select(p => p.Path); if (availablePageLayouts.Any()) { web.SetAvailablePageLayouts(site.RootWeb, availablePageLayouts); } // Set default page layout, if any var defaultPageLayout = template.Publishing.PageLayouts.FirstOrDefault(p => p.IsDefault); if (defaultPageLayout != null) { web.SetDefaultPageLayoutForSite(site.RootWeb, defaultPageLayout.Path); } return(parser); } }
public override TokenParser ProvisionObjects(Web web, ProvisioningTemplate template, TokenParser parser, ProvisioningTemplateApplyingInformation applyingInformation) { using (var scope = new PnPMonitoredScope(this.Name)) { web.EnsureProperties(w => w.Url); if (template.Header != null) { switch (template.Header.Layout) { case SiteHeaderLayout.Compact: { web.HeaderLayout = HeaderLayoutType.Compact; break; } case SiteHeaderLayout.Standard: { web.HeaderLayout = HeaderLayoutType.Standard; break; } } web.HeaderEmphasis = (SPVariantThemeType)Enum.Parse(typeof(SPVariantThemeType), template.Header.BackgroundEmphasis.ToString()); web.MegaMenuEnabled = template.Header.MenuStyle == SiteHeaderMenuStyle.MegaMenu; var jsonRequest = new { headerLayout = web.HeaderLayout, headerEmphasis = web.HeaderEmphasis, megaMenuEnabled = web.MegaMenuEnabled, }; web.ExecutePostAsync("/_api/web/SetChromeOptions", System.Text.Json.JsonSerializer.Serialize(jsonRequest)).GetAwaiter().GetResult(); //if (PnPProvisioningContext.Current != null) //{ // // Get an Access Token for the SetChromeOptions request // var spoResourceUri = new Uri(web.Url).Authority; // var accessToken = PnPProvisioningContext.Current.AcquireToken(spoResourceUri, null); // if (accessToken != null) // { // // Prepare the JSON request for SetChromeOptions // var jsonRequest = new // { // headerLayout = web.HeaderLayout, // headerEmphasis = web.HeaderEmphasis, // megaMenuEnabled = web.MegaMenuEnabled, // }; // // Build the URL of the SetChromeOptions API // var setChromeOptionsApiUrl = $"{web.Url}/_api/web/SetChromeOptions"; // // Make the POST request to the SetChromeOptions API // // and fail in case of any exception // HttpHelper.MakePostRequest(setChromeOptionsApiUrl, // jsonRequest, // "application/json", // accessToken); // } //} //else //{ // web.Update(); // web.Context.ExecuteQueryRetry(); //} } } return(parser); }
public override TokenParser ProvisionObjects(Web web, ProvisioningTemplate template, TokenParser parser, ProvisioningTemplateApplyingInformation applyingInformation) { using (var scope = new PnPMonitoredScope(this.Name)) { if (template.WebSettings != null) { // Check if this is not a noscript site as we're not allowed to update some properties bool isNoScriptSite = web.IsNoScriptSite(); web.EnsureProperties( w => w.NoCrawl, w => w.CommentsOnSitePagesDisabled, w => w.ExcludeFromOfflineClient, w => w.MembersCanShare, w => w.DisableFlows, w => w.DisableAppViews, w => w.HorizontalQuickLaunch, w => w.SearchScope, w => w.SearchBoxInNavBar, w => w.RootFolder, w => w.Title, w => w.Description, w => w.AlternateCssUrl, w => w.WebTemplate, w => w.HasUniqueRoleAssignments); var webSettings = template.WebSettings; // Since the IsSubSite function can trigger an executequery ensure it's called before any updates to the web object are done. if (!web.IsSubSite() || (web.IsSubSite() && web.HasUniqueRoleAssignments)) { String requestAccessEmailValue = parser.ParseString(webSettings.RequestAccessEmail); if (!String.IsNullOrEmpty(requestAccessEmailValue) && requestAccessEmailValue.Length >= 255) { requestAccessEmailValue = requestAccessEmailValue.Substring(0, 255); } if (!String.IsNullOrEmpty(requestAccessEmailValue)) { web.RequestAccessEmail = requestAccessEmailValue; web.Update(); web.Context.ExecuteQueryRetry(); } } if (!isNoScriptSite) { web.NoCrawl = webSettings.NoCrawl; } else { scope.LogWarning(CoreResources.Provisioning_ObjectHandlers_WebSettings_SkipNoCrawlUpdate); } if (web.CommentsOnSitePagesDisabled != webSettings.CommentsOnSitePagesDisabled) { web.CommentsOnSitePagesDisabled = webSettings.CommentsOnSitePagesDisabled; } if (web.ExcludeFromOfflineClient != webSettings.ExcludeFromOfflineClient) { web.ExcludeFromOfflineClient = webSettings.ExcludeFromOfflineClient; } if (web.MembersCanShare != webSettings.MembersCanShare) { web.MembersCanShare = webSettings.MembersCanShare; } if (web.DisableFlows != webSettings.DisableFlows) { web.DisableFlows = webSettings.DisableFlows; } if (web.DisableAppViews != webSettings.DisableAppViews) { web.DisableAppViews = webSettings.DisableAppViews; } if (web.HorizontalQuickLaunch != webSettings.HorizontalQuickLaunch) { web.HorizontalQuickLaunch = webSettings.HorizontalQuickLaunch; } if (web.SearchScope.ToString() != webSettings.SearchScope.ToString()) { web.SearchScope = (SearchScopeType)Enum.Parse(typeof(SearchScopeType), webSettings.SearchScope.ToString(), true); } if (web.SearchBoxInNavBar.ToString() != webSettings.SearchBoxInNavBar.ToString()) { web.SearchBoxInNavBar = (SearchBoxInNavBarType)Enum.Parse(typeof(SearchBoxInNavBarType), webSettings.SearchBoxInNavBar.ToString(), true); } string searchCenterUrl = parser.ParseString(webSettings.SearchCenterUrl); if (!string.IsNullOrEmpty(searchCenterUrl) && web.GetWebSearchCenterUrl(true) != searchCenterUrl) { web.SetWebSearchCenterUrl(searchCenterUrl); } var masterUrl = parser.ParseString(webSettings.MasterPageUrl); if (!string.IsNullOrEmpty(masterUrl)) { if (!isNoScriptSite) { web.MasterUrl = masterUrl; } else { scope.LogWarning(CoreResources.Provisioning_ObjectHandlers_WebSettings_SkipMasterPageUpdate); } } var customMasterUrl = parser.ParseString(webSettings.CustomMasterPageUrl); if (!string.IsNullOrEmpty(customMasterUrl)) { if (!isNoScriptSite) { web.CustomMasterUrl = customMasterUrl; } else { scope.LogWarning(CoreResources.Provisioning_ObjectHandlers_WebSettings_SkipCustomMasterPageUpdate); } } if (!String.IsNullOrEmpty(webSettings.Title)) { var newTitle = parser.ParseString(webSettings.Title); if (newTitle != web.Title) { web.Title = newTitle; } } if (!String.IsNullOrEmpty(webSettings.Description)) { var newDescription = parser.ParseString(webSettings.Description); if (newDescription != web.Description) { web.Description = newDescription; } } if (webSettings.SiteLogo != null) { var logoUrl = parser.ParseString(webSettings.SiteLogo); if (template.BaseSiteTemplate == "SITEPAGEPUBLISHING#0" && web.WebTemplate == "GROUP") { // logo provisioning throws when applying across base template IDs; provisioning fails in this case // this is the error that is already (rightly so) shown beforehand in the console: WARNING: The source site from which the template was generated had a base template ID value of SITEPAGEPUBLISHING#0, while the current target site has a base template ID value of GROUP#0. This could cause potential issues while applying the template. WriteMessage("Applying site logo across base template IDs is not possible. Skipping site logo provisioning.", ProvisioningMessageType.Warning); } else { // Modern site? Then we assume the SiteLogo is actually a filepath if (web.WebTemplate == "GROUP") { if (!string.IsNullOrEmpty(logoUrl) && !logoUrl.ToLower().Contains("_api/groupservice/getgroupimage")) { var fileBytes = ConnectorFileHelper.GetFileBytes(template.Connector, logoUrl); if (fileBytes != null && fileBytes.Length > 0) { var mimeType = ""; var imgUrl = logoUrl; if (imgUrl.Contains("?")) { imgUrl = imgUrl.Split(new[] { '?' })[0]; } if (imgUrl.EndsWith(".gif", StringComparison.InvariantCultureIgnoreCase)) { mimeType = "image/gif"; } if (imgUrl.EndsWith(".png", StringComparison.InvariantCultureIgnoreCase)) { mimeType = "image/png"; } if (imgUrl.EndsWith(".jpg", StringComparison.InvariantCultureIgnoreCase)) { mimeType = "image/jpeg"; } Sites.SiteCollection.SetGroupImageAsync((ClientContext)web.Context, fileBytes, mimeType).GetAwaiter().GetResult(); } } } else { web.SiteLogoUrl = logoUrl; } } } var welcomePage = parser.ParseString(webSettings.WelcomePage); if (!string.IsNullOrEmpty(welcomePage)) { if (welcomePage != web.RootFolder.WelcomePage) { web.RootFolder.WelcomePage = welcomePage; web.RootFolder.Update(); } } if (!string.IsNullOrEmpty(webSettings.AlternateCSS)) { var newAlternateCssUrl = parser.ParseString(webSettings.AlternateCSS); if (newAlternateCssUrl != web.AlternateCssUrl) { web.AlternateCssUrl = newAlternateCssUrl; } } // Temporary disabled as this change is a breaking change for folks that have not set this property in their provisioning templates //web.QuickLaunchEnabled = webSettings.QuickLaunchEnabled; web.Update(); web.Context.ExecuteQueryRetry(); if (webSettings.HubSiteUrl != null) { if (TenantExtensions.IsCurrentUserTenantAdmin(web.Context as ClientContext)) { var hubsiteUrl = parser.ParseString(webSettings.HubSiteUrl); try { using (var tenantContext = web.Context.Clone(web.GetTenantAdministrationUrl(), applyingInformation.AccessTokens)) { var tenant = new Tenant(tenantContext); tenant.ConnectSiteToHubSite(web.Url, hubsiteUrl); tenantContext.ExecuteQueryRetry(); } } catch (Exception ex) { WriteMessage($"Hub site association failed: {ex.Message}", ProvisioningMessageType.Warning); } } else { WriteMessage("You need to be a SharePoint admin when associating to a Hub site.", ProvisioningMessageType.Warning); } } } } return(parser); }
/// <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)) { web.Context.DisableReturnValueCache = true; 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 { 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 (!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()); } 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.SiteSettings)) { objectHandlers.Add(new ObjectSiteSettings()); } 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.ProvisioningTemplateStarted); 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.InternalName); try { tokenParser = handler.ProvisionObjects(web, template, tokenParser, provisioningInfo); } catch (Exception ex) { CallWebHooks(template, tokenParser, ProvisioningTemplateWebhookKind.ExceptionOccurred, handler.InternalName, ex); throw; } CallWebHooks(template, tokenParser, ProvisioningTemplateWebhookKind.ObjectHandlerProvisioningCompleted, handler.InternalName); } } // 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.ProvisioningTemplateCompleted); System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo(currentCultureInfoValue); } }
public override TokenParser ProvisionObjects(Web web, ProvisioningTemplate template, TokenParser parser, ProvisioningTemplateApplyingInformation applyingInformation) { using (var scope = new PnPMonitoredScope(this.Name)) { var systemPropertyBagEntriesExclusions = new List <string>(new[] { "_", "vti_", "dlc_", "ecm_", "profileschemaversion", "DesignPreview" }); // Check if this is not a noscript site as we're not allowed to write to the web property bag is that one bool isNoScriptSite = web.IsNoScriptSite(); if (isNoScriptSite) { return(parser); } // To handle situations where the propertybag is not updated fully when applying a theme, // we need to create a new context and use that one. Reloading the propertybag does not solve this. var webUrl = web.EnsureProperty(w => w.Url); var newContext = web.Context.Clone(webUrl); web = newContext.Web; foreach (var propbagEntry in template.PropertyBagEntries) { bool propExists = web.PropertyBagContainsKey(propbagEntry.Key); if (propbagEntry.Overwrite) { var systemProp = systemPropertyBagEntriesExclusions.Any(k => propbagEntry.Key.StartsWith(k, StringComparison.OrdinalIgnoreCase)); if (!systemProp || (systemProp && applyingInformation.OverwriteSystemPropertyBagValues)) { scope.LogDebug(CoreResources.Provisioning_ObjectHandlers_PropertyBagEntries_Overwriting_existing_propertybag_entry__0__with_value__1_, propbagEntry.Key, propbagEntry.Value); web.SetPropertyBagValue(propbagEntry.Key, parser.ParseString(propbagEntry.Value)); if (propbagEntry.Indexed) { web.AddIndexedPropertyBagKey(propbagEntry.Key); } } } else { if (!propExists) { scope.LogDebug(CoreResources.Provisioning_ObjectHandlers_PropertyBagEntries_Creating_new_propertybag_entry__0__with_value__1__2_, propbagEntry.Key, propbagEntry.Value, propbagEntry.Indexed ? ",Indexed = true" : ""); web.SetPropertyBagValue(propbagEntry.Key, parser.ParseString(propbagEntry.Value)); if (propbagEntry.Indexed) { web.AddIndexedPropertyBagKey(propbagEntry.Key); } } } } } return(parser); }