Beispiel #1
0
        private Microsoft.SharePoint.Client.File Load(ClientContext cc, PageTransformationInformation pageTransformationInformation, out List pagesLibrary)
        {
            cc.Web.EnsureProperty(w => w.ServerRelativeUrl);

            // Load the pages library and page file (if exists) in one go
            var listServerRelativeUrl = UrlUtility.Combine(cc.Web.ServerRelativeUrl, "SitePages");

            pagesLibrary = cc.Web.GetList(listServerRelativeUrl);

            if (pageTransformationInformation.CopyPageMetadata)
            {
                cc.Web.Context.Load(pagesLibrary, l => l.DefaultViewUrl, l => l.Id, l => l.BaseTemplate, l => l.OnQuickLaunch, l => l.DefaultViewUrl, l => l.Title,
                                    l => l.Hidden, l => l.EffectiveBasePermissions, l => l.RootFolder, l => l.RootFolder.ServerRelativeUrl,
                                    l => l.Fields.IncludeWithDefaultProperties(f => f.Id, f => f.Title, f => f.Hidden, f => f.InternalName, f => f.DefaultValue, f => f.Required));
            }
            else
            {
                cc.Web.Context.Load(pagesLibrary, l => l.DefaultViewUrl, l => l.Id, l => l.BaseTemplate, l => l.OnQuickLaunch, l => l.DefaultViewUrl, l => l.Title,
                                    l => l.Hidden, l => l.EffectiveBasePermissions, l => l.RootFolder, l => l.RootFolder.ServerRelativeUrl);
            }

            var file = cc.Web.GetFileByServerRelativeUrl($"{listServerRelativeUrl}/{pageTransformationInformation.Folder}{pageTransformationInformation.TargetPageName}");

            cc.Web.Context.Load(file, f => f.Exists, f => f.ListItemAllFields);

            if (pageTransformationInformation.KeepPageSpecificPermissions)
            {
                cc.Load(pageTransformationInformation.SourcePage, p => p.HasUniqueRoleAssignments);
            }

            try
            {
                cc.ExecuteQueryRetry();
            }
            catch (ServerException se)
            {
                if (se.ServerErrorTypeName == "System.IO.FileNotFoundException")
                {
                    pagesLibrary = null;
                }
                else
                {
                    throw;
                }
            }

            if (pagesLibrary == null)
            {
                throw new ArgumentException($"Site does not have a sitepages library and therefore this page can't be a client side page.");
            }

            if (!file.Exists)
            {
                throw new ArgumentException($"Page {pageTransformationInformation.TargetPageName} does not exist in current web");
            }

            return(file);
        }
Beispiel #2
0
 private static void SetPageTitle(PageTransformationInformation pageTransformationInformation, ClientSidePage targetPage)
 {
     if (pageTransformationInformation.SourcePage.FieldExistsAndUsed(Constants.FileLeafRefField))
     {
         string pageTitle = Path.GetFileNameWithoutExtension((pageTransformationInformation.SourcePage[Constants.FileLeafRefField].ToString()));
         if (!string.IsNullOrEmpty(pageTitle))
         {
             pageTitle            = pageTitle.First().ToString().ToUpper() + pageTitle.Substring(1);
             targetPage.PageTitle = pageTitle;
         }
     }
 }
Beispiel #3
0
        /// <summary>
        /// Transform the page
        /// </summary>
        /// <param name="pageTransformationInformation">Information about the page to transform</param>
        public void Transform(PageTransformationInformation pageTransformationInformation)
        {
            #region Input validation
            if (pageTransformationInformation.SourcePage == null)
            {
                throw new ArgumentNullException("SourcePage cannot be null");
            }

            // Validate page and it's eligibility for transformation
            if (!pageTransformationInformation.SourcePage.FieldExistsAndUsed(Constants.FileRefField) || !pageTransformationInformation.SourcePage.FieldExistsAndUsed(Constants.FileLeafRefField))
            {
                throw new ArgumentException("Page is not valid due to missing FileRef or FileLeafRef value");
            }

            string pageType = pageTransformationInformation.SourcePage.PageType();

            if (pageType.Equals("ClientSidePage", StringComparison.InvariantCultureIgnoreCase))
            {
                throw new ArgumentException("Page is a client side page...guess you don't want to transform it...");
            }

            if (pageType.Equals("AspxPage", StringComparison.InvariantCultureIgnoreCase))
            {
                throw new ArgumentException("Page is an basic aspx page...can't transform that one, sorry!");
            }
            #endregion

            #region Telemetry
            clientContext.ClientTag = $"SPDev:PageTransformator";
            clientContext.Load(clientContext.Web, p => p.Description, p => p.Id);
            clientContext.ExecuteQuery();
            #endregion

            #region Page creation
            // If no targetname specified then we'll come up with one
            if (string.IsNullOrEmpty(pageTransformationInformation.TargetPageName))
            {
                if (string.IsNullOrEmpty(pageTransformationInformation.TargetPagePrefix))
                {
                    pageTransformationInformation.SetDefaultTargetPagePrefix();
                }

                pageTransformationInformation.TargetPageName = $"{pageTransformationInformation.TargetPagePrefix}{pageTransformationInformation.SourcePage[Constants.FileLeafRefField].ToString()}";
            }

            // Check if page name is free to use
            bool           pageExists = false;
            ClientSidePage targetPage = null;
            try
            {
                targetPage = clientContext.Web.LoadClientSidePage(pageTransformationInformation.TargetPageName);
                pageExists = true;
            }
            catch (ArgumentException) { }

            if (pageExists)
            {
                if (!pageTransformationInformation.Overwrite)
                {
                    throw new ArgumentException($"There already exists a page with name {pageTransformationInformation.TargetPageName}.");
                }
                else
                {
                    targetPage.ClearPage();
                }
            }
            else
            {
                // Create a new client side page
                targetPage = clientContext.Web.AddClientSidePage(pageTransformationInformation.TargetPageName);
            }
            #endregion

            #region Home page handling
            bool replacedByOOBHomePage = false;
            // Check if the transformed page is the web's home page
            clientContext.Web.EnsureProperties(w => w.RootFolder.WelcomePage);
            var homePageUrl  = clientContext.Web.RootFolder.WelcomePage;
            var homepageName = Path.GetFileName(clientContext.Web.RootFolder.WelcomePage);
            if (homepageName.Equals(pageTransformationInformation.SourcePage[Constants.FileLeafRefField].ToString(), StringComparison.InvariantCultureIgnoreCase))
            {
                targetPage.LayoutType = ClientSidePageLayoutType.Home;
                if (pageTransformationInformation.ReplaceHomePageWithDefaultHomePage)
                {
                    targetPage.KeepDefaultWebParts = true;
                    replacedByOOBHomePage          = true;
                }
            }
            #endregion

            #region Article page handling
            if (!replacedByOOBHomePage)
            {
                #region Configure header from target page
                if (pageTransformationInformation.PageHeader == null || pageTransformationInformation.PageHeader.Type == ClientSidePageHeaderType.None)
                {
                    targetPage.RemovePageHeader();
                }
                else if (pageTransformationInformation.PageHeader.Type == ClientSidePageHeaderType.Default)
                {
                    targetPage.SetDefaultPageHeader();
                }
                else if (pageTransformationInformation.PageHeader.Type == ClientSidePageHeaderType.Custom)
                {
                    targetPage.SetCustomPageHeader(pageTransformationInformation.PageHeader.ImageServerRelativeUrl, pageTransformationInformation.PageHeader.TranslateX, pageTransformationInformation.PageHeader.TranslateY);
                }
                #endregion

                #region Analysis of the source page
                // Analyze the source page
                Tuple <PageLayout, List <WebPartEntity> > pageData = null;

                if (pageType.Equals("WikiPage", StringComparison.InvariantCultureIgnoreCase))
                {
                    pageData = new WikiPage(pageTransformationInformation.SourcePage, pageTransformation).Analyze();

                    // Wiki pages can contain embedded images and videos, which is not supported by the target RTE...split wiki text blocks so the transformator can handle the images and videos as separate web parts
                    if (pageTransformationInformation.HandleWikiImagesAndVideos)
                    {
                        pageData = new Tuple <PageLayout, List <WebPartEntity> >(pageData.Item1, new WikiTransformator().TransformPlusSplit(pageData.Item2));
                    }
                }
                else if (pageType.Equals("WebPartPage", StringComparison.InvariantCultureIgnoreCase))
                {
                    pageData = new WebPartPage(pageTransformationInformation.SourcePage, pageTransformation).Analyze(true);
                }
                #endregion

                #region Page title configuration
                // Set page title
                if (pageType.Equals("WikiPage", StringComparison.InvariantCultureIgnoreCase) && pageTransformationInformation.SourcePage.FieldExistsAndUsed(Constants.FileTitleField))
                {
                    targetPage.PageTitle = pageTransformationInformation.SourcePage[Constants.FileTitleField].ToString();
                }
                else if (pageType.Equals("WebPartPage"))
                {
                    var titleBarWebPart = pageData.Item2.Where(p => p.Type == WebParts.TitleBar).FirstOrDefault();
                    if (titleBarWebPart != null)
                    {
                        if (titleBarWebPart.Properties.ContainsKey("HeaderTitle") && !string.IsNullOrEmpty(titleBarWebPart.Properties["HeaderTitle"]))
                        {
                            targetPage.PageTitle = titleBarWebPart.Properties["HeaderTitle"];
                        }
                    }
                }

                if (pageTransformationInformation.PageTitleOverride != null)
                {
                    targetPage.PageTitle = pageTransformationInformation.PageTitleOverride(targetPage.PageTitle);
                }
                #endregion

                #region Page layout configuration
                // Use the default layout transformator
                ILayoutTransformator layoutTransformator = new LayoutTransformator(targetPage);

                // Do we have an override?
                if (pageTransformationInformation.LayoutTransformatorOverride != null)
                {
                    layoutTransformator = pageTransformationInformation.LayoutTransformatorOverride(targetPage);
                }

                // Apply the layout to the page
                layoutTransformator.Transform(pageData.Item1);
                #endregion

                #region Content transformation
                // Use the default content transformator
                IContentTransformator contentTransformator = new ContentTransformator(targetPage, pageTransformation);

                // Do we have an override?
                if (pageTransformationInformation.ContentTransformatorOverride != null)
                {
                    contentTransformator = pageTransformationInformation.ContentTransformatorOverride(targetPage, pageTransformation);
                }

                // Run the content transformator
                contentTransformator.Transform(pageData.Item2);
                #endregion
            }
            #endregion

            #region Page persisting
            // Persist the client side page
            targetPage.Save(pageTransformationInformation.TargetPageName);
            targetPage.Publish();

            // All went well so far...swap pages if that's needed
            if (pageTransformationInformation.TargetPageTakesSourcePageName)
            {
                //Load the source page
                var sourcePageUrl         = pageTransformationInformation.SourcePage[Constants.FileRefField].ToString();
                var orginalSourcePageName = pageTransformationInformation.SourcePage[Constants.FileLeafRefField].ToString();

                string path = sourcePageUrl.Replace(pageTransformationInformation.SourcePage[Constants.FileLeafRefField].ToString(), "");

                var sourcePage = this.clientContext.Web.GetFileByServerRelativeUrl(sourcePageUrl);
                this.clientContext.Load(sourcePage);
                this.clientContext.ExecuteQueryRetry();

                if (string.IsNullOrEmpty(pageTransformationInformation.SourcePagePrefix))
                {
                    pageTransformationInformation.SetDefaultSourcePagePrefix();
                }
                var newSourcePageUrl = $"{pageTransformationInformation.SourcePagePrefix}{pageTransformationInformation.SourcePage[Constants.FileLeafRefField].ToString()}";

                // Rename source page using the sourcepageprefix
                sourcePage.MoveTo($"{path}{newSourcePageUrl}", MoveOperations.None);
                this.clientContext.ExecuteQueryRetry();

                //Load the created target page
                var targetPageUrl  = $"{path}{pageTransformationInformation.TargetPageName}";
                var targetPageFile = this.clientContext.Web.GetFileByServerRelativeUrl(targetPageUrl);
                this.clientContext.Load(targetPageFile);
                this.clientContext.ExecuteQueryRetry();

                // Rename the target page to the original source page name
                targetPageFile.MoveTo($"{path}{orginalSourcePageName}", MoveOperations.Overwrite);
                this.clientContext.ExecuteQueryRetry();
            }
            #endregion
        }
