private static string DeterminePageName(TokenParser parser, BaseClientSidePage clientSidePage) { string pageName; if (clientSidePage is ClientSidePage) { if (clientSidePage.PromoteAsTemplate) { pageName = $"{System.IO.Path.GetFileNameWithoutExtension(parser.ParseString((clientSidePage as ClientSidePage).PageName))}.aspx"; } else { var parsedPageName = parser.ParseString((clientSidePage as ClientSidePage).PageName); var pageNameWithoutExtension = System.IO.Path.GetFileNameWithoutExtension(parsedPageName); var pageFolder = System.IO.Path.GetDirectoryName(parsedPageName); if (!string.IsNullOrEmpty(pageFolder)) { pageFolder += "/"; } pageName = $"{pageFolder}{pageNameWithoutExtension}.aspx"; } } else { pageName = parser.ParseString((clientSidePage as TranslatedClientSidePage).PageName); } return(pageName); }
private string PreCreatePage(Web web, ProvisioningTemplate template, TokenParser parser, BaseClientSidePage clientSidePage, string pagesLibrary, List pagesLibraryList, ref int currentPageIndex) { string pageName = DeterminePageName(parser, clientSidePage); string url = $"{pagesLibrary}/{pageName}"; if (clientSidePage.Layout == "Article" && clientSidePage.PromoteAsTemplate) { url = $"{pagesLibrary}/{Pages.ClientSidePage.GetTemplatesFolder(pagesLibraryList)}/{pageName}"; } // Write page level status messages, needed in case many pages are provisioned currentPageIndex++; WriteSubProgress("ClientSidePage", $"Create {pageName} stub", currentPageIndex, template.ClientSidePages.Count); url = UrlUtility.Combine(web.ServerRelativeUrl, url); var exists = true; try { var file = web.GetFileByServerRelativePath(ResourcePath.FromDecodedUrl(url)); web.Context.Load(file, f => f.UniqueId, f => f.ServerRelativePath, f => f.Exists); web.Context.ExecuteQueryRetry(); // Fill token parser.AddToken(new PageUniqueIdToken(web, file.ServerRelativePath.DecodedUrl.Substring(web.ServerRelativeUrl.Length).TrimStart("/".ToCharArray()), file.UniqueId)); parser.AddToken(new PageUniqueIdEncodedToken(web, file.ServerRelativePath.DecodedUrl.Substring(web.ServerRelativeUrl.Length).TrimStart("/".ToCharArray()), file.UniqueId)); exists = file.Exists; } catch (ServerException ex) { if (ex.ServerErrorTypeName == "System.IO.FileNotFoundException") { exists = false; } } if (!exists) { // Pre-create the page Pages.ClientSidePage page = web.AddClientSidePage(pageName); // Set page layout now, because once it's set, it can't be changed. if (!string.IsNullOrEmpty(clientSidePage.Layout)) { page.LayoutType = (Pages.ClientSidePageLayoutType)Enum.Parse(typeof(Pages.ClientSidePageLayoutType), clientSidePage.Layout); } if (clientSidePage.Layout == "Article" && clientSidePage.PromoteAsTemplate) { page.SaveAsTemplate(pageName); } else { page.Save(pageName); } var file = web.GetFileByServerRelativePath(ResourcePath.FromDecodedUrl(url)); web.Context.Load(file, f => f.UniqueId, f => f.ServerRelativePath); web.Context.ExecuteQueryRetry(); // Fill token parser.AddToken(new PageUniqueIdToken(web, file.ServerRelativePath.DecodedUrl.Substring(web.ServerRelativeUrl.Length).TrimStart("/".ToCharArray()), file.UniqueId)); parser.AddToken(new PageUniqueIdEncodedToken(web, file.ServerRelativePath.DecodedUrl.Substring(web.ServerRelativeUrl.Length).TrimStart("/".ToCharArray()), file.UniqueId)); // Track that we pre-added this page return(url); } return(null); }
private void CreatePage(Web web, ProvisioningTemplate template, TokenParser parser, PnPMonitoredScope scope, BaseClientSidePage clientSidePage, string pagesLibrary, List pagesLibraryList, ref int currentPageIndex, List <string> preCreatedPages) { string pageName = DeterminePageName(parser, clientSidePage); string url = $"{pagesLibrary}/{pageName}"; if (clientSidePage.Layout == "Article" && clientSidePage.PromoteAsTemplate) { if (clientSidePage is TranslatedClientSidePage) { url = $"{pagesLibrary}/{pageName}"; } else { url = $"{pagesLibrary}/{Pages.ClientSidePage.GetTemplatesFolder(pagesLibraryList)}/{pageName}"; } } // Write page level status messages, needed in case many pages are provisioned currentPageIndex++; int totalPages = 0; foreach (var p in template.ClientSidePages) { totalPages++; if (p.Translations.Any()) { totalPages += p.Translations.Count(); } } WriteSubProgress("Provision ClientSidePage", pageName, currentPageIndex, totalPages); url = UrlUtility.Combine(web.ServerRelativeUrl, url); var exists = true; try { var file = web.GetFileByServerRelativePath(ResourcePath.FromDecodedUrl(url)); web.Context.Load(file); web.Context.ExecuteQueryRetry(); } catch (ServerException ex) { if (ex.ServerErrorTypeName == "System.IO.FileNotFoundException") { exists = false; } } Pages.ClientSidePage page = null; if (exists) { if (clientSidePage.Overwrite || preCreatedPages.Contains(url)) { if (clientSidePage.Layout == "Article" && clientSidePage.PromoteAsTemplate) { // Get the existing template page if (clientSidePage is TranslatedClientSidePage) { page = web.LoadClientSidePage($"{pageName}"); } else { page = web.LoadClientSidePage($"{Pages.ClientSidePage.GetTemplatesFolder(pagesLibraryList)}/{pageName}"); } } else { // Get the existing page page = web.LoadClientSidePage(pageName); } // Clear the page page.ClearPage(); } else { scope.LogWarning(CoreResources.Provisioning_ObjectHandlers_ClientSidePages_NoOverWrite, pageName); return; } } else { // Create new client side page page = web.AddClientSidePage(pageName); } // Set page title string newTitle = parser.ParseString(clientSidePage.Title); if (page.PageTitle != newTitle) { page.PageTitle = newTitle; } // Page Header if (clientSidePage.Header != null) { switch (clientSidePage.Header.Type) { case ClientSidePageHeaderType.None: { page.RemovePageHeader(); break; } case ClientSidePageHeaderType.Default: { page.SetDefaultPageHeader(); break; } case ClientSidePageHeaderType.Custom: { var serverRelativeImageUrl = parser.ParseString(clientSidePage.Header.ServerRelativeImageUrl); if (clientSidePage.Header.TranslateX.HasValue && clientSidePage.Header.TranslateY.HasValue) { page.SetCustomPageHeader(serverRelativeImageUrl, clientSidePage.Header.TranslateX.Value, clientSidePage.Header.TranslateY.Value); } else { page.SetCustomPageHeader(serverRelativeImageUrl); } page.PageHeader.LayoutType = (Pages.ClientSidePageHeaderLayoutType)Enum.Parse(typeof(ClientSidePageHeaderLayoutType), clientSidePage.Header.LayoutType.ToString()); #if !SP2019 page.PageHeader.TextAlignment = (Pages.ClientSidePageHeaderTitleAlignment)Enum.Parse(typeof(ClientSidePageHeaderTextAlignment), clientSidePage.Header.TextAlignment.ToString()); page.PageHeader.ShowTopicHeader = clientSidePage.Header.ShowTopicHeader; page.PageHeader.ShowPublishDate = clientSidePage.Header.ShowPublishDate; page.PageHeader.TopicHeader = clientSidePage.Header.TopicHeader; page.PageHeader.AlternativeText = clientSidePage.Header.AlternativeText; page.PageHeader.Authors = clientSidePage.Header.Authors; page.PageHeader.AuthorByLine = clientSidePage.Header.AuthorByLine; page.PageHeader.AuthorByLineId = clientSidePage.Header.AuthorByLineId; #endif break; } } } // Set page layout if (!string.IsNullOrEmpty(clientSidePage.Layout)) { page.LayoutType = (Pages.ClientSidePageLayoutType)Enum.Parse(typeof(Pages.ClientSidePageLayoutType), clientSidePage.Layout); } if (!string.IsNullOrEmpty(clientSidePage.ThumbnailUrl)) { page.ThumbnailUrl = parser.ParseString(clientSidePage.ThumbnailUrl); } // Add content on the page, not needed for repost pages if (page.LayoutType != Pages.ClientSidePageLayoutType.RepostPage) { // Load existing available controls var componentsToAdd = page.AvailableClientSideComponents().ToList(); // if no section specified then add a default single column section if (!clientSidePage.Sections.Any()) { clientSidePage.Sections.Add(new CanvasSection() { Type = CanvasSectionType.OneColumn, Order = 10 }); } int sectionCount = -1; // Apply the "layout" and content foreach (var section in clientSidePage.Sections) { sectionCount++; switch (section.Type) { case CanvasSectionType.OneColumn: page.AddSection(Pages.CanvasSectionTemplate.OneColumn, section.Order, (Int32)section.BackgroundEmphasis); break; case CanvasSectionType.OneColumnFullWidth: page.AddSection(Pages.CanvasSectionTemplate.OneColumnFullWidth, section.Order, (Int32)section.BackgroundEmphasis); break; case CanvasSectionType.TwoColumn: page.AddSection(Pages.CanvasSectionTemplate.TwoColumn, section.Order, (Int32)section.BackgroundEmphasis); break; case CanvasSectionType.ThreeColumn: page.AddSection(Pages.CanvasSectionTemplate.ThreeColumn, section.Order, (Int32)section.BackgroundEmphasis); break; case CanvasSectionType.TwoColumnLeft: page.AddSection(Pages.CanvasSectionTemplate.TwoColumnLeft, section.Order, (Int32)section.BackgroundEmphasis); break; case CanvasSectionType.TwoColumnRight: page.AddSection(Pages.CanvasSectionTemplate.TwoColumnRight, section.Order, (Int32)section.BackgroundEmphasis); break; #if !SP2019 case CanvasSectionType.OneColumnVerticalSection: page.AddSection(Pages.CanvasSectionTemplate.OneColumnVerticalSection, section.Order, (Int32)section.BackgroundEmphasis, (Int32)section.VerticalSectionEmphasis); break; case CanvasSectionType.TwoColumnVerticalSection: page.AddSection(Pages.CanvasSectionTemplate.TwoColumnVerticalSection, section.Order, (Int32)section.BackgroundEmphasis, (Int32)section.VerticalSectionEmphasis); break; case CanvasSectionType.TwoColumnLeftVerticalSection: page.AddSection(Pages.CanvasSectionTemplate.TwoColumnLeftVerticalSection, section.Order, (Int32)section.BackgroundEmphasis, (Int32)section.VerticalSectionEmphasis); break; case CanvasSectionType.TwoColumnRightVerticalSection: page.AddSection(Pages.CanvasSectionTemplate.TwoColumnRightVerticalSection, section.Order, (Int32)section.BackgroundEmphasis, (Int32)section.VerticalSectionEmphasis); break; case CanvasSectionType.ThreeColumnVerticalSection: page.AddSection(Pages.CanvasSectionTemplate.ThreeColumnVerticalSection, section.Order, (Int32)section.BackgroundEmphasis, (Int32)section.VerticalSectionEmphasis); break; #endif default: page.AddSection(Pages.CanvasSectionTemplate.OneColumn, section.Order, (Int32)section.BackgroundEmphasis); break; } // Add controls to the section if (section.Controls.Any()) { // Safety measure: reset column order to 1 for columns marked with 0 or lower foreach (var control in section.Controls.Where(p => p.Column <= 0).ToList()) { control.Column = 1; } foreach (CanvasControl control in section.Controls) { Pages.ClientSideComponent baseControl = null; // Is it a text control? if (control.Type == WebPartType.Text) { Pages.ClientSideText textControl = new Pages.ClientSideText(); if (control.ControlProperties.Any()) { var textProperty = control.ControlProperties.First(); textControl.Text = parser.ParseString(textProperty.Value); } else { if (!string.IsNullOrEmpty(control.JsonControlData)) { var json = JsonConvert.DeserializeObject <Dictionary <string, string> >(control.JsonControlData); if (json.Count > 0) { textControl.Text = parser.ParseString(json.First().Value); } } } // Reduce column number by 1 due 0 start indexing page.AddControl(textControl, page.Sections[sectionCount].Columns[control.Column - 1], control.Order); } // It is a web part else { // apply token parsing on the web part properties control.JsonControlData = parser.ParseString(control.JsonControlData); // perform processing of web part properties (e.g. include listid property based list title property) var webPartPostProcessor = CanvasControlPostProcessorFactory.Resolve(control); webPartPostProcessor.Process(control, page); // Is a custom developed client side web part (3rd party) if (control.Type == WebPartType.Custom) { if (!string.IsNullOrEmpty(control.CustomWebPartName)) { baseControl = componentsToAdd.FirstOrDefault(p => p.Name.Equals(control.CustomWebPartName, StringComparison.InvariantCultureIgnoreCase)); } else if (control.ControlId != Guid.Empty) { baseControl = componentsToAdd.FirstOrDefault(p => p.Id.Equals($"{{{control.ControlId.ToString()}}}", StringComparison.CurrentCultureIgnoreCase)); if (baseControl == null) { baseControl = componentsToAdd.FirstOrDefault(p => p.Id.Equals(control.ControlId.ToString(), StringComparison.InvariantCultureIgnoreCase)); } } } // Is an OOB client side web part (1st party) else { string webPartName = ""; switch (control.Type) { case WebPartType.Image: webPartName = Pages.ClientSidePage.ClientSideWebPartEnumToName(Pages.DefaultClientSideWebParts.Image); break; #if !SP2019 case WebPartType.BingMap: webPartName = Pages.ClientSidePage.ClientSideWebPartEnumToName(Pages.DefaultClientSideWebParts.BingMap); break; case WebPartType.Button: webPartName = Pages.ClientSidePage.ClientSideWebPartEnumToName(Pages.DefaultClientSideWebParts.Button); break; case WebPartType.CallToAction: webPartName = Pages.ClientSidePage.ClientSideWebPartEnumToName(Pages.DefaultClientSideWebParts.CallToAction); break; case WebPartType.GroupCalendar: webPartName = Pages.ClientSidePage.ClientSideWebPartEnumToName(Pages.DefaultClientSideWebParts.GroupCalendar); break; case WebPartType.News: webPartName = Pages.ClientSidePage.ClientSideWebPartEnumToName(Pages.DefaultClientSideWebParts.News); break; case WebPartType.PowerBIReportEmbed: webPartName = Pages.ClientSidePage.ClientSideWebPartEnumToName(Pages.DefaultClientSideWebParts.PowerBIReportEmbed); break; case WebPartType.Sites: webPartName = Pages.ClientSidePage.ClientSideWebPartEnumToName(Pages.DefaultClientSideWebParts.Sites); break; case WebPartType.MicrosoftForms: webPartName = Pages.ClientSidePage.ClientSideWebPartEnumToName(Pages.DefaultClientSideWebParts.MicrosoftForms); break; case WebPartType.ClientWebPart: webPartName = Pages.ClientSidePage.ClientSideWebPartEnumToName(Pages.DefaultClientSideWebParts.ClientWebPart); break; #endif case WebPartType.ContentEmbed: webPartName = Pages.ClientSidePage.ClientSideWebPartEnumToName(Pages.DefaultClientSideWebParts.ContentEmbed); break; case WebPartType.ContentRollup: webPartName = Pages.ClientSidePage.ClientSideWebPartEnumToName(Pages.DefaultClientSideWebParts.ContentRollup); break; case WebPartType.DocumentEmbed: webPartName = Pages.ClientSidePage.ClientSideWebPartEnumToName(Pages.DefaultClientSideWebParts.DocumentEmbed); break; case WebPartType.Events: webPartName = Pages.ClientSidePage.ClientSideWebPartEnumToName(Pages.DefaultClientSideWebParts.Events); break; case WebPartType.Hero: webPartName = Pages.ClientSidePage.ClientSideWebPartEnumToName(Pages.DefaultClientSideWebParts.Hero); break; case WebPartType.ImageGallery: webPartName = Pages.ClientSidePage.ClientSideWebPartEnumToName(Pages.DefaultClientSideWebParts.ImageGallery); break; case WebPartType.LinkPreview: webPartName = Pages.ClientSidePage.ClientSideWebPartEnumToName(Pages.DefaultClientSideWebParts.LinkPreview); break; case WebPartType.List: webPartName = Pages.ClientSidePage.ClientSideWebPartEnumToName(Pages.DefaultClientSideWebParts.List); break; case WebPartType.NewsFeed: webPartName = Pages.ClientSidePage.ClientSideWebPartEnumToName(Pages.DefaultClientSideWebParts.NewsFeed); break; case WebPartType.NewsReel: webPartName = Pages.ClientSidePage.ClientSideWebPartEnumToName(Pages.DefaultClientSideWebParts.NewsReel); break; case WebPartType.PageTitle: webPartName = Pages.ClientSidePage.ClientSideWebPartEnumToName(Pages.DefaultClientSideWebParts.PageTitle); break; case WebPartType.People: webPartName = Pages.ClientSidePage.ClientSideWebPartEnumToName(Pages.DefaultClientSideWebParts.People); break; case WebPartType.QuickChart: webPartName = Pages.ClientSidePage.ClientSideWebPartEnumToName(Pages.DefaultClientSideWebParts.QuickChart); break; case WebPartType.QuickLinks: webPartName = Pages.ClientSidePage.ClientSideWebPartEnumToName(Pages.DefaultClientSideWebParts.QuickLinks); break; case WebPartType.SiteActivity: webPartName = Pages.ClientSidePage.ClientSideWebPartEnumToName(Pages.DefaultClientSideWebParts.SiteActivity); break; case WebPartType.VideoEmbed: webPartName = Pages.ClientSidePage.ClientSideWebPartEnumToName(Pages.DefaultClientSideWebParts.VideoEmbed); break; case WebPartType.YammerEmbed: webPartName = Pages.ClientSidePage.ClientSideWebPartEnumToName(Pages.DefaultClientSideWebParts.YammerEmbed); break; case WebPartType.CustomMessageRegion: webPartName = Pages.ClientSidePage.ClientSideWebPartEnumToName(Pages.DefaultClientSideWebParts.CustomMessageRegion); break; case WebPartType.Divider: webPartName = Pages.ClientSidePage.ClientSideWebPartEnumToName(Pages.DefaultClientSideWebParts.Divider); break; case WebPartType.Spacer: webPartName = Pages.ClientSidePage.ClientSideWebPartEnumToName(Pages.DefaultClientSideWebParts.Spacer); break; } baseControl = componentsToAdd.FirstOrDefault(p => p.Name.Equals(webPartName, StringComparison.InvariantCultureIgnoreCase)); } if (baseControl != null) { Pages.ClientSideWebPart myWebPart = new Pages.ClientSideWebPart(baseControl) { Order = control.Order }; if (!String.IsNullOrEmpty(control.JsonControlData)) { var json = JsonConvert.DeserializeObject <JObject>(control.JsonControlData); if (json["instanceId"] != null && json["instanceId"].Type != JTokenType.Null) { if (Guid.TryParse(json["instanceId"].Value <string>(), out Guid instanceId)) { myWebPart.instanceId = instanceId; } } } // Reduce column number by 1 due 0 start indexing page.AddControl(myWebPart, page.Sections[sectionCount].Columns[control.Column - 1], control.Order); // set properties using json string if (!String.IsNullOrEmpty(control.JsonControlData)) { myWebPart.PropertiesJson = control.JsonControlData; } // set using property collection if (control.ControlProperties.Any()) { // grab the "default" properties so we can deduct their types, needed to correctly apply the set properties var controlManifest = JObject.Parse(baseControl.Manifest); JToken controlProperties = null; if (controlManifest != null) { controlProperties = controlManifest.SelectToken("preconfiguredEntries[0].properties"); } foreach (var property in control.ControlProperties) { Type propertyType = typeof(string); if (controlProperties != null) { var defaultProperty = controlProperties.SelectToken(property.Key, false); if (defaultProperty != null) { propertyType = Type.GetType($"System.{defaultProperty.Type.ToString()}"); if (propertyType == null) { if (defaultProperty.Type.ToString().Equals("integer", StringComparison.InvariantCultureIgnoreCase)) { propertyType = typeof(int); } } } } myWebPart.Properties[property.Key] = JToken.FromObject(Convert.ChangeType(parser.ParseString(property.Value), propertyType)); } } } else { scope.LogWarning(CoreResources.Provisioning_ObjectHandlers_ClientSidePages_BaseControlNotFound, control.ControlId, control.CustomWebPartName); } } } } } } // Persist the page if (clientSidePage.Layout == "Article" && clientSidePage.PromoteAsTemplate) { page.SaveAsTemplate(pageName.Replace($"{Pages.ClientSidePage.GetTemplatesFolder(pagesLibraryList)}/", "")); } else { page.Save(pageName); } // Update page content type bool isDirty = false; if (!string.IsNullOrEmpty(clientSidePage.ContentTypeID)) { page.PageListItem[ContentTypeIdField] = clientSidePage.ContentTypeID; page.PageListItem.UpdateOverwriteVersion(); //page.PageListItem.Update(); web.Context.Load(page.PageListItem); isDirty = true; } if (clientSidePage.PromoteAsTemplate && page.LayoutType == Pages.ClientSidePageLayoutType.Article) { // Choice field, currently there's only one value possible and that's Template page.PageListItem[SPSitePageFlagsField] = ";#Template;#"; page.PageListItem.UpdateOverwriteVersion(); //page.PageListItem.Update(); web.Context.Load(page.PageListItem); isDirty = true; } if (isDirty) { web.Context.ExecuteQueryRetry(); } if (clientSidePage.FieldValues != null && clientSidePage.FieldValues.Any()) { ListItemUtilities.UpdateListItem(page.PageListItem, parser, clientSidePage.FieldValues, ListItemUtilities.ListItemUpdateType.UpdateOverwriteVersion); } // Set page property bag values if (clientSidePage.Properties != null && clientSidePage.Properties.Any()) { string pageFilePath = page.PageListItem[FileRefField].ToString(); var pageFile = web.GetFileByServerRelativeUrl(pageFilePath); web.Context.Load(pageFile, p => p.Properties); foreach (var pageProperty in clientSidePage.Properties) { if (!string.IsNullOrEmpty(pageProperty.Key)) { pageFile.Properties[pageProperty.Key] = pageProperty.Value; } } pageFile.Update(); web.Context.Load(page.PageListItem); web.Context.ExecuteQueryRetry(); } #if !SP2019 if (page.LayoutType != Pages.ClientSidePageLayoutType.SingleWebPartAppPage) { // Set commenting, ignore on pages of the type Home or page templates if (page.LayoutType != Pages.ClientSidePageLayoutType.Home && !clientSidePage.PromoteAsTemplate) { // Make it a news page if requested if (clientSidePage.PromoteAsNewsArticle) { page.PromoteAsNewsArticle(); } } if (page.LayoutType != Pages.ClientSidePageLayoutType.RepostPage) { if (clientSidePage.EnableComments) { page.EnableComments(); } else { page.DisableComments(); } } } #endif // Publish page, page templates cannot be published if (clientSidePage.Publish && !clientSidePage.PromoteAsTemplate) { page.Publish(); } // Set any security on the page if (clientSidePage.Security != null && clientSidePage.Security.RoleAssignments.Count != 0) { web.Context.Load(page.PageListItem); web.Context.ExecuteQueryRetry(); page.PageListItem.SetSecurity(parser, clientSidePage.Security); } }