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);
        }
Beispiel #2
0
        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);
 }
Beispiel #4
0
        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);
            }
        }
Beispiel #6
0
        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);
        }
Beispiel #8
0
        /// <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);
        }