Beispiel #4
0
        /// <summary>
        /// Transform the page
        /// </summary>
        /// <param name="pageTransformationInformation">Information about the page to transform</param>
        public void Transform(PageTransformationInformation pageTransformationInformation)
        {
            #region Input validation
            if (pageTransformationInformation.SourcePage == null)
            {
                throw new ArgumentNullException("SourcePage cannot be null");
            }

            // Validate page and it's eligibility for transformation
            if (!pageTransformationInformation.SourcePage.FieldExistsAndUsed(Constants.FileRefField) || !pageTransformationInformation.SourcePage.FieldExistsAndUsed(Constants.FileLeafRefField))
            {
                throw new ArgumentException("Page is not valid due to missing FileRef or FileLeafRef value");
            }

            string pageType = pageTransformationInformation.SourcePage.PageType();

            if (pageType.Equals("ClientSidePage", StringComparison.InvariantCultureIgnoreCase))
            {
                throw new ArgumentException("Page is a client side page...guess you don't want to transform it...");
            }

            if (pageType.Equals("AspxPage", StringComparison.InvariantCultureIgnoreCase))
            {
                throw new ArgumentException("Page is an basic aspx page...can't transform that one, sorry!");
            }

            if (pageType.Equals("PublishingPage", StringComparison.InvariantCultureIgnoreCase))
            {
                throw new ArgumentException("Page transformation for publishing pages is currently not supported.");
            }
            #endregion

            #region Telemetry
            clientContext.ClientTag = $"SPDev:PageTransformator";
            clientContext.Load(clientContext.Web, p => p.Description, p => p.Id);
            clientContext.ExecuteQuery();
            #endregion

            #region Page creation
            // If no targetname specified then we'll come up with one
            if (string.IsNullOrEmpty(pageTransformationInformation.TargetPageName))
            {
                if (string.IsNullOrEmpty(pageTransformationInformation.TargetPagePrefix))
                {
                    pageTransformationInformation.SetDefaultTargetPagePrefix();
                }

                pageTransformationInformation.TargetPageName = $"{pageTransformationInformation.TargetPagePrefix}{pageTransformationInformation.SourcePage[Constants.FileLeafRefField].ToString()}";
            }

            // Check if page name is free to use
            bool           pageExists = false;
            ClientSidePage targetPage = null;
            try
            {
                targetPage = clientContext.Web.LoadClientSidePage(pageTransformationInformation.TargetPageName);
                pageExists = true;
            }
            catch (ArgumentException) { }

            if (pageExists)
            {
                if (!pageTransformationInformation.Overwrite)
                {
                    throw new ArgumentException($"There already exists a page with name {pageTransformationInformation.TargetPageName}.");
                }
                else
                {
                    targetPage.ClearPage();
                }
            }
            else
            {
                // Create a new client side page
                targetPage = clientContext.Web.AddClientSidePage(pageTransformationInformation.TargetPageName);
            }
            #endregion

            #region Home page handling
            bool replacedByOOBHomePage = false;
            // Check if the transformed page is the web's home page
            clientContext.Web.EnsureProperties(w => w.RootFolder.WelcomePage);
            var homePageUrl  = clientContext.Web.RootFolder.WelcomePage;
            var homepageName = Path.GetFileName(clientContext.Web.RootFolder.WelcomePage);
            if (homepageName.Equals(pageTransformationInformation.SourcePage[Constants.FileLeafRefField].ToString(), StringComparison.InvariantCultureIgnoreCase))
            {
                targetPage.LayoutType = ClientSidePageLayoutType.Home;
                if (pageTransformationInformation.ReplaceHomePageWithDefaultHomePage)
                {
                    targetPage.KeepDefaultWebParts = true;
                    replacedByOOBHomePage          = true;
                }
            }
            #endregion

            #region Article page handling
            if (!replacedByOOBHomePage)
            {
                #region Configure header from target page
                if (pageTransformationInformation.PageHeader == null || pageTransformationInformation.PageHeader.Type == ClientSidePageHeaderType.None)
                {
                    targetPage.RemovePageHeader();
                }
                else if (pageTransformationInformation.PageHeader.Type == ClientSidePageHeaderType.Default)
                {
                    targetPage.SetDefaultPageHeader();
                }
                else if (pageTransformationInformation.PageHeader.Type == ClientSidePageHeaderType.Custom)
                {
                    targetPage.SetCustomPageHeader(pageTransformationInformation.PageHeader.ImageServerRelativeUrl, pageTransformationInformation.PageHeader.TranslateX, pageTransformationInformation.PageHeader.TranslateY);
                }
                #endregion

                #region Analysis of the source page
                // Analyze the source page
                Tuple <PageLayout, List <WebPartEntity> > pageData = null;

                if (pageType.Equals("WikiPage", StringComparison.InvariantCultureIgnoreCase))
                {
                    pageData = new WikiPage(pageTransformationInformation.SourcePage, pageTransformation).Analyze();

                    // Wiki pages can contain embedded images and videos, which is not supported by the target RTE...split wiki text blocks so the transformator can handle the images and videos as separate web parts
                    pageData = new Tuple <PageLayout, List <WebPartEntity> >(pageData.Item1, new WikiTransformatorSimple().TransformPlusSplit(pageData.Item2, pageTransformationInformation.HandleWikiImagesAndVideos));
                }
                else if (pageType.Equals("WebPartPage", StringComparison.InvariantCultureIgnoreCase))
                {
                    pageData = new WebPartPage(pageTransformationInformation.SourcePage, pageTransformation).Analyze(true);
                }
                #endregion

                #region Page title configuration
                // Set page title
                if (pageType.Equals("WikiPage", StringComparison.InvariantCultureIgnoreCase))
                {
                    SetPageTitle(pageTransformationInformation, targetPage);
                }
                else if (pageType.Equals("WebPartPage"))
                {
                    bool titleFound      = false;
                    var  titleBarWebPart = pageData.Item2.Where(p => p.Type == WebParts.TitleBar).FirstOrDefault();
                    if (titleBarWebPart != null)
                    {
                        if (titleBarWebPart.Properties.ContainsKey("HeaderTitle") && !string.IsNullOrEmpty(titleBarWebPart.Properties["HeaderTitle"]))
                        {
                            targetPage.PageTitle = titleBarWebPart.Properties["HeaderTitle"];
                            titleFound           = true;
                        }
                    }

                    if (!titleFound)
                    {
                        SetPageTitle(pageTransformationInformation, targetPage);
                    }
                }

                if (pageTransformationInformation.PageTitleOverride != null)
                {
                    targetPage.PageTitle = pageTransformationInformation.PageTitleOverride(targetPage.PageTitle);
                }
                #endregion

                #region Page layout configuration
                // Use the default layout transformator
                ILayoutTransformator layoutTransformator = new LayoutTransformator(targetPage);

                // Do we have an override?
                if (pageTransformationInformation.LayoutTransformatorOverride != null)
                {
                    layoutTransformator = pageTransformationInformation.LayoutTransformatorOverride(targetPage);
                }

                // Apply the layout to the page
                layoutTransformator.Transform(pageData.Item1);
                #endregion

                #region Page Banner creation
                if (!pageTransformationInformation.TargetPageTakesSourcePageName)
                {
                    if (pageTransformationInformation.ModernizationCenterInformation != null && pageTransformationInformation.ModernizationCenterInformation.AddPageAcceptBanner)
                    {
                        // Bump the row values for the existing web parts as we've inserted a new section
                        foreach (var section in targetPage.Sections)
                        {
                            section.Order = section.Order + 1;
                        }

                        // Add new section for banner part
                        targetPage.Sections.Insert(0, new CanvasSection(targetPage, CanvasSectionTemplate.OneColumn, 0));

                        // Bump the row values for the existing web parts as we've inserted a new section
                        foreach (var webpart in pageData.Item2)
                        {
                            webpart.Row = webpart.Row + 1;
                        }


                        var sourcePageUrl         = pageTransformationInformation.SourcePage[Constants.FileRefField].ToString();
                        var orginalSourcePageName = pageTransformationInformation.SourcePage[Constants.FileLeafRefField].ToString();
                        clientContext.Web.EnsureProperty(p => p.Url);
                        Uri host = new Uri(clientContext.Web.Url);

                        string path = $"{host.Scheme}://{host.DnsSafeHost}{sourcePageUrl.Replace(pageTransformationInformation.SourcePage[Constants.FileLeafRefField].ToString(), "")}";

                        // Add "fake" banner web part that then will be transformed onto the page
                        Dictionary <string, string> props = new Dictionary <string, string>(2)
                        {
                            { "SourcePage", $"{path}{orginalSourcePageName}" },
                            { "TargetPage", $"{path}{pageTransformationInformation.TargetPageName}" }
                        };

                        WebPartEntity bannerWebPart = new WebPartEntity()
                        {
                            Type       = WebParts.PageAcceptanceBanner,
                            Column     = 1,
                            Row        = 1,
                            Title      = "",
                            Order      = 0,
                            Properties = props,
                        };
                        pageData.Item2.Insert(0, bannerWebPart);
                    }
                }
                #endregion

                #region Content transformation
                // Use the default content transformator
                IContentTransformator contentTransformator = new ContentTransformator(targetPage, pageTransformation);

                // Do we have an override?
                if (pageTransformationInformation.ContentTransformatorOverride != null)
                {
                    contentTransformator = pageTransformationInformation.ContentTransformatorOverride(targetPage, pageTransformation);
                }

                // Run the content transformator
                contentTransformator.Transform(pageData.Item2);
                #endregion
            }
            #endregion

            #region Page persisting + permissions
            #region Save the page
            // Persist the client side page
            targetPage.Save(pageTransformationInformation.TargetPageName);
            targetPage.Publish();
            #endregion

            #region Permission handling
            if (pageTransformationInformation.KeepPageSpecificPermissions)
            {
                pageTransformationInformation.SourcePage.EnsureProperty(p => p.HasUniqueRoleAssignments);
                if (pageTransformationInformation.SourcePage.HasUniqueRoleAssignments)
                {
                    // Copy the unique permissions from source to target
                    // Get the unique permissions
                    this.clientContext.Load(pageTransformationInformation.SourcePage, a => a.RoleAssignments.Include(roleAsg => roleAsg.Member.LoginName,
                                                                                                                     roleAsg => roleAsg.RoleDefinitionBindings.Include(roleDef => roleDef.Name, roleDef => roleDef.Description)));
                    this.clientContext.ExecuteQueryRetry();

                    // Get target page information
                    this.clientContext.Load(targetPage.PageListItem, p => p.HasUniqueRoleAssignments, a => a.RoleAssignments.Include(roleAsg => roleAsg.Member.LoginName,
                                                                                                                                     roleAsg => roleAsg.RoleDefinitionBindings.Include(roleDef => roleDef.Name, roleDef => roleDef.Description)));
                    this.clientContext.ExecuteQueryRetry();

                    // Break permission inheritance on the target page if not done yet
                    if (!targetPage.PageListItem.HasUniqueRoleAssignments)
                    {
                        targetPage.PageListItem.BreakRoleInheritance(false, false);
                        this.clientContext.ExecuteQueryRetry();
                    }

                    // Apply new permissions
                    foreach (var roleAssignment in pageTransformationInformation.SourcePage.RoleAssignments)
                    {
                        var principal = this.clientContext.Web.SiteUsers.GetByLoginName(roleAssignment.Member.LoginName);
                        if (principal != null)
                        {
                            var roleDefinitionBindingCollection = new RoleDefinitionBindingCollection(this.clientContext);
                            foreach (var roleDef in roleAssignment.RoleDefinitionBindings)
                            {
                                roleDefinitionBindingCollection.Add(roleDef);
                            }

                            targetPage.PageListItem.RoleAssignments.Add(principal, roleDefinitionBindingCollection);
                        }
                    }
                    this.clientContext.ExecuteQueryRetry();
                }
            }
            #endregion

            #region Page name switching
            // All went well so far...swap pages if that's needed
            if (pageTransformationInformation.TargetPageTakesSourcePageName)
            {
                //Load the source page
                SwapPages(pageTransformationInformation);
            }
            #endregion
            #endregion
        }
