/Core/OfficeDevPnP.Core/Framework/Provisioning/ObjectHandlers/ObjectClientSidePageContents.cs

https://github.com/SharePoint/PnP-Sites-Core · C# · 249 lines · 205 code · 29 blank · 15 comment · 46 complexity · b65eb6bdc9cc817d0a185e97e9663e3a MD5 · raw file

  1. using Microsoft.SharePoint.Client;
  2. using OfficeDevPnP.Core.Diagnostics;
  3. using OfficeDevPnP.Core.Framework.Provisioning.Model;
  4. using OfficeDevPnP.Core.Framework.Provisioning.ObjectHandlers.Utilities;
  5. using System;
  6. using System.Collections.Generic;
  7. using System.Linq;
  8. using System.Text.RegularExpressions;
  9. namespace OfficeDevPnP.Core.Framework.Provisioning.ObjectHandlers
  10. {
  11. #if !SP2013 && !SP2016
  12. internal class ObjectClientSidePageContents : ObjectContentHandlerBase
  13. {
  14. public override string Name
  15. {
  16. get { return "Client Side Page Contents"; }
  17. }
  18. public override string InternalName => "ClientSidePageContents";
  19. public override TokenParser ProvisionObjects(Web web, ProvisioningTemplate template, TokenParser parser, ProvisioningTemplateApplyingInformation applyingInformation)
  20. {
  21. // This handler only extracts contents and adds them to the Files and Pages collection.
  22. return parser;
  23. }
  24. private const string CAMLQueryByExtension = @"
  25. <View Scope='Recursive'>
  26. <Query>
  27. <Where>
  28. <Contains>
  29. <FieldRef Name='File_x0020_Type'/>
  30. <Value Type='text'>aspx</Value>
  31. </Contains>
  32. </Where>
  33. </Query>
  34. </View>";
  35. private const string FileRefField = "FileRef";
  36. private const string FileLeafRefField = "FileLeafRef";
  37. private const string ClientSideApplicationId = "ClientSideApplicationId";
  38. private const string SPIsTranslation = "_SPIsTranslation";
  39. private const string SPTranslatedLanguages = "_SPTranslatedLanguages";
  40. private const string PageIDField = "UniqueId";
  41. private const string SPTranslationSourceItemId = "_SPTranslationSourceItemId";
  42. private const string SPTranslationLanguage = "_SPTranslationLanguage";
  43. private static readonly Guid FeatureId_Web_ModernPage = new Guid("B6917CB1-93A0-4B97-A84D-7CF49975D4EC");
  44. public const string TemplatesFolderGuid = "vti_TemplatesFolderGuid";
  45. public override ProvisioningTemplate ExtractObjects(Web web, ProvisioningTemplate template, ProvisioningTemplateCreationInformation creationInfo)
  46. {
  47. using (var scope = new PnPMonitoredScope(this.Name))
  48. {
  49. var clientSidePageContentsHelper = new ClientSidePageContentsHelper();
  50. // Extract the Home Page
  51. web.EnsureProperties(w => w.RootFolder.WelcomePage, w => w.ServerRelativeUrl, w => w.Url);
  52. var homePageUrl = web.RootFolder.WelcomePage;
  53. // Get pages library
  54. List sitePagesLibrary = null;
  55. try
  56. {
  57. ListCollection listCollection = web.Lists;
  58. listCollection.EnsureProperties(coll => coll.Include(li => li.BaseTemplate, li => li.RootFolder));
  59. sitePagesLibrary = listCollection.Where(p => p.BaseTemplate == (int)ListTemplateType.WebPageLibrary).FirstOrDefault();
  60. }
  61. catch
  62. {
  63. // fall back in case of exception when the site has been incorrectly provisioned which can cause access issues on lists/libraries.
  64. sitePagesLibrary = web.Lists.GetByTitle("Site Pages");
  65. sitePagesLibrary.EnsureProperties(l => l.BaseTemplate, l => l.RootFolder);
  66. }
  67. if (sitePagesLibrary != null)
  68. {
  69. var baseUrl = $"{sitePagesLibrary.RootFolder.ServerRelativeUrl}/";
  70. var templateFolderName = OfficeDevPnP.Core.Pages.ClientSidePage.DefaultTemplatesFolder;// string.Empty;
  71. var templateFolderString = sitePagesLibrary.GetPropertyBagValueString(TemplatesFolderGuid, null);
  72. Guid.TryParse(templateFolderString, out Guid templateFolderGuid);
  73. if (templateFolderGuid != Guid.Empty)
  74. {
  75. try
  76. {
  77. var templateFolder = ((ClientContext)sitePagesLibrary.Context).Web.GetFolderById(templateFolderGuid);
  78. templateFolderName = templateFolder.EnsureProperty(f => f.Name);
  79. }
  80. catch
  81. {
  82. //eat it and continue with default name
  83. }
  84. }
  85. CamlQuery query = new CamlQuery
  86. {
  87. ViewXml = CAMLQueryByExtension
  88. };
  89. var pages = sitePagesLibrary.GetItems(query);
  90. web.Context.Load(pages);
  91. web.Context.ExecuteQueryRetry();
  92. if (pages.FirstOrDefault() != null)
  93. {
  94. // Prep a list of pages to export allowing us hanlde translations
  95. List<PageToExport> pagesToExport = new List<PageToExport>();
  96. foreach(var page in pages)
  97. {
  98. PageToExport pageToExport = new PageToExport()
  99. {
  100. ListItem = page,
  101. IsTranslation = false,
  102. TranslatedLanguages = null,
  103. };
  104. // If multi-lingual is enabled these fields will be available on the SitePages library
  105. if (page.FieldValues.ContainsKey(SPIsTranslation) && page[SPIsTranslation] != null && !string.IsNullOrEmpty(page[SPIsTranslation].ToString()))
  106. {
  107. if (bool.TryParse(page[SPIsTranslation].ToString(), out bool isTranslation))
  108. {
  109. pageToExport.IsTranslation = isTranslation;
  110. }
  111. }
  112. if (page.FieldValues.ContainsKey(PageIDField) && page[PageIDField] != null && !string.IsNullOrEmpty(page[PageIDField].ToString()))
  113. {
  114. pageToExport.PageId = Guid.Parse(page[PageIDField].ToString());
  115. }
  116. if (page.FieldValues.ContainsKey(SPTranslationSourceItemId) && page[SPTranslationSourceItemId] != null && !string.IsNullOrEmpty(page[SPTranslationSourceItemId].ToString()))
  117. {
  118. pageToExport.SourcePageId = Guid.Parse(page[SPTranslationSourceItemId].ToString());
  119. }
  120. if (page.FieldValues.ContainsKey(SPTranslationLanguage) && page[SPTranslationLanguage] != null && !string.IsNullOrEmpty(page[SPTranslationLanguage].ToString()))
  121. {
  122. pageToExport.Language = page[SPTranslationLanguage].ToString();
  123. }
  124. if (page.FieldValues.ContainsKey(SPTranslatedLanguages) && page[SPTranslatedLanguages] != null && !string.IsNullOrEmpty(page[SPTranslatedLanguages].ToString()))
  125. {
  126. pageToExport.TranslatedLanguages = new List<string>(page[SPTranslatedLanguages] as string[]);
  127. }
  128. string pageUrl = null;
  129. string pageName = "";
  130. if (page.FieldValues.ContainsKey(FileRefField) && !String.IsNullOrEmpty(page[FileRefField].ToString()))
  131. {
  132. pageUrl = page[FileRefField].ToString();
  133. pageName = page[FileLeafRefField].ToString();
  134. }
  135. else
  136. {
  137. //skip page
  138. continue;
  139. }
  140. var isTemplate = false;
  141. // Is this page a template?
  142. if (pageUrl.IndexOf($"/{templateFolderName}/", StringComparison.InvariantCultureIgnoreCase) > -1)
  143. {
  144. isTemplate = true;
  145. }
  146. // Is this page the web's home page?
  147. bool isHomePage = false;
  148. if (pageUrl.EndsWith(homePageUrl, StringComparison.InvariantCultureIgnoreCase))
  149. {
  150. isHomePage = true;
  151. }
  152. // Get the name of the page, including the folder name
  153. pageName = Regex.Replace(pageUrl, baseUrl, "", RegexOptions.IgnoreCase);
  154. pageToExport.IsHomePage = isHomePage;
  155. pageToExport.IsTemplate = isTemplate;
  156. pageToExport.PageName = pageName;
  157. pageToExport.PageUrl = pageUrl;
  158. pagesToExport.Add(pageToExport);
  159. }
  160. // Populate SourcePageName to make it easier to hookup translations at export time
  161. foreach (var page in pagesToExport.Where(p => p.IsTranslation))
  162. {
  163. var sourcePage = pagesToExport.Where(p => p.PageId == page.SourcePageId).FirstOrDefault();
  164. if (sourcePage != null)
  165. {
  166. page.SourcePageName = sourcePage.PageName;
  167. }
  168. }
  169. var currentPageIndex = 1;
  170. foreach (var page in pagesToExport.OrderBy(p=>p.IsTranslation))
  171. {
  172. if (creationInfo.IncludeAllClientSidePages || page.IsHomePage)
  173. {
  174. // Is this a client side page?
  175. if (FieldExistsAndUsed(page.ListItem, ClientSideApplicationId) && page.ListItem[ClientSideApplicationId].ToString().Equals(FeatureId_Web_ModernPage.ToString(), StringComparison.InvariantCultureIgnoreCase))
  176. {
  177. WriteSubProgress("ClientSidePage", !string.IsNullOrWhiteSpace(page.PageName) ? page.PageName : page.PageUrl, currentPageIndex, pages.Count);
  178. // extract the page using the OOB logic
  179. clientSidePageContentsHelper.ExtractClientSidePage(web, template, creationInfo, scope, page);
  180. }
  181. }
  182. currentPageIndex++;
  183. }
  184. }
  185. }
  186. // If a base template is specified then use that one to "cleanup" the generated template model
  187. if (creationInfo.BaseTemplate != null)
  188. {
  189. template = CleanupEntities(template, creationInfo.BaseTemplate);
  190. }
  191. }
  192. return template;
  193. }
  194. private static bool FieldExistsAndUsed(ListItem item, string fieldName)
  195. {
  196. return (item.FieldValues.ContainsKey(fieldName) && item[fieldName] != null);
  197. }
  198. private ProvisioningTemplate CleanupEntities(ProvisioningTemplate template, ProvisioningTemplate baseTemplate)
  199. {
  200. return template;
  201. }
  202. public override bool WillProvision(Web web, ProvisioningTemplate template, ProvisioningTemplateApplyingInformation applyingInformation)
  203. {
  204. if (!_willProvision.HasValue)
  205. {
  206. _willProvision = false;
  207. }
  208. return _willProvision.Value;
  209. }
  210. public override bool WillExtract(Web web, ProvisioningTemplate template, ProvisioningTemplateCreationInformation creationInfo)
  211. {
  212. if (!_willExtract.HasValue)
  213. {
  214. _willExtract = true;
  215. }
  216. return _willExtract.Value;
  217. }
  218. }
  219. #endif
  220. }