Beispiel #5
0
        /// <summary>
        /// Performs the logic needed to swap a genered Migrated_Page.aspx to Page.aspx and then Page.aspx to Old_Page.aspx
        /// </summary>
        /// <param name="pageTransformationInformation">Information about the page to transform</param>
        public void SwapPages(PageTransformationInformation pageTransformationInformation)
        {
            var sourcePageUrl         = pageTransformationInformation.SourcePage[Constants.FileRefField].ToString();
            var orginalSourcePageName = pageTransformationInformation.SourcePage[Constants.FileLeafRefField].ToString();

            string path = sourcePageUrl.Replace(pageTransformationInformation.SourcePage[Constants.FileLeafRefField].ToString(), "");

            var sourcePage = this.clientContext.Web.GetFileByServerRelativeUrl(sourcePageUrl);

            this.clientContext.Load(sourcePage);
            this.clientContext.ExecuteQueryRetry();

            if (string.IsNullOrEmpty(pageTransformationInformation.SourcePagePrefix))
            {
                pageTransformationInformation.SetDefaultSourcePagePrefix();
            }
            var newSourcePageUrl = $"{pageTransformationInformation.SourcePagePrefix}{pageTransformationInformation.SourcePage[Constants.FileLeafRefField].ToString()}";

            // Rename source page using the sourcepageprefix
            // STEP1: First copy the source page to a new name. We on purpose use CopyTo as we want to avoid that "linked" url's get
            //        patched up during a MoveTo operation as that would also patch the url's in our new modern page
            sourcePage.CopyTo($"{path}{newSourcePageUrl}", true);
            this.clientContext.ExecuteQueryRetry();

            //Load the created target page
            var targetPageUrl  = $"{path}{pageTransformationInformation.TargetPageName}";
            var targetPageFile = this.clientContext.Web.GetFileByServerRelativeUrl(targetPageUrl);

            this.clientContext.Load(targetPageFile);
            this.clientContext.ExecuteQueryRetry();

            // STEP2: Fix possible navigation entries to point to the "copied" source page first
            // Rename the target page to the original source page name
            // CopyTo and MoveTo with option to overwrite first internally delete the file to overwrite, which
            // results in all page navigation nodes pointing to this file to be deleted. Hence let's point these
            // navigation entries first to the copied version of the page we just created
            this.clientContext.Web.Context.Load(this.clientContext.Web, w => w.Navigation.QuickLaunch, w => w.Navigation.TopNavigationBar);
            this.clientContext.Web.Context.ExecuteQueryRetry();

            bool navWasFixed = false;
            IQueryable <NavigationNode> currentNavNodes = null;
            IQueryable <NavigationNode> globalNavNodes  = null;
            var currentNavigation = this.clientContext.Web.Navigation.QuickLaunch;
            var globalNavigation  = this.clientContext.Web.Navigation.TopNavigationBar;

            // Check for nav nodes
            currentNavNodes = currentNavigation.Where(n => n.Url.Equals(sourcePageUrl, StringComparison.InvariantCultureIgnoreCase));
            globalNavNodes  = globalNavigation.Where(n => n.Url.Equals(sourcePageUrl, StringComparison.InvariantCultureIgnoreCase));

            if (currentNavNodes.Count() > 0 || globalNavNodes.Count() > 0)
            {
                navWasFixed = true;
                foreach (var node in currentNavNodes)
                {
                    node.Url = $"{path}{newSourcePageUrl}";
                    node.Update();
                }
                foreach (var node in globalNavNodes)
                {
                    node.Url = $"{path}{newSourcePageUrl}";
                    node.Update();
                }
                this.clientContext.ExecuteQueryRetry();
            }

            // STEP3: Now copy the created modern page over the original source page, at this point the new page has the same name as the original page had before transformation
            targetPageFile.CopyTo($"{path}{orginalSourcePageName}", true);
            this.clientContext.ExecuteQueryRetry();

            // STEP4: Finish with restoring the page navigation: update the navlinks to point back the original page name
            if (navWasFixed)
            {
                // Reload the navigation entries as did update them
                this.clientContext.Web.Context.Load(this.clientContext.Web, w => w.Navigation.QuickLaunch, w => w.Navigation.TopNavigationBar);
                this.clientContext.Web.Context.ExecuteQueryRetry();

                currentNavigation = this.clientContext.Web.Navigation.QuickLaunch;
                globalNavigation  = this.clientContext.Web.Navigation.TopNavigationBar;
                if (!string.IsNullOrEmpty($"{path}{newSourcePageUrl}"))
                {
                    currentNavNodes = currentNavigation.Where(n => n.Url.Equals($"{path}{newSourcePageUrl}", StringComparison.InvariantCultureIgnoreCase));
                    globalNavNodes  = globalNavigation.Where(n => n.Url.Equals($"{path}{newSourcePageUrl}", StringComparison.InvariantCultureIgnoreCase));
                }

                foreach (var node in currentNavNodes)
                {
                    node.Url = sourcePageUrl;
                    node.Update();
                }
                foreach (var node in globalNavNodes)
                {
                    node.Url = sourcePageUrl;
                    node.Update();
                }
                this.clientContext.ExecuteQueryRetry();
            }

            //STEP5: Conclude with deleting the originally created modern page as we did copy that already in step 3
            targetPageFile.DeleteObject();
            this.clientContext.ExecuteQueryRetry();
        }
Beispiel #6
0
        internal void CopyPageMetadata(PageTransformationInformation pageTransformationInformation, string pageType, ClientSidePage targetPage, List targetPagesLibrary)
        {
            var  fieldsToCopy        = CacheManager.Instance.GetFieldsToCopy(this.sourceClientContext.Web, targetPagesLibrary, pageType);
            bool listItemWasReloaded = false;

            if (fieldsToCopy.Count > 0)
            {
                // Load the target page list item
                targetPage.Context.Load(targetPage.PageListItem);
                targetPage.Context.ExecuteQueryRetry();

                pageTransformationInformation.SourcePage.EnsureProperty(p => p.ContentType);

                // regular fields
                bool isDirty = false;

                var  sitePagesServerRelativeUrl = OfficeDevPnP.Core.Utilities.UrlUtility.Combine(targetPage.Context.Web.ServerRelativeUrl.TrimEnd(new char[] { '/' }), "sitepages");
                List targetSitePagesLibrary     = targetPage.Context.Web.GetList(sitePagesServerRelativeUrl);
                targetPage.Context.Load(targetSitePagesLibrary, l => l.Fields.IncludeWithDefaultProperties(f => f.Id, f => f.Title, f => f.Hidden, f => f.InternalName, f => f.DefaultValue, f => f.Required, f => f.StaticName));
                targetPage.Context.ExecuteQueryRetry();

                string contentTypeId = CacheManager.Instance.GetContentTypeId(targetPage.PageListItem.ParentList, pageTransformationInformation.SourcePage.ContentType.Name);
                if (!string.IsNullOrEmpty(contentTypeId))
                {
                    // Load the target page list item, needs to be loaded as it was previously saved and we need to avoid version conflicts
                    targetPage.Context.Load(targetPage.PageListItem);
                    targetPage.Context.ExecuteQueryRetry();
                    listItemWasReloaded = true;

                    targetPage.PageListItem[Constants.ContentTypeIdField] = contentTypeId;
                    targetPage.PageListItem.UpdateOverwriteVersion();
                    isDirty = true;
                }

                // taxonomy fields
                foreach (var fieldToCopy in fieldsToCopy.Where(p => p.FieldType == "TaxonomyFieldTypeMulti" || p.FieldType == "TaxonomyFieldType"))
                {
                    if (!listItemWasReloaded)
                    {
                        // Load the target page list item, needs to be loaded as it was previously saved and we need to avoid version conflicts
                        targetPage.Context.Load(targetPage.PageListItem);
                        targetPage.Context.ExecuteQueryRetry();
                        listItemWasReloaded = true;
                    }
                    switch (fieldToCopy.FieldType)
                    {
                    case "TaxonomyFieldTypeMulti":
                    {
                        var taxFieldBeforeCast = targetSitePagesLibrary.Fields.Where(p => p.StaticName.Equals(fieldToCopy.FieldName)).FirstOrDefault();
                        if (taxFieldBeforeCast != null)
                        {
                            var taxField = targetPage.Context.CastTo <TaxonomyField>(taxFieldBeforeCast);

                            if (pageTransformationInformation.SourcePage[fieldToCopy.FieldName] != null)
                            {
                                if (pageTransformationInformation.SourcePage[fieldToCopy.FieldName] is TaxonomyFieldValueCollection)
                                {
                                    var valueCollectionToCopy   = (pageTransformationInformation.SourcePage[fieldToCopy.FieldName] as TaxonomyFieldValueCollection);
                                    var taxonomyFieldValueArray = valueCollectionToCopy.Select(taxonomyFieldValue => $"-1;#{taxonomyFieldValue.Label}|{taxonomyFieldValue.TermGuid}");
                                    var valueCollection         = new TaxonomyFieldValueCollection(targetPage.Context, string.Join(";#", taxonomyFieldValueArray), taxField);
                                    taxField.SetFieldValueByValueCollection(targetPage.PageListItem, valueCollection);
                                }
                                else if (pageTransformationInformation.SourcePage[fieldToCopy.FieldName] is Dictionary <string, object> )
                                {
                                    var taxDictionaryList     = (pageTransformationInformation.SourcePage[fieldToCopy.FieldName] as Dictionary <string, object>);
                                    var valueCollectionToCopy = taxDictionaryList["_Child_Items_"] as Object[];

                                    List <string> taxonomyFieldValueArray = new List <string>();
                                    for (int i = 0; i < valueCollectionToCopy.Length; i++)
                                    {
                                        var taxDictionary = valueCollectionToCopy[i] as Dictionary <string, object>;
                                        taxonomyFieldValueArray.Add($"-1;#{taxDictionary["Label"].ToString()}|{taxDictionary["TermGuid"].ToString()}");
                                    }
                                    var valueCollection = new TaxonomyFieldValueCollection(targetPage.Context, string.Join(";#", taxonomyFieldValueArray), taxField);
                                    taxField.SetFieldValueByValueCollection(targetPage.PageListItem, valueCollection);
                                }

                                isDirty = true;
                                LogInfo($"{LogStrings.TransformCopyingMetaDataField} {fieldToCopy.FieldName}", LogStrings.Heading_CopyingPageMetadata);
                            }
                        }
                        else
                        {
                            LogWarning($"{LogStrings.TransformCopyingMetaDataFieldSkipped} {fieldToCopy.FieldName}", LogStrings.Heading_CopyingPageMetadata);
                            break;
                        }
                        break;
                    }

                    case "TaxonomyFieldType":
                    {
                        var taxFieldBeforeCast = targetSitePagesLibrary.Fields.Where(p => p.StaticName.Equals(fieldToCopy.FieldName)).FirstOrDefault();
                        if (taxFieldBeforeCast != null)
                        {
                            var taxField = targetPage.Context.CastTo <TaxonomyField>(taxFieldBeforeCast);
                            var taxValue = new TaxonomyFieldValue();
                            if (pageTransformationInformation.SourcePage[fieldToCopy.FieldName] != null)
                            {
                                if (pageTransformationInformation.SourcePage[fieldToCopy.FieldName] is TaxonomyFieldValue)
                                {
                                    taxValue.Label    = (pageTransformationInformation.SourcePage[fieldToCopy.FieldName] as TaxonomyFieldValue).Label;
                                    taxValue.TermGuid = (pageTransformationInformation.SourcePage[fieldToCopy.FieldName] as TaxonomyFieldValue).TermGuid;
                                    taxValue.WssId    = -1;
                                }
                                else if (pageTransformationInformation.SourcePage[fieldToCopy.FieldName] is Dictionary <string, object> )
                                {
                                    var taxDictionary = (pageTransformationInformation.SourcePage[fieldToCopy.FieldName] as Dictionary <string, object>);
                                    taxValue.Label    = taxDictionary["Label"].ToString();
                                    taxValue.TermGuid = taxDictionary["TermGuid"].ToString();
                                    taxValue.WssId    = -1;
                                }
                                taxField.SetFieldValueByValue(targetPage.PageListItem, taxValue);
                                isDirty = true;
                                LogInfo($"{LogStrings.TransformCopyingMetaDataField} {fieldToCopy.FieldName}", LogStrings.Heading_CopyingPageMetadata);
                            }
                        }
                        else
                        {
                            LogWarning($"{LogStrings.TransformCopyingMetaDataFieldSkipped} {fieldToCopy.FieldName}", LogStrings.Heading_CopyingPageMetadata);
                            break;
                        }
                        break;
                    }
                    }
                }

                if (isDirty)
                {
                    targetPage.PageListItem.UpdateOverwriteVersion();
                    targetPage.Context.Load(targetPage.PageListItem);
                    targetPage.Context.ExecuteQueryRetry();
                    isDirty = false;
                }

                foreach (var fieldToCopy in fieldsToCopy.Where(p => p.FieldType != "TaxonomyFieldTypeMulti" && p.FieldType != "TaxonomyFieldType"))
                {
                    var targetField = targetSitePagesLibrary.Fields.Where(p => p.StaticName.Equals(fieldToCopy.FieldName)).FirstOrDefault();

                    if (targetField != null && pageTransformationInformation.SourcePage[fieldToCopy.FieldName] != null)
                    {
                        if (fieldToCopy.FieldType == "User" || fieldToCopy.FieldType == "UserMulti")
                        {
                            if (pageTransformationInformation.IsCrossFarmTransformation)
                            {
                                // we can't copy these fields in a cross farm scenario as we do not yet support user account mapping
                                LogWarning($"{LogStrings.TransformCopyingUserMetaDataFieldSkipped} {fieldToCopy.FieldName}", LogStrings.Heading_CopyingPageMetadata);
                            }
                            else
                            {
                                object fieldValueToSet = pageTransformationInformation.SourcePage[fieldToCopy.FieldName];
                                if (fieldValueToSet is FieldUserValue)
                                {
                                    using (var clonedTargetContext = targetPage.Context.Clone(targetPage.Context.Web.GetUrl()))
                                    {
                                        try
                                        {
                                            var user = clonedTargetContext.Web.EnsureUser((fieldValueToSet as FieldUserValue).LookupValue);
                                            clonedTargetContext.Load(user);
                                            clonedTargetContext.ExecuteQueryRetry();

                                            // Prep a new FieldUserValue object instance and update the list item
                                            var newUser = new FieldUserValue()
                                            {
                                                LookupId = user.Id
                                            };
                                            targetPage.PageListItem[fieldToCopy.FieldName] = newUser;
                                        }
                                        catch (Exception ex)
                                        {
                                            LogWarning(string.Format(LogStrings.Warning_UserIsNotResolving, (fieldValueToSet as FieldUserValue).LookupValue, ex.Message), LogStrings.Heading_CopyingPageMetadata);
                                        }
                                    }
                                }
                                else
                                {
                                    List <FieldUserValue> userValues = new List <FieldUserValue>();
                                    using (var clonedTargetContext = targetPage.Context.Clone(targetPage.Context.Web.GetUrl()))
                                    {
                                        foreach (var currentUser in (fieldValueToSet as Array))
                                        {
                                            try
                                            {
                                                var user = clonedTargetContext.Web.EnsureUser((currentUser as FieldUserValue).LookupValue);
                                                clonedTargetContext.Load(user);
                                                clonedTargetContext.ExecuteQueryRetry();

                                                // Prep a new FieldUserValue object instance
                                                var newUser = new FieldUserValue()
                                                {
                                                    LookupId = user.Id
                                                };

                                                userValues.Add(newUser);
                                            }
                                            catch (Exception ex)
                                            {
                                                LogWarning(string.Format(LogStrings.Warning_UserIsNotResolving, (fieldValueToSet as FieldUserValue).LookupValue, ex.Message), LogStrings.Heading_CopyingPageMetadata);
                                            }
                                        }

                                        if (userValues.Count > 0)
                                        {
                                            targetPage.PageListItem[fieldToCopy.FieldName] = userValues.ToArray();
                                        }
                                    }
                                }
                            }
                        }
                        else
                        {
                            // Handling of "special" fields

                            // PostCategory is a default field on a blog post, but it's a lookup. Let's copy as regular field
                            if (fieldToCopy.FieldId.Equals(Constants.PostCategory))
                            {
                                string postCategoryFieldValue = null;
                                if (((FieldLookupValue[])pageTransformationInformation.SourcePage[fieldToCopy.FieldName]).Length > 1)
                                {
                                    postCategoryFieldValue += ";#";
                                    foreach (var fieldLookupValue in (FieldLookupValue[])pageTransformationInformation.SourcePage[fieldToCopy.FieldName])
                                    {
                                        postCategoryFieldValue = postCategoryFieldValue + fieldLookupValue.LookupValue + ";#";
                                    }
                                }
                                else
                                {
                                    postCategoryFieldValue = ((FieldLookupValue[])pageTransformationInformation.SourcePage[fieldToCopy.FieldName])[0].LookupValue;
                                }

                                targetPage.PageListItem[fieldToCopy.FieldName] = postCategoryFieldValue;
                            }
                            // Regular field handling
                            else
                            {
                                targetPage.PageListItem[fieldToCopy.FieldName] = pageTransformationInformation.SourcePage[fieldToCopy.FieldName];
                            }
                        }

                        isDirty = true;
                        LogInfo($"{LogStrings.TransformCopyingMetaDataField} {fieldToCopy.FieldName}", LogStrings.Heading_CopyingPageMetadata);
                    }
                    else
                    {
                        LogWarning($"{LogStrings.TransformCopyingMetaDataFieldSkipped} {fieldToCopy.FieldName}", LogStrings.Heading_CopyingPageMetadata);
                    }
                }

                if (isDirty)
                {
                    targetPage.PageListItem.UpdateOverwriteVersion();
                    targetPage.Context.Load(targetPage.PageListItem);
                    targetPage.Context.ExecuteQueryRetry();
                    isDirty = false;
                }
            }
        }
        internal void CopyPageMetadata(PageTransformationInformation pageTransformationInformation, ClientSidePage targetPage, List pagesLibrary)
        {
            var fieldsToCopy = CacheManager.Instance.GetFieldsToCopy(this.sourceClientContext.Web, pagesLibrary);

            if (fieldsToCopy.Count > 0)
            {
                // Load the target page list item
                this.sourceClientContext.Load(targetPage.PageListItem);
                this.sourceClientContext.ExecuteQueryRetry();

                // regular fields
                bool isDirty = false;
                foreach (var fieldToCopy in fieldsToCopy.Where(p => p.FieldType != "TaxonomyFieldTypeMulti" && p.FieldType != "TaxonomyFieldType"))
                {
                    if (pageTransformationInformation.SourcePage[fieldToCopy.FieldName] != null)
                    {
                        targetPage.PageListItem[fieldToCopy.FieldName] = pageTransformationInformation.SourcePage[fieldToCopy.FieldName];
                        isDirty = true;

                        LogInfo($"{LogStrings.TransformCopyingMetaDataField} {fieldToCopy.FieldName}", LogStrings.Heading_CopyingPageMetadata);
                    }
                }

                if (isDirty)
                {
                    targetPage.PageListItem.Update();
                    this.sourceClientContext.Load(targetPage.PageListItem);
                    this.sourceClientContext.ExecuteQueryRetry();
                    isDirty = false;
                }

                // taxonomy fields
                foreach (var fieldToCopy in fieldsToCopy.Where(p => p.FieldType == "TaxonomyFieldTypeMulti" || p.FieldType == "TaxonomyFieldType"))
                {
                    switch (fieldToCopy.FieldType)
                    {
                    case "TaxonomyFieldTypeMulti":
                    {
                        var taxFieldBeforeCast = pagesLibrary.Fields.Where(p => p.Id.Equals(fieldToCopy.FieldId)).FirstOrDefault();
                        if (taxFieldBeforeCast != null)
                        {
                            var taxField = this.sourceClientContext.CastTo <TaxonomyField>(taxFieldBeforeCast);

                            if (pageTransformationInformation.SourcePage[fieldToCopy.FieldName] != null)
                            {
                                if (pageTransformationInformation.SourcePage[fieldToCopy.FieldName] is TaxonomyFieldValueCollection)
                                {
                                    var valueCollectionToCopy   = (pageTransformationInformation.SourcePage[fieldToCopy.FieldName] as TaxonomyFieldValueCollection);
                                    var taxonomyFieldValueArray = valueCollectionToCopy.Select(taxonomyFieldValue => $"-1;#{taxonomyFieldValue.Label}|{taxonomyFieldValue.TermGuid}");
                                    var valueCollection         = new TaxonomyFieldValueCollection(this.sourceClientContext, string.Join(";#", taxonomyFieldValueArray), taxField);
                                    taxField.SetFieldValueByValueCollection(targetPage.PageListItem, valueCollection);
                                }
                                else if (pageTransformationInformation.SourcePage[fieldToCopy.FieldName] is Dictionary <string, object> )
                                {
                                    var taxDictionaryList     = (pageTransformationInformation.SourcePage[fieldToCopy.FieldName] as Dictionary <string, object>);
                                    var valueCollectionToCopy = taxDictionaryList["_Child_Items_"] as Object[];

                                    List <string> taxonomyFieldValueArray = new List <string>();
                                    for (int i = 0; i < valueCollectionToCopy.Length; i++)
                                    {
                                        var taxDictionary = valueCollectionToCopy[i] as Dictionary <string, object>;
                                        taxonomyFieldValueArray.Add($"-1;#{taxDictionary["Label"].ToString()}|{taxDictionary["TermGuid"].ToString()}");
                                    }
                                    var valueCollection = new TaxonomyFieldValueCollection(this.sourceClientContext, string.Join(";#", taxonomyFieldValueArray), taxField);
                                    taxField.SetFieldValueByValueCollection(targetPage.PageListItem, valueCollection);
                                }

                                isDirty = true;
                                LogInfo($"{LogStrings.TransformCopyingMetaDataField} {fieldToCopy.FieldName}", LogStrings.Heading_CopyingPageMetadata);
                            }
                        }
                        break;
                    }

                    case "TaxonomyFieldType":
                    {
                        var taxFieldBeforeCast = pagesLibrary.Fields.Where(p => p.Id.Equals(fieldToCopy.FieldId)).FirstOrDefault();
                        if (taxFieldBeforeCast != null)
                        {
                            var taxField = this.sourceClientContext.CastTo <TaxonomyField>(taxFieldBeforeCast);
                            var taxValue = new TaxonomyFieldValue();
                            if (pageTransformationInformation.SourcePage[fieldToCopy.FieldName] != null)
                            {
                                if (pageTransformationInformation.SourcePage[fieldToCopy.FieldName] is TaxonomyFieldValue)
                                {
                                    taxValue.Label    = (pageTransformationInformation.SourcePage[fieldToCopy.FieldName] as TaxonomyFieldValue).Label;
                                    taxValue.TermGuid = (pageTransformationInformation.SourcePage[fieldToCopy.FieldName] as TaxonomyFieldValue).TermGuid;
                                    taxValue.WssId    = -1;
                                }
                                else if (pageTransformationInformation.SourcePage[fieldToCopy.FieldName] is Dictionary <string, object> )
                                {
                                    var taxDictionary = (pageTransformationInformation.SourcePage[fieldToCopy.FieldName] as Dictionary <string, object>);
                                    taxValue.Label    = taxDictionary["Label"].ToString();
                                    taxValue.TermGuid = taxDictionary["TermGuid"].ToString();
                                    taxValue.WssId    = -1;
                                }
                                taxField.SetFieldValueByValue(targetPage.PageListItem, taxValue);
                                isDirty = true;
                                LogInfo($"{LogStrings.TransformCopyingMetaDataField} {fieldToCopy.FieldName}", LogStrings.Heading_CopyingPageMetadata);
                            }
                        }
                        break;
                    }
                    }
                }

                if (isDirty)
                {
                    targetPage.PageListItem.Update();
                    this.sourceClientContext.Load(targetPage.PageListItem);
                    this.sourceClientContext.ExecuteQueryRetry();
                }
            }
        }
Beispiel #8
0
        /// <summary>
        /// Transform the page
        /// </summary>
        /// <param name="pageTransformationInformation">Information about the page to transform</param>
        public void Transform(PageTransformationInformation pageTransformationInformation)
        {
            #region Input validation
            if (pageTransformationInformation.SourcePage == null)
            {
                throw new ArgumentNullException("SourcePage cannot be null");
            }

            // Validate page and it's eligibility for transformation
            if (!pageTransformationInformation.SourcePage.FieldExistsAndUsed(Constants.FileRefField) || !pageTransformationInformation.SourcePage.FieldExistsAndUsed(Constants.FileLeafRefField))
            {
                throw new ArgumentException("Page is not valid due to missing FileRef or FileLeafRef value");
            }

            string pageType = pageTransformationInformation.SourcePage.PageType();

            if (pageType.Equals("ClientSidePage", StringComparison.InvariantCultureIgnoreCase))
            {
                throw new ArgumentException("Page is a client side page...guess you don't want to transform it...");
            }

            if (pageType.Equals("AspxPage", StringComparison.InvariantCultureIgnoreCase))
            {
                throw new ArgumentException("Page is an basic aspx page...can't transform that one, sorry!");
            }
            #endregion

            #region Telemetry
            clientContext.ClientTag = $"SPDev:PageTransformator";
            clientContext.Load(clientContext.Web, p => p.Description, p => p.Id);
            clientContext.ExecuteQuery();
            #endregion

            #region Page creation
            // If no targetname specified then we'll come up with one
            if (string.IsNullOrEmpty(pageTransformationInformation.TargetPageName))
            {
                if (string.IsNullOrEmpty(pageTransformationInformation.TargetPagePrefix))
                {
                    pageTransformationInformation.SetDefaultTargetPagePrefix();
                }

                pageTransformationInformation.TargetPageName = $"{pageTransformationInformation.TargetPagePrefix}{pageTransformationInformation.SourcePage[Constants.FileLeafRefField].ToString()}";
            }

            // Check if page name is free to use
            bool           pageExists = false;
            ClientSidePage targetPage = null;
            try
            {
                targetPage = clientContext.Web.LoadClientSidePage(pageTransformationInformation.TargetPageName);
                pageExists = true;
            }
            catch (ArgumentException) { }

            if (pageExists)
            {
                if (!pageTransformationInformation.Overwrite)
                {
                    throw new ArgumentException($"There already exists a page with name {pageTransformationInformation.TargetPageName}.");
                }
                else
                {
                    targetPage.ClearPage();
                }
            }
            else
            {
                // Create a new client side page
                targetPage = clientContext.Web.AddClientSidePage(pageTransformationInformation.TargetPageName);
            }
            #endregion

            #region Home page handling
            bool replacedByOOBHomePage = false;
            // Check if the transformed page is the web's home page
            clientContext.Web.EnsureProperties(w => w.RootFolder.WelcomePage);
            var homePageUrl  = clientContext.Web.RootFolder.WelcomePage;
            var homepageName = Path.GetFileName(clientContext.Web.RootFolder.WelcomePage);
            if (homepageName.Equals(pageTransformationInformation.SourcePage[Constants.FileLeafRefField].ToString(), StringComparison.InvariantCultureIgnoreCase))
            {
                targetPage.LayoutType = ClientSidePageLayoutType.Home;
                if (pageTransformationInformation.ReplaceHomePageWithDefaultHomePage)
                {
                    targetPage.KeepDefaultWebParts = true;
                    replacedByOOBHomePage          = true;
                }
            }
            #endregion

            #region Article page handling
            if (!replacedByOOBHomePage)
            {
                #region Configure header from target page
                if (pageTransformationInformation.PageHeader == null || pageTransformationInformation.PageHeader.Type == ClientSidePageHeaderType.None)
                {
                    targetPage.RemovePageHeader();
                }
                else if (pageTransformationInformation.PageHeader.Type == ClientSidePageHeaderType.Default)
                {
                    targetPage.SetDefaultPageHeader();
                }
                else if (pageTransformationInformation.PageHeader.Type == ClientSidePageHeaderType.Custom)
                {
                    targetPage.SetCustomPageHeader(pageTransformationInformation.PageHeader.ImageServerRelativeUrl, pageTransformationInformation.PageHeader.TranslateX, pageTransformationInformation.PageHeader.TranslateY);
                }
                #endregion

                #region Analysis of the source page
                // Analyze the source page
                Tuple <PageLayout, List <WebPartEntity> > pageData = null;

                if (pageType.Equals("WikiPage", StringComparison.InvariantCultureIgnoreCase))
                {
                    pageData = new WikiPage(pageTransformationInformation.SourcePage, pageTransformation).Analyze();

                    // Wiki pages can contain embedded images and videos, which is not supported by the target RTE...split wiki text blocks so the transformator can handle the images and videos as separate web parts
                    if (pageTransformationInformation.HandleWikiImagesAndVideos)
                    {
                        pageData = new Tuple <PageLayout, List <WebPartEntity> >(pageData.Item1, new WikiTransformator().TransformPlusSplit(pageData.Item2));
                    }
                }
                else if (pageType.Equals("WebPartPage", StringComparison.InvariantCultureIgnoreCase))
                {
                    pageData = new WebPartPage(pageTransformationInformation.SourcePage, pageTransformation).Analyze(true);
                }
                #endregion

                #region Page title configuration
                // Set page title
                if (pageType.Equals("WikiPage", StringComparison.InvariantCultureIgnoreCase))
                {
                    SetPageTitle(pageTransformationInformation, targetPage);
                }
                else if (pageType.Equals("WebPartPage"))
                {
                    bool titleFound      = false;
                    var  titleBarWebPart = pageData.Item2.Where(p => p.Type == WebParts.TitleBar).FirstOrDefault();
                    if (titleBarWebPart != null)
                    {
                        if (titleBarWebPart.Properties.ContainsKey("HeaderTitle") && !string.IsNullOrEmpty(titleBarWebPart.Properties["HeaderTitle"]))
                        {
                            targetPage.PageTitle = titleBarWebPart.Properties["HeaderTitle"];
                            titleFound           = true;
                        }
                    }

                    if (!titleFound)
                    {
                        SetPageTitle(pageTransformationInformation, targetPage);
                    }
                }

                if (pageTransformationInformation.PageTitleOverride != null)
                {
                    targetPage.PageTitle = pageTransformationInformation.PageTitleOverride(targetPage.PageTitle);
                }
                #endregion

                #region Page layout configuration
                // Use the default layout transformator
                ILayoutTransformator layoutTransformator = new LayoutTransformator(targetPage);

                // Do we have an override?
                if (pageTransformationInformation.LayoutTransformatorOverride != null)
                {
                    layoutTransformator = pageTransformationInformation.LayoutTransformatorOverride(targetPage);
                }

                // Apply the layout to the page
                layoutTransformator.Transform(pageData.Item1);
                #endregion

                #region Content transformation
                // Use the default content transformator
                IContentTransformator contentTransformator = new ContentTransformator(targetPage, pageTransformation);

                // Do we have an override?
                if (pageTransformationInformation.ContentTransformatorOverride != null)
                {
                    contentTransformator = pageTransformationInformation.ContentTransformatorOverride(targetPage, pageTransformation);
                }

                // Run the content transformator
                contentTransformator.Transform(pageData.Item2);
                #endregion
            }
            #endregion

            #region Page persisting + permissions
            // Persist the client side page
            targetPage.Save(pageTransformationInformation.TargetPageName);
            targetPage.Publish();

            #region Permission handling
            if (pageTransformationInformation.KeepPageSpecificPermissions)
            {
                pageTransformationInformation.SourcePage.EnsureProperty(p => p.HasUniqueRoleAssignments);
                if (pageTransformationInformation.SourcePage.HasUniqueRoleAssignments)
                {
                    // Copy the unique permissions from source to target
                    // Get the unique permissions
                    this.clientContext.Load(pageTransformationInformation.SourcePage, a => a.RoleAssignments.Include(roleAsg => roleAsg.Member.LoginName,
                                                                                                                     roleAsg => roleAsg.RoleDefinitionBindings.Include(roleDef => roleDef.Name, roleDef => roleDef.Description)));
                    this.clientContext.ExecuteQueryRetry();

                    // Get target page information
                    this.clientContext.Load(targetPage.PageListItem, p => p.HasUniqueRoleAssignments, a => a.RoleAssignments.Include(roleAsg => roleAsg.Member.LoginName,
                                                                                                                                     roleAsg => roleAsg.RoleDefinitionBindings.Include(roleDef => roleDef.Name, roleDef => roleDef.Description)));
                    this.clientContext.ExecuteQueryRetry();

                    // Break permission inheritance on the target page if not done yet
                    if (!targetPage.PageListItem.HasUniqueRoleAssignments)
                    {
                        targetPage.PageListItem.BreakRoleInheritance(false, false);
                        this.clientContext.ExecuteQueryRetry();
                    }

                    // Apply new permissions
                    foreach (var roleAssignment in pageTransformationInformation.SourcePage.RoleAssignments)
                    {
                        var principal = this.clientContext.Web.SiteUsers.GetByLoginName(roleAssignment.Member.LoginName);
                        if (principal != null)
                        {
                            var roleDefinitionBindingCollection = new RoleDefinitionBindingCollection(this.clientContext);
                            foreach (var roleDef in roleAssignment.RoleDefinitionBindings)
                            {
                                roleDefinitionBindingCollection.Add(roleDef);
                            }

                            targetPage.PageListItem.RoleAssignments.Add(principal, roleDefinitionBindingCollection);
                        }
                    }
                    this.clientContext.ExecuteQueryRetry();
                }
            }
            #endregion

            #region Page name switching
            // All went well so far...swap pages if that's needed
            if (pageTransformationInformation.TargetPageTakesSourcePageName)
            {
                //Load the source page
                var sourcePageUrl         = pageTransformationInformation.SourcePage[Constants.FileRefField].ToString();
                var orginalSourcePageName = pageTransformationInformation.SourcePage[Constants.FileLeafRefField].ToString();

                string path = sourcePageUrl.Replace(pageTransformationInformation.SourcePage[Constants.FileLeafRefField].ToString(), "");

                var sourcePage = this.clientContext.Web.GetFileByServerRelativeUrl(sourcePageUrl);
                this.clientContext.Load(sourcePage);
                this.clientContext.ExecuteQueryRetry();

                if (string.IsNullOrEmpty(pageTransformationInformation.SourcePagePrefix))
                {
                    pageTransformationInformation.SetDefaultSourcePagePrefix();
                }
                var newSourcePageUrl = $"{pageTransformationInformation.SourcePagePrefix}{pageTransformationInformation.SourcePage[Constants.FileLeafRefField].ToString()}";

                // Rename source page using the sourcepageprefix
                // STEP1: First copy the source page to a new name. We on purpose use CopyTo as we want to avoid that "linked" url's get
                //        patched up during a MoveTo operation as that would also patch the url's in our new modern page
                sourcePage.CopyTo($"{path}{newSourcePageUrl}", true);
                this.clientContext.ExecuteQueryRetry();

                //Load the created target page
                var targetPageUrl  = $"{path}{pageTransformationInformation.TargetPageName}";
                var targetPageFile = this.clientContext.Web.GetFileByServerRelativeUrl(targetPageUrl);
                this.clientContext.Load(targetPageFile);
                this.clientContext.ExecuteQueryRetry();

                // STEP2: Fix possible navigation entries to point to the "copied" source page first
                // Rename the target page to the original source page name
                // CopyTo and MoveTo with option to overwrite first internally delete the file to overwrite, which
                // results in all page navigation nodes pointing to this file to be deleted. Hence let's point these
                // navigation entries first to the copied version of the page we just created
                this.clientContext.Web.Context.Load(this.clientContext.Web, w => w.Navigation.QuickLaunch, w => w.Navigation.TopNavigationBar);
                this.clientContext.Web.Context.ExecuteQueryRetry();

                bool navWasFixed = false;
                IQueryable <NavigationNode> currentNavNodes = null;
                IQueryable <NavigationNode> globalNavNodes  = null;
                var currentNavigation = this.clientContext.Web.Navigation.QuickLaunch;
                var globalNavigation  = this.clientContext.Web.Navigation.TopNavigationBar;
                // Check for nav nodes
                currentNavNodes = currentNavigation.Where(n => n.Url.Equals(sourcePageUrl, StringComparison.InvariantCultureIgnoreCase));
                globalNavNodes  = globalNavigation.Where(n => n.Url.Equals(sourcePageUrl, StringComparison.InvariantCultureIgnoreCase));

                if (currentNavNodes.Count() > 0 || globalNavNodes.Count() > 0)
                {
                    navWasFixed = true;
                    foreach (var node in currentNavNodes)
                    {
                        node.Url = $"{path}{newSourcePageUrl}";
                        node.Update();
                    }
                    foreach (var node in globalNavNodes)
                    {
                        node.Url = $"{path}{newSourcePageUrl}";
                        node.Update();
                    }
                    this.clientContext.ExecuteQueryRetry();
                }

                // STEP3: Now copy the created modern page over the original source page, at this point the new page has the same name as the original page had before transformation
                targetPageFile.CopyTo($"{path}{orginalSourcePageName}", true);
                this.clientContext.ExecuteQueryRetry();

                // STEP4: Finish with restoring the page navigation: update the navlinks to point back the original page name
                if (navWasFixed)
                {
                    // Reload the navigation entries as did update them
                    this.clientContext.Web.Context.Load(this.clientContext.Web, w => w.Navigation.QuickLaunch, w => w.Navigation.TopNavigationBar);
                    this.clientContext.Web.Context.ExecuteQueryRetry();

                    currentNavigation = this.clientContext.Web.Navigation.QuickLaunch;
                    globalNavigation  = this.clientContext.Web.Navigation.TopNavigationBar;
                    if (!string.IsNullOrEmpty($"{path}{newSourcePageUrl}"))
                    {
                        currentNavNodes = currentNavigation.Where(n => n.Url.Equals($"{path}{newSourcePageUrl}", StringComparison.InvariantCultureIgnoreCase));
                        globalNavNodes  = globalNavigation.Where(n => n.Url.Equals($"{path}{newSourcePageUrl}", StringComparison.InvariantCultureIgnoreCase));
                    }

                    foreach (var node in currentNavNodes)
                    {
                        node.Url = sourcePageUrl;
                        node.Update();
                    }
                    foreach (var node in globalNavNodes)
                    {
                        node.Url = sourcePageUrl;
                        node.Update();
                    }
                    this.clientContext.ExecuteQueryRetry();
                }

                //STEP5: Conclude with deleting the originally created modern page as we did copy that already in step 3
                targetPageFile.DeleteObject();
                this.clientContext.ExecuteQueryRetry();
            }
            #endregion
            #endregion
        }
Beispiel #9
0
        /// <summary>
        /// Transform the page
        /// </summary>
        /// <param name="pageTransformationInformation">Information about the page to transform</param>
        /// <returns>The path to created modern page</returns>
        public string Transform(PageTransformationInformation pageTransformationInformation)
        {
            #region Input validation
            if (pageTransformationInformation.SourcePage == null)
            {
                throw new ArgumentNullException("SourcePage cannot be null");
            }

            // Validate page and it's eligibility for transformation
            if (!pageTransformationInformation.SourcePage.FieldExistsAndUsed(Constants.FileRefField) || !pageTransformationInformation.SourcePage.FieldExistsAndUsed(Constants.FileLeafRefField))
            {
                throw new ArgumentException("Page is not valid due to missing FileRef or FileLeafRef value");
            }

            string pageType = pageTransformationInformation.SourcePage.PageType();

            if (pageType.Equals("ClientSidePage", StringComparison.InvariantCultureIgnoreCase))
            {
                throw new ArgumentException("Page already is a modern client side page...no need to transform it.");
            }

            if (pageType.Equals("AspxPage", StringComparison.InvariantCultureIgnoreCase))
            {
                throw new ArgumentException("Page is an basic aspx page...can't currently transform that one, sorry!");
            }

            if (pageType.Equals("PublishingPage", StringComparison.InvariantCultureIgnoreCase))
            {
                throw new ArgumentException("Page transformation for publishing pages is currently not supported.");
            }
            #endregion

            #region Telemetry
#if DEBUG && MEASURE
            Start();
#endif
            DateTime transformationStartDateTime = DateTime.Now;
            clientContext.ClientTag = $"SPDev:PageTransformator";
            // Load all web properties needed further one
            clientContext.Load(clientContext.Web, p => p.Id, p => p.ServerRelativeUrl, p => p.RootFolder.WelcomePage, p => p.Url);
            clientContext.Load(clientContext.Site, p => p.RootWeb.ServerRelativeUrl, p => p.Id);
            // Use regular ExecuteQuery as we want to send this custom clienttag
            clientContext.ExecuteQuery();
#if DEBUG && MEASURE
            Stop("Telemetry");
#endif
            #endregion

            #region Page creation
            // Detect if the page is living inside a folder
            string pageFolder = "";
            if (pageTransformationInformation.SourcePage.FieldExistsAndUsed(Constants.FileDirRefField))
            {
                var fileRefFieldValue = pageTransformationInformation.SourcePage[Constants.FileDirRefField].ToString();
                pageFolder = fileRefFieldValue.Replace($"{clientContext.Web.ServerRelativeUrl}/SitePages", "").Trim();

                if (pageFolder.Length > 0)
                {
                    if (pageFolder.Contains("/"))
                    {
                        if (pageFolder == "/")
                        {
                            pageFolder = "";
                        }
                        else
                        {
                            pageFolder = pageFolder.Substring(1);
                        }
                    }

                    // Add a trailing slash
                    pageFolder = pageFolder + "/";
                }
            }
            pageTransformationInformation.Folder = pageFolder;

            // If no targetname specified then we'll come up with one
            if (string.IsNullOrEmpty(pageTransformationInformation.TargetPageName))
            {
                if (string.IsNullOrEmpty(pageTransformationInformation.TargetPagePrefix))
                {
                    pageTransformationInformation.SetDefaultTargetPagePrefix();
                }

                pageTransformationInformation.TargetPageName = $"{pageTransformationInformation.TargetPagePrefix}{pageTransformationInformation.SourcePage[Constants.FileLeafRefField].ToString()}";
            }

            // Check if page name is free to use
#if DEBUG && MEASURE
            Start();
#endif
            bool           pageExists   = false;
            ClientSidePage targetPage   = null;
            List           pagesLibrary = null;
            Microsoft.SharePoint.Client.File existingFile = null;
            try
            {
                // Just try to load the page in the fastest possible manner, we only want to see if the page exists or not
                existingFile = Load(clientContext, pageTransformationInformation, out pagesLibrary);
                pageExists   = true;
            }
            catch (ArgumentException) { }
#if DEBUG && MEASURE
            Stop("Load Page");
#endif

            if (pageExists)
            {
                if (!pageTransformationInformation.Overwrite)
                {
                    throw new ArgumentException($"There already exists a page with name {pageTransformationInformation.TargetPageName}.");
                }
            }

            // Create the client side page

            targetPage = clientContext.Web.AddClientSidePage($"{pageTransformationInformation.Folder}{pageTransformationInformation.TargetPageName}");
            #endregion

            #region Home page handling
#if DEBUG && MEASURE
            Start();
#endif
            bool replacedByOOBHomePage = false;
            // Check if the transformed page is the web's home page
            if (clientContext.Web.RootFolder.IsPropertyAvailable("WelcomePage") && !string.IsNullOrEmpty(clientContext.Web.RootFolder.WelcomePage))
            {
                var homePageUrl  = clientContext.Web.RootFolder.WelcomePage;
                var homepageName = Path.GetFileName(clientContext.Web.RootFolder.WelcomePage);
                if (homepageName.Equals(pageTransformationInformation.SourcePage[Constants.FileLeafRefField].ToString(), StringComparison.InvariantCultureIgnoreCase))
                {
                    targetPage.LayoutType = ClientSidePageLayoutType.Home;
                    if (pageTransformationInformation.ReplaceHomePageWithDefaultHomePage)
                    {
                        targetPage.KeepDefaultWebParts = true;
                        replacedByOOBHomePage          = true;
                    }
                }
            }
#if DEBUG && MEASURE
            Stop("Home page handling");
#endif
            #endregion

            #region Article page handling
            if (!replacedByOOBHomePage)
            {
                #region Configure header from target page
#if DEBUG && MEASURE
                Start();
#endif
                if (pageTransformationInformation.PageHeader == null || pageTransformationInformation.PageHeader.Type == ClientSidePageHeaderType.None)
                {
                    targetPage.RemovePageHeader();
                }
                else if (pageTransformationInformation.PageHeader.Type == ClientSidePageHeaderType.Default)
                {
                    targetPage.SetDefaultPageHeader();
                }
                else if (pageTransformationInformation.PageHeader.Type == ClientSidePageHeaderType.Custom)
                {
                    targetPage.SetCustomPageHeader(pageTransformationInformation.PageHeader.ImageServerRelativeUrl, pageTransformationInformation.PageHeader.TranslateX, pageTransformationInformation.PageHeader.TranslateY);
                }
#if DEBUG && MEASURE
                Stop("Target page header");
#endif
                #endregion

                #region Analysis of the source page
#if DEBUG && MEASURE
                Start();
#endif
                // Analyze the source page
                Tuple <PageLayout, List <WebPartEntity> > pageData = null;

                if (pageType.Equals("WikiPage", StringComparison.InvariantCultureIgnoreCase))
                {
                    pageData = new WikiPage(pageTransformationInformation.SourcePage, pageTransformation).Analyze();

                    // Wiki pages can contain embedded images and videos, which is not supported by the target RTE...split wiki text blocks so the transformator can handle the images and videos as separate web parts
                    pageData = new Tuple <PageLayout, List <WebPartEntity> >(pageData.Item1, new WikiTransformatorSimple().TransformPlusSplit(pageData.Item2, pageTransformationInformation.HandleWikiImagesAndVideos));
                }
                else if (pageType.Equals("WebPartPage", StringComparison.InvariantCultureIgnoreCase))
                {
                    pageData = new WebPartPage(pageTransformationInformation.SourcePage, pageTransformation).Analyze(true);
                }
#if DEBUG && MEASURE
                Stop("Analyze page");
#endif
                #endregion

                #region Page title configuration
#if DEBUG && MEASURE
                Start();
#endif
                // Set page title
                if (pageType.Equals("WikiPage", StringComparison.InvariantCultureIgnoreCase))
                {
                    SetPageTitle(pageTransformationInformation, targetPage);
                }
                else if (pageType.Equals("WebPartPage"))
                {
                    bool titleFound      = false;
                    var  titleBarWebPart = pageData.Item2.Where(p => p.Type == WebParts.TitleBar).FirstOrDefault();
                    if (titleBarWebPart != null)
                    {
                        if (titleBarWebPart.Properties.ContainsKey("HeaderTitle") && !string.IsNullOrEmpty(titleBarWebPart.Properties["HeaderTitle"]))
                        {
                            targetPage.PageTitle = titleBarWebPart.Properties["HeaderTitle"];
                            titleFound           = true;
                        }
                    }

                    if (!titleFound)
                    {
                        SetPageTitle(pageTransformationInformation, targetPage);
                    }
                }

                if (pageTransformationInformation.PageTitleOverride != null)
                {
                    targetPage.PageTitle = pageTransformationInformation.PageTitleOverride(targetPage.PageTitle);
                }
#if DEBUG && MEASURE
                Stop("Set page title");
#endif
                #endregion

                #region Page layout configuration
#if DEBUG && MEASURE
                Start();
#endif
                // Use the default layout transformator
                ILayoutTransformator layoutTransformator = new LayoutTransformator(targetPage);

                // Do we have an override?
                if (pageTransformationInformation.LayoutTransformatorOverride != null)
                {
                    layoutTransformator = pageTransformationInformation.LayoutTransformatorOverride(targetPage);
                }

                // Apply the layout to the page
                layoutTransformator.Transform(pageData.Item1);
#if DEBUG && MEASURE
                Stop("Page layout");
#endif
                #endregion

                #region Page Banner creation
                if (!pageTransformationInformation.TargetPageTakesSourcePageName)
                {
                    if (pageTransformationInformation.ModernizationCenterInformation != null && pageTransformationInformation.ModernizationCenterInformation.AddPageAcceptBanner)
                    {
#if DEBUG && MEASURE
                        Start();
#endif
                        // Bump the row values for the existing web parts as we've inserted a new section
                        foreach (var section in targetPage.Sections)
                        {
                            section.Order = section.Order + 1;
                        }

                        // Add new section for banner part
                        targetPage.Sections.Insert(0, new CanvasSection(targetPage, CanvasSectionTemplate.OneColumn, 0));

                        // Bump the row values for the existing web parts as we've inserted a new section
                        foreach (var webpart in pageData.Item2)
                        {
                            webpart.Row = webpart.Row + 1;
                        }


                        var sourcePageUrl         = pageTransformationInformation.SourcePage[Constants.FileRefField].ToString();
                        var orginalSourcePageName = pageTransformationInformation.SourcePage[Constants.FileLeafRefField].ToString();
                        Uri host = new Uri(clientContext.Web.Url);

                        string path = $"{host.Scheme}://{host.DnsSafeHost}{sourcePageUrl.Replace(pageTransformationInformation.SourcePage[Constants.FileLeafRefField].ToString(), "")}";

                        // Add "fake" banner web part that then will be transformed onto the page
                        Dictionary <string, string> props = new Dictionary <string, string>(2)
                        {
                            { "SourcePage", $"{path}{orginalSourcePageName}" },
                            { "TargetPage", $"{path}{pageTransformationInformation.TargetPageName}" }
                        };

                        WebPartEntity bannerWebPart = new WebPartEntity()
                        {
                            Type       = WebParts.PageAcceptanceBanner,
                            Column     = 1,
                            Row        = 1,
                            Title      = "",
                            Order      = 0,
                            Properties = props,
                        };
                        pageData.Item2.Insert(0, bannerWebPart);
#if DEBUG && MEASURE
                        Stop("Page Banner");
#endif
                    }
                }
                #endregion

                #region Content transformation
#if DEBUG && MEASURE
                Start();
#endif
                // Use the default content transformator
                IContentTransformator contentTransformator = new ContentTransformator(targetPage, pageTransformation);

                // Do we have an override?
                if (pageTransformationInformation.ContentTransformatorOverride != null)
                {
                    contentTransformator = pageTransformationInformation.ContentTransformatorOverride(targetPage, pageTransformation);
                }

                // Run the content transformator
                contentTransformator.Transform(pageData.Item2);
#if DEBUG && MEASURE
                Stop("Content transformation");
#endif
                #endregion
            }
            #endregion

            #region Page persisting + permissions
            #region Save the page
#if DEBUG && MEASURE
            Start();
#endif
            // Persist the client side page
            targetPage.Save($"{pageTransformationInformation.Folder}{pageTransformationInformation.TargetPageName}", existingFile, pagesLibrary);

            // Tag the file with a page modernization version stamp
            try
            {
                string path           = pageTransformationInformation.SourcePage[Constants.FileRefField].ToString().Replace(pageTransformationInformation.SourcePage[Constants.FileLeafRefField].ToString(), "");
                var    targetPageUrl  = $"{path}{pageTransformationInformation.TargetPageName}";
                var    targetPageFile = this.clientContext.Web.GetFileByServerRelativeUrl(targetPageUrl);
                this.clientContext.Load(targetPageFile, p => p.Properties);
                targetPageFile.Properties["sharepointpnp_pagemodernization"] = this.version;
                targetPageFile.Update();

                // Try to publish, if publish is not needed then this will return an error that we'll be ignoring
                targetPageFile.Publish("Page modernization initial publish");

                this.clientContext.ExecuteQueryRetry();
            }
            catch (Exception ex)
            {
                // Eat exceptions as this is not critical for the generated page
            }

#if DEBUG && MEASURE
            Stop("Persist page");
#endif
            #endregion

            #region Page metadata handling
            if (pageTransformationInformation.CopyPageMetadata)
            {
#if DEBUG && MEASURE
                Start();
#endif
                // Copy the page metadata
                CopyPageMetadata(pageTransformationInformation, targetPage, pagesLibrary);
#if DEBUG && MEASURE
                Stop("Page metadata handling");
#endif
            }
            #endregion

            #region Permission handling
            ListItemPermission listItemPermissionsToKeep = null;
            if (pageTransformationInformation.KeepPageSpecificPermissions)
            {
#if DEBUG && MEASURE
                Start();
#endif
                // Check if we do have item level permissions we want to take over
                listItemPermissionsToKeep = GetItemLevelPermissions(pagesLibrary, pageTransformationInformation.SourcePage, targetPage.PageListItem);

                if (!pageTransformationInformation.TargetPageTakesSourcePageName)
                {
                    // If we're not doing a page name swap now we need to update the target item with the needed item level permissions
                    ApplyItemLevelPermissions(targetPage.PageListItem, listItemPermissionsToKeep);
                }
#if DEBUG && MEASURE
                Stop("Permission handling");
#endif
            }
            #endregion

            #region Page name switching
            // All went well so far...swap pages if that's needed
            if (pageTransformationInformation.TargetPageTakesSourcePageName)
            {
#if DEBUG && MEASURE
                Start();
#endif
                //Load the source page
                SwapPages(pageTransformationInformation, listItemPermissionsToKeep);
#if DEBUG && MEASURE
                Stop("Pagename swap");
#endif
            }
            #endregion

            #region Telemetry
            if (!pageTransformationInformation.SkipTelemetry && this.pageTelemetry != null)
            {
                TimeSpan duration = DateTime.Now.Subtract(transformationStartDateTime);
                this.pageTelemetry.LogTransformationDone(duration);
                this.pageTelemetry.Flush();
            }
            #endregion

            #region Return final page url
            if (!pageTransformationInformation.TargetPageTakesSourcePageName)
            {
                string path          = pageTransformationInformation.SourcePage[Constants.FileRefField].ToString().Replace(pageTransformationInformation.SourcePage[Constants.FileLeafRefField].ToString(), "");
                var    targetPageUrl = $"{path}{pageTransformationInformation.TargetPageName}";
                return(targetPageUrl);
            }
            else
            {
                return(pageTransformationInformation.SourcePage[Constants.FileRefField].ToString());
            }
            #endregion

            #endregion
        }