public override TokenParser ProvisionObjects(Web web, ProvisioningTemplate template, TokenParser parser, ProvisioningTemplateApplyingInformation applyingInformation) { using (var scope = new PnPMonitoredScope(this.Name)) { if (template.SitePolicy != null) { if (web.GetSitePolicyByName(template.SitePolicy) != null) // Site Policy Available? { web.ApplySitePolicy(template.SitePolicy); scope.LogInfo(CoreResources.Provisioning_ObjectHandlers_SitePolicy_PolicyAdded, template.SitePolicy); } else { scope.LogWarning(CoreResources.Provisioning_ObjectHandlers_SitePolicy_PolicyNotFound, template.SitePolicy); } } } return parser; }
internal static void LocalizeView(this Microsoft.SharePoint.Client.View view, Web web, string token, TokenParser parser, PnPMonitoredScope scope) { if (CanUseAcceptLanguageHeaderForLocalization(web)) { var context = web.Context; var resourceValues = parser.GetResourceTokenResourceValues(token); foreach (var resourceValue in resourceValues) { // Save property with correct locale on the request to make it stick // http://sadomovalex.blogspot.no/2015/09/localize-web-part-titles-via-client.html context.PendingRequest.RequestExecutor.WebRequest.Headers["Accept-Language"] = resourceValue.Item1; view.Title = resourceValue.Item2; view.Update(); context.ExecuteQueryRetry(); } } else { // warning scope.LogWarning(CoreResources.Provisioning_Extensions_ViewLocalization_Skip); } }
public override TokenParser ProvisionObjects(Web web, ProvisioningTemplate template, TokenParser parser, ProvisioningTemplateApplyingInformation applyingInformation) { using (var scope = new PnPMonitoredScope(this.Name)) { if (!template.Lists.Any()) { return(parser); } web.EnsureProperties(w => w.ServerRelativeUrl); web.Context.Load(web.Lists, lc => lc.IncludeWithDefaultProperties(l => l.RootFolder.ServerRelativeUrl)); web.Context.ExecuteQueryRetry(); #region DataRows foreach (var listInstance in template.Lists) { if (listInstance.DataRows != null && listInstance.DataRows.Any()) { scope.LogDebug(CoreResources.Provisioning_ObjectHandlers_ListInstancesDataRows_Processing_data_rows_for__0_, listInstance.Title); // Retrieve the target list var list = web.Lists.GetByTitle(parser.ParseString(listInstance.Title)); web.Context.Load(list); // Retrieve the fields' types from the list Microsoft.SharePoint.Client.FieldCollection fields = list.Fields; web.Context.Load(fields, fs => fs.Include(f => f.InternalName, f => f.FieldTypeKind, f => f.TypeAsString, f => f.ReadOnlyField, f => f.Title)); web.Context.ExecuteQueryRetry(); var keyColumnType = "Text"; var parsedKeyColumn = parser.ParseString(listInstance.DataRows.KeyColumn); if (!string.IsNullOrEmpty(parsedKeyColumn)) { var keyColumn = fields.FirstOrDefault(f => f.InternalName.Equals(parsedKeyColumn, StringComparison.InvariantCultureIgnoreCase)); if (keyColumn != null) { switch (keyColumn.FieldTypeKind) { case FieldType.User: case FieldType.Lookup: keyColumnType = "Lookup"; break; case FieldType.URL: keyColumnType = "Url"; break; case FieldType.DateTime: keyColumnType = "DateTime"; break; case FieldType.Number: case FieldType.Counter: keyColumnType = "Number"; break; } } } foreach (var dataRow in listInstance.DataRows) { try { scope.LogDebug(CoreResources.Provisioning_ObjectHandlers_ListInstancesDataRows_Creating_list_item__0_, listInstance.DataRows.IndexOf(dataRow) + 1); bool processItem = true; ListItem listitem = null; if (!string.IsNullOrEmpty(listInstance.DataRows.KeyColumn)) { // Get value from key column var dataRowValues = dataRow.Values.Where(v => v.Key == listInstance.DataRows.KeyColumn).ToList(); // if it is empty, skip the check if (dataRowValues.Any()) { var query = $@"<View><Query><Where><Eq><FieldRef Name=""{parsedKeyColumn}""/><Value Type=""{keyColumnType}"">{parser.ParseString(dataRowValues.FirstOrDefault().Value)}</Value></Eq></Where></Query><RowLimit>1</RowLimit></View>"; var camlQuery = new CamlQuery() { ViewXml = query }; var existingItems = list.GetItems(camlQuery); list.Context.Load(existingItems); list.Context.ExecuteQueryRetry(); if (existingItems.Count > 0) { if (listInstance.DataRows.UpdateBehavior == UpdateBehavior.Skip) { processItem = false; } else { listitem = existingItems[0]; processItem = true; } } } } if (processItem) { if (listitem == null) { var listitemCI = new ListItemCreationInformation(); listitem = list.AddItem(listitemCI); } ListItemUtilities.UpdateListItem(web, listitem, parser, fields, dataRow.Values); if (dataRow.Security != null && (dataRow.Security.ClearSubscopes || dataRow.Security.CopyRoleAssignments || dataRow.Security.RoleAssignments.Count > 0)) { listitem.SetSecurity(parser, dataRow.Security); } } } catch (ServerException ex) { if (ex.ServerErrorTypeName.Equals("Microsoft.SharePoint.SPDuplicateValuesFoundException", StringComparison.InvariantCultureIgnoreCase) && applyingInformation.IgnoreDuplicateDataRowErrors) { scope.LogWarning(CoreResources.Provisioning_ObjectHandlers_ListInstancesDataRows_Creating_listitem_duplicate); continue; } } catch (Exception ex) { scope.LogError(CoreResources.Provisioning_ObjectHandlers_ListInstancesDataRows_Creating_listitem_failed___0_____1_, ex.Message, ex.StackTrace); throw; } } } } #endregion DataRows } return(parser); }
public override ProvisioningTemplate ExtractObjects(Web web, ProvisioningTemplate template, ProvisioningTemplateCreationInformation creationInfo) { using (var scope = new PnPMonitoredScope(this.Name)) { web.EnsureProperties(w => w.ServerRelativeUrl, w => w.Url); var serverRelativeUrl = web.ServerRelativeUrl; // For each list in the site var lists = web.Lists; web.Context.Load(lists, lc => lc.IncludeWithDefaultProperties( l => l.ContentTypes, l => l.Views, l => l.EnableModeration, l => l.ForceCheckout, l => l.BaseTemplate, l => l.OnQuickLaunch, l => l.RootFolder.ServerRelativeUrl, l => l.UserCustomActions, l => l.MajorVersionLimit, l => l.MajorWithMinorVersionsLimit, l => l.DraftVersionVisibility, l => l.DocumentTemplateUrl, l => l.Fields.IncludeWithDefaultProperties( f => f.Id, f => f.Title, f => f.Hidden, f => f.InternalName, f => f.DefaultValue, f => f.Required))); web.Context.ExecuteQueryRetry(); var allLists = new List<List>(); if (web.IsSubSite()) { // If current web is subweb then include the lists in the rootweb for lookup column support var rootWeb = (web.Context as ClientContext).Site.RootWeb; rootWeb.Context.Load(rootWeb.Lists, lsts => lsts.Include(l => l.Id, l => l.Title)); rootWeb.Context.ExecuteQueryRetry(); foreach (var rootList in rootWeb.Lists) { allLists.Add(rootList); } } foreach (var list in lists) { allLists.Add(list); } // Let's see if there are workflow subscriptions Microsoft.SharePoint.Client.WorkflowServices.WorkflowSubscription[] workflowSubscriptions = null; try { workflowSubscriptions = web.GetWorkflowSubscriptions(); } catch (ServerException) { // If there is no workflow service present in the farm this method will throw an error. // Swallow the exception } // Retrieve all not hidden lists and the Workflow History Lists, just in case there are active workflow subscriptions foreach (var siteList in lists.AsEnumerable().Where(l => (l.Hidden == false || ((workflowSubscriptions != null && workflowSubscriptions.Length > 0) && l.BaseTemplate == 140)))) { ListInstance baseTemplateList = null; if (creationInfo.BaseTemplate != null) { // Check if we need to skip this list...if so let's do it before we gather all the other information for this list...improves performance var index = creationInfo.BaseTemplate.Lists.FindIndex(f => f.Url.Equals(siteList.RootFolder.ServerRelativeUrl.Substring(serverRelativeUrl.Length + 1)) && f.TemplateType.Equals(siteList.BaseTemplate)); if (index != -1) { baseTemplateList = creationInfo.BaseTemplate.Lists[index]; } } var contentTypeFields = new List<FieldRef>(); var list = new ListInstance { Description = siteList.Description, EnableVersioning = siteList.EnableVersioning, TemplateType = siteList.BaseTemplate, Title = siteList.Title, Hidden = siteList.Hidden, EnableFolderCreation = siteList.EnableFolderCreation, DocumentTemplate = Tokenize(siteList.DocumentTemplateUrl, web.Url), ContentTypesEnabled = siteList.ContentTypesEnabled, Url = siteList.RootFolder.ServerRelativeUrl.Substring(serverRelativeUrl.Length).TrimStart('/'), TemplateFeatureID = siteList.TemplateFeatureId, EnableAttachments = siteList.EnableAttachments, OnQuickLaunch = siteList.OnQuickLaunch, EnableModeration = siteList.EnableModeration, MaxVersionLimit = siteList.IsPropertyAvailable("MajorVersionLimit") ? siteList.MajorVersionLimit : 0, EnableMinorVersions = siteList.EnableMinorVersions, MinorVersionLimit = siteList.IsPropertyAvailable("MajorWithMinorVersionsLimit") ? siteList.MajorWithMinorVersionsLimit : 0, ForceCheckout = siteList.IsPropertyAvailable("ForceCheckout") ? siteList.ForceCheckout : false, DraftVersionVisibility = siteList.IsPropertyAvailable("DraftVersionVisibility") ? (int)siteList.DraftVersionVisibility : 0, }; if (creationInfo.PersistMultiLanguageResources) { #if !SP2013 if (UserResourceExtensions.PersistResourceValue(siteList.TitleResource, string.Format("List_{0}_Title", siteList.Title.Replace(" ", "_")), template, creationInfo)) { list.Title = string.Format("{{res:List_{0}_Title}}", siteList.Title.Replace(" ", "_")); } if (UserResourceExtensions.PersistResourceValue(siteList.DescriptionResource, string.Format("List_{0}_Description", siteList.Title.Replace(" ", "_")), template, creationInfo)) { list.Description = string.Format("{{res:List_{0}_Description}}", siteList.Title.Replace(" ", "_")); } #endif } list = ExtractContentTypes(web, siteList, contentTypeFields, list); list = ExtractViews(siteList, list); list = ExtractFields(web, siteList, contentTypeFields, list, allLists, creationInfo, template); list = ExtractUserCustomActions(web, siteList, list, creationInfo, template); list.Security = siteList.GetSecurity(); var logCTWarning = false; if (baseTemplateList != null) { if (!baseTemplateList.Equals(list)) { scope.LogDebug(CoreResources.Provisioning_ObjectHandlers_ListInstances_Adding_list___0_____1_, list.Title, list.Url); template.Lists.Add(list); if (list.ContentTypesEnabled && list.ContentTypeBindings.Any() && web.IsSubSite()) { logCTWarning = true; } } } else { scope.LogDebug(CoreResources.Provisioning_ObjectHandlers_ListInstances_Adding_list___0_____1_, list.Title, list.Url); template.Lists.Add(list); if (list.ContentTypesEnabled && list.ContentTypeBindings.Any() && web.IsSubSite()) { logCTWarning = true; } } if (logCTWarning) { scope.LogWarning("You are extracting a template from a subweb. List '{0}' refers to content types. Content types are not exported when extracting a template from a subweb", siteList.Title); WriteWarning(string.Format("You are extracting a template from a subweb. List '{0}' refers to content types. Content types are not exported when extracting a template from a subweb", siteList.Title), ProvisioningMessageType.Warning); } } } return template; }
private Tuple<List, TokenParser> CreateList(Web web, ListInstance list, TokenParser parser, PnPMonitoredScope scope) { var listCreate = new ListCreationInformation(); listCreate.Description = list.Description; listCreate.TemplateType = list.TemplateType; listCreate.Title = parser.ParseString(list.Title); // the line of code below doesn't add the list to QuickLaunch // the OnQuickLaunch property is re-set on the Created List object listCreate.QuickLaunchOption = list.OnQuickLaunch ? QuickLaunchOptions.On : QuickLaunchOptions.Off; listCreate.Url = parser.ParseString(list.Url); listCreate.TemplateFeatureId = list.TemplateFeatureID; var createdList = web.Lists.Add(listCreate); createdList.Update(); web.Context.Load(createdList, l => l.BaseTemplate); web.Context.ExecuteQueryRetry(); if (!String.IsNullOrEmpty(list.DocumentTemplate)) { createdList.DocumentTemplateUrl = parser.ParseString(list.DocumentTemplate); } // EnableAttachments are not supported for DocumentLibraries and Surveys // TODO: the user should be warned if (createdList.BaseTemplate != (int)ListTemplateType.DocumentLibrary && createdList.BaseTemplate != (int)ListTemplateType.Survey) { createdList.EnableAttachments = list.EnableAttachments; } createdList.EnableModeration = list.EnableModeration; // Done for all other lists than for Survey - With Surveys versioning configuration will cause an exception if (createdList.BaseTemplate != (int)ListTemplateType.Survey) { createdList.EnableVersioning = list.EnableVersioning; if (list.EnableVersioning) { #if !CLIENTSDKV15 createdList.MajorVersionLimit = list.MaxVersionLimit; #endif if (createdList.BaseTemplate == (int)ListTemplateType.DocumentLibrary) { // Only supported on Document Libraries createdList.EnableMinorVersions = list.EnableMinorVersions; createdList.DraftVersionVisibility = (DraftVisibilityType)list.DraftVersionVisibility; if (list.EnableMinorVersions) { createdList.MajorWithMinorVersionsLimit = list.MinorVersionLimit; // Set only if enabled, otherwise you'll get exception due setting value to zero. // DraftVisibilityType.Approver is available only when the EnableModeration option of the list is true if (DraftVisibilityType.Approver == (DraftVisibilityType)list.DraftVersionVisibility) { if (list.EnableModeration) { createdList.DraftVersionVisibility = (DraftVisibilityType)list.DraftVersionVisibility; } else { scope.LogWarning(CoreResources.Provisioning_ObjectHandlers_ListInstances_DraftVersionVisibility_not_applied_because_EnableModeration_is_not_set_to_true); WriteWarning(CoreResources.Provisioning_ObjectHandlers_ListInstances_DraftVersionVisibility_not_applied_because_EnableModeration_is_not_set_to_true, ProvisioningMessageType.Warning); } } else { createdList.DraftVersionVisibility = (DraftVisibilityType)list.DraftVersionVisibility; } } } } } createdList.OnQuickLaunch = list.OnQuickLaunch; if (createdList.BaseTemplate != (int)ListTemplateType.DiscussionBoard) { createdList.EnableFolderCreation = list.EnableFolderCreation; } createdList.Hidden = list.Hidden; createdList.ContentTypesEnabled = list.ContentTypesEnabled; createdList.Update(); web.Context.Load(createdList.Views); web.Context.Load(createdList, l => l.Id); web.Context.Load(createdList, l => l.RootFolder.ServerRelativeUrl); web.Context.Load(createdList.ContentTypes); web.Context.ExecuteQueryRetry(); // Remove existing content types only if there are custom content type bindings var contentTypesToRemove = new List<ContentType>(); if (list.RemoveExistingContentTypes && list.ContentTypeBindings.Count > 0) { contentTypesToRemove.AddRange(createdList.ContentTypes); } ContentTypeBinding defaultCtBinding = null; foreach (var ctBinding in list.ContentTypeBindings) { var tempCT = web.GetContentTypeById(ctBinding.ContentTypeId, searchInSiteHierarchy: true); if (tempCT != null) { // Check if CT is already available var name = tempCT.EnsureProperty(ct => ct.Name); if (!createdList.ContentTypeExistsByName(name)) { createdList.AddContentTypeToListById(ctBinding.ContentTypeId, searchContentTypeInSiteHierarchy: true); } if (ctBinding.Default) { defaultCtBinding = ctBinding; } } } // default ContentTypeBinding should be set last because // list extension .SetDefaultContentTypeToList() re-sets // the list.RootFolder UniqueContentTypeOrder property // which may cause missing CTs from the "New Button" if (defaultCtBinding != null) { createdList.SetDefaultContentTypeToList(defaultCtBinding.ContentTypeId); } // Effectively remove existing content types, if any foreach (var ct in contentTypesToRemove) { ct.DeleteObject(); web.Context.ExecuteQueryRetry(); } if (list.Security != null) { createdList.SetSecurity(parser, list.Security); } return Tuple.Create(createdList, parser); }
public override ProvisioningTemplate ExtractObjects(Web web, ProvisioningTemplate template, ProvisioningTemplateCreationInformation creationInfo) { using (var scope = new PnPMonitoredScope(this.Name)) { // Extract the Home Page web.EnsureProperties(w => w.RootFolder.WelcomePage, w => w.ServerRelativeUrl, w => w.Url); var homepageUrl = web.RootFolder.WelcomePage; if (string.IsNullOrEmpty(homepageUrl)) { homepageUrl = "Default.aspx"; } var welcomePageUrl = UrlUtility.Combine(web.ServerRelativeUrl, homepageUrl); var file = web.GetFileByServerRelativeUrl(welcomePageUrl); try { var listItem = file.EnsureProperty(f => f.ListItemAllFields); if (listItem != null) { if (listItem.FieldValues.ContainsKey("WikiField")) { // Wiki page var fullUri = new Uri(UrlUtility.Combine(web.Url, web.RootFolder.WelcomePage)); var folderPath = fullUri.Segments.Take(fullUri.Segments.Count() - 1).ToArray().Aggregate((i, x) => i + x).TrimEnd('/'); var fileName = fullUri.Segments[fullUri.Segments.Count() - 1]; var homeFile = web.GetFileByServerRelativeUrl(welcomePageUrl); LimitedWebPartManager limitedWPManager = homeFile.GetLimitedWebPartManager(PersonalizationScope.Shared); web.Context.Load(limitedWPManager); var webParts = web.GetWebParts(welcomePageUrl); var page = new Page() { Layout = WikiPageLayout.Custom, Overwrite = true, Url = Tokenize(fullUri.PathAndQuery, web.Url), }; var pageContents = listItem.FieldValues["WikiField"].ToString(); Regex regexClientIds = new Regex(@"id=\""div_(?<ControlId>(\w|\-)+)"); if (regexClientIds.IsMatch(pageContents)) { foreach (Match webPartMatch in regexClientIds.Matches(pageContents)) { String serverSideControlId = webPartMatch.Groups["ControlId"].Value; try { String serverSideControlIdToSearchFor = String.Format("g_{0}", serverSideControlId.Replace("-", "_")); WebPartDefinition webPart = limitedWPManager.WebParts.GetByControlId(serverSideControlIdToSearchFor); web.Context.Load(webPart, wp => wp.Id, wp => wp.WebPart.Title, wp => wp.WebPart.ZoneIndex ); web.Context.ExecuteQueryRetry(); var webPartxml = TokenizeWebPartXml(web, web.GetWebPartXml(webPart.Id, welcomePageUrl)); page.WebParts.Add(new Model.WebPart() { Title = webPart.WebPart.Title, Contents = webPartxml, Order = (uint)webPart.WebPart.ZoneIndex, Row = 1, // By default we will create a onecolumn layout, add the webpart to it, and later replace the wikifield on the page to position the webparts correctly. Column = 1 // By default we will create a onecolumn layout, add the webpart to it, and later replace the wikifield on the page to position the webparts correctly. }); pageContents = Regex.Replace(pageContents, serverSideControlId, string.Format("{{webpartid:{0}}}", webPart.WebPart.Title), RegexOptions.IgnoreCase); } catch (ServerException) { scope.LogWarning("Found a WebPart ID which is not available on the server-side. ID: {0}", serverSideControlId); } } } page.Fields.Add("WikiField", pageContents); template.Pages.Add(page); // Set the homepage if (template.WebSettings == null) { template.WebSettings = new WebSettings(); } template.WebSettings.WelcomePage = homepageUrl; } else { if (web.Context.HasMinimalServerLibraryVersion(Constants.MINIMUMZONEIDREQUIREDSERVERVERSION)) { // Not a wikipage template = GetFileContents(web, template, welcomePageUrl, creationInfo, scope); if (template.WebSettings == null) { template.WebSettings = new WebSettings(); } template.WebSettings.WelcomePage = homepageUrl; } else { WriteWarning(string.Format("Page content export requires a server version that is newer than the current server. Server version is {0}, minimal required is {1}", web.Context.ServerLibraryVersion, Constants.MINIMUMZONEIDREQUIREDSERVERVERSION), ProvisioningMessageType.Warning); scope.LogWarning("Page content export requires a server version that is newer than the current server. Server version is {0}, minimal required is {1}", web.Context.ServerLibraryVersion, Constants.MINIMUMZONEIDREQUIREDSERVERVERSION); } } } } catch (ServerException ex) { if (ex.ServerErrorCode != -2146232832) { throw; } else { if (web.Context.HasMinimalServerLibraryVersion(Constants.MINIMUMZONEIDREQUIREDSERVERVERSION)) { // Page does not belong to a list, extract the file as is template = GetFileContents(web, template, welcomePageUrl, creationInfo, scope); if (template.WebSettings == null) { template.WebSettings = new WebSettings(); } template.WebSettings.WelcomePage = homepageUrl; } else { WriteWarning(string.Format("Page content export requires a server version that is newer than the current server. Server version is {0}, minimal required is {1}", web.Context.ServerLibraryVersion, Constants.MINIMUMZONEIDREQUIREDSERVERVERSION), ProvisioningMessageType.Warning); scope.LogWarning("Page content export requires a server version that is newer than the current server. Server version is {0}, minimal required is {1}", web.Context.ServerLibraryVersion, Constants.MINIMUMZONEIDREQUIREDSERVERVERSION); } } } // If a base template is specified then use that one to "cleanup" the generated template model if (creationInfo.BaseTemplate != null) { template = CleanupEntities(template, creationInfo.BaseTemplate); } } return template; }
private static void UpdateContentType(Web web, Microsoft.SharePoint.Client.ContentType existingContentType, ContentType templateContentType, TokenParser parser, PnPMonitoredScope scope, bool isNoScriptSite = false) { var isDirty = false; if (existingContentType.Hidden != templateContentType.Hidden) { scope.LogPropertyUpdate("Hidden"); existingContentType.Hidden = templateContentType.Hidden; isDirty = true; } if (existingContentType.ReadOnly != templateContentType.ReadOnly) { scope.LogPropertyUpdate("ReadOnly"); existingContentType.ReadOnly = templateContentType.ReadOnly; isDirty = true; } if (existingContentType.Sealed != templateContentType.Sealed) { scope.LogPropertyUpdate("Sealed"); existingContentType.Sealed = templateContentType.Sealed; isDirty = true; } if (templateContentType.Description != null && existingContentType.Description != parser.ParseString(templateContentType.Description)) { scope.LogPropertyUpdate("Description"); existingContentType.Description = parser.ParseString(templateContentType.Description); isDirty = true; } if (templateContentType.DocumentTemplate != null && existingContentType.DocumentTemplate != parser.ParseString(templateContentType.DocumentTemplate)) { scope.LogPropertyUpdate("DocumentTemplate"); existingContentType.DocumentTemplate = parser.ParseString(templateContentType.DocumentTemplate); isDirty = true; } if (existingContentType.Name != parser.ParseString(templateContentType.Name)) { scope.LogPropertyUpdate("Name"); existingContentType.Name = parser.ParseString(templateContentType.Name); isDirty = true; // CT is being renamed, add an extra token to the tokenparser parser.AddToken(new ContentTypeIdToken(web, existingContentType.Name, existingContentType.StringId)); } if (templateContentType.Group != null && existingContentType.Group != parser.ParseString(templateContentType.Group)) { scope.LogPropertyUpdate("Group"); existingContentType.Group = parser.ParseString(templateContentType.Group); isDirty = true; } if (!isNoScriptSite) { if (templateContentType.DisplayFormUrl != null && existingContentType.DisplayFormUrl != parser.ParseString(templateContentType.DisplayFormUrl)) { scope.LogPropertyUpdate("DisplayFormUrl"); existingContentType.DisplayFormUrl = parser.ParseString(templateContentType.DisplayFormUrl); isDirty = true; } if (templateContentType.EditFormUrl != null && existingContentType.EditFormUrl != parser.ParseString(templateContentType.EditFormUrl)) { scope.LogPropertyUpdate("EditFormUrl"); existingContentType.EditFormUrl = parser.ParseString(templateContentType.EditFormUrl); isDirty = true; } if (templateContentType.NewFormUrl != null && existingContentType.NewFormUrl != parser.ParseString(templateContentType.NewFormUrl)) { scope.LogPropertyUpdate("NewFormUrl"); existingContentType.NewFormUrl = parser.ParseString(templateContentType.NewFormUrl); isDirty = true; } } else { if (!String.IsNullOrEmpty(parser.ParseString(templateContentType.DisplayFormUrl)) || !String.IsNullOrEmpty(parser.ParseString(templateContentType.EditFormUrl)) || !String.IsNullOrEmpty(parser.ParseString(templateContentType.NewFormUrl))) { // log message scope.LogWarning(CoreResources.Provisioning_ObjectHandlers_ContentTypes_SkipCustomFormUrls, existingContentType.Name); } } #if !SP2013 if (templateContentType.Name.ContainsResourceToken()) { existingContentType.NameResource.SetUserResourceValue(templateContentType.Name, parser); isDirty = true; } if (templateContentType.Description.ContainsResourceToken()) { existingContentType.DescriptionResource.SetUserResourceValue(templateContentType.Description, parser); isDirty = true; } #endif if (isDirty) { existingContentType.Update(true); web.Context.ExecuteQueryRetry(); } // Delta handling existingContentType.EnsureProperty(c => c.FieldLinks); List<Guid> targetIds = existingContentType.FieldLinks.AsEnumerable().Select(c1 => c1.Id).ToList(); List<Guid> sourceIds = templateContentType.FieldRefs.Select(c1 => c1.Id).ToList(); var fieldsNotPresentInTarget = sourceIds.Except(targetIds).ToArray(); if (fieldsNotPresentInTarget.Any()) { foreach (var fieldId in fieldsNotPresentInTarget) { var fieldRef = templateContentType.FieldRefs.Find(fr => fr.Id == fieldId); var field = web.Fields.GetById(fieldId); scope.LogDebug(CoreResources.Provisioning_ObjectHandlers_ContentTypes_Adding_field__0__to_content_type, fieldId); web.AddFieldToContentType(existingContentType, field, fieldRef.Required, fieldRef.Hidden); } } isDirty = false; foreach (var fieldId in targetIds.Intersect(sourceIds)) { var fieldLink = existingContentType.FieldLinks.FirstOrDefault(fl => fl.Id == fieldId); var fieldRef = templateContentType.FieldRefs.Find(fr => fr.Id == fieldId); if (fieldRef != null) { scope.LogDebug(CoreResources.Provisioning_ObjectHandlers_ContentTypes_Field__0__exists_in_content_type, fieldId); if (fieldLink.Required != fieldRef.Required) { scope.LogPropertyUpdate("Required"); fieldLink.Required = fieldRef.Required; isDirty = true; } if (fieldLink.Hidden != fieldRef.Hidden) { scope.LogPropertyUpdate("Hidden"); fieldLink.Hidden = fieldRef.Hidden; isDirty = true; } } } // The new CT is a DocumentSet, and the target should be, as well if (templateContentType.DocumentSetTemplate != null) { if (!Microsoft.SharePoint.Client.DocumentSet.DocumentSetTemplate.IsChildOfDocumentSetContentType(web.Context, existingContentType).Value) { scope.LogError(CoreResources.Provisioning_ObjectHandlers_ContentTypes_InvalidDocumentSet_Update_Request, existingContentType.Id, existingContentType.Name); } else { Microsoft.SharePoint.Client.DocumentSet.DocumentSetTemplate templateToUpdate = Microsoft.SharePoint.Client.DocumentSet.DocumentSetTemplate.GetDocumentSetTemplate(web.Context, existingContentType); // TODO: Implement Delta Handling scope.LogWarning(CoreResources.Provisioning_ObjectHandlers_ContentTypes_DocumentSet_DeltaHandling_OnHold, existingContentType.Id, existingContentType.Name); } } if (isDirty) { existingContentType.Update(true); web.Context.ExecuteQueryRetry(); } }
public override TokenParser ProvisionObjects(Web web, ProvisioningTemplate template, TokenParser parser, ProvisioningTemplateApplyingInformation applyingInformation) { using (var scope = new PnPMonitoredScope(this.Name)) { var context = web.Context as ClientContext; web.EnsureProperties(w => w.ServerRelativeUrl); // Check if this is not a noscript site as we're not allowed to update some properties bool isNoScriptSite = web.IsNoScriptSite(); foreach (var clientSidePage in template.ClientSidePages) { // determine pages library string pagesLibrary = "SitePages"; string pageName = $"{System.IO.Path.GetFileNameWithoutExtension(clientSidePage.PageName)}.aspx"; string url = $"{pagesLibrary}/{pageName}"; url = UrlUtility.Combine(web.ServerRelativeUrl, url); var exists = true; Microsoft.SharePoint.Client.File file = null; try { file = web.GetFileByServerRelativeUrl(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) { // Get the existing page page = web.LoadClientSidePage(pageName); // Clear the page page.ClearPage(); } else { scope.LogWarning(CoreResources.Provisioning_ObjectHandlers_ClientSidePages_NoOverWrite, pageName); } } else { // Create new client side page page = web.AddClientSidePage(pageName); } // Load existing available controls var componentsToAdd = page.AvailableClientSideComponents(); // 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); break; case CanvasSectionType.OneColumnFullWidth: page.AddSection(Pages.CanvasSectionTemplate.OneColumnFullWidth, section.Order); break; case CanvasSectionType.TwoColumn: page.AddSection(Pages.CanvasSectionTemplate.TwoColumn, section.Order); break; case CanvasSectionType.ThreeColumn: page.AddSection(Pages.CanvasSectionTemplate.ThreeColumn, section.Order); break; case CanvasSectionType.TwoColumnLeft: page.AddSection(Pages.CanvasSectionTemplate.TwoColumnLeft, section.Order); break; case CanvasSectionType.TwoColumnRight: page.AddSection(Pages.CanvasSectionTemplate.TwoColumnRight, section.Order); break; default: page.AddSection(Pages.CanvasSectionTemplate.OneColumn, section.Order); 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 (var 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 = textProperty.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 { // Is a custom developed client side web part (3rd party) if (control.Type == WebPartType.Custom) { if (!string.IsNullOrEmpty(control.CustomWebPartName)) { baseControl = componentsToAdd.Where(p => p.Name.Equals(control.CustomWebPartName, StringComparison.InvariantCultureIgnoreCase)).FirstOrDefault(); } else if (control.ControlId != Guid.Empty) { baseControl = componentsToAdd.Where(p => p.Id.Equals($"{{{control.ControlId.ToString()}}}", StringComparison.CurrentCultureIgnoreCase)).FirstOrDefault(); } } // 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; case WebPartType.BingMap: webPartName = Pages.ClientSidePage.ClientSideWebPartEnumToName(Pages.DefaultClientSideWebParts.BingMap); break; 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.GroupCalendar: webPartName = Pages.ClientSidePage.ClientSideWebPartEnumToName(Pages.DefaultClientSideWebParts.GroupCalendar); 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.PowerBIReportEmbed: webPartName = Pages.ClientSidePage.ClientSideWebPartEnumToName(Pages.DefaultClientSideWebParts.PowerBIReportEmbed); 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; default: break; } baseControl = componentsToAdd.Where(p => p.Name.Equals(webPartName, StringComparison.InvariantCultureIgnoreCase)).FirstOrDefault(); } if (baseControl != null) { Pages.ClientSideWebPart myWebPart = new Pages.ClientSideWebPart(baseControl) { Order = control.Order }; // 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 page.Save(pageName); // Make it a news page if requested if (clientSidePage.PromoteAsNewsArticle) { page.PromoteAsNewsArticle(); } } } return(parser); }
public override ProvisioningTemplate ExtractObjects(Web web, ProvisioningTemplate template, ProvisioningTemplateCreationInformation creationInfo) { using (var scope = new PnPMonitoredScope(this.Name)) { web.EnsureProperties(w => w.ServerRelativeUrl, w => w.Url); var serverRelativeUrl = web.ServerRelativeUrl; // For each list in the site var lists = web.Lists; web.Context.Load(lists, lc => lc.IncludeWithDefaultProperties( l => l.ContentTypes, l => l.Views, l => l.BaseTemplate, l => l.OnQuickLaunch, l => l.RootFolder.ServerRelativeUrl, l => l.Fields.IncludeWithDefaultProperties( f => f.Id, f => f.Title, f => f.Hidden, f => f.InternalName, f => f.Required))); web.Context.ExecuteQueryRetry(); // Let's see if there are workflow subscriptions Microsoft.SharePoint.Client.WorkflowServices.WorkflowSubscription[] workflowSubscriptions = null; try { workflowSubscriptions = web.GetWorkflowSubscriptions(); } catch (ServerException) { // If there is no workflow service present in the farm this method will throw an error. // Swallow the exception } // Retrieve all not hidden lists and the Workflow History Lists, just in case there are active workflow subscriptions foreach (var siteList in lists.AsEnumerable().Where(l => (l.Hidden == false || ((workflowSubscriptions != null && workflowSubscriptions.Length > 0) && l.BaseTemplate == 140)))) { ListInstance baseTemplateList = null; if (creationInfo.BaseTemplate != null) { // Check if we need to skip this list...if so let's do it before we gather all the other information for this list...improves performance var index = creationInfo.BaseTemplate.Lists.FindIndex(f => f.Url.Equals(siteList.RootFolder.ServerRelativeUrl.Substring(serverRelativeUrl.Length + 1)) && f.TemplateType.Equals(siteList.BaseTemplate)); if (index != -1) { baseTemplateList = creationInfo.BaseTemplate.Lists[index]; } } var contentTypeFields = new List<FieldRef>(); var list = new ListInstance { Description = siteList.Description, EnableVersioning = siteList.EnableVersioning, TemplateType = siteList.BaseTemplate, Title = siteList.Title, Hidden = siteList.Hidden, EnableFolderCreation = siteList.EnableFolderCreation, DocumentTemplate = Tokenize(siteList.DocumentTemplateUrl, web.Url), ContentTypesEnabled = siteList.ContentTypesEnabled, Url = siteList.RootFolder.ServerRelativeUrl.Substring(serverRelativeUrl.Length).TrimStart('/'), TemplateFeatureID = siteList.TemplateFeatureId, EnableAttachments = siteList.EnableAttachments, OnQuickLaunch = siteList.OnQuickLaunch, MaxVersionLimit = siteList.IsObjectPropertyInstantiated("MajorVersionLimit") ? siteList.MajorVersionLimit : 0, EnableMinorVersions = siteList.EnableMinorVersions, MinorVersionLimit = siteList.IsObjectPropertyInstantiated("MajorWithMinorVersionsLimit") ? siteList.MajorWithMinorVersionsLimit : 0 }; var count = 0; foreach (var ct in siteList.ContentTypes) { web.Context.Load(ct, c => c.Parent); web.Context.ExecuteQueryRetry(); list.ContentTypeBindings.Add(new ContentTypeBinding { ContentTypeId = ct.Parent != null ? ct.Parent.StringId : ct.StringId, Default = count == 0 }); //if (ct.Parent != null) //{ // //Add the parent to the list of content types // if (!BuiltInContentTypeId.Contains(ct.Parent.StringId)) // { // list.ContentTypeBindings.Add(new ContentTypeBinding { ContentTypeId = ct.Parent.StringId, Default = count == 0 }); // } //} //else //{ // list.ContentTypeBindings.Add(new ContentTypeBinding { ContentTypeId = ct.StringId, Default = count == 0 }); //} web.Context.Load(ct.FieldLinks); web.Context.ExecuteQueryRetry(); foreach (var fieldLink in ct.FieldLinks) { if (!fieldLink.Hidden) { contentTypeFields.Add(new FieldRef() { Id = fieldLink.Id }); } } count++; } foreach (var view in siteList.Views.AsEnumerable().Where(view => !view.Hidden)) { var schemaElement = XElement.Parse(view.ListViewXml); // Toolbar is not supported var toolbarElement = schemaElement.Descendants("Toolbar").FirstOrDefault(); if (toolbarElement != null) { toolbarElement.Remove(); } // XslLink is not supported var xslLinkElement = schemaElement.Descendants("XslLink").FirstOrDefault(); if (xslLinkElement != null) { xslLinkElement.Remove(); } list.Views.Add(new View { SchemaXml = schemaElement.ToString() }); } var siteColumns = web.Fields; web.Context.Load(siteColumns, scs => scs.Include(sc => sc.Id)); web.Context.ExecuteQueryRetry(); foreach (var field in siteList.Fields.AsEnumerable().Where(field => !field.Hidden)) { if (siteColumns.FirstOrDefault(sc => sc.Id == field.Id) != null) { var addField = true; if (siteList.ContentTypesEnabled && contentTypeFields.FirstOrDefault(c => c.Id == field.Id) == null) { if (contentTypeFields.FirstOrDefault(c => c.Id == field.Id) == null) { addField = false; } } var fieldElement = XElement.Parse(field.SchemaXml); var sourceId = fieldElement.Attribute("SourceID") != null ? fieldElement.Attribute("SourceID").Value : null; if (sourceId != null && sourceId == "http://schemas.microsoft.com/sharepoint/v3") { if (field.InternalName == "Editor" || field.InternalName == "Author" || field.InternalName == "Title" || field.InternalName == "ID" || field.InternalName == "Created" || field.InternalName == "Modified" || field.InternalName == "Attachments" || field.InternalName == "_UIVersionString" || field.InternalName == "DocIcon" || field.InternalName == "LinkTitleNoMenu" || field.InternalName == "LinkTitle" || field.InternalName == "Edit" || field.InternalName == "AppAuthor" || field.InternalName == "AppEditor" || field.InternalName == "ContentType" || field.InternalName == "ItemChildCount" || field.InternalName == "FolderChildCount" || field.InternalName == "LinkFilenameNoMenu" || field.InternalName == "LinkFilename" || field.InternalName == "_CopySource" || field.InternalName == "ParentVersionString" || field.InternalName == "ParentLeafName" || field.InternalName == "_CheckinComment" || field.InternalName == "FileLeafRef" || field.InternalName == "FileSizeDisplay" || field.InternalName == "Preview" || field.InternalName == "ThumbnailOnForm") { addField = false; } } if (addField) { list.FieldRefs.Add(new FieldRef(field.InternalName) { Id = field.Id, DisplayName = field.Title, Required = field.Required, Hidden = field.Hidden, }); } } else { list.Fields.Add((new Model.Field { SchemaXml = field.SchemaXml })); } list.Security = siteList.GetSecurity(); } var logCTWarning = false; if (baseTemplateList != null) { if (!baseTemplateList.Equals(list)) { scope.LogDebug(CoreResources.Provisioning_ObjectHandlers_ListInstances_Adding_list___0_____1_, list.Title, list.Url); template.Lists.Add(list); if (list.ContentTypesEnabled && list.ContentTypeBindings.Any() && web.IsSubSite()) { logCTWarning = true; } } } else { scope.LogDebug(CoreResources.Provisioning_ObjectHandlers_ListInstances_Adding_list___0_____1_, list.Title, list.Url); template.Lists.Add(list); if (list.ContentTypesEnabled && list.ContentTypeBindings.Any() && web.IsSubSite()) { logCTWarning = true; } } if (logCTWarning) { scope.LogWarning("You are extracting a template from a subweb. List '{0}' refers to content types. Content types are not exported when extracting a template from a subweb", list.Title); WriteWarning(string.Format("You are extracting a template from a subweb. List '{0}' refers to content types. Content types are not exported when extracting a template from a subweb", list.Title), ProvisioningMessageType.Warning); } } } return template; }
public override TokenParser ProvisionObjects(Web web, ProvisioningTemplate template, TokenParser parser, ProvisioningTemplateApplyingInformation applyingInformation) { using (var scope = new PnPMonitoredScope(this.Name)) { // Check if this is not a noscript site as we're not allowed to write to the web property bag is that one bool isNoScriptSite = web.IsNoScriptSite(); var context = web.Context as ClientContext; web.EnsureProperties(w => w.ServerRelativeUrl, w => w.Url); // Build on the fly the list of additional files coming from the Directories var directoryFiles = new List <Model.File>(); foreach (var directory in template.Directories) { var metadataProperties = directory.GetMetadataProperties(); directoryFiles.AddRange(directory.GetDirectoryFiles(metadataProperties)); } foreach (var file in template.Files.Union(directoryFiles)) { var folderName = parser.ParseString(file.Folder); if (folderName.ToLower().StartsWith((web.ServerRelativeUrl.ToLower()))) { folderName = folderName.Substring(web.ServerRelativeUrl.Length); } if (SkipFile(isNoScriptSite, file.Src, folderName)) { // add log message scope.LogWarning(CoreResources.Provisioning_ObjectHandlers_Files_SkipFileUpload, file.Src, folderName); continue; } var folder = web.EnsureFolderPath(folderName); var checkedOut = false; var targetFile = folder.GetFile(template.Connector.GetFilenamePart(file.Src)); if (targetFile != null) { if (file.Overwrite) { scope.LogDebug(CoreResources.Provisioning_ObjectHandlers_Files_Uploading_and_overwriting_existing_file__0_, file.Src); checkedOut = CheckOutIfNeeded(web, targetFile); using (var stream = GetFileStream(template, file)) { targetFile = UploadFile(template, file, folder, stream); } } else { checkedOut = CheckOutIfNeeded(web, targetFile); } } else { using (var stream = GetFileStream(template, file)) { scope.LogDebug(CoreResources.Provisioning_ObjectHandlers_Files_Uploading_file__0_, file.Src); targetFile = UploadFile(template, file, folder, stream); } checkedOut = CheckOutIfNeeded(web, targetFile); } if (targetFile != null) { if (file.Properties != null && file.Properties.Any()) { Dictionary <string, string> transformedProperties = file.Properties.ToDictionary(property => property.Key, property => parser.ParseString(property.Value)); SetFileProperties(targetFile, transformedProperties, false); } #if !SP2013 bool webPartsNeedLocalization = false; #endif if (file.WebParts != null && file.WebParts.Any()) { targetFile.EnsureProperties(f => f.ServerRelativeUrl); var existingWebParts = web.GetWebParts(targetFile.ServerRelativeUrl).ToList(); foreach (var webPart in file.WebParts) { // check if the webpart is already set on the page if (existingWebParts.FirstOrDefault(w => w.WebPart.Title == parser.ParseString(webPart.Title)) == null) { scope.LogDebug(CoreResources.Provisioning_ObjectHandlers_Files_Adding_webpart___0___to_page, webPart.Title); var wpEntity = new WebPartEntity(); wpEntity.WebPartTitle = parser.ParseString(webPart.Title); wpEntity.WebPartXml = parser.ParseString(webPart.Contents).Trim(new[] { '\n', ' ' }); wpEntity.WebPartZone = webPart.Zone; wpEntity.WebPartIndex = (int)webPart.Order; var wpd = web.AddWebPartToWebPartPage(targetFile.ServerRelativeUrl, wpEntity); #if !SP2013 if (webPart.Title.ContainsResourceToken()) { // update data based on where it was added - needed in order to localize wp title #if !SP2016 wpd.EnsureProperties(w => w.ZoneId, w => w.WebPart, w => w.WebPart.Properties); webPart.Zone = wpd.ZoneId; #else wpd.EnsureProperties(w => w.WebPart, w => w.WebPart.Properties); #endif webPart.Order = (uint)wpd.WebPart.ZoneIndex; webPartsNeedLocalization = true; } #endif } } } #if !SP2013 if (webPartsNeedLocalization) { file.LocalizeWebParts(web, parser, targetFile, scope); } #endif switch (file.Level) { case Model.FileLevel.Published: { targetFile.PublishFileToLevel(Microsoft.SharePoint.Client.FileLevel.Published); break; } case Model.FileLevel.Draft: { targetFile.PublishFileToLevel(Microsoft.SharePoint.Client.FileLevel.Draft); break; } default: { if (checkedOut) { targetFile.CheckIn("", CheckinType.MajorCheckIn); web.Context.ExecuteQueryRetry(); } break; } } // Don't set security when nothing is defined. This otherwise breaks on files set outside of a list if (file.Security != null && (file.Security.ClearSubscopes == true || file.Security.CopyRoleAssignments == true || file.Security.RoleAssignments.Count > 0)) { targetFile.ListItemAllFields.SetSecurity(parser, file.Security); } } } } return(parser); }
public override ProvisioningTemplate ExtractObjects(Web web, ProvisioningTemplate template, ProvisioningTemplateCreationInformation creationInfo) { using (var scope = new PnPMonitoredScope(this.Name)) { // Extract the Home Page web.EnsureProperties(w => w.RootFolder.WelcomePage, w => w.ServerRelativeUrl, w => w.Url); var homepageUrl = web.RootFolder.WelcomePage; if (string.IsNullOrEmpty(homepageUrl)) { homepageUrl = "Default.aspx"; } var welcomePageUrl = UrlUtility.Combine(web.ServerRelativeUrl, homepageUrl); List pagesLibrary = web.GetPagesLibrary(); var items = pagesLibrary.GetItems(CamlQuery.CreateAllItemsQuery()); web.Context.Load(items, i => i.Include(it => it.DisplayName, it => it.File)); web.Context.ExecuteQuery(); foreach (ListItem listItem in items) { try { //var listItem = file.EnsureProperty(f => f.ListItemAllFields); if (listItem != null) { File file = listItem.File; if (listItem.FieldValues.ContainsKey("WikiField") && listItem.FieldValues["WikiField"] != null) { // Wiki page var fullUri = new Uri(UrlUtility.Combine(new Uri(web.Url).GetLeftPart(UriPartial.Authority), file.ServerRelativeUrl)); var folderPath = fullUri.Segments.Take(fullUri.Segments.Count() - 1).ToArray().Aggregate((i, x) => i + x).TrimEnd('/'); LimitedWebPartManager limitedWPManager = file.GetLimitedWebPartManager(PersonalizationScope.Shared); web.Context.Load(limitedWPManager); var webParts = web.GetWebParts(file.ServerRelativeUrl); var page = new Page() { Layout = WikiPageLayout.Custom, Overwrite = true, Url = Tokenize(fullUri.PathAndQuery, web.Url), }; var pageContents = listItem.FieldValues["WikiField"].ToString(); Regex regexClientIds = new Regex(@"id=\""div_(?<ControlId>(\w|\-)+)"); if (regexClientIds.IsMatch(pageContents)) { foreach (Match webPartMatch in regexClientIds.Matches(pageContents)) { String serverSideControlId = webPartMatch.Groups["ControlId"].Value; try { String serverSideControlIdToSearchFor = String.Format("g_{0}", serverSideControlId.Replace("-", "_")); WebPartDefinition webPart = limitedWPManager.WebParts.GetByControlId(serverSideControlIdToSearchFor); web.Context.Load(webPart, wp => wp.Id, wp => wp.WebPart.Title, wp => wp.WebPart.ZoneIndex ); web.Context.ExecuteQueryRetry(); var webPartxml = TokenizeWebPartXml(web, web.GetWebPartXml(webPart.Id, file.ServerRelativeUrl)); page.WebParts.Add(new Model.WebPart() { Title = webPart.WebPart.Title, Contents = webPartxml, Order = (uint)webPart.WebPart.ZoneIndex, Row = 1, // By default we will create a onecolumn layout, add the webpart to it, and later replace the wikifield on the page to position the webparts correctly. Column = 1 // By default we will create a onecolumn layout, add the webpart to it, and later replace the wikifield on the page to position the webparts correctly. }); pageContents = Regex.Replace(pageContents, serverSideControlId, string.Format("{{webpartid:{0}}}", webPart.WebPart.Title), RegexOptions.IgnoreCase); } catch (ServerException) { scope.LogWarning("Found a WebPart ID which is not available on the server-side. ID: {0}", serverSideControlId); } } } page.Fields.Add("WikiField", pageContents); template.Pages.Add(page); // Set the homepage if (template.WebSettings == null) { template.WebSettings = new WebSettings(); } template.WebSettings.WelcomePage = homepageUrl; } else { if (web.Context.HasMinimalServerLibraryVersion(Constants.MINIMUMZONEIDREQUIREDSERVERVERSION)) { // Not a wikipage template = GetFileContents(web, template, file.ServerRelativeUrl, creationInfo, scope); if (template.WebSettings == null) { template.WebSettings = new WebSettings(); } template.WebSettings.WelcomePage = homepageUrl; } else { WriteMessage(string.Format("Page content export requires a server version that is newer than the current server. Server version is {0}, minimal required is {1}", web.Context.ServerLibraryVersion, Constants.MINIMUMZONEIDREQUIREDSERVERVERSION), ProvisioningMessageType.Warning); scope.LogWarning("Page content export requires a server version that is newer than the current server. Server version is {0}, minimal required is {1}", web.Context.ServerLibraryVersion, Constants.MINIMUMZONEIDREQUIREDSERVERVERSION); } } } } catch (ServerException ex) { if (ex.ServerErrorCode != -2146232832) { throw; } else { if (web.Context.HasMinimalServerLibraryVersion(Constants.MINIMUMZONEIDREQUIREDSERVERVERSION)) { // Page does not belong to a list, extract the file as is template = GetFileContents(web, template, welcomePageUrl, creationInfo, scope); if (template.WebSettings == null) { template.WebSettings = new WebSettings(); } template.WebSettings.WelcomePage = homepageUrl; } else { WriteMessage(string.Format("Page content export requires a server version that is newer than the current server. Server version is {0}, minimal required is {1}", web.Context.ServerLibraryVersion, Constants.MINIMUMZONEIDREQUIREDSERVERVERSION), ProvisioningMessageType.Warning); scope.LogWarning("Page content export requires a server version that is newer than the current server. Server version is {0}, minimal required is {1}", web.Context.ServerLibraryVersion, Constants.MINIMUMZONEIDREQUIREDSERVERVERSION); } } } } // If a base template is specified then use that one to "cleanup" the generated template model if (creationInfo.BaseTemplate != null) { template = CleanupEntities(template, creationInfo.BaseTemplate); } } return(template); }
public override TokenParser ProvisionObjects(Web web, ProvisioningTemplate template, TokenParser parser, ProvisioningTemplateApplyingInformation applyingInformation) { using (var scope = new PnPMonitoredScope(this.Name)) { var site = (web.Context as ClientContext).Site; // Check if this is not a noscript site as publishing features are not supported if (web.IsNoScriptSite()) { scope.LogWarning(CoreResources.Provisioning_ObjectHandlers_Publishing_SkipProvisioning); return parser; } var webFeatureActive = web.IsFeatureActive(PUBLISHING_FEATURE_WEB); var siteFeatureActive = site.IsFeatureActive(PUBLISHING_FEATURE_SITE); if (template.Publishing.AutoCheckRequirements == AutoCheckRequirementsOptions.SkipIfNotCompliant && !webFeatureActive) { scope.LogDebug("Publishing Feature (Web Scoped) not active. Skipping provisioning of Publishing settings"); return parser; } else if (template.Publishing.AutoCheckRequirements == AutoCheckRequirementsOptions.MakeCompliant) { if (!siteFeatureActive) { scope.LogDebug("Making site compliant for publishing"); site.ActivateFeature(PUBLISHING_FEATURE_SITE); web.ActivateFeature(PUBLISHING_FEATURE_WEB); } else { if (!web.IsFeatureActive(PUBLISHING_FEATURE_WEB)) { scope.LogDebug("Making site compliant for publishing"); web.ActivateFeature(PUBLISHING_FEATURE_WEB); } } } else { throw new Exception("Publishing Feature not active. Provisioning failed"); } // Set allowed web templates var availableWebTemplates = template.Publishing.AvailableWebTemplates.Select(t => new WebTemplateEntity() { LanguageCode = t.LanguageCode.ToString(), TemplateName = t.TemplateName }).ToList(); if (availableWebTemplates.Any()) { web.SetAvailableWebTemplates(availableWebTemplates); } if (template.Publishing.DesignPackage != null) { var package = template.Publishing.DesignPackage; var tempFileName = Path.Combine(Path.GetTempPath(), template.Connector.GetFilenamePart(package.DesignPackagePath)); scope.LogDebug("Saving {0} to temporary file: {1}", package.DesignPackagePath, tempFileName); using (var stream = template.Connector.GetFileStream(package.DesignPackagePath)) { using (var outstream = System.IO.File.Create(tempFileName)) { stream.CopyTo(outstream); } } scope.LogDebug("Installing design package"); site.InstallSolution(package.PackageGuid, tempFileName, package.MajorVersion, package.MinorVersion); System.IO.File.Delete(tempFileName); } // Set allowed page layouts var availablePageLayouts = template.Publishing.PageLayouts.Select(p => p.Path); if (availablePageLayouts.Any()) { web.SetAvailablePageLayouts(site.RootWeb, availablePageLayouts); } // Set default page layout, if any var defaultPageLayout = template.Publishing.PageLayouts.FirstOrDefault(p => p.IsDefault); if (defaultPageLayout != null) { web.SetDefaultPageLayoutForSite(site.RootWeb, defaultPageLayout.Path); } return parser; } }
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); } }
public override TokenParser ProvisionObjects(Web web, ProvisioningTemplate template, TokenParser parser, ProvisioningTemplateApplyingInformation applyingInformation) { using (var scope = new PnPMonitoredScope(this.Name)) { if (template.WebSettings != null) { // Check if this is not a noscript site as we're not allowed to update some properties bool isNoScriptSite = web.IsNoScriptSite(); web.EnsureProperties( #if !ONPREMISES w => w.CommentsOnSitePagesDisabled, #endif w => w.WebTemplate, w => w.HasUniqueRoleAssignments); var webSettings = template.WebSettings; #if !ONPREMISES if (!isNoScriptSite) { web.NoCrawl = webSettings.NoCrawl; } else { scope.LogWarning(CoreResources.Provisioning_ObjectHandlers_WebSettings_SkipNoCrawlUpdate); } #endif if (!web.IsSubSite() || (web.IsSubSite() && web.HasUniqueRoleAssignments)) { String requestAccessEmailValue = parser.ParseString(webSettings.RequestAccessEmail); if (!String.IsNullOrEmpty(requestAccessEmailValue) && requestAccessEmailValue.Length >= 255) { requestAccessEmailValue = requestAccessEmailValue.Substring(0, 255); } if (!String.IsNullOrEmpty(requestAccessEmailValue)) { web.RequestAccessEmail = requestAccessEmailValue; web.Update(); web.Context.ExecuteQueryRetry(); } } #if !ONPREMISES if (web.CommentsOnSitePagesDisabled != webSettings.CommentsOnSitePagesDisabled) { web.CommentsOnSitePagesDisabled = webSettings.CommentsOnSitePagesDisabled; } #endif var masterUrl = parser.ParseString(webSettings.MasterPageUrl); if (!string.IsNullOrEmpty(masterUrl)) { if (!isNoScriptSite) { web.MasterUrl = masterUrl; } else { scope.LogWarning(CoreResources.Provisioning_ObjectHandlers_WebSettings_SkipMasterPageUpdate); } } var customMasterUrl = parser.ParseString(webSettings.CustomMasterPageUrl); if (!string.IsNullOrEmpty(customMasterUrl)) { if (!isNoScriptSite) { web.CustomMasterUrl = customMasterUrl; } else { scope.LogWarning(CoreResources.Provisioning_ObjectHandlers_WebSettings_SkipCustomMasterPageUpdate); } } if (webSettings.Title != null) { web.Title = parser.ParseString(webSettings.Title); } if (webSettings.Description != null) { web.Description = parser.ParseString(webSettings.Description); } if (webSettings.SiteLogo != null) { var logoUrl = parser.ParseString(webSettings.SiteLogo); // Modern site? Then we assume the SiteLogo is actually a filepath if (web.WebTemplate == "GROUP") { #if !ONPREMISES if (!string.IsNullOrEmpty(logoUrl) && !logoUrl.ToLower().Contains("_api/groupservice/getgroupimage")) { var fileBytes = ConnectorFileHelper.GetFileBytes(template.Connector, logoUrl); if (fileBytes != null && fileBytes.Length > 0) { #if !NETSTANDARD2_0 var mimeType = MimeMapping.GetMimeMapping(logoUrl); #else var mimeType = ""; var imgUrl = logoUrl; if (imgUrl.Contains("?")) { imgUrl = imgUrl.Split(new[] { '?' })[0]; } if (imgUrl.EndsWith(".gif", StringComparison.InvariantCultureIgnoreCase)) { mimeType = "image/gif"; } if (imgUrl.EndsWith(".png", StringComparison.InvariantCultureIgnoreCase)) { mimeType = "image/png"; } if (imgUrl.EndsWith(".jpg", StringComparison.InvariantCultureIgnoreCase)) { mimeType = "image/jpeg"; } #endif Sites.SiteCollection.SetGroupImage((ClientContext)web.Context, fileBytes, mimeType).GetAwaiter().GetResult(); } } #endif } else { web.SiteLogoUrl = logoUrl; } } var welcomePage = parser.ParseString(webSettings.WelcomePage); if (!string.IsNullOrEmpty(welcomePage)) { web.RootFolder.WelcomePage = welcomePage; web.RootFolder.Update(); } if (webSettings.AlternateCSS != null) { web.AlternateCssUrl = parser.ParseString(webSettings.AlternateCSS); } web.Update(); web.Context.ExecuteQueryRetry(); #if !ONPREMISES if (webSettings.HubSiteUrl != null) { var hubsiteUrl = parser.ParseString(webSettings.HubSiteUrl); try { using (var tenantContext = web.Context.Clone(web.GetTenantAdministrationUrl(), applyingInformation.AccessTokens)) { var tenant = new Tenant(tenantContext); tenant.ConnectSiteToHubSite(web.Url, hubsiteUrl); tenantContext.ExecuteQueryRetry(); } } catch (Exception ex) { WriteMessage($"Hub site association failed: {ex.Message}", ProvisioningMessageType.Warning); } } #endif } } return(parser); }
private void UpdateField(Web web, string fieldId, XElement templateFieldElement, PnPMonitoredScope scope, TokenParser parser) { var existingField = web.Fields.GetById(Guid.Parse(fieldId)); web.Context.Load(existingField, f => f.SchemaXml); web.Context.ExecuteQueryRetry(); XElement existingFieldElement = XElement.Parse(existingField.SchemaXml); XNodeEqualityComparer equalityComparer = new XNodeEqualityComparer(); if (equalityComparer.GetHashCode(existingFieldElement) != equalityComparer.GetHashCode(templateFieldElement)) // Is field different in template? { if (existingFieldElement.Attribute("Type").Value == templateFieldElement.Attribute("Type").Value) // Is existing field of the same type? { var listIdentifier = templateFieldElement.Attribute("List") != null?templateFieldElement.Attribute("List").Value : null; if (listIdentifier != null) { // Temporary remove list attribute from list templateFieldElement.Attribute("List").Remove(); } foreach (var attribute in templateFieldElement.Attributes()) { if (existingFieldElement.Attribute(attribute.Name) != null) { existingFieldElement.Attribute(attribute.Name).Value = attribute.Value; } else { existingFieldElement.Add(attribute); } } foreach (var element in templateFieldElement.Elements()) { if (existingFieldElement.Element(element.Name) != null) { existingFieldElement.Element(element.Name).Remove(); } existingFieldElement.Add(element); } if (existingFieldElement.Attribute("Version") != null) { existingFieldElement.Attributes("Version").Remove(); } existingField.SchemaXml = parser.ParseString(existingFieldElement.ToString(), "~sitecollection", "~site"); existingField.UpdateAndPushChanges(true); web.Context.Load(existingField, f => f.TypeAsString, f => f.DefaultValue); web.Context.ExecuteQueryRetry(); if ((existingField.TypeAsString == "TaxonomyFieldType" || existingField.TypeAsString == "TaxonomyFieldTypeMulti") && !string.IsNullOrEmpty(existingField.DefaultValue)) { var taxField = web.Context.CastTo <TaxonomyField>(existingField); ValidateTaxonomyFieldDefaultValue(taxField); } } else { var fieldName = existingFieldElement.Attribute("Name") != null?existingFieldElement.Attribute("Name").Value : existingFieldElement.Attribute("StaticName").Value; WriteWarning(string.Format(CoreResources.Provisioning_ObjectHandlers_Fields_Field__0____1___exists_but_is_of_different_type__Skipping_field_, fieldName, fieldId), ProvisioningMessageType.Warning); scope.LogWarning(CoreResources.Provisioning_ObjectHandlers_Fields_Field__0____1___exists_but_is_of_different_type__Skipping_field_, fieldName, fieldId); } } }
public override TokenParser ProvisionObjects(Web web, ProvisioningTemplate template, TokenParser parser, ProvisioningTemplateApplyingInformation applyingInformation) { using (var scope = new PnPMonitoredScope(this.Name)) { // Check if this is not a noscript site as we're not allowed to write to the web property bag is that one bool isNoScriptSite = web.IsNoScriptSite(); web.EnsureProperties(w => w.ServerRelativeUrl, w => w.Url); // Build on the fly the list of additional files coming from the Directories var directoryFiles = new List <Model.File>(); foreach (var directory in template.Directories) { var metadataProperties = directory.GetMetadataProperties(); directoryFiles.AddRange(directory.GetDirectoryFiles(metadataProperties)); } var filesToProcess = template.Files.Union(directoryFiles).ToArray(); var siteAssetsFiles = filesToProcess.Where(f => f.Folder.ToLower().Contains("siteassets")).FirstOrDefault(); if (siteAssetsFiles != null) { // Need this so that we dont have access denied error during the first time upload, especially for modern sites web.Lists.EnsureSiteAssetsLibrary(); web.Context.ExecuteQueryRetry(); } var currentFileIndex = 0; var originalWeb = web; // Used to store and re-store context in case files are deployed to masterpage gallery foreach (var file in filesToProcess) { file.Src = parser.ParseString(file.Src); var targetFileName = parser.ParseString( !String.IsNullOrEmpty(file.TargetFileName) ? file.TargetFileName : template.Connector.GetFilenamePart(file.Src) ); currentFileIndex++; WriteSubProgress("File", targetFileName, currentFileIndex, filesToProcess.Length); var folderName = parser.ParseString(file.Folder); if (folderName.ToLower().Contains("/_catalogs/")) { // Edge case where you have files in the template which should be provisioned to the site collection // master page gallery and not to a connected subsite web = web.Context.GetSiteCollectionContext().Web; web.EnsureProperties(w => w.ServerRelativeUrl, w => w.Url); } if (folderName.ToLower().StartsWith((web.ServerRelativeUrl.ToLower()))) { folderName = folderName.Substring(web.ServerRelativeUrl.Length); } if (SkipFile(isNoScriptSite, targetFileName, folderName)) { // add log message scope.LogWarning(CoreResources.Provisioning_ObjectHandlers_Files_SkipFileUpload, targetFileName, folderName); continue; } var folder = web.EnsureFolderPath(folderName); folder.EnsureProperties(p => p.UniqueId, p => p.ServerRelativeUrl); parser.AddToken(new FileUniqueIdToken(web, folder.ServerRelativeUrl.Substring(web.ServerRelativeUrl.Length).TrimStart("/".ToCharArray()), folder.UniqueId)); parser.AddToken(new FileUniqueIdEncodedToken(web, folder.ServerRelativeUrl.Substring(web.ServerRelativeUrl.Length).TrimStart("/".ToCharArray()), folder.UniqueId)); var checkedOut = false; var targetFile = folder.GetFile(template.Connector.GetFilenamePart(targetFileName)); if (targetFile != null) { if (file.Overwrite) { scope.LogDebug(CoreResources.Provisioning_ObjectHandlers_Files_Uploading_and_overwriting_existing_file__0_, targetFileName); checkedOut = CheckOutIfNeeded(web, targetFile); using (var stream = FileUtilities.GetFileStream(template, file)) { targetFile = UploadFile(folder, stream, targetFileName, file.Overwrite); } } else { checkedOut = CheckOutIfNeeded(web, targetFile); } } else { using (var stream = FileUtilities.GetFileStream(template, file)) { if (stream == null) { throw new FileNotFoundException($"File {file.Src} does not exist"); } else { scope.LogDebug(CoreResources.Provisioning_ObjectHandlers_Files_Uploading_file__0_, targetFileName); targetFile = UploadFile(folder, stream, targetFileName, file.Overwrite); } } checkedOut = CheckOutIfNeeded(web, targetFile); } if (targetFile != null) { // Add the fileuniqueid tokens targetFile.EnsureProperties(p => p.UniqueId, p => p.ServerRelativePath); // Add ListItemId token, given that a file can live outside of a library ensure this does not break provisioning try { web.Context.Load(targetFile, p => p.ListItemAllFields.Id); web.Context.ExecuteQueryRetry(); if (targetFile.ListItemAllFields.ServerObjectIsNull.HasValue && !targetFile.ListItemAllFields.ServerObjectIsNull.Value) { parser.AddToken(new FileListItemIdToken(web, targetFile.ServerRelativePath.DecodedUrl.Substring(web.ServerRelativeUrl.Length).TrimStart("/".ToCharArray()), targetFile.ListItemAllFields.Id)); } } catch (ServerException ex) { // If this throws ServerException (does not belong to list), then shouldn't be trying to set properties) // Handling the exception stating the "The object specified does not belong to a list." if (ex.ServerErrorCode != -2113929210) { throw; } } parser.AddToken(new FileUniqueIdToken(web, targetFile.ServerRelativePath.DecodedUrl.Substring(web.ServerRelativeUrl.Length).TrimStart("/".ToCharArray()), targetFile.UniqueId)); parser.AddToken(new FileUniqueIdEncodedToken(web, targetFile.ServerRelativePath.DecodedUrl.Substring(web.ServerRelativeUrl.Length).TrimStart("/".ToCharArray()), targetFile.UniqueId)); bool webPartsNeedLocalization = false; if (file.WebParts != null && file.WebParts.Any()) { targetFile.EnsureProperties(f => f.ServerRelativePath); var existingWebParts = web.GetWebParts(targetFile.ServerRelativePath.DecodedUrl).ToList(); foreach (var webPart in file.WebParts) { // check if the webpart is already set on the page if (existingWebParts.FirstOrDefault(w => w.WebPart.Title == parser.ParseString(webPart.Title)) == null) { scope.LogDebug(CoreResources.Provisioning_ObjectHandlers_Files_Adding_webpart___0___to_page, webPart.Title); var wpEntity = new WebPartEntity { WebPartTitle = parser.ParseString(webPart.Title), WebPartXml = parser.ParseXmlString(webPart.Contents).Trim(new[] { '\n', ' ' }), WebPartZone = webPart.Zone, WebPartIndex = (int)webPart.Order }; var wpd = web.AddWebPartToWebPartPage(targetFile.ServerRelativePath.DecodedUrl, wpEntity); if (webPart.Title.ContainsResourceToken()) { // update data based on where it was added - needed in order to localize wp title wpd.EnsureProperties(w => w.ZoneId, w => w.WebPart, w => w.WebPart.Properties); webPart.Zone = wpd.ZoneId; webPart.Order = (uint)wpd.WebPart.ZoneIndex; webPartsNeedLocalization = true; } } } } if (webPartsNeedLocalization) { file.LocalizeWebParts(web, parser, targetFile, scope); } //Set Properties before Checkin if (file.Properties != null && file.Properties.Any()) { Dictionary <string, string> transformedProperties = file.Properties.ToDictionary(property => property.Key, property => parser.ParseString(property.Value)); SetFileProperties(targetFile, transformedProperties, parser, false); } switch (file.Level) { case Model.FileLevel.Published: { targetFile.PublishFileToLevel(Microsoft.SharePoint.Client.FileLevel.Published); break; } case Model.FileLevel.Draft: { targetFile.PublishFileToLevel(Microsoft.SharePoint.Client.FileLevel.Draft); break; } default: { if (checkedOut) { targetFile.CheckIn("", CheckinType.MajorCheckIn); web.Context.ExecuteQueryRetry(); } break; } } // Don't set security when nothing is defined. This otherwise breaks on files set outside of a list if (file.Security != null && (file.Security.ClearSubscopes == true || file.Security.CopyRoleAssignments == true || file.Security.RoleAssignments.Count > 0)) { targetFile.ListItemAllFields.SetSecurity(parser, file.Security, WriteMessage); } } web = originalWeb; // restore context in case files are provisioned to the master page gallery #1059 } } WriteMessage("Done processing files", ProvisioningMessageType.Completed); return(parser); }
public override TokenParser ProvisionObjects(Web web, ProvisioningTemplate template, TokenParser parser, ProvisioningTemplateApplyingInformation applyingInformation) { using (var scope = new PnPMonitoredScope(this.Name)) { if (template.WebSettings != null) { // Check if this is not a noscript site as we're not allowed to update some properties bool isNoScriptSite = web.IsNoScriptSite(); web.EnsureProperties( #if !ONPREMISES w => w.CommentsOnSitePagesDisabled, #endif w => w.HasUniqueRoleAssignments); var webSettings = template.WebSettings; #if !ONPREMISES if (!isNoScriptSite) { web.NoCrawl = webSettings.NoCrawl; } else { scope.LogWarning(CoreResources.Provisioning_ObjectHandlers_WebSettings_SkipNoCrawlUpdate); } if (!web.IsSubSite() || (web.IsSubSite() && web.HasUniqueRoleAssignments)) { String requestAccessEmailValue = parser.ParseString(webSettings.RequestAccessEmail); if (!String.IsNullOrEmpty(requestAccessEmailValue) && requestAccessEmailValue.Length >= 255) { requestAccessEmailValue = requestAccessEmailValue.Substring(0, 255); } if (!String.IsNullOrEmpty(requestAccessEmailValue)) { web.RequestAccessEmail = requestAccessEmailValue; web.Update(); web.Context.ExecuteQueryRetry(); } } if (web.CommentsOnSitePagesDisabled != webSettings.CommentsOnSitePagesDisabled) { web.CommentsOnSitePagesDisabled = webSettings.CommentsOnSitePagesDisabled; } #endif var masterUrl = parser.ParseString(webSettings.MasterPageUrl); if (!string.IsNullOrEmpty(masterUrl)) { if (!isNoScriptSite) { web.MasterUrl = masterUrl; } else { scope.LogWarning(CoreResources.Provisioning_ObjectHandlers_WebSettings_SkipMasterPageUpdate); } } var customMasterUrl = parser.ParseString(webSettings.CustomMasterPageUrl); if (!string.IsNullOrEmpty(customMasterUrl)) { if (!isNoScriptSite) { web.CustomMasterUrl = customMasterUrl; } else { scope.LogWarning(CoreResources.Provisioning_ObjectHandlers_WebSettings_SkipCustomMasterPageUpdate); } } if (webSettings.Title != null) { web.Title = parser.ParseString(webSettings.Title); } if (webSettings.Description != null) { web.Description = parser.ParseString(webSettings.Description); } if (webSettings.SiteLogo != null) { web.SiteLogoUrl = parser.ParseString(webSettings.SiteLogo); } var welcomePage = parser.ParseString(webSettings.WelcomePage); if (!string.IsNullOrEmpty(welcomePage)) { web.RootFolder.WelcomePage = welcomePage; web.RootFolder.Update(); } if (webSettings.AlternateCSS != null) { web.AlternateCssUrl = parser.ParseString(webSettings.AlternateCSS); } web.Update(); web.Context.ExecuteQueryRetry(); #if !ONPREMISES if (webSettings.HubSiteUrl != null) { var hubsiteUrl = parser.ParseString(webSettings.HubSiteUrl); try { using (var tenantContext = web.Context.Clone(web.GetTenantAdministrationUrl())) { var tenant = new Tenant(tenantContext); tenant.ConnectSiteToHubSite(web.Url, hubsiteUrl); tenantContext.ExecuteQueryRetry(); } } catch (Exception ex) { WriteMessage($"Hub site association failed: {ex.Message}", ProvisioningMessageType.Warning); } } #endif } } return(parser); }
public override ProvisioningTemplate ExtractObjects(Web web, ProvisioningTemplate template, ProvisioningTemplateCreationInformation creationInfo) { using (var scope = new PnPMonitoredScope(this.Name)) { // Extract the Home Page web.EnsureProperties(w => w.RootFolder.WelcomePage, w => w.ServerRelativeUrl, w => w.Url); var homepageUrl = web.RootFolder.WelcomePage; if (string.IsNullOrEmpty(homepageUrl)) { homepageUrl = "Default.aspx"; } var welcomePageUrl = UrlUtility.Combine(web.ServerRelativeUrl, homepageUrl); var file = web.GetFileByServerRelativeUrl(welcomePageUrl); try { var listItem = file.EnsureProperty(f => f.ListItemAllFields); if (listItem != null) { if (listItem.FieldValues.ContainsKey("WikiField") && listItem.FieldValues["WikiField"] != null) { // Wiki page var fullUri = new Uri(UrlUtility.Combine(web.Url, web.RootFolder.WelcomePage)); //var folderPath = fullUri.Segments.Take(fullUri.Segments.Count() - 1).ToArray().Aggregate((i, x) => i + x).TrimEnd('/'); //var fileName = fullUri.Segments[fullUri.Segments.Count() - 1]; var homeFile = web.GetFileByServerRelativeUrl(welcomePageUrl); var limitedWPManager = homeFile.GetLimitedWebPartManager(PersonalizationScope.Shared); web.Context.Load(limitedWPManager); //var webParts = web.GetWebParts(welcomePageUrl); var page = new Page() { Layout = WikiPageLayout.Custom, Overwrite = true, Url = Tokenize(fullUri.PathAndQuery, web.Url), }; var pageContents = listItem.FieldValues["WikiField"].ToString(); Regex regexClientIds = new Regex(@"id=\""div_(?<ControlId>(\w|\-)+)"); if (regexClientIds.IsMatch(pageContents)) { foreach (Match webPartMatch in regexClientIds.Matches(pageContents)) { String serverSideControlId = webPartMatch.Groups["ControlId"].Value; try { var serverSideControlIdToSearchFor = $"g_{serverSideControlId.Replace("-", "_")}"; var webPart = limitedWPManager.WebParts.GetByControlId(serverSideControlIdToSearchFor); web.Context.Load(webPart, wp => wp.Id, wp => wp.WebPart.Title, wp => wp.WebPart.ZoneIndex ); web.Context.ExecuteQueryRetry(); var webPartxml = TokenizeWebPartXml(web, web.GetWebPartXml(webPart.Id, welcomePageUrl)); page.WebParts.Add(new Model.WebPart() { Title = webPart.WebPart.Title, Contents = webPartxml, Order = (uint)webPart.WebPart.ZoneIndex, Row = 1, // By default we will create a onecolumn layout, add the webpart to it, and later replace the wikifield on the page to position the webparts correctly. Column = 1 // By default we will create a onecolumn layout, add the webpart to it, and later replace the wikifield on the page to position the webparts correctly. }); pageContents = Regex.Replace(pageContents, serverSideControlId, $"{{webpartid:{webPart.WebPart.Title}}}", RegexOptions.IgnoreCase); } catch (ServerException) { scope.LogWarning("Found a WebPart ID which is not available on the server-side. ID: {0}", serverSideControlId); } } } page.Fields.Add("WikiField", pageContents); template.Pages.Add(page); // Set the homepage if (template.WebSettings == null) { template.WebSettings = new WebSettings(); } template.WebSettings.WelcomePage = homepageUrl; } else if (listItem.FieldValues.ContainsKey("ClientSideApplicationId") && listItem.FieldValues["ClientSideApplicationId"] != null && listItem.FieldValues["ClientSideApplicationId"].ToString().ToLower() == "b6917cb1-93a0-4b97-a84d-7cf49975d4ec") { // this is a client side page, so let's skip it since it's handled by the Client Side Page contents handler } else { if (web.Context.HasMinimalServerLibraryVersion(Constants.MINIMUMZONEIDREQUIREDSERVERVERSION) || creationInfo.SkipVersionCheck) { // Not a wikipage template = GetFileContents(web, template, welcomePageUrl, creationInfo, scope); if (template.WebSettings == null) { template.WebSettings = new WebSettings(); } template.WebSettings.WelcomePage = homepageUrl; } else { WriteMessage( $"Page content export requires a server version that is newer than the current server. Server version is {web.Context.ServerLibraryVersion}, minimal required is {Constants.MINIMUMZONEIDREQUIREDSERVERVERSION}. Set SkipVersionCheck to true to override this check.", ProvisioningMessageType.Warning); scope.LogWarning("Page content export requires a server version that is newer than the current server. Server version is {0}, minimal required is {1}", web.Context.ServerLibraryVersion, Constants.MINIMUMZONEIDREQUIREDSERVERVERSION); } } } } catch (ServerException ex) { //ignore this error. The default page is not a page but a list view. if (ex.ServerErrorCode != -2146232832 && ex.HResult != -2146233088) { throw; } else { if (ex.HResult != -2146233088) { if (web.Context.HasMinimalServerLibraryVersion(Constants.MINIMUMZONEIDREQUIREDSERVERVERSION) || creationInfo.SkipVersionCheck) { // Page does not belong to a list, extract the file as is template = GetFileContents(web, template, welcomePageUrl, creationInfo, scope); if (template.WebSettings == null) { template.WebSettings = new WebSettings(); } template.WebSettings.WelcomePage = homepageUrl; } else { WriteMessage( $"Page content export requires a server version that is newer than the current server. Server version is {web.Context.ServerLibraryVersion}, minimal required is {Constants.MINIMUMZONEIDREQUIREDSERVERVERSION}. Set SkipVersionCheck to true to override this check.", ProvisioningMessageType.Warning); scope.LogWarning("Page content export requires a server version that is newer than the current server. Server version is {0}, minimal required is {1}", web.Context.ServerLibraryVersion, Constants.MINIMUMZONEIDREQUIREDSERVERVERSION); } } } } // If a base template is specified then use that one to "cleanup" the generated template model if (creationInfo.BaseTemplate != null) { template = CleanupEntities(template, creationInfo.BaseTemplate); } } return(template); }
public override TokenParser ProvisionObjects(Web web, ProvisioningTemplate template, TokenParser parser, ProvisioningTemplateApplyingInformation applyingInformation) { using (var scope = new PnPMonitoredScope(this.Name)) { if (template.AuditSettings != null) { // Check if this is not a noscript site as we're not allowed to update some properties bool isNoScriptSite = web.IsNoScriptSite(); var site = (web.Context as ClientContext).Site; site.EnsureProperties(s => s.Audit, s => s.AuditLogTrimmingRetention, s => s.TrimAuditLog); var siteAuditSettings = site.Audit; var isDirty = false; if (template.AuditSettings.AuditFlags != siteAuditSettings.AuditFlags) { site.Audit.AuditFlags = template.AuditSettings.AuditFlags; site.Audit.Update(); isDirty = true; } if (!isNoScriptSite) { if (template.AuditSettings.AuditLogTrimmingRetention != site.AuditLogTrimmingRetention) { site.AuditLogTrimmingRetention = template.AuditSettings.AuditLogTrimmingRetention; isDirty = true; } } else { scope.LogWarning(CoreResources.Provisioning_ObjectHandlers_Audit_SkipAuditLogTrimmingRetention); } if (template.AuditSettings.TrimAuditLog != site.TrimAuditLog) { site.TrimAuditLog = template.AuditSettings.TrimAuditLog; isDirty = true; } if (isDirty) { web.Context.ExecuteQueryRetry(); } } } return parser; }
/// <summary> /// Extracts a client side page /// </summary> /// <param name="web">Web to extract the page from</param> /// <param name="template">Current provisioning template that will hold the extracted page</param> /// <param name="creationInfo">ProvisioningTemplateCreationInformation passed into the provisioning engine</param> /// <param name="scope">Scope used for logging</param> /// <param name="pageUrl">Url of the page to extract</param> /// <param name="pageName">Name of the page to extract</param> /// <param name="isHomePage">Is this a home page?</param> /// <param name="isTemplate">Is this a template?</param> public void ExtractClientSidePage(Web web, ProvisioningTemplate template, ProvisioningTemplateCreationInformation creationInfo, PnPMonitoredScope scope, string pageUrl, string pageName, bool isHomePage, bool isTemplate = false) { bool excludeAuthorInformation = false; if (creationInfo.ExtractConfiguration != null && creationInfo.ExtractConfiguration.Pages != null) { excludeAuthorInformation = creationInfo.ExtractConfiguration.Pages.ExcludeAuthorInformation; } try { List <string> errorneousOrNonImageFileGuids = new List <string>(); var pageToExtract = web.LoadClientSidePage(pageName); if (pageToExtract.Sections.Count == 0 && pageToExtract.Controls.Count == 0 && isHomePage) { // This is default home page which was not customized...and as such there's no page definition stored in the list item. We don't need to extact this page. scope.LogInfo(CoreResources.Provisioning_ObjectHandlers_ClientSidePageContents_DefaultHomePage); } else { // Get the page content type string pageContentTypeId = pageToExtract.PageListItem[ContentTypeIdField].ToString(); if (!string.IsNullOrEmpty(pageContentTypeId)) { pageContentTypeId = GetParentIdValue(pageContentTypeId); } var isNews = pageToExtract.LayoutType != Pages.ClientSidePageLayoutType.Home && int.Parse(pageToExtract.PageListItem[OfficeDevPnP.Core.Pages.ClientSidePage.PromotedStateField].ToString()) == (int)Pages.PromotedState.Promoted; // Create the page var extractedPageInstance = new ClientSidePage() { PageName = pageName, PromoteAsNewsArticle = isNews, PromoteAsTemplate = isTemplate, Overwrite = true, Publish = true, Layout = pageToExtract.LayoutType.ToString(), EnableComments = !pageToExtract.CommentsDisabled, Title = pageToExtract.PageTitle, ContentTypeID = !pageContentTypeId.Equals(BuiltInContentTypeId.ModernArticlePage, StringComparison.InvariantCultureIgnoreCase) ? pageContentTypeId : null, ThumbnailUrl = pageToExtract.ThumbnailUrl != null?TokenizeJsonControlData(web, pageToExtract.ThumbnailUrl) : "" }; if (pageToExtract.PageHeader != null) { var extractedHeader = new ClientSidePageHeader() { Type = (ClientSidePageHeaderType)Enum.Parse(typeof(Pages.ClientSidePageHeaderType), pageToExtract.PageHeader.Type.ToString()), ServerRelativeImageUrl = TokenizeJsonControlData(web, pageToExtract.PageHeader.ImageServerRelativeUrl), TranslateX = pageToExtract.PageHeader.TranslateX, TranslateY = pageToExtract.PageHeader.TranslateY, LayoutType = (ClientSidePageHeaderLayoutType)Enum.Parse(typeof(Pages.ClientSidePageHeaderLayoutType), pageToExtract.PageHeader.LayoutType.ToString()), #if !SP2019 TextAlignment = (ClientSidePageHeaderTextAlignment)Enum.Parse(typeof(Pages.ClientSidePageHeaderTitleAlignment), pageToExtract.PageHeader.TextAlignment.ToString()), ShowTopicHeader = pageToExtract.PageHeader.ShowTopicHeader, ShowPublishDate = pageToExtract.PageHeader.ShowPublishDate, TopicHeader = pageToExtract.PageHeader.TopicHeader, AlternativeText = pageToExtract.PageHeader.AlternativeText, Authors = !excludeAuthorInformation ? pageToExtract.PageHeader.Authors : "", AuthorByLine = !excludeAuthorInformation ? pageToExtract.PageHeader.AuthorByLine : "", AuthorByLineId = !excludeAuthorInformation ? pageToExtract.PageHeader.AuthorByLineId : -1 #endif }; extractedPageInstance.Header = extractedHeader; // Add the page header image to template if that was requested if (creationInfo.PersistBrandingFiles && !string.IsNullOrEmpty(pageToExtract.PageHeader.ImageServerRelativeUrl)) { IncludePageHeaderImageInExport(web, pageToExtract.PageHeader.ImageServerRelativeUrl, template, creationInfo, scope); } } // define reusable RegEx pre-compiled objects string guidPattern = "\"{?[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12}}?\""; Regex regexGuidPattern = new Regex(guidPattern, RegexOptions.Compiled); string guidPatternEncoded = "=[a-fA-F0-9]{8}(?:%2D|-)([a-fA-F0-9]{4}(?:%2D|-)){3}[a-fA-F0-9]{12}"; Regex regexGuidPatternEncoded = new Regex(guidPatternEncoded, RegexOptions.Compiled); string guidPatternNoDashes = "[a-fA-F0-9]{32}"; Regex regexGuidPatternNoDashes = new Regex(guidPatternNoDashes, RegexOptions.Compiled); string siteAssetUrlsPattern = "(?:\")(?<AssetUrl>[\\w|\\.|\\/|:|-]*\\/SiteAssets\\/SitePages\\/[\\w|\\.|\\/|:|-]*)(?:\")"; // OLD RegEx with Catastrophic Backtracking: @".*""(.*?/SiteAssets/SitePages/.+?)"".*"; Regex regexSiteAssetUrls = new Regex(siteAssetUrlsPattern, RegexOptions.Compiled); if (creationInfo.PersistBrandingFiles && !string.IsNullOrEmpty(extractedPageInstance.ThumbnailUrl)) { var thumbnailFileIds = new List <Guid>(); CollectImageFilesFromGenericGuids(regexGuidPatternNoDashes, null, extractedPageInstance.ThumbnailUrl, thumbnailFileIds); if (thumbnailFileIds.Count == 1) { var file = web.GetFileById(thumbnailFileIds[0]); web.Context.Load(file, f => f.Level, f => f.ServerRelativeUrl, f => f.UniqueId); web.Context.ExecuteQueryRetry(); // Item1 = was file added to the template // Item2 = file name (if file found) var imageAddedTuple = LoadAndAddPageImage(web, file, template, creationInfo, scope); if (imageAddedTuple.Item1) { extractedPageInstance.ThumbnailUrl = Regex.Replace(extractedPageInstance.ThumbnailUrl, file.UniqueId.ToString("N"), $"{{fileuniqueid:{file.ServerRelativeUrl.Substring(web.ServerRelativeUrl.Length).TrimStart("/".ToCharArray())}}}"); } } } // Add the sections foreach (var section in pageToExtract.Sections) { // Set order var sectionInstance = new CanvasSection() { Order = section.Order, BackgroundEmphasis = (Emphasis)section.ZoneEmphasis, }; if (section.VerticalSectionColumn != null) { sectionInstance.VerticalSectionEmphasis = (Emphasis)section.VerticalSectionColumn.VerticalSectionEmphasis; } // Set section type switch (section.Type) { case Pages.CanvasSectionTemplate.OneColumn: sectionInstance.Type = CanvasSectionType.OneColumn; break; case Pages.CanvasSectionTemplate.TwoColumn: sectionInstance.Type = CanvasSectionType.TwoColumn; break; case Pages.CanvasSectionTemplate.TwoColumnLeft: sectionInstance.Type = CanvasSectionType.TwoColumnLeft; break; case Pages.CanvasSectionTemplate.TwoColumnRight: sectionInstance.Type = CanvasSectionType.TwoColumnRight; break; case Pages.CanvasSectionTemplate.ThreeColumn: sectionInstance.Type = CanvasSectionType.ThreeColumn; break; case Pages.CanvasSectionTemplate.OneColumnFullWidth: sectionInstance.Type = CanvasSectionType.OneColumnFullWidth; break; #if !SP2019 case Pages.CanvasSectionTemplate.OneColumnVerticalSection: sectionInstance.Type = CanvasSectionType.OneColumnVerticalSection; break; case Pages.CanvasSectionTemplate.TwoColumnVerticalSection: sectionInstance.Type = CanvasSectionType.TwoColumnVerticalSection; break; case Pages.CanvasSectionTemplate.TwoColumnLeftVerticalSection: sectionInstance.Type = CanvasSectionType.TwoColumnLeftVerticalSection; break; case Pages.CanvasSectionTemplate.TwoColumnRightVerticalSection: sectionInstance.Type = CanvasSectionType.TwoColumnRightVerticalSection; break; case Pages.CanvasSectionTemplate.ThreeColumnVerticalSection: sectionInstance.Type = CanvasSectionType.ThreeColumnVerticalSection; break; #endif default: sectionInstance.Type = CanvasSectionType.OneColumn; break; } // Add controls to section foreach (var column in section.Columns) { foreach (var control in column.Controls) { // Create control CanvasControl controlInstance = new CanvasControl() { Column = column.IsVerticalSectionColumn ? section.Columns.IndexOf(column) + 1 : column.Order, ControlId = control.InstanceId, Order = control.Order, }; // Set control type if (control.Type == typeof(Pages.ClientSideText)) { controlInstance.Type = WebPartType.Text; // Set text content controlInstance.ControlProperties = new System.Collections.Generic.Dictionary <string, string>(1) { { "Text", TokenizeJsonTextData(web, (control as Pages.ClientSideText).Text) } }; } else { // set ControlId to webpart id controlInstance.ControlId = Guid.Parse((control as Pages.ClientSideWebPart).WebPartId); var webPartType = Pages.ClientSidePage.NameToClientSideWebPartEnum((control as Pages.ClientSideWebPart).WebPartId); switch (webPartType) { case Pages.DefaultClientSideWebParts.ContentRollup: controlInstance.Type = WebPartType.ContentRollup; break; #if !SP2019 case Pages.DefaultClientSideWebParts.BingMap: controlInstance.Type = WebPartType.BingMap; break; case Pages.DefaultClientSideWebParts.Button: controlInstance.Type = WebPartType.Button; break; case Pages.DefaultClientSideWebParts.CallToAction: controlInstance.Type = WebPartType.CallToAction; break; case Pages.DefaultClientSideWebParts.News: controlInstance.Type = WebPartType.News; break; case Pages.DefaultClientSideWebParts.PowerBIReportEmbed: controlInstance.Type = WebPartType.PowerBIReportEmbed; break; case Pages.DefaultClientSideWebParts.Sites: controlInstance.Type = WebPartType.Sites; break; case Pages.DefaultClientSideWebParts.GroupCalendar: controlInstance.Type = WebPartType.GroupCalendar; break; case Pages.DefaultClientSideWebParts.MicrosoftForms: controlInstance.Type = WebPartType.MicrosoftForms; break; case Pages.DefaultClientSideWebParts.ClientWebPart: controlInstance.Type = WebPartType.ClientWebPart; break; #endif case Pages.DefaultClientSideWebParts.ContentEmbed: controlInstance.Type = WebPartType.ContentEmbed; break; case Pages.DefaultClientSideWebParts.DocumentEmbed: controlInstance.Type = WebPartType.DocumentEmbed; break; case Pages.DefaultClientSideWebParts.Image: controlInstance.Type = WebPartType.Image; break; case Pages.DefaultClientSideWebParts.ImageGallery: controlInstance.Type = WebPartType.ImageGallery; break; case Pages.DefaultClientSideWebParts.LinkPreview: controlInstance.Type = WebPartType.LinkPreview; break; case Pages.DefaultClientSideWebParts.NewsFeed: controlInstance.Type = WebPartType.NewsFeed; break; case Pages.DefaultClientSideWebParts.NewsReel: controlInstance.Type = WebPartType.NewsReel; break; case Pages.DefaultClientSideWebParts.QuickChart: controlInstance.Type = WebPartType.QuickChart; break; case Pages.DefaultClientSideWebParts.SiteActivity: controlInstance.Type = WebPartType.SiteActivity; break; case Pages.DefaultClientSideWebParts.VideoEmbed: controlInstance.Type = WebPartType.VideoEmbed; break; case Pages.DefaultClientSideWebParts.YammerEmbed: controlInstance.Type = WebPartType.YammerEmbed; break; case Pages.DefaultClientSideWebParts.Events: controlInstance.Type = WebPartType.Events; break; case Pages.DefaultClientSideWebParts.Hero: controlInstance.Type = WebPartType.Hero; break; case Pages.DefaultClientSideWebParts.List: controlInstance.Type = WebPartType.List; break; case Pages.DefaultClientSideWebParts.PageTitle: controlInstance.Type = WebPartType.PageTitle; break; case Pages.DefaultClientSideWebParts.People: controlInstance.Type = WebPartType.People; break; case Pages.DefaultClientSideWebParts.QuickLinks: controlInstance.Type = WebPartType.QuickLinks; break; case Pages.DefaultClientSideWebParts.CustomMessageRegion: controlInstance.Type = WebPartType.CustomMessageRegion; break; case Pages.DefaultClientSideWebParts.Divider: controlInstance.Type = WebPartType.Divider; break; case Pages.DefaultClientSideWebParts.Spacer: controlInstance.Type = WebPartType.Spacer; break; case Pages.DefaultClientSideWebParts.ThirdParty: controlInstance.Type = WebPartType.Custom; break; default: controlInstance.Type = WebPartType.Custom; break; } if (excludeAuthorInformation) { #if !SP2019 if (webPartType == Pages.DefaultClientSideWebParts.News) { var properties = (control as Pages.ClientSideWebPart).Properties; var authorTokens = properties.SelectTokens("$..author").ToList(); foreach (var authorToken in authorTokens) { authorToken.Parent.Remove(); } var authorAccountNameTokens = properties.SelectTokens("$..authorAccountName").ToList(); foreach (var authorAccountNameToken in authorAccountNameTokens) { authorAccountNameToken.Parent.Remove(); } (control as Pages.ClientSideWebPart).PropertiesJson = properties.ToString(); } #endif } string jsonControlData = "\"id\": \"" + (control as Pages.ClientSideWebPart).WebPartId + "\", \"instanceId\": \"" + (control as Pages.ClientSideWebPart).InstanceId + "\", \"title\": " + JsonConvert.ToString((control as Pages.ClientSideWebPart).Title) + ", \"description\": " + JsonConvert.ToString((control as Pages.ClientSideWebPart).Description) + ", \"dataVersion\": \"" + (control as Pages.ClientSideWebPart).DataVersion + "\", \"properties\": " + (control as Pages.ClientSideWebPart).PropertiesJson + ""; // set the control properties if ((control as Pages.ClientSideWebPart).ServerProcessedContent != null) { // If we have serverProcessedContent then also export that one, it's important as some controls depend on this information to be present string serverProcessedContent = (control as Pages.ClientSideWebPart).ServerProcessedContent.ToString(Formatting.None); jsonControlData = jsonControlData + ", \"serverProcessedContent\": " + serverProcessedContent + ""; } if ((control as Pages.ClientSideWebPart).DynamicDataPaths != null) { // If we have serverProcessedContent then also export that one, it's important as some controls depend on this information to be present string dynamicDataPaths = (control as Pages.ClientSideWebPart).DynamicDataPaths.ToString(Formatting.None); jsonControlData = jsonControlData + ", \"dynamicDataPaths\": " + dynamicDataPaths + ""; } if ((control as Pages.ClientSideWebPart).DynamicDataValues != null) { // If we have serverProcessedContent then also export that one, it's important as some controls depend on this information to be present string dynamicDataValues = (control as Pages.ClientSideWebPart).DynamicDataValues.ToString(Formatting.None); jsonControlData = jsonControlData + ", \"dynamicDataValues\": " + dynamicDataValues + ""; } controlInstance.JsonControlData = "{" + jsonControlData + "}"; var untokenizedJsonControlData = controlInstance.JsonControlData; // Tokenize the JsonControlData controlInstance.JsonControlData = TokenizeJsonControlData(web, controlInstance.JsonControlData); // Export relevant files if this flag is set if (creationInfo.PersistBrandingFiles) { List <Guid> fileGuids = new List <Guid>(); Dictionary <string, string> exportedFiles = new Dictionary <string, string>(); Dictionary <string, string> exportedPages = new Dictionary <string, string>(); CollectSiteAssetImageFiles(regexSiteAssetUrls, web, untokenizedJsonControlData, fileGuids); CollectImageFilesFromGenericGuids(regexGuidPattern, regexGuidPatternEncoded, untokenizedJsonControlData, fileGuids); // Iterate over the found guids to see if they're exportable files foreach (var uniqueId in fileGuids) { try { if (!exportedFiles.ContainsKey(uniqueId.ToString()) && !errorneousOrNonImageFileGuids.Contains(uniqueId.ToString())) { // Try to see if this is a file var file = web.GetFileById(uniqueId); web.Context.Load(file, f => f.Level, f => f.ServerRelativeUrl); web.Context.ExecuteQueryRetry(); // Item1 = was file added to the template // Item2 = file name (if file found) var imageAddedTuple = LoadAndAddPageImage(web, file, template, creationInfo, scope); if (!string.IsNullOrEmpty(imageAddedTuple.Item2)) { if (!imageAddedTuple.Item2.EndsWith(".aspx", StringComparison.InvariantCultureIgnoreCase)) { if (imageAddedTuple.Item1) { // Keep track of the exported file path and it's UniqueId exportedFiles.Add(uniqueId.ToString(), file.ServerRelativeUrl.Substring(web.ServerRelativeUrl.Length).TrimStart("/".ToCharArray())); } } else { if (!exportedPages.ContainsKey(uniqueId.ToString())) { exportedPages.Add(uniqueId.ToString(), file.ServerRelativeUrl.Substring(web.ServerRelativeUrl.Length).TrimStart("/".ToCharArray())); } } } } } catch (Exception ex) { scope.LogWarning(CoreResources.Provisioning_ObjectHandlers_ClientSidePageContents_ErrorDuringFileExport, ex.Message); errorneousOrNonImageFileGuids.Add(uniqueId.ToString()); } } // Tokenize based on the found files, use a different token for encoded guids do we can later on replace by a new encoded guid foreach (var exportedFile in exportedFiles) { controlInstance.JsonControlData = Regex.Replace(controlInstance.JsonControlData, exportedFile.Key.Replace("-", "%2D"), $"{{fileuniqueidencoded:{exportedFile.Value}}}", RegexOptions.IgnoreCase); controlInstance.JsonControlData = Regex.Replace(controlInstance.JsonControlData, exportedFile.Key, $"{{fileuniqueid:{exportedFile.Value}}}", RegexOptions.IgnoreCase); } foreach (var exportedPage in exportedPages) { controlInstance.JsonControlData = Regex.Replace(controlInstance.JsonControlData, exportedPage.Key.Replace("-", "%2D"), $"{{pageuniqueidencoded:{exportedPage.Value}}}", RegexOptions.IgnoreCase); controlInstance.JsonControlData = Regex.Replace(controlInstance.JsonControlData, exportedPage.Key, $"{{pageuniqueid:{exportedPage.Value}}}", RegexOptions.IgnoreCase); } } } // add control to section sectionInstance.Controls.Add(controlInstance); } } extractedPageInstance.Sections.Add(sectionInstance); } // Renumber the sections...when editing modern homepages you can end up with section with order 0.5 or 0.75...let's ensure we render section as of 1 int sectionOrder = 1; foreach (var sectionInstance in extractedPageInstance.Sections) { sectionInstance.Order = sectionOrder; sectionOrder++; } // Add the page to the template template.ClientSidePages.Add(extractedPageInstance); // Set the homepage if (isHomePage) { if (template.WebSettings == null) { template.WebSettings = new WebSettings(); } if (pageUrl.StartsWith(web.ServerRelativeUrl, StringComparison.InvariantCultureIgnoreCase)) { template.WebSettings.WelcomePage = pageUrl.Replace(web.ServerRelativeUrl + "/", ""); } else { template.WebSettings.WelcomePage = pageUrl; } } } } catch (ArgumentException ex) { scope.LogWarning(CoreResources.Provisioning_ObjectHandlers_ClientSidePageContents_NoValidPage, ex.Message); } }
private bool PersistFile(Web web, ProvisioningTemplateCreationInformation creationInfo, PnPMonitoredScope scope, string serverRelativeUrl) { var success = false; if (creationInfo.PersistBrandingFiles) { if (creationInfo.FileConnector != null) { try { var file = web.GetFileByServerRelativeUrl(serverRelativeUrl); string fileName = string.Empty; if (serverRelativeUrl.IndexOf("/") > -1) { fileName = serverRelativeUrl.Substring(serverRelativeUrl.LastIndexOf("/") + 1); } else { fileName = serverRelativeUrl; } web.Context.Load(file); web.Context.ExecuteQueryRetry(); ClientResult<Stream> stream = file.OpenBinaryStream(); web.Context.ExecuteQueryRetry(); using (Stream memStream = new MemoryStream()) { CopyStream(stream.Value, memStream); memStream.Position = 0; creationInfo.FileConnector.SaveFileStream(fileName, memStream); } success = true; } catch (ServerException ex1) { // If we are referring a file from a location outside of the current web or at a location where we cannot retrieve the file an exception is thrown. We swallow this exception. if (ex1.ServerErrorCode != -2147024809) { throw; } else { scope.LogWarning("File is not necessarily located in the current web. Not retrieving {0}", serverRelativeUrl); } } } else { WriteWarning("No connector present to persist homepage.", ProvisioningMessageType.Error); scope.LogError("No connector present to persist homepage"); } } else { success = true; } return success; }
public override ProvisioningTemplate ExtractObjects(Web web, ProvisioningTemplate template, ProvisioningTemplateCreationInformation creationInfo) { if (template.Workflows == null) { template.Workflows = new Workflows(); } using (var scope = new PnPMonitoredScope(this.Name)) { if (creationInfo.FileConnector == null) { scope.LogWarning("Cannot export Workflow definitions without a FileConnector."); } else { // Pre-load useful properties web.EnsureProperties(w => w.Id, w => w.ServerRelativeUrl, w => w.Url); // Retrieve all the lists and libraries var lists = web.Lists; web.Context.Load(lists); web.Context.ExecuteQueryRetry(); // Retrieve the workflow definitions (including unpublished ones) Microsoft.SharePoint.Client.WorkflowServices.WorkflowDefinition[] definitions = null; try { definitions = web.GetWorkflowDefinitions(false); } catch (ServerException) { // If there is no workflow service present in the farm this method will throw an error. // Swallow the exception } if (definitions != null) { template.Workflows.WorkflowDefinitions.AddRange( from d in definitions.AsEnumerable() select new Model.WorkflowDefinition(d.Properties.TokenizeWorkflowDefinitionProperties(lists)) { AssociationUrl = d.AssociationUrl, Description = d.Description, DisplayName = d.DisplayName, DraftVersion = d.DraftVersion, FormField = d.FormField, Id = d.Id, InitiationUrl = d.InitiationUrl, Published = d.Published, RequiresAssociationForm = d.RequiresAssociationForm, RequiresInitiationForm = d.RequiresInitiationForm, RestrictToScope = (!String.IsNullOrEmpty(d.RestrictToScope) && Guid.Parse(d.RestrictToScope) != web.Id) ? WorkflowExtension.TokenizeListIdProperty(d.RestrictToScope, lists) : null, RestrictToType = !String.IsNullOrEmpty(d.RestrictToType) ? d.RestrictToType : "Universal", XamlPath = d.Xaml.SaveXamlToFile(d.Id, creationInfo.FileConnector, lists), } ); foreach (var d in definitions.AsEnumerable()) { if (d.RequiresInitiationForm) { PersistWorkflowForm(web, template, creationInfo, scope, d.InitiationUrl); } if (d.RequiresAssociationForm) { PersistWorkflowForm(web, template, creationInfo, scope, d.AssociationUrl); } } } // Retrieve the workflow subscriptions Microsoft.SharePoint.Client.WorkflowServices.WorkflowSubscription[] subscriptions = null; try { subscriptions = web.GetWorkflowSubscriptions(); } catch (ServerException) { // If there is no workflow service present in the farm this method will throw an error. // Swallow the exception } if (subscriptions != null) { #if ONPREMISES template.Workflows.WorkflowSubscriptions.AddRange( from s in subscriptions.AsEnumerable() select new Model.WorkflowSubscription(s.PropertyDefinitions.TokenizeWorkflowSubscriptionProperties(lists)) { DefinitionId = s.DefinitionId, Enabled = s.Enabled, EventSourceId = s.EventSourceId != web.Id ? String.Format("{{listid:{0}}}", lists.First(l => l.Id == s.EventSourceId).Title) : null, EventTypes = s.EventTypes.ToList(), ManualStartBypassesActivationLimit = s.ManualStartBypassesActivationLimit, Name = s.Name, ListId = s.EventSourceId != web.Id ? String.Format("{{listid:{0}}}", lists.First(l => l.Id == s.EventSourceId).Title) : null, StatusFieldName = s.StatusFieldName, } ); #else template.Workflows.WorkflowSubscriptions.AddRange( from s in subscriptions.AsEnumerable() select new Model.WorkflowSubscription(s.PropertyDefinitions.TokenizeWorkflowSubscriptionProperties(lists)) { DefinitionId = s.DefinitionId, Enabled = s.Enabled, EventSourceId = s.EventSourceId != web.Id ? WorkflowExtension.TokenizeListIdProperty(s.EventSourceId.ToString(), lists) : null, EventTypes = s.EventTypes.ToList(), ManualStartBypassesActivationLimit = s.ManualStartBypassesActivationLimit, Name = s.Name, ListId = s.EventSourceId != web.Id ? WorkflowExtension.TokenizeListIdProperty(s.EventSourceId.ToString(), lists) : null, ParentContentTypeId = s.ParentContentTypeId, StatusFieldName = s.StatusFieldName, } ); #endif } } } return(template); }
private Tuple<List, TokenParser> UpdateList(Web web, List existingList, ListInstance templateList, TokenParser parser, PnPMonitoredScope scope) { web.Context.Load(existingList, l => l.Title, l => l.Description, l => l.OnQuickLaunch, l => l.Hidden, l => l.ContentTypesEnabled, l => l.EnableAttachments, l => l.EnableFolderCreation, l => l.EnableMinorVersions, l => l.DraftVersionVisibility, l => l.Views #if !CLIENTSDKV15 , l => l.MajorWithMinorVersionsLimit #endif ); web.Context.ExecuteQueryRetry(); if (existingList.BaseTemplate == templateList.TemplateType) { var isDirty = false; if (parser.ParseString(templateList.Title) != existingList.Title) { existingList.Title = parser.ParseString(templateList.Title); isDirty = true; } if (!string.IsNullOrEmpty(templateList.DocumentTemplate)) { if (existingList.DocumentTemplateUrl != parser.ParseString(templateList.DocumentTemplate)) { existingList.DocumentTemplateUrl = parser.ParseString(templateList.DocumentTemplate); isDirty = true; } } if (!string.IsNullOrEmpty(templateList.Description) && templateList.Description != existingList.Description) { existingList.Description = templateList.Description; isDirty = true; } if (templateList.Hidden != existingList.Hidden) { existingList.Hidden = templateList.Hidden; isDirty = true; } if (templateList.OnQuickLaunch != existingList.OnQuickLaunch) { existingList.OnQuickLaunch = templateList.OnQuickLaunch; isDirty = true; } if (templateList.ContentTypesEnabled != existingList.ContentTypesEnabled) { existingList.ContentTypesEnabled = templateList.ContentTypesEnabled; isDirty = true; } if (existingList.BaseTemplate != (int)ListTemplateType.Survey && existingList.BaseTemplate != (int)ListTemplateType.DocumentLibrary) { // https://msdn.microsoft.com/EN-US/library/microsoft.sharepoint.splist.enableattachments.aspx // The EnableAttachments property does not apply to any list that has a base type of Survey or DocumentLibrary. // If you set this property to true for either type of list, it throws an SPException. if (templateList.EnableAttachments != existingList.EnableAttachments) { existingList.EnableAttachments = templateList.EnableAttachments; isDirty = true; } } if (existingList.BaseTemplate != (int)ListTemplateType.DiscussionBoard) { if (templateList.EnableFolderCreation != existingList.EnableFolderCreation) { existingList.EnableFolderCreation = templateList.EnableFolderCreation; isDirty = true; } } if (templateList.EnableVersioning) { if (existingList.EnableVersioning != templateList.EnableVersioning) { existingList.EnableVersioning = templateList.EnableVersioning; isDirty = true; } #if !CLIENTSDKV15 if (existingList.IsObjectPropertyInstantiated("MajorVersionLimit") && existingList.MajorVersionLimit != templateList.MaxVersionLimit) { existingList.MajorVersionLimit = templateList.MaxVersionLimit; isDirty = true; } #endif if (existingList.BaseTemplate == (int)ListTemplateType.DocumentLibrary) { // Only supported on Document Libraries if (templateList.EnableMinorVersions != existingList.EnableMinorVersions) { existingList.EnableMinorVersions = templateList.EnableMinorVersions; isDirty = true; } if ((DraftVisibilityType)templateList.DraftVersionVisibility != existingList.DraftVersionVisibility) { existingList.DraftVersionVisibility = (DraftVisibilityType)templateList.DraftVersionVisibility; isDirty = true; } if (templateList.EnableMinorVersions) { if (templateList.MinorVersionLimit != existingList.MajorWithMinorVersionsLimit) { existingList.MajorWithMinorVersionsLimit = templateList.MinorVersionLimit; } if (DraftVisibilityType.Approver == (DraftVisibilityType)templateList.DraftVersionVisibility) { if (templateList.EnableModeration) { if ((DraftVisibilityType)templateList.DraftVersionVisibility != existingList.DraftVersionVisibility) { existingList.DraftVersionVisibility = (DraftVisibilityType)templateList.DraftVersionVisibility; isDirty = true; } } } else { if ((DraftVisibilityType)templateList.DraftVersionVisibility != existingList.DraftVersionVisibility) { existingList.DraftVersionVisibility = (DraftVisibilityType)templateList.DraftVersionVisibility; isDirty = true; } } } } } if (isDirty) { existingList.Update(); web.Context.ExecuteQueryRetry(); } if (existingList.ContentTypesEnabled) { // Check if we need to add a content type var existingContentTypes = existingList.ContentTypes; web.Context.Load(existingContentTypes, cts => cts.Include(ct => ct.StringId)); web.Context.ExecuteQueryRetry(); var bindingsToAdd = templateList.ContentTypeBindings.Where(ctb => existingContentTypes.All(ct => !ctb.ContentTypeId.Equals(ct.StringId, StringComparison.InvariantCultureIgnoreCase))).ToList(); var defaultCtBinding = templateList.ContentTypeBindings.FirstOrDefault(ctb => ctb.Default == true); foreach (var ctb in bindingsToAdd) { existingList.AddContentTypeToListById(ctb.ContentTypeId, searchContentTypeInSiteHierarchy: true); } // default ContentTypeBinding should be set last because // list extension .SetDefaultContentTypeToList() re-sets // the list.RootFolder UniqueContentTypeOrder property // which may cause missing CTs from the "New Button" if (defaultCtBinding != null) { existingList.SetDefaultContentTypeToList(defaultCtBinding.ContentTypeId); } } if (templateList.Security != null) { existingList.SetSecurity(parser, templateList.Security); } return Tuple.Create(existingList, parser); } else { scope.LogWarning(CoreResources.Provisioning_ObjectHandlers_ListInstances_List__0____1____2___exists_but_is_of_a_different_type__Skipping_list_, templateList.Title, templateList.Url, existingList.Id); WriteWarning(string.Format(CoreResources.Provisioning_ObjectHandlers_ListInstances_List__0____1____2___exists_but_is_of_a_different_type__Skipping_list_, templateList.Title, templateList.Url, existingList.Id), ProvisioningMessageType.Warning); return null; } }
public override TokenParser ProvisionObjects(Web web, ProvisioningTemplate template, TokenParser parser, ProvisioningTemplateApplyingInformation applyingInformation) { using (var scope = new PnPMonitoredScope(this.Name)) { if (template.Navigation != null) { if (!WebSupportsProvisionNavigation(web, template)) { scope.LogDebug(CoreResources.Provisioning_ObjectHandlers_Navigation_Context_web_is_not_publishing); return(parser); } // Check if this is not a noscript site as navigation features are not supported if (web.IsNoScriptSite()) { scope.LogWarning(CoreResources.Provisioning_ObjectHandlers_Navigation_SkipProvisioning); return(parser); } // Retrieve the current web navigation settings var navigationSettings = new WebNavigationSettings(web.Context, web); web.Context.Load(navigationSettings, ns => ns.CurrentNavigation, ns => ns.GlobalNavigation); web.Context.ExecuteQueryRetry(); if (template.Navigation.GlobalNavigation != null) { switch (template.Navigation.GlobalNavigation.NavigationType) { case GlobalNavigationType.Inherit: navigationSettings.GlobalNavigation.Source = StandardNavigationSource.InheritFromParentWeb; web.Navigation.UseShared = true; break; case GlobalNavigationType.Managed: if (template.Navigation.GlobalNavigation.ManagedNavigation == null) { throw new ApplicationException(CoreResources.Provisioning_ObjectHandlers_Navigation_missing_global_managed_navigation); } navigationSettings.GlobalNavigation.Source = StandardNavigationSource.TaxonomyProvider; navigationSettings.GlobalNavigation.TermStoreId = Guid.Parse(parser.ParseString(template.Navigation.GlobalNavigation.ManagedNavigation.TermStoreId)); navigationSettings.GlobalNavigation.TermSetId = Guid.Parse(parser.ParseString(template.Navigation.GlobalNavigation.ManagedNavigation.TermSetId)); break; case GlobalNavigationType.Structural: default: if (template.Navigation.GlobalNavigation.StructuralNavigation == null) { throw new ApplicationException(CoreResources.Provisioning_ObjectHandlers_Navigation_missing_global_structural_navigation); } ProvisionGlobalStructuralNavigation(web, template.Navigation.GlobalNavigation.StructuralNavigation, parser, applyingInformation.ClearNavigation, scope); break; } web.Context.ExecuteQueryRetry(); } if (template.Navigation.CurrentNavigation != null) { switch (template.Navigation.CurrentNavigation.NavigationType) { case CurrentNavigationType.Inherit: navigationSettings.CurrentNavigation.Source = StandardNavigationSource.InheritFromParentWeb; break; case CurrentNavigationType.Managed: if (template.Navigation.CurrentNavigation.ManagedNavigation == null) { throw new ApplicationException(CoreResources.Provisioning_ObjectHandlers_Navigation_missing_current_managed_navigation); } navigationSettings.CurrentNavigation.Source = StandardNavigationSource.TaxonomyProvider; navigationSettings.CurrentNavigation.TermStoreId = Guid.Parse(parser.ParseString(template.Navigation.CurrentNavigation.ManagedNavigation.TermStoreId)); navigationSettings.CurrentNavigation.TermSetId = Guid.Parse(parser.ParseString(template.Navigation.CurrentNavigation.ManagedNavigation.TermSetId)); break; case CurrentNavigationType.StructuralLocal: web.SetPropertyBagValue(NavigationShowSiblings, "false"); if (template.Navigation.CurrentNavigation.StructuralNavigation == null) { throw new ApplicationException(CoreResources.Provisioning_ObjectHandlers_Navigation_missing_current_structural_navigation); } ProvisionCurrentStructuralNavigation(web, template.Navigation.CurrentNavigation.StructuralNavigation, parser, applyingInformation.ClearNavigation, scope); break; case CurrentNavigationType.Structural: default: if (template.Navigation.CurrentNavigation.StructuralNavigation == null) { throw new ApplicationException(CoreResources.Provisioning_ObjectHandlers_Navigation_missing_current_structural_navigation); } ProvisionCurrentStructuralNavigation(web, template.Navigation.CurrentNavigation.StructuralNavigation, parser, applyingInformation.ClearNavigation, scope); break; } web.Context.ExecuteQueryRetry(); } } } return(parser); }
public override ProvisioningTemplate ExtractObjects(Web web, ProvisioningTemplate template, ProvisioningTemplateCreationInformation creationInfo) { if (template.Workflows == null) { template.Workflows = new Workflows(); } using (var scope = new PnPMonitoredScope(this.Name)) { if (creationInfo.FileConnector == null) { scope.LogWarning("Cannot export Workflow definitions without a FileConnector."); } else { // Pre-load useful properties web.EnsureProperty(w => w.Id); // Retrieve all the lists and libraries var lists = web.Lists; web.Context.Load(lists); web.Context.ExecuteQuery(); // Retrieve the workflow definitions (including unpublished ones) Microsoft.SharePoint.Client.WorkflowServices.WorkflowDefinition[] definitions = null; try { definitions = web.GetWorkflowDefinitions(false); } catch (ServerException) { // If there is no workflow service present in the farm this method will throw an error. // Swallow the exception } if (definitions != null) { template.Workflows.WorkflowDefinitions.AddRange( from d in definitions select new Model.WorkflowDefinition(d.Properties.TokenizeWorkflowDefinitionProperties(lists)) { AssociationUrl = d.AssociationUrl, Description = d.Description, DisplayName = d.DisplayName, DraftVersion = d.DraftVersion, FormField = d.FormField, Id = d.Id, InitiationUrl = d.InitiationUrl, Published = d.Published, RequiresAssociationForm = d.RequiresAssociationForm, RequiresInitiationForm = d.RequiresInitiationForm, RestrictToScope = (!String.IsNullOrEmpty(d.RestrictToScope) && Guid.Parse(d.RestrictToScope) != web.Id) ? WorkflowExtension.TokenizeListIdProperty(d.RestrictToScope, lists) : null, RestrictToType = !String.IsNullOrEmpty(d.RestrictToType) ? d.RestrictToType : "Universal", XamlPath = d.Xaml.SaveXamlToFile(d.Id, creationInfo.FileConnector), } ); } // Retrieve the workflow subscriptions Microsoft.SharePoint.Client.WorkflowServices.WorkflowSubscription[] subscriptions = null; try { subscriptions = web.GetWorkflowSubscriptions(); } catch (ServerException) { // If there is no workflow service present in the farm this method will throw an error. // Swallow the exception } if (subscriptions != null) { #if CLIENTSDKV15 template.Workflows.WorkflowSubscriptions.AddRange( from s in subscriptions select new Model.WorkflowSubscription(s.PropertyDefinitions.TokenizeWorkflowSubscriptionProperties(lists)) { DefinitionId = s.DefinitionId, Enabled = s.Enabled, EventSourceId = s.EventSourceId != web.Id ? String.Format("{{listid:{0}}}", lists.First(l => l.Id == s.EventSourceId).Title) : null, EventTypes = s.EventTypes.ToList(), ManualStartBypassesActivationLimit = s.ManualStartBypassesActivationLimit, Name = s.Name, ListId = s.EventSourceId != web.Id ? String.Format("{{listid:{0}}}", lists.First(l => l.Id == s.EventSourceId).Title) : null, StatusFieldName = s.StatusFieldName, } ); #else template.Workflows.WorkflowSubscriptions.AddRange( from s in subscriptions select new Model.WorkflowSubscription(s.PropertyDefinitions.TokenizeWorkflowSubscriptionProperties(lists)) { DefinitionId = s.DefinitionId, Enabled = s.Enabled, EventSourceId = s.EventSourceId != web.Id ? WorkflowExtension.TokenizeListIdProperty(s.EventSourceId.ToString(), lists) : null, EventTypes = s.EventTypes.ToList(), ManualStartBypassesActivationLimit = s.ManualStartBypassesActivationLimit, Name = s.Name, ListId = s.EventSourceId != web.Id ? WorkflowExtension.TokenizeListIdProperty(s.EventSourceId.ToString(), lists) : null, ParentContentTypeId = s.ParentContentTypeId, StatusFieldName = s.StatusFieldName, } ); #endif } } } return template; }
public override TokenParser ProvisionObjects(Web web, ProvisioningTemplate template, TokenParser parser, ProvisioningTemplateApplyingInformation applyingInformation) { using (var scope = new PnPMonitoredScope(this.Name)) { // Check if this is not a noscript site as we're not allowed to update some properties bool isNoScriptSite = web.IsNoScriptSite(); web.Context.Load(web.ContentTypes, ct => ct.IncludeWithDefaultProperties(c => c.StringId, c => c.FieldLinks, c => c.FieldLinks.Include(fl => fl.Id, fl => fl.Required, fl => fl.Hidden))); web.Context.Load(web.Fields, fld => fld.IncludeWithDefaultProperties(f => f.Id)); web.Context.ExecuteQueryRetry(); var existingCTs = web.ContentTypes.ToList(); var existingFields = web.Fields.ToList(); var currentCtIndex = 0; var doProvision = true; if (web.IsSubSite() && !applyingInformation.ProvisionContentTypesToSubWebs) { WriteMessage("This template contains content types and you are provisioning to a subweb. If you still want to provision these content types, set the ProvisionContentTypesToSubWebs property to true.", ProvisioningMessageType.Warning); doProvision = false; } if (doProvision) { foreach (var ct in template.ContentTypes.OrderBy(ct => ct.Id)) // ordering to handle references to parent content types that can be in the same template { currentCtIndex++; WriteMessage($"Content Type|{ct.Name}|{currentCtIndex}|{template.ContentTypes.Count}", ProvisioningMessageType.Progress); var existingCT = existingCTs.FirstOrDefault(c => c.StringId.Equals(ct.Id, StringComparison.OrdinalIgnoreCase)); if (existingCT == null) { scope.LogDebug(CoreResources.Provisioning_ObjectHandlers_ContentTypes_Creating_new_Content_Type___0_____1_, ct.Id, ct.Name); var newCT = CreateContentType(web, ct, parser, template.Connector ?? null, scope, existingCTs, existingFields, isNoScriptSite); if (newCT != null) { existingCTs.Add(newCT); } } else { if (ct.Overwrite) { scope.LogDebug(CoreResources.Provisioning_ObjectHandlers_ContentTypes_Recreating_existing_Content_Type___0_____1_, ct.Id, ct.Name); existingCT.DeleteObject(); web.Context.ExecuteQueryRetry(); var newCT = CreateContentType(web, ct, parser, template.Connector ?? null, scope, existingCTs, existingFields, isNoScriptSite); if (newCT != null) { existingCTs.Add(newCT); } } else { // We can't update a sealed content type unless we change sealed to false if (!existingCT.Sealed || !ct.Sealed) { scope.LogDebug(CoreResources.Provisioning_ObjectHandlers_ContentTypes_Updating_existing_Content_Type___0_____1_, ct.Id, ct.Name); UpdateContentType(web, existingCT, ct, parser, scope); } else { scope.LogWarning(CoreResources.Provisioning_ObjectHandlers_ContentTypes_Updating_existing_Content_Type_Sealed, ct.Id, ct.Name); } } } } } } WriteMessage($"Done processing Content Types", ProvisioningMessageType.Completed); return(parser); }
private Field UpdateField(ClientObject web, ListInfo listInfo, Guid fieldId, XElement templateFieldElement, Field existingField, PnPMonitoredScope scope, TokenParser parser, string originalFieldXml) { Field field = null; web.Context.Load(existingField, f => f.SchemaXmlWithResourceTokens); web.Context.ExecuteQueryRetry(); var existingFieldElement = XElement.Parse(existingField.SchemaXmlWithResourceTokens); var equalityComparer = new XNodeEqualityComparer(); // Is field different in template? if (equalityComparer.GetHashCode(existingFieldElement) != equalityComparer.GetHashCode(templateFieldElement)) { // Is existing field of the same type? if (existingFieldElement.Attribute("Type").Value == templateFieldElement.Attribute("Type").Value) { templateFieldElement = PrepareField(templateFieldElement); if (IsFieldXmlValid(parser.ParseString(templateFieldElement.ToString()), parser, web.Context)) { foreach (var attribute in templateFieldElement.Attributes()) { if (existingFieldElement.Attribute(attribute.Name) != null) { existingFieldElement.Attribute(attribute.Name).Value = attribute.Value; } else { existingFieldElement.Add(attribute); } } foreach (var element in templateFieldElement.Elements()) { if (existingFieldElement.Element(element.Name) != null) { existingFieldElement.Element(element.Name).Remove(); } existingFieldElement.Add(element); } if (existingFieldElement.Attribute("Version") != null) { existingFieldElement.Attributes("Version").Remove(); } existingField.SchemaXml = parser.ParseString(existingFieldElement.ToString(), "~sitecollection", "~site"); existingField.UpdateAndPushChanges(true); web.Context.ExecuteQueryRetry(); bool isDirty = false; #if !SP2013 if (originalFieldXml.ContainsResourceToken()) { var originalFieldElement = XElement.Parse(originalFieldXml); var nameAttributeValue = originalFieldElement.Attribute("DisplayName") != null ? originalFieldElement.Attribute("DisplayName").Value : ""; if (nameAttributeValue.ContainsResourceToken()) { if (existingField.TitleResource.SetUserResourceValue(nameAttributeValue, parser)) { isDirty = true; } } var descriptionAttributeValue = originalFieldElement.Attribute("Description") != null ? originalFieldElement.Attribute("Description").Value : ""; if (descriptionAttributeValue.ContainsResourceToken()) { if (existingField.DescriptionResource.SetUserResourceValue(descriptionAttributeValue, parser)) { isDirty = true; } } } #endif if (isDirty) { existingField.Update(); web.Context.ExecuteQueryRetry(); field = existingField; } } else { // The field Xml was found invalid var tokenString = parser.GetLeftOverTokens(originalFieldXml).Aggregate(String.Empty, (acc, i) => acc + " " + i); scope.LogError("The field was found invalid: {0}", tokenString); throw new Exception(string.Format("The field was found invalid: {0}", tokenString)); } } else { var fieldName = existingFieldElement.Attribute("Name") != null ? existingFieldElement.Attribute("Name").Value : existingFieldElement.Attribute("StaticName").Value; scope.LogWarning(CoreResources.Provisioning_ObjectHandlers_ListInstances_Field__0____1___exists_in_list__2____3___but_is_of_different_type__Skipping_field_, fieldName, fieldId, listInfo.TemplateList.Title, listInfo.SiteList.Id); WriteWarning(string.Format(CoreResources.Provisioning_ObjectHandlers_ListInstances_Field__0____1___exists_in_list__2____3___but_is_of_different_type__Skipping_field_, fieldName, fieldId, listInfo.TemplateList.Title, listInfo.SiteList.Id), ProvisioningMessageType.Warning); } } return field; }
public override ProvisioningTemplate ExtractObjects(Web web, ProvisioningTemplate template, ProvisioningTemplateCreationInformation creationInfo) { using (var scope = new PnPMonitoredScope(this.Name)) { // Extract the Home Page web.EnsureProperties(w => w.RootFolder.WelcomePage, w => w.ServerRelativeUrl, w => w.Url); var homePageUrl = web.RootFolder.WelcomePage; var homepageName = System.IO.Path.GetFileName(web.RootFolder.WelcomePage); if (string.IsNullOrEmpty(homepageName)) { homepageName = "Home.aspx"; } try { var homePage = web.LoadClientSidePage(homepageName); if (homePage.Sections.Count == 0 && homePage.Controls.Count == 0) { // This is default home page which was not customized...and as such there's no page definition stored in the list item. We don't need to extact this page. scope.LogInfo(CoreResources.Provisioning_ObjectHandlers_ClientSidePageContents_DefaultHomePage); } else { // Create the page var homePageInstance = new ClientSidePage() { PageName = homepageName, PromoteAsNewsArticle = false, Overwrite = false, }; // Add the sections foreach (var section in homePage.Sections) { // Set order var sectionInstance = new CanvasSection() { Order = section.Order, }; // Set section type switch (section.Type) { case Pages.CanvasSectionTemplate.OneColumn: sectionInstance.Type = CanvasSectionType.OneColumn; break; case Pages.CanvasSectionTemplate.TwoColumn: sectionInstance.Type = CanvasSectionType.TwoColumn; break; case Pages.CanvasSectionTemplate.TwoColumnLeft: sectionInstance.Type = CanvasSectionType.TwoColumnLeft; break; case Pages.CanvasSectionTemplate.TwoColumnRight: sectionInstance.Type = CanvasSectionType.TwoColumnRight; break; case Pages.CanvasSectionTemplate.ThreeColumn: sectionInstance.Type = CanvasSectionType.ThreeColumn; break; case Pages.CanvasSectionTemplate.OneColumnFullWidth: sectionInstance.Type = CanvasSectionType.OneColumnFullWidth; break; default: sectionInstance.Type = CanvasSectionType.OneColumn; break; } // Add controls to section foreach (var column in section.Columns) { foreach (var control in column.Controls) { // Create control CanvasControl controlInstance = new CanvasControl() { Column = column.Order, ControlId = control.InstanceId, Order = control.Order, }; // Set control type if (control.Type == typeof(Pages.ClientSideText)) { controlInstance.Type = WebPartType.Text; // Set text content controlInstance.ControlProperties = new System.Collections.Generic.Dictionary <string, string>(1) { { "Text", (control as Pages.ClientSideText).Text } }; } else { // set ControlId to webpart id controlInstance.ControlId = Guid.Parse((control as Pages.ClientSideWebPart).WebPartId); var webPartType = Pages.ClientSidePage.NameToClientSideWebPartEnum((control as Pages.ClientSideWebPart).WebPartId); switch (webPartType) { case Pages.DefaultClientSideWebParts.ContentRollup: controlInstance.Type = WebPartType.ContentRollup; break; case Pages.DefaultClientSideWebParts.BingMap: controlInstance.Type = WebPartType.BingMap; break; case Pages.DefaultClientSideWebParts.ContentEmbed: controlInstance.Type = WebPartType.ContentEmbed; break; case Pages.DefaultClientSideWebParts.DocumentEmbed: controlInstance.Type = WebPartType.DocumentEmbed; break; case Pages.DefaultClientSideWebParts.Image: controlInstance.Type = WebPartType.Image; break; case Pages.DefaultClientSideWebParts.ImageGallery: controlInstance.Type = WebPartType.ImageGallery; break; case Pages.DefaultClientSideWebParts.LinkPreview: controlInstance.Type = WebPartType.LinkPreview; break; case Pages.DefaultClientSideWebParts.NewsFeed: controlInstance.Type = WebPartType.NewsFeed; break; case Pages.DefaultClientSideWebParts.NewsReel: controlInstance.Type = WebPartType.NewsReel; break; case Pages.DefaultClientSideWebParts.PowerBIReportEmbed: controlInstance.Type = WebPartType.PowerBIReportEmbed; break; case Pages.DefaultClientSideWebParts.QuickChart: controlInstance.Type = WebPartType.QuickChart; break; case Pages.DefaultClientSideWebParts.SiteActivity: controlInstance.Type = WebPartType.SiteActivity; break; case Pages.DefaultClientSideWebParts.VideoEmbed: controlInstance.Type = WebPartType.VideoEmbed; break; case Pages.DefaultClientSideWebParts.YammerEmbed: controlInstance.Type = WebPartType.YammerEmbed; break; case Pages.DefaultClientSideWebParts.Events: controlInstance.Type = WebPartType.Events; break; case Pages.DefaultClientSideWebParts.GroupCalendar: controlInstance.Type = WebPartType.GroupCalendar; break; case Pages.DefaultClientSideWebParts.Hero: controlInstance.Type = WebPartType.Hero; break; case Pages.DefaultClientSideWebParts.List: controlInstance.Type = WebPartType.List; break; case Pages.DefaultClientSideWebParts.PageTitle: controlInstance.Type = WebPartType.PageTitle; break; case Pages.DefaultClientSideWebParts.People: controlInstance.Type = WebPartType.People; break; case Pages.DefaultClientSideWebParts.QuickLinks: controlInstance.Type = WebPartType.QuickLinks; break; case Pages.DefaultClientSideWebParts.ThirdParty: controlInstance.Type = WebPartType.Custom; break; default: controlInstance.Type = WebPartType.Custom; break; } // set the control properties controlInstance.JsonControlData = (control as Pages.ClientSideWebPart).PropertiesJson; // Tokenize the JsonControlData controlInstance.JsonControlData = TokenizeJsonControlData(web, controlInstance.JsonControlData); } // add control to section sectionInstance.Controls.Add(controlInstance); } } homePageInstance.Sections.Add(sectionInstance); } // Renumber the sections...when editing modern homepages you can end up with section with order 0.5 or 0.75...let's ensure we render section as of 1 int sectionOrder = 1; foreach (var sectionInstance in homePageInstance.Sections) { sectionInstance.Order = sectionOrder; sectionOrder++; } // Add the page to the template template.ClientSidePages.Add(homePageInstance); // Set the homepage if (template.WebSettings == null) { template.WebSettings = new WebSettings(); } template.WebSettings.WelcomePage = homePageUrl; } } catch (ArgumentException ex) { scope.LogWarning(CoreResources.Provisioning_ObjectHandlers_ClientSidePageContents_NoValidPage, ex.Message); } // If a base template is specified then use that one to "cleanup" the generated template model if (creationInfo.BaseTemplate != null) { template = CleanupEntities(template, creationInfo.BaseTemplate); } } return(template); }
private Tuple<List, TokenParser> CreateList(Web web, ListInstance list, TokenParser parser, PnPMonitoredScope scope, bool isNoScriptSite = false) { List createdList; if (list.Url.Equals("SiteAssets") && list.TemplateType == (int)ListTemplateType.DocumentLibrary) { //Ensure that the Site Assets library is created using the out of the box creation mechanism //Site Assets that are created using the EnsureSiteAssetsLibrary method slightly differ from //default Document Libraries. See issue 512 (https://github.com/OfficeDev/PnP-Sites-Core/issues/512) //for details about the issue fixed by this approach. createdList = web.Lists.EnsureSiteAssetsLibrary(); //Check that Title and Description have the correct values web.Context.Load(createdList, l => l.Title, l => l.Description); web.Context.ExecuteQueryRetry(); var isDirty = false; if (!string.Equals(createdList.Description, list.Description)) { createdList.Description = list.Description; isDirty = true; } if (!string.Equals(createdList.Title, list.Title)) { createdList.Title = list.Title; isDirty = true; } if (isDirty) { createdList.Update(); web.Context.ExecuteQueryRetry(); } } else { var listCreate = new ListCreationInformation(); listCreate.Description = list.Description; listCreate.TemplateType = list.TemplateType; listCreate.Title = parser.ParseString(list.Title); // the line of code below doesn't add the list to QuickLaunch // the OnQuickLaunch property is re-set on the Created List object listCreate.QuickLaunchOption = list.OnQuickLaunch ? QuickLaunchOptions.On : QuickLaunchOptions.Off; listCreate.Url = parser.ParseString(list.Url); listCreate.TemplateFeatureId = list.TemplateFeatureID; createdList = web.Lists.Add(listCreate); createdList.Update(); } web.Context.Load(createdList, l => l.BaseTemplate); web.Context.ExecuteQueryRetry(); #if !SP2013 if (list.Title.ContainsResourceToken()) { createdList.TitleResource.SetUserResourceValue(list.Title, parser); } if (list.Description.ContainsResourceToken()) { createdList.DescriptionResource.SetUserResourceValue(list.Description, parser); } #endif if (!String.IsNullOrEmpty(list.DocumentTemplate)) { createdList.DocumentTemplateUrl = parser.ParseString(list.DocumentTemplate); } // EnableAttachments are not supported for DocumentLibraries, Survey and PictureLibraries // TODO: the user should be warned if (createdList.BaseTemplate != (int)ListTemplateType.DocumentLibrary && createdList.BaseTemplate != (int)ListTemplateType.Survey && createdList.BaseTemplate != (int)ListTemplateType.PictureLibrary) { createdList.EnableAttachments = list.EnableAttachments; } createdList.EnableModeration = list.EnableModeration; createdList.ForceCheckout = list.ForceCheckout; // Done for all other lists than for Survey - With Surveys versioning configuration will cause an exception if (createdList.BaseTemplate != (int)ListTemplateType.Survey) { createdList.EnableVersioning = list.EnableVersioning; if (list.EnableVersioning) { #if !SP2013 createdList.MajorVersionLimit = list.MaxVersionLimit; #endif // DraftVisibilityType.Approver is available only when the EnableModeration option of the list is true if (DraftVisibilityType.Approver == (DraftVisibilityType)list.DraftVersionVisibility) { if (list.EnableModeration) { createdList.DraftVersionVisibility = (DraftVisibilityType)list.DraftVersionVisibility; } else { scope.LogWarning(CoreResources.Provisioning_ObjectHandlers_ListInstances_DraftVersionVisibility_not_applied_because_EnableModeration_is_not_set_to_true); WriteWarning(CoreResources.Provisioning_ObjectHandlers_ListInstances_DraftVersionVisibility_not_applied_because_EnableModeration_is_not_set_to_true, ProvisioningMessageType.Warning); } } else { createdList.DraftVersionVisibility = (DraftVisibilityType)list.DraftVersionVisibility; } if (createdList.BaseTemplate == (int)ListTemplateType.DocumentLibrary) { // Only supported on Document Libraries createdList.EnableMinorVersions = list.EnableMinorVersions; createdList.DraftVersionVisibility = (DraftVisibilityType)list.DraftVersionVisibility; if (list.EnableMinorVersions) { createdList.MajorWithMinorVersionsLimit = list.MinorVersionLimit; // Set only if enabled, otherwise you'll get exception due setting value to zero. } } } } createdList.OnQuickLaunch = list.OnQuickLaunch; if (createdList.BaseTemplate != (int)ListTemplateType.DiscussionBoard && createdList.BaseTemplate != (int)ListTemplateType.Events) { createdList.EnableFolderCreation = list.EnableFolderCreation; } createdList.Hidden = list.Hidden; if (createdList.BaseTemplate != (int)ListTemplateType.Survey) { createdList.ContentTypesEnabled = list.ContentTypesEnabled; } createdList.Update(); web.Context.Load(createdList.Views); web.Context.Load(createdList, l => l.Id); web.Context.Load(createdList, l => l.RootFolder.ServerRelativeUrl); web.Context.Load(createdList.ContentTypes); web.Context.ExecuteQueryRetry(); if (createdList.BaseTemplate != (int)ListTemplateType.Survey) { // Remove existing content types only if there are custom content type bindings var contentTypesToRemove = new List<ContentType>(); if (list.RemoveExistingContentTypes && list.ContentTypeBindings.Count > 0) { contentTypesToRemove.AddRange(createdList.ContentTypes); } ContentTypeBinding defaultCtBinding = null; foreach (var ctBinding in list.ContentTypeBindings) { var tempCT = web.GetContentTypeById(ctBinding.ContentTypeId, searchInSiteHierarchy: true); if (tempCT != null) { // Get the name of the existing CT var name = tempCT.EnsureProperty(ct => ct.Name); // If the CT does not exist in the target list, and we don't have to remove it if (!createdList.ContentTypeExistsByName(name) && !ctBinding.Remove) { // Then add it to the target list createdList.AddContentTypeToListById(ctBinding.ContentTypeId, searchContentTypeInSiteHierarchy: true); } // Else if the CT exists in the target list, and we have to remove it else if (createdList.ContentTypeExistsByName(name) && ctBinding.Remove) { // Then remove it from the target list createdList.RemoveContentTypeByName(name); } if (ctBinding.Default) { defaultCtBinding = ctBinding; } } } // default ContentTypeBinding should be set last because // list extension .SetDefaultContentTypeToList() re-sets // the list.RootFolder UniqueContentTypeOrder property // which may cause missing CTs from the "New Button" if (defaultCtBinding != null) { createdList.SetDefaultContentTypeToList(defaultCtBinding.ContentTypeId); } // Effectively remove existing content types, if any foreach (var ct in contentTypesToRemove) { var shouldDelete = true; shouldDelete &= (createdList.BaseTemplate != (int)ListTemplateType.DocumentLibrary || !ct.StringId.StartsWith(BuiltInContentTypeId.Folder + "00")); if (shouldDelete) { ct.DeleteObject(); web.Context.ExecuteQueryRetry(); } } } // Add any custom action if (list.UserCustomActions.Any()) { if (!isNoScriptSite) { foreach (var userCustomAction in list.UserCustomActions) { CreateListCustomAction(createdList, parser, userCustomAction); } web.Context.ExecuteQueryRetry(); } else { scope.LogWarning(CoreResources.Provisioning_ObjectHandlers_ListInstances_SkipAddingOrUpdatingCustomActions); } } if (list.Security != null) { createdList.SetSecurity(parser, list.Security); } return Tuple.Create(createdList, parser); }
/// <summary> /// Actual implementation of the apply templates /// </summary> /// <param name="web"></param> /// <param name="template"></param> /// <param name="provisioningInfo"></param> /// <param name="calledFromHierarchy"></param> /// <param name="tokenParser"></param> internal void ApplyRemoteTemplate(Web web, ProvisioningTemplate template, ProvisioningTemplateApplyingInformation provisioningInfo, bool calledFromHierarchy = false, TokenParser tokenParser = null) { using (var scope = new PnPMonitoredScope(CoreResources.Provisioning_ObjectHandlers_Provisioning)) { #if !SP2013 web.Context.DisableReturnValueCache = true; #endif ProvisioningProgressDelegate progressDelegate = null; ProvisioningMessagesDelegate messagesDelegate = null; ProvisioningSiteProvisionedDelegate siteProvisionedDelegate = null; if (provisioningInfo != null) { if (provisioningInfo.OverwriteSystemPropertyBagValues == true) { scope.LogInfo(CoreResources.SiteToTemplateConversion_ApplyRemoteTemplate_OverwriteSystemPropertyBagValues_is_to_true); } progressDelegate = provisioningInfo.ProgressDelegate; if (provisioningInfo.ProgressDelegate != null) { scope.LogInfo(CoreResources.SiteToTemplateConversion_ProgressDelegate_registered); } messagesDelegate = provisioningInfo.MessagesDelegate; if (provisioningInfo.MessagesDelegate != null) { scope.LogInfo(CoreResources.SiteToTemplateConversion_MessagesDelegate_registered); } siteProvisionedDelegate = provisioningInfo.SiteProvisionedDelegate; } else { // When no provisioning info was passed then we want to execute all handlers provisioningInfo = new ProvisioningTemplateApplyingInformation(); provisioningInfo.HandlersToProcess = Handlers.All; } // Check if scope is present and if so, matches the current site. When scope was not set the returned value will be ProvisioningTemplateScope.Undefined if (template.Scope == ProvisioningTemplateScope.RootSite) { if (web.IsSubSite()) { scope.LogError(CoreResources.SiteToTemplateConversion_ScopeOfTemplateDoesNotMatchTarget); throw new Exception(CoreResources.SiteToTemplateConversion_ScopeOfTemplateDoesNotMatchTarget); } } var currentCultureInfoValue = System.Threading.Thread.CurrentThread.CurrentCulture.LCID; if (!string.IsNullOrEmpty(template.TemplateCultureInfo)) { int cultureInfoValue = System.Threading.Thread.CurrentThread.CurrentCulture.LCID; if (int.TryParse(template.TemplateCultureInfo, out cultureInfoValue)) { System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo(cultureInfoValue); } else { System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo(template.TemplateCultureInfo); } } // Check if the target site shares the same base template with the template's source site var targetSiteTemplateId = web.GetBaseTemplateId(); if (!String.IsNullOrEmpty(targetSiteTemplateId) && !String.IsNullOrEmpty(template.BaseSiteTemplate)) { if (!targetSiteTemplateId.Equals(template.BaseSiteTemplate, StringComparison.InvariantCultureIgnoreCase)) { var templatesNotMatchingWarning = String.Format(CoreResources.Provisioning_Asymmetric_Base_Templates, template.BaseSiteTemplate, targetSiteTemplateId); scope.LogWarning(templatesNotMatchingWarning); messagesDelegate?.Invoke(templatesNotMatchingWarning, ProvisioningMessageType.Warning); } } // Always ensure the Url property is loaded. In the tokens we need this and we don't want to call ExecuteQuery as this can // impact delta scenarions (calling ExecuteQuery before the planned update is called) web.EnsureProperty(w => w.Url); List <ObjectHandlerBase> objectHandlers = new List <ObjectHandlerBase>(); if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.RegionalSettings)) { objectHandlers.Add(new ObjectRegionalSettings()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.SupportedUILanguages)) { objectHandlers.Add(new ObjectSupportedUILanguages()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.AuditSettings)) { objectHandlers.Add(new ObjectAuditSettings()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.SitePolicy)) { objectHandlers.Add(new ObjectSitePolicy()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.SiteSecurity)) { objectHandlers.Add(new ObjectSiteSecurity()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.Features)) { objectHandlers.Add(new ObjectFeatures()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.TermGroups)) { objectHandlers.Add(new ObjectTermGroups()); } // Process 3 times these providers to handle proper ordering of artefact creation when dealing with lookup fields // 1st. create fields, content and list without lookup fields if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.Fields) || provisioningInfo.HandlersToProcess.HasFlag(Handlers.Lists)) { objectHandlers.Add(new ObjectField(FieldAndListProvisioningStepHelper.Step.ListAndStandardFields)); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.ContentTypes)) { objectHandlers.Add(new ObjectContentType(FieldAndListProvisioningStepHelper.Step.ListAndStandardFields)); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.Lists)) { objectHandlers.Add(new ObjectListInstance(FieldAndListProvisioningStepHelper.Step.ListAndStandardFields)); } // 2nd. create lookup fields (which requires lists to be present if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.Fields) || provisioningInfo.HandlersToProcess.HasFlag(Handlers.Lists)) { objectHandlers.Add(new ObjectField(FieldAndListProvisioningStepHelper.Step.LookupFields)); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.ContentTypes)) { objectHandlers.Add(new ObjectContentType(FieldAndListProvisioningStepHelper.Step.LookupFields)); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.Lists)) { objectHandlers.Add(new ObjectListInstance(FieldAndListProvisioningStepHelper.Step.LookupFields)); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.Files)) { objectHandlers.Add(new ObjectFiles()); } // 3rd. Create remaining objects in lists (views, user custom actions, ...) if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.Lists)) { objectHandlers.Add(new ObjectListInstance(FieldAndListProvisioningStepHelper.Step.ListSettings)); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.Fields) || provisioningInfo.HandlersToProcess.HasFlag(Handlers.Lists)) { objectHandlers.Add(new ObjectListInstanceDataRows()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.Workflows)) { objectHandlers.Add(new ObjectWorkflows()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.Pages)) { objectHandlers.Add(new ObjectPages()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.PageContents)) { objectHandlers.Add(new ObjectPageContents()); } #if !ONPREMISES if (!calledFromHierarchy && provisioningInfo.HandlersToProcess.HasFlag(Handlers.Tenant)) { objectHandlers.Add(new ObjectTenant()); } #endif #if !SP2013 && !SP2016 if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.ApplicationLifecycleManagement)) { objectHandlers.Add(new ObjectApplicationLifecycleManagement()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.Pages)) { objectHandlers.Add(new ObjectClientSidePages()); } #endif #if !ONPREMISES if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.SiteHeader)) { objectHandlers.Add(new ObjectSiteHeaderSettings()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.SiteFooter)) { objectHandlers.Add(new ObjectSiteFooterSettings()); } #endif if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.CustomActions)) { objectHandlers.Add(new ObjectCustomActions()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.Publishing)) { objectHandlers.Add(new ObjectPublishing()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.ComposedLook)) { objectHandlers.Add(new ObjectComposedLook()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.SearchSettings)) { objectHandlers.Add(new ObjectSearchSettings()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.PropertyBagEntries)) { objectHandlers.Add(new ObjectPropertyBagEntry()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.WebSettings)) { objectHandlers.Add(new ObjectWebSettings()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.SiteSettings)) { objectHandlers.Add(new ObjectSiteSettings()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.Theme)) { objectHandlers.Add(new ObjectTheme()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.Navigation)) { objectHandlers.Add(new ObjectNavigation()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.ImageRenditions)) { objectHandlers.Add(new ObjectImageRenditions()); } objectHandlers.Add(new ObjectLocalization()); // Always add this one, check is done in the handler if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.ExtensibilityProviders)) { objectHandlers.Add(new ObjectExtensibilityHandlers()); } // Only persist template information in case this flag is set: this will allow the engine to // work with lesser permissions if (provisioningInfo.PersistTemplateInfo) { objectHandlers.Add(new ObjectPersistTemplateInfo()); } var count = objectHandlers.Count(o => o.ReportProgress && o.WillProvision(web, template, provisioningInfo)) + 1; progressDelegate?.Invoke("Initializing engine", 1, count); // handlers + initializing message) if (tokenParser == null) { tokenParser = new TokenParser(web, template); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.ExtensibilityProviders)) { var extensibilityHandler = objectHandlers.OfType <ObjectExtensibilityHandlers>().First(); extensibilityHandler.AddExtendedTokens(web, template, tokenParser, provisioningInfo); } int step = 2; // Remove potentially unsupported artifacts var cleaner = new NoScriptTemplateCleaner(web); if (messagesDelegate != null) { cleaner.MessagesDelegate = messagesDelegate; } template = cleaner.CleanUpBeforeProvisioning(template); CallWebHooks(template, tokenParser, ProvisioningTemplateWebhookKind.ProvisioningTemplateStarted); foreach (var handler in objectHandlers) { if (handler.WillProvision(web, template, provisioningInfo)) { if (messagesDelegate != null) { handler.MessagesDelegate = messagesDelegate; } if (handler.ReportProgress && progressDelegate != null) { progressDelegate(handler.Name, step, count); step++; } CallWebHooks(template, tokenParser, ProvisioningTemplateWebhookKind.ObjectHandlerProvisioningStarted, handler.InternalName); try { tokenParser = handler.ProvisionObjects(web, template, tokenParser, provisioningInfo); } catch (Exception ex) { CallWebHooks(template, tokenParser, ProvisioningTemplateWebhookKind.ExceptionOccurred, handler.InternalName, ex); throw ex; } CallWebHooks(template, tokenParser, ProvisioningTemplateWebhookKind.ObjectHandlerProvisioningCompleted, handler.InternalName); } } // Notify the completed provisioning of the site web.EnsureProperties(w => w.Title, w => w.Url); siteProvisionedDelegate?.Invoke(web.Title, web.Url); CallWebHooks(template, tokenParser, ProvisioningTemplateWebhookKind.ProvisioningTemplateCompleted); System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo(currentCultureInfoValue); } }
/// <summary> /// Extracts a client side page /// </summary> /// <param name="web">Web to extract the page from</param> /// <param name="template">Current provisioning template that will hold the extracted page</param> /// <param name="creationInfo">ProvisioningTemplateCreationInformation passed into the provisioning engine</param> /// <param name="scope">Scope used for logging</param> /// <param name="pageUrl">Url of the page to extract</param> /// <param name="pageName">Name of the page to extract</param> /// <param name="isHomePage">Is this a home page?</param> public void ExtractClientSidePage(Web web, ProvisioningTemplate template, ProvisioningTemplateCreationInformation creationInfo, PnPMonitoredScope scope, string pageUrl, string pageName, bool isHomePage) { try { var pageToExtract = web.LoadClientSidePage(pageName); if (pageToExtract.Sections.Count == 0 && pageToExtract.Controls.Count == 0) { // This is default home page which was not customized...and as such there's no page definition stored in the list item. We don't need to extact this page. scope.LogInfo(CoreResources.Provisioning_ObjectHandlers_ClientSidePageContents_DefaultHomePage); } else { // Create the page var extractedPageInstance = new ClientSidePage() { PageName = pageName, PromoteAsNewsArticle = false, Overwrite = true, Publish = true, Layout = pageToExtract.LayoutType.ToString(), EnableComments = !pageToExtract.CommentsDisabled, }; // Add the sections foreach (var section in pageToExtract.Sections) { // Set order var sectionInstance = new CanvasSection() { Order = section.Order, }; // Set section type switch (section.Type) { case Pages.CanvasSectionTemplate.OneColumn: sectionInstance.Type = CanvasSectionType.OneColumn; break; case Pages.CanvasSectionTemplate.TwoColumn: sectionInstance.Type = CanvasSectionType.TwoColumn; break; case Pages.CanvasSectionTemplate.TwoColumnLeft: sectionInstance.Type = CanvasSectionType.TwoColumnLeft; break; case Pages.CanvasSectionTemplate.TwoColumnRight: sectionInstance.Type = CanvasSectionType.TwoColumnRight; break; case Pages.CanvasSectionTemplate.ThreeColumn: sectionInstance.Type = CanvasSectionType.ThreeColumn; break; case Pages.CanvasSectionTemplate.OneColumnFullWidth: sectionInstance.Type = CanvasSectionType.OneColumnFullWidth; break; default: sectionInstance.Type = CanvasSectionType.OneColumn; break; } // Add controls to section foreach (var column in section.Columns) { foreach (var control in column.Controls) { // Create control CanvasControl controlInstance = new CanvasControl() { Column = column.Order, ControlId = control.InstanceId, Order = control.Order, }; // Set control type if (control.Type == typeof(Pages.ClientSideText)) { controlInstance.Type = WebPartType.Text; // Set text content controlInstance.ControlProperties = new System.Collections.Generic.Dictionary <string, string>(1) { { "Text", TokenizeJsonTextData(web, (control as Pages.ClientSideText).Text) } }; } else { // set ControlId to webpart id controlInstance.ControlId = Guid.Parse((control as Pages.ClientSideWebPart).WebPartId); var webPartType = Pages.ClientSidePage.NameToClientSideWebPartEnum((control as Pages.ClientSideWebPart).WebPartId); switch (webPartType) { case Pages.DefaultClientSideWebParts.ContentRollup: controlInstance.Type = WebPartType.ContentRollup; break; case Pages.DefaultClientSideWebParts.BingMap: controlInstance.Type = WebPartType.BingMap; break; case Pages.DefaultClientSideWebParts.ContentEmbed: controlInstance.Type = WebPartType.ContentEmbed; break; case Pages.DefaultClientSideWebParts.DocumentEmbed: controlInstance.Type = WebPartType.DocumentEmbed; break; case Pages.DefaultClientSideWebParts.Image: controlInstance.Type = WebPartType.Image; break; case Pages.DefaultClientSideWebParts.ImageGallery: controlInstance.Type = WebPartType.ImageGallery; break; case Pages.DefaultClientSideWebParts.LinkPreview: controlInstance.Type = WebPartType.LinkPreview; break; case Pages.DefaultClientSideWebParts.NewsFeed: controlInstance.Type = WebPartType.NewsFeed; break; case Pages.DefaultClientSideWebParts.NewsReel: controlInstance.Type = WebPartType.NewsReel; break; case Pages.DefaultClientSideWebParts.PowerBIReportEmbed: controlInstance.Type = WebPartType.PowerBIReportEmbed; break; case Pages.DefaultClientSideWebParts.QuickChart: controlInstance.Type = WebPartType.QuickChart; break; case Pages.DefaultClientSideWebParts.SiteActivity: controlInstance.Type = WebPartType.SiteActivity; break; case Pages.DefaultClientSideWebParts.VideoEmbed: controlInstance.Type = WebPartType.VideoEmbed; break; case Pages.DefaultClientSideWebParts.YammerEmbed: controlInstance.Type = WebPartType.YammerEmbed; break; case Pages.DefaultClientSideWebParts.Events: controlInstance.Type = WebPartType.Events; break; case Pages.DefaultClientSideWebParts.GroupCalendar: controlInstance.Type = WebPartType.GroupCalendar; break; case Pages.DefaultClientSideWebParts.Hero: controlInstance.Type = WebPartType.Hero; break; case Pages.DefaultClientSideWebParts.List: controlInstance.Type = WebPartType.List; break; case Pages.DefaultClientSideWebParts.PageTitle: controlInstance.Type = WebPartType.PageTitle; break; case Pages.DefaultClientSideWebParts.People: controlInstance.Type = WebPartType.People; break; case Pages.DefaultClientSideWebParts.QuickLinks: controlInstance.Type = WebPartType.QuickLinks; break; case Pages.DefaultClientSideWebParts.CustomMessageRegion: controlInstance.Type = WebPartType.CustomMessageRegion; break; case Pages.DefaultClientSideWebParts.Divider: controlInstance.Type = WebPartType.Divider; break; case Pages.DefaultClientSideWebParts.MicrosoftForms: controlInstance.Type = WebPartType.MicrosoftForms; break; case Pages.DefaultClientSideWebParts.Spacer: controlInstance.Type = WebPartType.Spacer; break; case Pages.DefaultClientSideWebParts.ThirdParty: controlInstance.Type = WebPartType.Custom; break; default: controlInstance.Type = WebPartType.Custom; break; } // set the control properties if ((control as Pages.ClientSideWebPart).ServerProcessedContent != null) { // If we have serverProcessedContent then also export that one, it's important as some controls depend on this information to be present string serverProcessedContent = (control as Pages.ClientSideWebPart).ServerProcessedContent.ToString(Formatting.None); controlInstance.JsonControlData = "{ \"serverProcessedContent\": " + serverProcessedContent + ", \"properties\": " + (control as Pages.ClientSideWebPart).PropertiesJson + "}"; } else { controlInstance.JsonControlData = (control as Pages.ClientSideWebPart).PropertiesJson; } // Tokenize the JsonControlData controlInstance.JsonControlData = TokenizeJsonControlData(web, controlInstance.JsonControlData); // Export relevant files if this flag is set if (creationInfo.PersistBrandingFiles) { List <Guid> fileGuids = new List <Guid>(); Dictionary <string, string> exportedFiles = new Dictionary <string, string>(); Dictionary <string, string> exportedPages = new Dictionary <string, string>(); // grab all the guids in the already tokenized json and check try to get them as a file string guidPattern = "\"[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12}\""; Regex regexClientIds = new Regex(guidPattern); if (regexClientIds.IsMatch(controlInstance.JsonControlData)) { foreach (Match guidMatch in regexClientIds.Matches(controlInstance.JsonControlData)) { Guid uniqueId; if (Guid.TryParse(guidMatch.Value.Trim("\"".ToCharArray()), out uniqueId)) { fileGuids.Add(uniqueId); } } } // grab all the encoded guids in the already tokenized json and check try to get them as a file guidPattern = "=[a-fA-F0-9]{8}%2D([a-fA-F0-9]{4}%2D){3}[a-fA-F0-9]{12}"; regexClientIds = new Regex(guidPattern); if (regexClientIds.IsMatch(controlInstance.JsonControlData)) { foreach (Match guidMatch in regexClientIds.Matches(controlInstance.JsonControlData)) { Guid uniqueId; if (Guid.TryParse(guidMatch.Value.TrimStart("=".ToCharArray()), out uniqueId)) { fileGuids.Add(uniqueId); } } } // Iterate over the found guids to see if they're exportable files foreach (var uniqueId in fileGuids) { try { if (!exportedFiles.ContainsKey(uniqueId.ToString())) { // Try to see if this is a file var file = web.GetFileById(uniqueId); web.Context.Load(file, f => f.Level, f => f.ServerRelativeUrl); web.Context.ExecuteQueryRetry(); // If we got here it's a file, let's grab the file's path and name var baseUri = new Uri(web.Url); var fullUri = new Uri(baseUri, file.ServerRelativeUrl); var folderPath = HttpUtility.UrlDecode(fullUri.Segments.Take(fullUri.Segments.Count() - 1).ToArray().Aggregate((i, x) => i + x).TrimEnd('/')); var fileName = HttpUtility.UrlDecode(fullUri.Segments[fullUri.Segments.Count() - 1]); // Don't export aspx files as some web parts refer to other client side pages --> pages have to be either exported as well or already exist in the target site if (!fileName.EndsWith(".aspx", StringComparison.InvariantCultureIgnoreCase)) { var templateFolderPath = folderPath.Substring(web.ServerRelativeUrl.Length).TrimStart("/".ToCharArray()); // Avoid duplicate file entries var fileAlreadyExported = template.Files.Where(p => p.Folder.Equals(templateFolderPath, StringComparison.CurrentCultureIgnoreCase) && p.Src.Equals(fileName, StringComparison.CurrentCultureIgnoreCase)).FirstOrDefault(); if (fileAlreadyExported == null) { // Add a File to the template template.Files.Add(new Model.File() { Folder = templateFolderPath, Src = $"{templateFolderPath}/{fileName}", Overwrite = true, Level = (Model.FileLevel)Enum.Parse(typeof(Model.FileLevel), file.Level.ToString()) }); // Export the file PersistFile(web, creationInfo, scope, folderPath, fileName); // Keep track of the exported file path and it's UniqueId exportedFiles.Add(uniqueId.ToString(), file.ServerRelativeUrl.Substring(web.ServerRelativeUrl.Length).TrimStart("/".ToCharArray())); } } else { if (!exportedPages.ContainsKey(uniqueId.ToString())) { exportedPages.Add(uniqueId.ToString(), file.ServerRelativeUrl.Substring(web.ServerRelativeUrl.Length).TrimStart("/".ToCharArray())); } } } } catch (Exception ex) { scope.LogWarning(CoreResources.Provisioning_ObjectHandlers_ClientSidePageContents_ErrorDuringFileExport, ex.Message); } } // Tokenize based on the found files, use a different token for encoded guids do we can later on replace by a new encoded guid foreach (var exportedFile in exportedFiles) { controlInstance.JsonControlData = Regex.Replace(controlInstance.JsonControlData, exportedFile.Key.Replace("-", "%2D"), $"{{fileuniqueidencoded:{exportedFile.Value}}}", RegexOptions.IgnoreCase); controlInstance.JsonControlData = Regex.Replace(controlInstance.JsonControlData, exportedFile.Key, $"{{fileuniqueid:{exportedFile.Value}}}", RegexOptions.IgnoreCase); } foreach (var exportedPage in exportedPages) { controlInstance.JsonControlData = Regex.Replace(controlInstance.JsonControlData, exportedPage.Key.Replace("-", "%2D"), $"{{pageuniqueidencoded:{exportedPage.Value}}}", RegexOptions.IgnoreCase); controlInstance.JsonControlData = Regex.Replace(controlInstance.JsonControlData, exportedPage.Key, $"{{pageuniqueid:{exportedPage.Value}}}", RegexOptions.IgnoreCase); } } } // add control to section sectionInstance.Controls.Add(controlInstance); } } extractedPageInstance.Sections.Add(sectionInstance); } // Renumber the sections...when editing modern homepages you can end up with section with order 0.5 or 0.75...let's ensure we render section as of 1 int sectionOrder = 1; foreach (var sectionInstance in extractedPageInstance.Sections) { sectionInstance.Order = sectionOrder; sectionOrder++; } // Add the page to the template template.ClientSidePages.Add(extractedPageInstance); // Set the homepage if (isHomePage) { if (template.WebSettings == null) { template.WebSettings = new WebSettings(); } if (pageUrl.StartsWith(web.ServerRelativeUrl, StringComparison.InvariantCultureIgnoreCase)) { template.WebSettings.WelcomePage = pageUrl.Replace(web.ServerRelativeUrl + "/", ""); } else { template.WebSettings.WelcomePage = pageUrl; } } } } catch (ArgumentException ex) { scope.LogWarning(CoreResources.Provisioning_ObjectHandlers_ClientSidePageContents_NoValidPage, ex.Message); } }
private bool PersistFile(Web web, ProvisioningTemplateCreationInformation creationInfo, PnPMonitoredScope scope, string serverRelativeUrl) { var success = false; if (creationInfo.PersistBrandingFiles) { if (creationInfo.FileConnector != null) { if (UrlUtility.IsIisVirtualDirectory(serverRelativeUrl)) { scope.LogWarning("File is not located in the content database. Not retrieving {0}", serverRelativeUrl); return(success); } try { var file = web.GetFileByServerRelativeUrl(serverRelativeUrl); string fileName = string.Empty; if (serverRelativeUrl.IndexOf("/") > -1) { fileName = serverRelativeUrl.Substring(serverRelativeUrl.LastIndexOf("/") + 1); } else { fileName = serverRelativeUrl; } web.Context.Load(file); web.Context.ExecuteQueryRetry(); ClientResult <Stream> stream = file.OpenBinaryStream(); web.Context.ExecuteQueryRetry(); using (Stream memStream = new MemoryStream()) { CopyStream(stream.Value, memStream); memStream.Position = 0; creationInfo.FileConnector.SaveFileStream(fileName, memStream); } success = true; } catch (ServerException ex1) { // If we are referring a file from a location outside of the current web or at a location where we cannot retrieve the file an exception is thrown. We swallow this exception. if (ex1.ServerErrorCode != -2147024809) { throw; } else { scope.LogWarning("File is not necessarily located in the current web. Not retrieving {0}", serverRelativeUrl); } } } else { WriteWarning("No connector present to persist homepage.", ProvisioningMessageType.Error); scope.LogError("No connector present to persist homepage"); } } else { success = true; } return(success); }
private bool PersistFile(Web web, ProvisioningTemplateCreationInformation creationInfo, PnPMonitoredScope scope, string serverRelativeUrl) { var success = false; if (creationInfo.PersistBrandingFiles) { if (creationInfo.FileConnector != null) { if (UrlUtility.IsIisVirtualDirectory(serverRelativeUrl)) { scope.LogWarning("File is not located in the content database. Not retrieving {0}", serverRelativeUrl); return(success); } try { var file = web.GetFileByServerRelativeUrl(serverRelativeUrl); string fileName = string.Empty; if (serverRelativeUrl.IndexOf("/") > -1) { fileName = serverRelativeUrl.Substring(serverRelativeUrl.LastIndexOf("/") + 1); } else { fileName = serverRelativeUrl; } web.Context.Load(file); web.Context.ExecuteQueryRetry(); ClientResult <Stream> stream = file.OpenBinaryStream(); web.Context.ExecuteQueryRetry(); var baseUri = new Uri(web.Url); var fullUri = new Uri(baseUri, file.ServerRelativeUrl); var folderPath = HttpUtility.UrlDecode(fullUri.Segments.Take(fullUri.Segments.Count() - 1).ToArray().Aggregate((i, x) => i + x).TrimEnd('/')); // Configure the filename to use fileName = HttpUtility.UrlDecode(fullUri.Segments[fullUri.Segments.Count() - 1]); // Build up a site relative container URL...might end up empty as well String container = HttpUtility.UrlDecode(folderPath.Replace(web.ServerRelativeUrl, "")).Trim('/').Replace("/", "\\"); using (Stream memStream = new MemoryStream()) { CopyStream(stream.Value, memStream); memStream.Position = 0; if (!string.IsNullOrEmpty(container)) { creationInfo.FileConnector.SaveFileStream(fileName, container, memStream); } else { creationInfo.FileConnector.SaveFileStream(fileName, memStream); } } success = true; } catch (ServerException ex1) { // If we are referring a file from a location outside of the current web or at a location where we cannot retrieve the file an exception is thrown. We swallow this exception. if (ex1.ServerErrorCode != -2147024809) { throw; } else { scope.LogWarning("File is not necessarily located in the current web. Not retrieving {0}", serverRelativeUrl); } } } else { WriteMessage("No connector present to persist homepage.", ProvisioningMessageType.Error); scope.LogError("No connector present to persist homepage"); } } else { success = true; } return(success); }
public override TokenParser ProvisionObjects(Web web, ProvisioningTemplate template, TokenParser parser, ProvisioningTemplateApplyingInformation applyingInformation) { using (var scope = new PnPMonitoredScope(this.Name)) { if (template.WebSettings != null) { // Check if this is not a noscript site as we're not allowed to update some properties bool isNoScriptSite = web.IsNoScriptSite(); web.EnsureProperty(w => w.HasUniqueRoleAssignments); var webSettings = template.WebSettings; #if !ONPREMISES if (!isNoScriptSite) { web.NoCrawl = webSettings.NoCrawl; } else { scope.LogWarning(CoreResources.Provisioning_ObjectHandlers_WebSettings_SkipNoCrawlUpdate); } if (!web.IsSubSite() || (web.IsSubSite() && web.HasUniqueRoleAssignments)) { String requestAccessEmailValue = parser.ParseString(webSettings.RequestAccessEmail); if (!String.IsNullOrEmpty(requestAccessEmailValue) && requestAccessEmailValue.Length >= 255) { requestAccessEmailValue = requestAccessEmailValue.Substring(0, 255); } if (!String.IsNullOrEmpty(requestAccessEmailValue)) { web.RequestAccessEmail = requestAccessEmailValue; web.Update(); web.Context.ExecuteQueryRetry(); } } #endif var masterUrl = parser.ParseString(webSettings.MasterPageUrl); if (!string.IsNullOrEmpty(masterUrl)) { if (!isNoScriptSite) { web.MasterUrl = masterUrl; } else { scope.LogWarning(CoreResources.Provisioning_ObjectHandlers_WebSettings_SkipMasterPageUpdate); } } var customMasterUrl = parser.ParseString(webSettings.CustomMasterPageUrl); if (!string.IsNullOrEmpty(customMasterUrl)) { if (!isNoScriptSite) { web.CustomMasterUrl = customMasterUrl; } else { scope.LogWarning(CoreResources.Provisioning_ObjectHandlers_WebSettings_SkipCustomMasterPageUpdate); } } if (webSettings.Title != null) { web.Title = parser.ParseString(webSettings.Title); } if (webSettings.Description != null) { web.Description = parser.ParseString(webSettings.Description); } if (webSettings.SiteLogo != null) { web.SiteLogoUrl = parser.ParseString(webSettings.SiteLogo); } var welcomePage = parser.ParseString(webSettings.WelcomePage); if (!string.IsNullOrEmpty(welcomePage)) { web.RootFolder.WelcomePage = welcomePage; web.RootFolder.Update(); } if (webSettings.AlternateCSS != null) { web.AlternateCssUrl = parser.ParseString(webSettings.AlternateCSS); } web.Update(); web.Context.ExecuteQueryRetry(); } } return(parser); }
private static Microsoft.SharePoint.Client.ContentType CreateContentType(Web web, ContentType templateContentType, TokenParser parser, FileConnectorBase connector, PnPMonitoredScope scope, List<Microsoft.SharePoint.Client.ContentType> existingCTs = null, List<Microsoft.SharePoint.Client.Field> existingFields = null, bool isNoScriptSite = false) { var name = parser.ParseString(templateContentType.Name); var description = parser.ParseString(templateContentType.Description); var id = parser.ParseString(templateContentType.Id); var group = parser.ParseString(templateContentType.Group); var createdCT = web.CreateContentType(name, description, id, group); foreach (var fieldRef in templateContentType.FieldRefs) { Microsoft.SharePoint.Client.Field field = null; try { // Try to get the field by ID field = web.Fields.GetById(fieldRef.Id); } catch (ArgumentException) { // In case of failure, if we have the name if (!String.IsNullOrEmpty(fieldRef.Name)) { // Let's try with that one field = web.Fields.GetByInternalNameOrTitle(fieldRef.Name); } } // Add it to the target content type // Notice that this code will fail if the field does not exist web.AddFieldToContentType(createdCT, field, fieldRef.Required, fieldRef.Hidden); } // Add new CTs parser.AddToken(new ContentTypeIdToken(web, name, id)); #if !ONPREMISES // Set resources if (templateContentType.Name.ContainsResourceToken()) { createdCT.NameResource.SetUserResourceValue(templateContentType.Name, parser); } if (templateContentType.Description.ContainsResourceToken()) { createdCT.DescriptionResource.SetUserResourceValue(templateContentType.Description, parser); } #endif //Reorder the elements so that the new created Content Type has the same order as defined in the //template. The order can be different if the new Content Type inherits from another Content Type. //In this case the new Content Type has all field of the original Content Type and missing fields //will be added at the end. To fix this issue we ordering the fields once more. createdCT.FieldLinks.Reorder(templateContentType.FieldRefs.Select(fld => parser.ParseString(fld.Name)).ToArray()); createdCT.ReadOnly = templateContentType.ReadOnly; createdCT.Hidden = templateContentType.Hidden; createdCT.Sealed = templateContentType.Sealed; if (templateContentType.DocumentSetTemplate == null) { // Only apply a document template when the contenttype is not a document set if (!string.IsNullOrEmpty(parser.ParseString(templateContentType.DocumentTemplate))) { createdCT.DocumentTemplate = parser.ParseString(templateContentType.DocumentTemplate); } } // Skipping updates of forms as we can't upload forms to noscript sites if (!isNoScriptSite) { if (!String.IsNullOrEmpty(parser.ParseString(templateContentType.NewFormUrl))) { createdCT.NewFormUrl = parser.ParseString(templateContentType.NewFormUrl); } if (!String.IsNullOrEmpty(parser.ParseString(templateContentType.EditFormUrl))) { createdCT.EditFormUrl = parser.ParseString(templateContentType.EditFormUrl); } if (!String.IsNullOrEmpty(parser.ParseString(templateContentType.DisplayFormUrl))) { createdCT.DisplayFormUrl = parser.ParseString(templateContentType.DisplayFormUrl); } } else { if (!String.IsNullOrEmpty(parser.ParseString(templateContentType.DisplayFormUrl)) || !String.IsNullOrEmpty(parser.ParseString(templateContentType.EditFormUrl)) || !String.IsNullOrEmpty(parser.ParseString(templateContentType.NewFormUrl))) { // log message scope.LogWarning(CoreResources.Provisioning_ObjectHandlers_ContentTypes_SkipCustomFormUrls, name); } } createdCT.Update(true); web.Context.ExecuteQueryRetry(); // If the CT is a DocumentSet if (templateContentType.DocumentSetTemplate != null) { // Retrieve a reference to the DocumentSet Content Type Microsoft.SharePoint.Client.DocumentSet.DocumentSetTemplate documentSetTemplate = Microsoft.SharePoint.Client.DocumentSet.DocumentSetTemplate.GetDocumentSetTemplate(web.Context, createdCT); // Load the collections to allow for deletion scenarions web.Context.Load(documentSetTemplate, d => d.AllowedContentTypes, d => d.DefaultDocuments, d => d.SharedFields, d => d.WelcomePageFields); web.Context.ExecuteQueryRetry(); if (!String.IsNullOrEmpty(templateContentType.DocumentSetTemplate.WelcomePage)) { // TODO: Customize the WelcomePage of the DocumentSet } // Add additional content types to the set of allowed content types bool hasDefaultDocumentContentTypeInTemplate = false; foreach (String ctId in templateContentType.DocumentSetTemplate.AllowedContentTypes) { Microsoft.SharePoint.Client.ContentType ct = existingCTs.FirstOrDefault(c => c.StringId == ctId); if (ct != null) { if (ct.Id.StringValue.Equals("0x0101", StringComparison.InvariantCultureIgnoreCase)) { hasDefaultDocumentContentTypeInTemplate = true; } documentSetTemplate.AllowedContentTypes.Add(ct.Id); } } // If the default document content type (0x0101) is not in our definition then remove it if (!hasDefaultDocumentContentTypeInTemplate) { Microsoft.SharePoint.Client.ContentType ct = existingCTs.FirstOrDefault(c => c.StringId == "0x0101"); if (ct != null) { documentSetTemplate.AllowedContentTypes.Remove(ct.Id); } } if (!isNoScriptSite) { foreach (var doc in templateContentType.DocumentSetTemplate.DefaultDocuments) { Microsoft.SharePoint.Client.ContentType ct = existingCTs.FirstOrDefault(c => c.StringId == doc.ContentTypeId); if (ct != null) { using (Stream fileStream = connector.GetFileStream(doc.FileSourcePath)) { documentSetTemplate.DefaultDocuments.Add(doc.Name, ct.Id, ReadFullStream(fileStream)); } } } } else { if (templateContentType.DocumentSetTemplate.DefaultDocuments.Any()) { scope.LogWarning(CoreResources.Provisioning_ObjectHandlers_ContentTypes_SkipDocumentSetDefaultDocuments, name); } } foreach (var sharedField in templateContentType.DocumentSetTemplate.SharedFields) { Microsoft.SharePoint.Client.Field field = existingFields.FirstOrDefault(f => f.Id == sharedField); if (field != null) { documentSetTemplate.SharedFields.Add(field); } } foreach (var welcomePageField in templateContentType.DocumentSetTemplate.WelcomePageFields) { Microsoft.SharePoint.Client.Field field = existingFields.FirstOrDefault(f => f.Id == welcomePageField); if (field != null) { documentSetTemplate.WelcomePageFields.Add(field); } } documentSetTemplate.Update(true); web.Context.ExecuteQueryRetry(); } web.Context.Load(createdCT); web.Context.ExecuteQueryRetry(); return createdCT; }
private static Microsoft.SharePoint.Client.ContentType CreateContentType(Web web, ContentType templateContentType, TokenParser parser, FileConnectorBase connector, PnPMonitoredScope scope, List <Microsoft.SharePoint.Client.ContentType> existingCTs = null, List <Microsoft.SharePoint.Client.Field> existingFields = null, bool isNoScriptSite = false) { var name = parser.ParseString(templateContentType.Name); var description = parser.ParseString(templateContentType.Description); var id = parser.ParseString(templateContentType.Id); var group = parser.ParseString(templateContentType.Group); var createdCT = web.CreateContentType(name, description, id, group); foreach (var fieldRef in templateContentType.FieldRefs) { Microsoft.SharePoint.Client.Field field = null; try { // Try to get the field by ID field = web.Fields.GetById(fieldRef.Id); } catch (ArgumentException) { // In case of failure, if we have the name if (!String.IsNullOrEmpty(fieldRef.Name)) { // Let's try with that one field = web.Fields.GetByInternalNameOrTitle(fieldRef.Name); } } // Add it to the target content type // Notice that this code will fail if the field does not exist web.AddFieldToContentType(createdCT, field, fieldRef.Required, fieldRef.Hidden); } // Add new CTs parser.AddToken(new ContentTypeIdToken(web, name, id)); #if !ONPREMISES // Set resources if (templateContentType.Name.ContainsResourceToken()) { createdCT.NameResource.SetUserResourceValue(templateContentType.Name, parser); } if (templateContentType.Description.ContainsResourceToken()) { createdCT.DescriptionResource.SetUserResourceValue(templateContentType.Description, parser); } #endif //Reorder the elements so that the new created Content Type has the same order as defined in the //template. The order can be different if the new Content Type inherits from another Content Type. //In this case the new Content Type has all field of the original Content Type and missing fields //will be added at the end. To fix this issue we ordering the fields once more. createdCT.FieldLinks.Reorder(templateContentType.FieldRefs.Select(fld => parser.ParseString(fld.Name)).ToArray()); createdCT.ReadOnly = templateContentType.ReadOnly; createdCT.Hidden = templateContentType.Hidden; createdCT.Sealed = templateContentType.Sealed; if (templateContentType.DocumentSetTemplate == null) { // Only apply a document template when the contenttype is not a document set if (!string.IsNullOrEmpty(parser.ParseString(templateContentType.DocumentTemplate))) { createdCT.DocumentTemplate = parser.ParseString(templateContentType.DocumentTemplate); } } // Skipping updates of forms as we can't upload forms to noscript sites if (!isNoScriptSite) { if (!String.IsNullOrEmpty(parser.ParseString(templateContentType.NewFormUrl))) { createdCT.NewFormUrl = parser.ParseString(templateContentType.NewFormUrl); } if (!String.IsNullOrEmpty(parser.ParseString(templateContentType.EditFormUrl))) { createdCT.EditFormUrl = parser.ParseString(templateContentType.EditFormUrl); } if (!String.IsNullOrEmpty(parser.ParseString(templateContentType.DisplayFormUrl))) { createdCT.DisplayFormUrl = parser.ParseString(templateContentType.DisplayFormUrl); } } else { if (!String.IsNullOrEmpty(parser.ParseString(templateContentType.DisplayFormUrl)) || !String.IsNullOrEmpty(parser.ParseString(templateContentType.EditFormUrl)) || !String.IsNullOrEmpty(parser.ParseString(templateContentType.NewFormUrl))) { // log message scope.LogWarning(CoreResources.Provisioning_ObjectHandlers_ContentTypes_SkipCustomFormUrls, name); } } createdCT.Update(true); web.Context.ExecuteQueryRetry(); // If the CT is a DocumentSet if (templateContentType.DocumentSetTemplate != null) { // Retrieve a reference to the DocumentSet Content Type Microsoft.SharePoint.Client.DocumentSet.DocumentSetTemplate documentSetTemplate = Microsoft.SharePoint.Client.DocumentSet.DocumentSetTemplate.GetDocumentSetTemplate(web.Context, createdCT); // Load the collections to allow for deletion scenarions web.Context.Load(documentSetTemplate, d => d.AllowedContentTypes, d => d.DefaultDocuments, d => d.SharedFields, d => d.WelcomePageFields); web.Context.ExecuteQueryRetry(); if (!String.IsNullOrEmpty(templateContentType.DocumentSetTemplate.WelcomePage)) { // TODO: Customize the WelcomePage of the DocumentSet } // Add additional content types to the set of allowed content types bool hasDefaultDocumentContentTypeInTemplate = false; foreach (String ctId in templateContentType.DocumentSetTemplate.AllowedContentTypes) { Microsoft.SharePoint.Client.ContentType ct = existingCTs.FirstOrDefault(c => c.StringId == ctId); if (ct != null) { if (ct.Id.StringValue.Equals("0x0101", StringComparison.InvariantCultureIgnoreCase)) { hasDefaultDocumentContentTypeInTemplate = true; } documentSetTemplate.AllowedContentTypes.Add(ct.Id); } } // If the default document content type (0x0101) is not in our definition then remove it if (!hasDefaultDocumentContentTypeInTemplate) { Microsoft.SharePoint.Client.ContentType ct = existingCTs.FirstOrDefault(c => c.StringId == "0x0101"); if (ct != null) { documentSetTemplate.AllowedContentTypes.Remove(ct.Id); } } if (!isNoScriptSite) { foreach (var doc in templateContentType.DocumentSetTemplate.DefaultDocuments) { Microsoft.SharePoint.Client.ContentType ct = existingCTs.FirstOrDefault(c => c.StringId == doc.ContentTypeId); if (ct != null) { using (Stream fileStream = connector.GetFileStream(doc.FileSourcePath)) { documentSetTemplate.DefaultDocuments.Add(doc.Name, ct.Id, ReadFullStream(fileStream)); } } } } else { if (templateContentType.DocumentSetTemplate.DefaultDocuments.Any()) { scope.LogWarning(CoreResources.Provisioning_ObjectHandlers_ContentTypes_SkipDocumentSetDefaultDocuments, name); } } foreach (var sharedField in templateContentType.DocumentSetTemplate.SharedFields) { Microsoft.SharePoint.Client.Field field = existingFields.FirstOrDefault(f => f.Id == sharedField); if (field != null) { documentSetTemplate.SharedFields.Add(field); } } foreach (var welcomePageField in templateContentType.DocumentSetTemplate.WelcomePageFields) { Microsoft.SharePoint.Client.Field field = existingFields.FirstOrDefault(f => f.Id == welcomePageField); if (field != null) { documentSetTemplate.WelcomePageFields.Add(field); } } documentSetTemplate.Update(true); web.Context.ExecuteQueryRetry(); } web.Context.Load(createdCT); web.Context.ExecuteQueryRetry(); return(createdCT); }
public override TokenParser ProvisionObjects(Web web, ProvisioningTemplate template, TokenParser parser, ProvisioningTemplateApplyingInformation applyingInformation) { using (var scope = new PnPMonitoredScope(this.Name)) { if (template.ComposedLook != null && !template.ComposedLook.Equals(ComposedLook.Empty)) { // Check if this is not a noscript site as themes and composed looks are not supported if (web.IsNoScriptSite()) { scope.LogWarning(CoreResources.Provisioning_ObjectHandlers_ComposedLooks_NoSiteCheck); return parser; } bool executeQueryNeeded = false; if (executeQueryNeeded) { web.Context.ExecuteQueryRetry(); } if (String.IsNullOrEmpty(template.ComposedLook.ColorFile) && String.IsNullOrEmpty(template.ComposedLook.FontFile) && String.IsNullOrEmpty(template.ComposedLook.BackgroundFile)) { // Apply OOB theme web.SetComposedLookByUrl(template.ComposedLook.Name, "", "", ""); } else { // Apply custom theme string colorFile = null; if (!string.IsNullOrEmpty(template.ComposedLook.ColorFile)) { colorFile = parser.ParseString(template.ComposedLook.ColorFile); } string backgroundFile = null; if (!string.IsNullOrEmpty(template.ComposedLook.BackgroundFile)) { backgroundFile = parser.ParseString(template.ComposedLook.BackgroundFile); } string fontFile = null; if (!string.IsNullOrEmpty(template.ComposedLook.FontFile)) { fontFile = parser.ParseString(template.ComposedLook.FontFile); } string masterUrl = null; if (template.WebSettings != null && !string.IsNullOrEmpty(template.WebSettings.MasterPageUrl)) { masterUrl = parser.ParseString(template.WebSettings.MasterPageUrl); } web.CreateComposedLookByUrl(template.ComposedLook.Name, colorFile, fontFile, backgroundFile, masterUrl); web.SetComposedLookByUrl(template.ComposedLook.Name, colorFile, fontFile, backgroundFile, masterUrl); } // Persist composed look info in property bag var composedLookJson = JsonConvert.SerializeObject(template.ComposedLook); web.SetPropertyBagValue("_PnP_ProvisioningTemplateComposedLookInfo", composedLookJson); } } return parser; }
private static void UpdateContentType(Web web, Microsoft.SharePoint.Client.ContentType existingContentType, ContentType templateContentType, TokenParser parser, PnPMonitoredScope scope, bool isNoScriptSite = false) { var isDirty = false; if (existingContentType.Hidden != templateContentType.Hidden) { scope.LogPropertyUpdate("Hidden"); existingContentType.Hidden = templateContentType.Hidden; isDirty = true; } if (existingContentType.ReadOnly != templateContentType.ReadOnly) { scope.LogPropertyUpdate("ReadOnly"); existingContentType.ReadOnly = templateContentType.ReadOnly; isDirty = true; } if (existingContentType.Sealed != templateContentType.Sealed) { scope.LogPropertyUpdate("Sealed"); existingContentType.Sealed = templateContentType.Sealed; isDirty = true; } if (templateContentType.Description != null && existingContentType.Description != parser.ParseString(templateContentType.Description)) { scope.LogPropertyUpdate("Description"); existingContentType.Description = parser.ParseString(templateContentType.Description); isDirty = true; } if (templateContentType.DocumentTemplate != null && existingContentType.DocumentTemplate != parser.ParseString(templateContentType.DocumentTemplate)) { scope.LogPropertyUpdate("DocumentTemplate"); existingContentType.DocumentTemplate = parser.ParseString(templateContentType.DocumentTemplate); isDirty = true; } if (existingContentType.Name != parser.ParseString(templateContentType.Name)) { scope.LogPropertyUpdate("Name"); existingContentType.Name = parser.ParseString(templateContentType.Name); isDirty = true; // CT is being renamed, add an extra token to the tokenparser parser.AddToken(new ContentTypeIdToken(web, existingContentType.Name, existingContentType.StringId)); } if (templateContentType.Group != null && existingContentType.Group != parser.ParseString(templateContentType.Group)) { scope.LogPropertyUpdate("Group"); existingContentType.Group = parser.ParseString(templateContentType.Group); isDirty = true; } if (!isNoScriptSite) { if (templateContentType.DisplayFormUrl != null && existingContentType.DisplayFormUrl != parser.ParseString(templateContentType.DisplayFormUrl)) { scope.LogPropertyUpdate("DisplayFormUrl"); existingContentType.DisplayFormUrl = parser.ParseString(templateContentType.DisplayFormUrl); isDirty = true; } if (templateContentType.EditFormUrl != null && existingContentType.EditFormUrl != parser.ParseString(templateContentType.EditFormUrl)) { scope.LogPropertyUpdate("EditFormUrl"); existingContentType.EditFormUrl = parser.ParseString(templateContentType.EditFormUrl); isDirty = true; } if (templateContentType.NewFormUrl != null && existingContentType.NewFormUrl != parser.ParseString(templateContentType.NewFormUrl)) { scope.LogPropertyUpdate("NewFormUrl"); existingContentType.NewFormUrl = parser.ParseString(templateContentType.NewFormUrl); isDirty = true; } } else { if (!String.IsNullOrEmpty(parser.ParseString(templateContentType.DisplayFormUrl)) || !String.IsNullOrEmpty(parser.ParseString(templateContentType.EditFormUrl)) || !String.IsNullOrEmpty(parser.ParseString(templateContentType.NewFormUrl))) { // log message scope.LogWarning(CoreResources.Provisioning_ObjectHandlers_ContentTypes_SkipCustomFormUrls, existingContentType.Name); } } #if !SP2013 if (templateContentType.Name.ContainsResourceToken()) { existingContentType.NameResource.SetUserResourceValue(templateContentType.Name, parser); isDirty = true; } if (templateContentType.Description.ContainsResourceToken()) { existingContentType.DescriptionResource.SetUserResourceValue(templateContentType.Description, parser); isDirty = true; } #endif if (isDirty) { existingContentType.Update(true); web.Context.ExecuteQueryRetry(); } // Delta handling existingContentType.EnsureProperty(c => c.FieldLinks); List <Guid> targetIds = existingContentType.FieldLinks.AsEnumerable().Select(c1 => c1.Id).ToList(); List <Guid> sourceIds = templateContentType.FieldRefs.Select(c1 => c1.Id).ToList(); var fieldsNotPresentInTarget = sourceIds.Except(targetIds).ToArray(); if (fieldsNotPresentInTarget.Any()) { foreach (var fieldId in fieldsNotPresentInTarget) { var fieldRef = templateContentType.FieldRefs.Find(fr => fr.Id == fieldId); var field = web.Fields.GetById(fieldId); scope.LogDebug(CoreResources.Provisioning_ObjectHandlers_ContentTypes_Adding_field__0__to_content_type, fieldId); web.AddFieldToContentType(existingContentType, field, fieldRef.Required, fieldRef.Hidden); } } isDirty = false; foreach (var fieldId in targetIds.Intersect(sourceIds)) { var fieldLink = existingContentType.FieldLinks.FirstOrDefault(fl => fl.Id == fieldId); var fieldRef = templateContentType.FieldRefs.Find(fr => fr.Id == fieldId); if (fieldRef != null) { scope.LogDebug(CoreResources.Provisioning_ObjectHandlers_ContentTypes_Field__0__exists_in_content_type, fieldId); if (fieldLink.Required != fieldRef.Required) { scope.LogPropertyUpdate("Required"); fieldLink.Required = fieldRef.Required; isDirty = true; } if (fieldLink.Hidden != fieldRef.Hidden) { scope.LogPropertyUpdate("Hidden"); fieldLink.Hidden = fieldRef.Hidden; isDirty = true; } } } // The new CT is a DocumentSet, and the target should be, as well if (templateContentType.DocumentSetTemplate != null) { if (!Microsoft.SharePoint.Client.DocumentSet.DocumentSetTemplate.IsChildOfDocumentSetContentType(web.Context, existingContentType).Value) { scope.LogError(CoreResources.Provisioning_ObjectHandlers_ContentTypes_InvalidDocumentSet_Update_Request, existingContentType.Id, existingContentType.Name); } else { Microsoft.SharePoint.Client.DocumentSet.DocumentSetTemplate templateToUpdate = Microsoft.SharePoint.Client.DocumentSet.DocumentSetTemplate.GetDocumentSetTemplate(web.Context, existingContentType); // TODO: Implement Delta Handling scope.LogWarning(CoreResources.Provisioning_ObjectHandlers_ContentTypes_DocumentSet_DeltaHandling_OnHold, existingContentType.Id, existingContentType.Name); } } if (isDirty) { existingContentType.Update(true); web.Context.ExecuteQueryRetry(); } }
public override TokenParser ProvisionObjects(Web web, ProvisioningTemplate template, TokenParser parser, ProvisioningTemplateApplyingInformation applyingInformation) { using (var scope = new PnPMonitoredScope(this.Name)) { if (template.Lists.Any()) { var rootWeb = (web.Context as ClientContext).Site.RootWeb; web.EnsureProperties(w => w.ServerRelativeUrl); web.Context.Load(web.Lists, lc => lc.IncludeWithDefaultProperties(l => l.RootFolder.ServerRelativeUrl)); web.Context.ExecuteQueryRetry(); var existingLists = web.Lists.AsEnumerable<List>().Select(existingList => existingList.RootFolder.ServerRelativeUrl).ToList(); var serverRelativeUrl = web.ServerRelativeUrl; #region DataRows foreach (var listInstance in template.Lists) { if (listInstance.DataRows != null && listInstance.DataRows.Any()) { scope.LogDebug(CoreResources.Provisioning_ObjectHandlers_ListInstancesDataRows_Processing_data_rows_for__0_, listInstance.Title); // Retrieve the target list var list = web.Lists.GetByTitle(parser.ParseString(listInstance.Title)); web.Context.Load(list); // Retrieve the fields' types from the list Microsoft.SharePoint.Client.FieldCollection fields = list.Fields; web.Context.Load(fields, fs => fs.Include(f => f.InternalName, f => f.FieldTypeKind)); web.Context.ExecuteQueryRetry(); foreach (var dataRow in listInstance.DataRows) { try { scope.LogDebug(CoreResources.Provisioning_ObjectHandlers_ListInstancesDataRows_Creating_list_item__0_, listInstance.DataRows.IndexOf(dataRow) + 1); var listitemCI = new ListItemCreationInformation(); var listitem = list.AddItem(listitemCI); foreach (var dataValue in dataRow.Values) { Field dataField = fields.FirstOrDefault( f => f.InternalName == parser.ParseString(dataValue.Key)); if (dataField != null) { String fieldValue = parser.ParseString(dataValue.Value); switch (dataField.FieldTypeKind) { case FieldType.Geolocation: // FieldGeolocationValue - Expected format: Altitude,Latitude,Longitude,Measure var geolocationArray = fieldValue.Split(','); if (geolocationArray.Length == 4) { var geolocationValue = new FieldGeolocationValue { Altitude = Double.Parse(geolocationArray[0]), Latitude = Double.Parse(geolocationArray[1]), Longitude = Double.Parse(geolocationArray[2]), Measure = Double.Parse(geolocationArray[3]), }; listitem[parser.ParseString(dataValue.Key)] = geolocationValue; } else { listitem[parser.ParseString(dataValue.Key)] = fieldValue; } break; case FieldType.Lookup: // FieldLookupValue - Expected format: LookupID or LookupID,LookupID,LookupID... if (fieldValue.Contains(",")) { var lookupValues = new List<FieldLookupValue>(); fieldValue.Split(',').All(value => { lookupValues.Add(new FieldLookupValue { LookupId = int.Parse(value), }); return true; }); listitem[parser.ParseString(dataValue.Key)] = lookupValues.ToArray(); } else { var lookupValue = new FieldLookupValue { LookupId = int.Parse(fieldValue), }; listitem[parser.ParseString(dataValue.Key)] = lookupValue; } break; case FieldType.URL: // FieldUrlValue - Expected format: URL,Description var urlArray = fieldValue.Split(','); var linkValue = new FieldUrlValue(); if (urlArray.Length == 2) { linkValue.Url = urlArray[0]; linkValue.Description = urlArray[1]; } else { linkValue.Url = urlArray[0]; linkValue.Description = urlArray[0]; } listitem[parser.ParseString(dataValue.Key)] = linkValue; break; case FieldType.User: // FieldUserValue - Expected format: loginName or loginName,loginName,loginName... if (fieldValue.Contains(",")) { var userValues = new List<FieldUserValue>(); fieldValue.Split(',').All(value => { var user = web.EnsureUser(value); web.Context.Load(user); web.Context.ExecuteQueryRetry(); if (user != null) { userValues.Add(new FieldUserValue { LookupId = user.Id, }); ; } return true; }); listitem[parser.ParseString(dataValue.Key)] = userValues.ToArray(); } else { var user = web.EnsureUser(fieldValue); web.Context.Load(user); web.Context.ExecuteQueryRetry(); if (user != null) { var userValue = new FieldUserValue { LookupId = user.Id, }; listitem[parser.ParseString(dataValue.Key)] = userValue; } else { listitem[parser.ParseString(dataValue.Key)] = fieldValue; } } break; case FieldType.DateTime: var dateTime = DateTime.MinValue; if (DateTime.TryParse(fieldValue, out dateTime)) { listitem[parser.ParseString(dataValue.Key)] = dateTime; } break; default: listitem[parser.ParseString(dataValue.Key)] = fieldValue; break; } } } listitem.Update(); web.Context.ExecuteQueryRetry(); // TODO: Run in batches? if (dataRow.Security != null && dataRow.Security.RoleAssignments.Count != 0) { listitem.SetSecurity(parser, dataRow.Security); } } catch (Exception ex) { if (ex.GetType().Equals(typeof(ServerException)) && (ex as ServerException).ServerErrorTypeName.Equals("Microsoft.SharePoint.SPDuplicateValuesFoundException", StringComparison.InvariantCultureIgnoreCase) && applyingInformation.IgnoreDuplicateDataRowErrors) { scope.LogWarning(CoreResources.Provisioning_ObjectHandlers_ListInstancesDataRows_Creating_listitem_duplicate); continue; } else { scope.LogError(CoreResources.Provisioning_ObjectHandlers_ListInstancesDataRows_Creating_listitem_failed___0_____1_, ex.Message, ex.StackTrace); throw; } } } } } #endregion } } return parser; }
internal static void UpdateCustomAction(TokenParser parser, PnPMonitoredScope scope, CustomAction customAction, UserCustomAction existingCustomAction, bool isNoScriptSite = false) { var isDirty = false; if (isNoScriptSite) { scope.LogWarning(CoreResources.Provisioning_ObjectHandlers_CustomActions_SkippingAddUpdateDueToNoScript, customAction.Name); return; } // Otherwise we update it if (customAction.CommandUIExtension != null) { if (existingCustomAction.CommandUIExtension != parser.ParseString(customAction.CommandUIExtension.ToString())) { scope.LogPropertyUpdate("CommandUIExtension"); existingCustomAction.CommandUIExtension = parser.ParseString(customAction.CommandUIExtension.ToString()); isDirty = true; } } else { // Required to allow for a delta action to blank out the CommandUIExtension attribute if (existingCustomAction.CommandUIExtension != null) { scope.LogPropertyUpdate("CommandUIExtension"); existingCustomAction.CommandUIExtension = null; isDirty = true; } } if (existingCustomAction.Description != customAction.Description) { scope.LogPropertyUpdate("Description"); existingCustomAction.Description = customAction.Description; isDirty = true; } #if !ONPREMISES if (customAction.Description.ContainsResourceToken()) { if (existingCustomAction.DescriptionResource.SetUserResourceValue(customAction.Description, parser)) { isDirty = true; } } #endif if (existingCustomAction.Group != customAction.Group) { scope.LogPropertyUpdate("Group"); existingCustomAction.Group = customAction.Group; isDirty = true; } if (existingCustomAction.ImageUrl != parser.ParseString(customAction.ImageUrl)) { scope.LogPropertyUpdate("ImageUrl"); existingCustomAction.ImageUrl = parser.ParseString(customAction.ImageUrl); isDirty = true; } if (existingCustomAction.Location != customAction.Location) { scope.LogPropertyUpdate("Location"); existingCustomAction.Location = customAction.Location; isDirty = true; } if (existingCustomAction.RegistrationId != customAction.RegistrationId) { scope.LogPropertyUpdate("RegistrationId"); existingCustomAction.RegistrationId = customAction.RegistrationId; isDirty = true; } if (existingCustomAction.RegistrationType != customAction.RegistrationType) { scope.LogPropertyUpdate("RegistrationType"); existingCustomAction.RegistrationType = customAction.RegistrationType; isDirty = true; } if (existingCustomAction.ScriptBlock != parser.ParseString(customAction.ScriptBlock)) { scope.LogPropertyUpdate("ScriptBlock"); existingCustomAction.ScriptBlock = parser.ParseString(customAction.ScriptBlock); isDirty = true; } if (existingCustomAction.ScriptSrc != parser.ParseString(customAction.ScriptSrc, "~site", "~sitecollection")) { scope.LogPropertyUpdate("ScriptSrc"); existingCustomAction.ScriptSrc = parser.ParseString(customAction.ScriptSrc, "~site", "~sitecollection"); isDirty = true; } if (existingCustomAction.Sequence != customAction.Sequence) { scope.LogPropertyUpdate("Sequence"); existingCustomAction.Sequence = customAction.Sequence; isDirty = true; } if (existingCustomAction.Title != parser.ParseString(customAction.Title)) { scope.LogPropertyUpdate("Title"); existingCustomAction.Title = parser.ParseString(customAction.Title); isDirty = true; } #if !ONPREMISES if (customAction.Title.ContainsResourceToken()) { if (existingCustomAction.TitleResource.SetUserResourceValue(customAction.Title, parser)) { isDirty = true; } } #endif if (existingCustomAction.Url != parser.ParseString(customAction.Url)) { scope.LogPropertyUpdate("Url"); existingCustomAction.Url = parser.ParseString(customAction.Url); isDirty = true; } if (isDirty) { existingCustomAction.Update(); existingCustomAction.Context.ExecuteQueryRetry(); } }
private static void UpdateContentType(Web web, Microsoft.SharePoint.Client.ContentType existingContentType, ContentType templateContentType, TokenParser parser, PnPMonitoredScope scope) { var isDirty = false; if (existingContentType.Hidden != templateContentType.Hidden) { scope.LogPropertyUpdate("Hidden"); existingContentType.Hidden = templateContentType.Hidden; isDirty = true; } if (existingContentType.ReadOnly != templateContentType.ReadOnly) { scope.LogPropertyUpdate("ReadOnly"); existingContentType.ReadOnly = templateContentType.ReadOnly; isDirty = true; } if (existingContentType.Sealed != templateContentType.Sealed) { scope.LogPropertyUpdate("Sealed"); existingContentType.Sealed = templateContentType.Sealed; isDirty = true; } if (templateContentType.Description != null && existingContentType.Description != parser.ParseString(templateContentType.Description)) { scope.LogPropertyUpdate("Description"); existingContentType.Description = parser.ParseString(templateContentType.Description); isDirty = true; } if (templateContentType.DocumentTemplate != null && existingContentType.DocumentTemplate != parser.ParseString(templateContentType.DocumentTemplate)) { scope.LogPropertyUpdate("DocumentTemplate"); existingContentType.DocumentTemplate = parser.ParseString(templateContentType.DocumentTemplate); isDirty = true; } if (existingContentType.Name != parser.ParseString(templateContentType.Name)) { scope.LogPropertyUpdate("Name"); existingContentType.Name = parser.ParseString(templateContentType.Name); isDirty = true; } if (templateContentType.Group != null && existingContentType.Group != parser.ParseString(templateContentType.Group)) { scope.LogPropertyUpdate("Group"); existingContentType.Group = parser.ParseString(templateContentType.Group); isDirty = true; } if (isDirty) { existingContentType.Update(true); web.Context.ExecuteQueryRetry(); } // Delta handling List<Guid> targetIds = existingContentType.FieldLinks.AsEnumerable().Select(c1 => c1.Id).ToList(); List<Guid> sourceIds = templateContentType.FieldRefs.Select(c1 => c1.Id).ToList(); var fieldsNotPresentInTarget = sourceIds.Except(targetIds).ToArray(); if (fieldsNotPresentInTarget.Any()) { foreach (var fieldId in fieldsNotPresentInTarget) { var fieldRef = templateContentType.FieldRefs.Find(fr => fr.Id == fieldId); var field = web.Fields.GetById(fieldId); scope.LogDebug(CoreResources.Provisioning_ObjectHandlers_ContentTypes_Adding_field__0__to_content_type, fieldId); web.AddFieldToContentType(existingContentType, field, fieldRef.Required, fieldRef.Hidden); } } isDirty = false; foreach (var fieldId in targetIds.Intersect(sourceIds)) { var fieldLink = existingContentType.FieldLinks.FirstOrDefault(fl => fl.Id == fieldId); var fieldRef = templateContentType.FieldRefs.Find(fr => fr.Id == fieldId); if (fieldRef != null) { scope.LogDebug(CoreResources.Provisioning_ObjectHandlers_ContentTypes_Field__0__exists_in_content_type, fieldId); if (fieldLink.Required != fieldRef.Required) { scope.LogPropertyUpdate("Required"); fieldLink.Required = fieldRef.Required; isDirty = true; } if (fieldLink.Hidden != fieldRef.Hidden) { scope.LogPropertyUpdate("Hidden"); fieldLink.Hidden = fieldRef.Hidden; isDirty = true; } } } // The new CT is a DocumentSet, and the target should be, as well if (templateContentType.DocumentSetTemplate != null) { if (!Microsoft.SharePoint.Client.DocumentSet.DocumentSetTemplate.IsChildOfDocumentSetContentType(web.Context, existingContentType).Value) { scope.LogError(CoreResources.Provisioning_ObjectHandlers_ContentTypes_InvalidDocumentSet_Update_Request, existingContentType.Id, existingContentType.Name); } else { Microsoft.SharePoint.Client.DocumentSet.DocumentSetTemplate templateToUpdate = Microsoft.SharePoint.Client.DocumentSet.DocumentSetTemplate.GetDocumentSetTemplate(web.Context, existingContentType); // TODO: Implement Delta Handling scope.LogWarning(CoreResources.Provisioning_ObjectHandlers_ContentTypes_DocumentSet_DeltaHandling_OnHold, existingContentType.Id, existingContentType.Name); } } if (isDirty) { existingContentType.Update(true); web.Context.ExecuteQueryRetry(); } }
private void ProvisionCustomActionImplementation(object parent, CustomActionCollection customActions, TokenParser parser, PnPMonitoredScope scope, bool isNoScriptSite= false) { Web web = null; Site site = null; if (parent is Site) { site = parent as Site; // Switch parser context; parser.Rebase(site.RootWeb); } else { web = parent as Web; // Switch parser context parser.Rebase(web); } foreach (var customAction in customActions) { if (isNoScriptSite) { scope.LogWarning(CoreResources.Provisioning_ObjectHandlers_CustomActions_SkippingAddUpdateDueToNoScript, customAction.Name); continue; } var caExists = false; if (site != null) { caExists = site.CustomActionExists(customAction.Name); } else { caExists = web.CustomActionExists(customAction.Name); } // If the CustomAction does not exist, we don't have to remove it, and it is enabled if (!caExists && !customAction.Remove && customAction.Enabled) { // Then we add it to the target var customActionEntity = new CustomActionEntity() { CommandUIExtension = customAction.CommandUIExtension != null ? parser.ParseString(customAction.CommandUIExtension.ToString()) : string.Empty, Description = parser.ParseString(customAction.Description), Group = customAction.Group, ImageUrl = parser.ParseString(customAction.ImageUrl), Location = customAction.Location, Name = customAction.Name, RegistrationId = customAction.RegistrationId, RegistrationType = customAction.RegistrationType, Remove = customAction.Remove, Rights = customAction.Rights, ScriptBlock = parser.ParseString(customAction.ScriptBlock), ScriptSrc = parser.ParseString(customAction.ScriptSrc, "~site", "~sitecollection"), Sequence = customAction.Sequence, Title = parser.ParseString(customAction.Title), Url = parser.ParseString(customAction.Url) }; if (site != null) { scope.LogDebug(CoreResources.Provisioning_ObjectHandlers_CustomActions_Adding_custom_action___0___to_scope_Site, customActionEntity.Name); site.AddCustomAction(customActionEntity); #if !ONPREMISES if ((!string.IsNullOrEmpty(customAction.Title) && customAction.Title.ContainsResourceToken()) || (!string.IsNullOrEmpty(customAction.Description) && customAction.Description.ContainsResourceToken())) { var uca = site.GetCustomActions().Where(uc => uc.Name == customAction.Name).FirstOrDefault(); SetCustomActionResourceValues(parser, customAction, uca); } #endif } else { scope.LogDebug(CoreResources.Provisioning_ObjectHandlers_CustomActions_Adding_custom_action___0___to_scope_Web, customActionEntity.Name); web.AddCustomAction(customActionEntity); #if !ONPREMISES if (customAction.Title.ContainsResourceToken() || customAction.Description.ContainsResourceToken()) { var uca = web.GetCustomActions().Where(uc => uc.Name == customAction.Name).FirstOrDefault(); SetCustomActionResourceValues(parser, customAction, uca); } #endif } } else { UserCustomAction existingCustomAction = null; if (site != null) { existingCustomAction = site.GetCustomActions().FirstOrDefault(c => c.Name == customAction.Name); } else { existingCustomAction = web.GetCustomActions().FirstOrDefault(c => c.Name == customAction.Name); } if (existingCustomAction != null) { // If we have to remove the existing CustomAction if (customAction.Remove) { // We simply remove it existingCustomAction.DeleteObject(); existingCustomAction.Context.ExecuteQueryRetry(); } else { UpdateCustomAction(parser, scope, customAction, existingCustomAction, isNoScriptSite); } } } } }
private void UpdateField(Web web, string fieldId, XElement templateFieldElement, PnPMonitoredScope scope, TokenParser parser, string originalFieldXml) { var existingField = web.Fields.GetById(Guid.Parse(fieldId)); web.Context.Load(existingField, f => f.SchemaXml); web.Context.ExecuteQueryRetry(); XElement existingFieldElement = XElement.Parse(existingField.SchemaXml); XNodeEqualityComparer equalityComparer = new XNodeEqualityComparer(); if (equalityComparer.GetHashCode(existingFieldElement) != equalityComparer.GetHashCode(templateFieldElement)) // Is field different in template? { if (existingFieldElement.Attribute("Type").Value == templateFieldElement.Attribute("Type").Value) // Is existing field of the same type? { if (IsFieldXmlValid(parser.ParseString(originalFieldXml), parser, web.Context)) { var listIdentifier = templateFieldElement.Attribute("List") != null ? templateFieldElement.Attribute("List").Value : null; if (listIdentifier != null) { // Temporary remove list attribute from list templateFieldElement.Attribute("List").Remove(); } foreach (var attribute in templateFieldElement.Attributes()) { if (existingFieldElement.Attribute(attribute.Name) != null) { existingFieldElement.Attribute(attribute.Name).Value = attribute.Value; } else { existingFieldElement.Add(attribute); } } foreach (var element in templateFieldElement.Elements()) { if (existingFieldElement.Element(element.Name) != null) { existingFieldElement.Element(element.Name).Remove(); } existingFieldElement.Add(element); } if (existingFieldElement.Attribute("Version") != null) { existingFieldElement.Attributes("Version").Remove(); } existingField.SchemaXml = parser.ParseString(existingFieldElement.ToString(), "~sitecollection", "~site"); existingField.UpdateAndPushChanges(true); web.Context.Load(existingField, f => f.TypeAsString, f => f.DefaultValue); web.Context.ExecuteQueryRetry(); bool isDirty = false; #if !CLIENTSDKV15 if (originalFieldXml.ContainsResourceToken()) { var originalFieldElement = XElement.Parse(originalFieldXml); var nameAttributeValue = originalFieldElement.Attribute("Title") != null ? originalFieldElement.Attribute("Title").Value : ""; if (nameAttributeValue.ContainsResourceToken()) { existingField.TitleResource.SetUserResourceValue(nameAttributeValue, parser); isDirty = true; } var descriptionAttributeValue = originalFieldElement.Attribute("Description") != null ? originalFieldElement.Attribute("Description").Value : ""; if (descriptionAttributeValue.ContainsResourceToken()) { existingField.DescriptionResource.SetUserResourceValue(descriptionAttributeValue, parser); isDirty = true; } } #endif if (isDirty) { existingField.Update(); web.Context.ExecuteQuery(); } if ((existingField.TypeAsString == "TaxonomyFieldType" || existingField.TypeAsString == "TaxonomyFieldTypeMulti") && !string.IsNullOrEmpty(existingField.DefaultValue)) { var taxField = web.Context.CastTo<TaxonomyField>(existingField); ValidateTaxonomyFieldDefaultValue(taxField); } } else { // The field Xml was found invalid var tokenString = parser.GetLeftOverTokens(originalFieldXml).Aggregate(String.Empty, (acc, i) => acc + " " + i); scope.LogError("The field was found invalid: {0}", tokenString); throw new Exception(string.Format("The field was found invalid: {0}", tokenString)); } } else { var fieldName = existingFieldElement.Attribute("Name") != null ? existingFieldElement.Attribute("Name").Value : existingFieldElement.Attribute("StaticName").Value; WriteWarning(string.Format(CoreResources.Provisioning_ObjectHandlers_Fields_Field__0____1___exists_but_is_of_different_type__Skipping_field_, fieldName, fieldId), ProvisioningMessageType.Warning); scope.LogWarning(CoreResources.Provisioning_ObjectHandlers_Fields_Field__0____1___exists_but_is_of_different_type__Skipping_field_, fieldName, fieldId); } } }
public override TokenParser ProvisionObjects(Web web, ProvisioningTemplate template, TokenParser parser, ProvisioningTemplateApplyingInformation applyingInformation) { using (var scope = new PnPMonitoredScope(this.Name)) { if (template.Lists.Any()) { var rootWeb = (web.Context as ClientContext).Site.RootWeb; web.EnsureProperties(w => w.ServerRelativeUrl); web.Context.Load(web.Lists, lc => lc.IncludeWithDefaultProperties(l => l.RootFolder.ServerRelativeUrl)); web.Context.ExecuteQueryRetry(); var existingLists = web.Lists.AsEnumerable <List>().Select(existingList => existingList.RootFolder.ServerRelativeUrl).ToList(); var serverRelativeUrl = web.ServerRelativeUrl; #region DataRows foreach (var listInstance in template.Lists) { if (listInstance.DataRows != null && listInstance.DataRows.Any()) { scope.LogDebug(CoreResources.Provisioning_ObjectHandlers_ListInstancesDataRows_Processing_data_rows_for__0_, listInstance.Title); // Retrieve the target list var list = web.Lists.GetByTitle(parser.ParseString(listInstance.Title)); web.Context.Load(list); // Retrieve the fields' types from the list Microsoft.SharePoint.Client.FieldCollection fields = list.Fields; web.Context.Load(fields, fs => fs.Include(f => f.InternalName, f => f.FieldTypeKind)); web.Context.ExecuteQueryRetry(); foreach (var dataRow in listInstance.DataRows) { try { scope.LogDebug(CoreResources.Provisioning_ObjectHandlers_ListInstancesDataRows_Creating_list_item__0_, listInstance.DataRows.IndexOf(dataRow) + 1); var listitemCI = new ListItemCreationInformation(); var listitem = list.AddItem(listitemCI); foreach (var dataValue in dataRow.Values) { Field dataField = fields.FirstOrDefault( f => f.InternalName == parser.ParseString(dataValue.Key)); if (dataField != null) { String fieldValue = parser.ParseString(dataValue.Value); switch (dataField.FieldTypeKind) { case FieldType.Geolocation: // FieldGeolocationValue - Expected format: Altitude,Latitude,Longitude,Measure var geolocationArray = fieldValue.Split(','); if (geolocationArray.Length == 4) { var geolocationValue = new FieldGeolocationValue { Altitude = Double.Parse(geolocationArray[0]), Latitude = Double.Parse(geolocationArray[1]), Longitude = Double.Parse(geolocationArray[2]), Measure = Double.Parse(geolocationArray[3]), }; listitem[parser.ParseString(dataValue.Key)] = geolocationValue; } else { listitem[parser.ParseString(dataValue.Key)] = fieldValue; } break; case FieldType.Lookup: // FieldLookupValue - Expected format: LookupID or LookupID,LookupID,LookupID... if (fieldValue.Contains(",")) { var lookupValues = new List <FieldLookupValue>(); fieldValue.Split(',').All(value => { lookupValues.Add(new FieldLookupValue { LookupId = int.Parse(value), }); return(true); }); listitem[parser.ParseString(dataValue.Key)] = lookupValues.ToArray(); } else { var lookupValue = new FieldLookupValue { LookupId = int.Parse(fieldValue), }; listitem[parser.ParseString(dataValue.Key)] = lookupValue; } break; case FieldType.URL: // FieldUrlValue - Expected format: URL,Description var urlArray = fieldValue.Split(','); var linkValue = new FieldUrlValue(); if (urlArray.Length == 2) { linkValue.Url = urlArray[0]; linkValue.Description = urlArray[1]; } else { linkValue.Url = urlArray[0]; linkValue.Description = urlArray[0]; } listitem[parser.ParseString(dataValue.Key)] = linkValue; break; case FieldType.User: // FieldUserValue - Expected format: loginName or loginName,loginName,loginName... if (fieldValue.Contains(",")) { var userValues = new List <FieldUserValue>(); fieldValue.Split(',').All(value => { var user = web.EnsureUser(value); web.Context.Load(user); web.Context.ExecuteQueryRetry(); if (user != null) { userValues.Add(new FieldUserValue { LookupId = user.Id, });; } return(true); }); listitem[parser.ParseString(dataValue.Key)] = userValues.ToArray(); } else { var user = web.EnsureUser(fieldValue); web.Context.Load(user); web.Context.ExecuteQueryRetry(); if (user != null) { var userValue = new FieldUserValue { LookupId = user.Id, }; listitem[parser.ParseString(dataValue.Key)] = userValue; } else { listitem[parser.ParseString(dataValue.Key)] = fieldValue; } } break; case FieldType.DateTime: var dateTime = DateTime.MinValue; if (DateTime.TryParse(fieldValue, out dateTime)) { listitem[parser.ParseString(dataValue.Key)] = dateTime; } break; default: listitem[parser.ParseString(dataValue.Key)] = fieldValue; break; } } } listitem.Update(); web.Context.ExecuteQueryRetry(); // TODO: Run in batches? if (dataRow.Security != null && (dataRow.Security.ClearSubscopes == true || dataRow.Security.CopyRoleAssignments == true || dataRow.Security.RoleAssignments.Count > 0)) { listitem.SetSecurity(parser, dataRow.Security); } } catch (Exception ex) { if (ex.GetType().Equals(typeof(ServerException)) && (ex as ServerException).ServerErrorTypeName.Equals("Microsoft.SharePoint.SPDuplicateValuesFoundException", StringComparison.InvariantCultureIgnoreCase) && applyingInformation.IgnoreDuplicateDataRowErrors) { scope.LogWarning(CoreResources.Provisioning_ObjectHandlers_ListInstancesDataRows_Creating_listitem_duplicate); continue; } else { scope.LogError(CoreResources.Provisioning_ObjectHandlers_ListInstancesDataRows_Creating_listitem_failed___0_____1_, ex.Message, ex.StackTrace); throw; } } } } } #endregion } } return(parser); }
private void UpdateField(ClientObject web, ListInfo listInfo, Guid fieldId, XElement templateFieldElement, Field existingField, PnPMonitoredScope scope, TokenParser parser) { web.Context.Load(existingField, f => f.SchemaXml); web.Context.ExecuteQueryRetry(); var existingFieldElement = XElement.Parse(existingField.SchemaXml); var equalityComparer = new XNodeEqualityComparer(); // Is field different in template? if (equalityComparer.GetHashCode(existingFieldElement) != equalityComparer.GetHashCode(templateFieldElement)) { // Is existing field of the same type? if (existingFieldElement.Attribute("Type").Value == templateFieldElement.Attribute("Type").Value) { templateFieldElement = PrepareField(templateFieldElement); foreach (var attribute in templateFieldElement.Attributes()) { if (existingFieldElement.Attribute(attribute.Name) != null) { existingFieldElement.Attribute(attribute.Name).Value = attribute.Value; } else { existingFieldElement.Add(attribute); } } foreach (var element in templateFieldElement.Elements()) { if (existingFieldElement.Element(element.Name) != null) { existingFieldElement.Element(element.Name).Remove(); } existingFieldElement.Add(element); } if (existingFieldElement.Attribute("Version") != null) { existingFieldElement.Attributes("Version").Remove(); } existingField.SchemaXml = parser.ParseString(existingFieldElement.ToString(), "~sitecollection", "~site"); existingField.UpdateAndPushChanges(true); web.Context.ExecuteQueryRetry(); } else { var fieldName = existingFieldElement.Attribute("Name") != null ? existingFieldElement.Attribute("Name").Value : existingFieldElement.Attribute("StaticName").Value; scope.LogWarning(CoreResources.Provisioning_ObjectHandlers_ListInstances_Field__0____1___exists_in_list__2____3___but_is_of_different_type__Skipping_field_, fieldName, fieldId, listInfo.TemplateList.Title, listInfo.SiteList.Id); WriteWarning(string.Format(CoreResources.Provisioning_ObjectHandlers_ListInstances_Field__0____1___exists_in_list__2____3___but_is_of_different_type__Skipping_field_, fieldName, fieldId, listInfo.TemplateList.Title, listInfo.SiteList.Id), ProvisioningMessageType.Warning); } } }
public override TokenParser ProvisionObjects(Web web, ProvisioningTemplate template, TokenParser parser, ProvisioningTemplateApplyingInformation applyingInformation) { using (var scope = new PnPMonitoredScope(this.Name)) { web.EnsureProperties(w => w.ServerRelativeUrl); // determine pages library string pagesLibrary = "SitePages"; List <string> preCreatedPages = new List <string>(); // pre create the needed pages so we can fill the needed tokens which might be used later on when we put web parts on those pages foreach (var clientSidePage in template.ClientSidePages) { string pageName = $"{System.IO.Path.GetFileNameWithoutExtension(clientSidePage.PageName)}.aspx"; string url = $"{pagesLibrary}/{pageName}"; url = UrlUtility.Combine(web.ServerRelativeUrl, url); var exists = true; try { var file = web.GetFileByServerRelativeUrl(url); web.Context.Load(file, f => f.UniqueId, f => f.ServerRelativeUrl); web.Context.ExecuteQueryRetry(); // Fill token parser.AddToken(new PageUniqueIdToken(web, file.ServerRelativeUrl.Substring(web.ServerRelativeUrl.Length).TrimStart("/".ToCharArray()), file.UniqueId)); parser.AddToken(new PageUniqueIdEncodedToken(web, file.ServerRelativeUrl.Substring(web.ServerRelativeUrl.Length).TrimStart("/".ToCharArray()), file.UniqueId)); } catch (ServerException ex) { if (ex.ServerErrorTypeName == "System.IO.FileNotFoundException") { exists = false; } } if (!exists) { // Pre-create the page Pages.ClientSidePage page = web.AddClientSidePage(pageName); page.Save(pageName); var file = web.GetFileByServerRelativeUrl(url); web.Context.Load(file, f => f.UniqueId, f => f.ServerRelativeUrl); web.Context.ExecuteQueryRetry(); // Fill token parser.AddToken(new PageUniqueIdToken(web, file.ServerRelativeUrl.Substring(web.ServerRelativeUrl.Length).TrimStart("/".ToCharArray()), file.UniqueId)); parser.AddToken(new PageUniqueIdEncodedToken(web, file.ServerRelativeUrl.Substring(web.ServerRelativeUrl.Length).TrimStart("/".ToCharArray()), file.UniqueId)); // Track that we pre-added this page preCreatedPages.Add(url); } } // Iterate over the pages and create/update them foreach (var clientSidePage in template.ClientSidePages) { string pageName = $"{System.IO.Path.GetFileNameWithoutExtension(clientSidePage.PageName)}.aspx"; string url = $"{pagesLibrary}/{pageName}"; url = UrlUtility.Combine(web.ServerRelativeUrl, url); var exists = true; try { var file = web.GetFileByServerRelativeUrl(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)) { // Get the existing page page = web.LoadClientSidePage(pageName); // Clear the page page.ClearPage(); } else { scope.LogWarning(CoreResources.Provisioning_ObjectHandlers_ClientSidePages_NoOverWrite, pageName); continue; } } else { // Create new client side page page = web.AddClientSidePage(pageName); } // Set page layout if (!string.IsNullOrEmpty(clientSidePage.Layout)) { if (clientSidePage.Layout.Equals("Article", StringComparison.InvariantCultureIgnoreCase)) { page.LayoutType = Pages.ClientSidePageLayoutType.Article; } else if (clientSidePage.Layout.Equals("Home", StringComparison.InvariantCultureIgnoreCase)) { page.LayoutType = Pages.ClientSidePageLayoutType.Home; } } // 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); break; case CanvasSectionType.OneColumnFullWidth: page.AddSection(Pages.CanvasSectionTemplate.OneColumnFullWidth, section.Order); break; case CanvasSectionType.TwoColumn: page.AddSection(Pages.CanvasSectionTemplate.TwoColumn, section.Order); break; case CanvasSectionType.ThreeColumn: page.AddSection(Pages.CanvasSectionTemplate.ThreeColumn, section.Order); break; case CanvasSectionType.TwoColumnLeft: page.AddSection(Pages.CanvasSectionTemplate.TwoColumnLeft, section.Order); break; case CanvasSectionType.TwoColumnRight: page.AddSection(Pages.CanvasSectionTemplate.TwoColumnRight, section.Order); break; default: page.AddSection(Pages.CanvasSectionTemplate.OneColumn, section.Order); 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); // 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)); } } // 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; case WebPartType.BingMap: webPartName = Pages.ClientSidePage.ClientSideWebPartEnumToName(Pages.DefaultClientSideWebParts.BingMap); break; 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.GroupCalendar: webPartName = Pages.ClientSidePage.ClientSideWebPartEnumToName(Pages.DefaultClientSideWebParts.GroupCalendar); 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.PowerBIReportEmbed: webPartName = Pages.ClientSidePage.ClientSideWebPartEnumToName(Pages.DefaultClientSideWebParts.PowerBIReportEmbed); 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.MicrosoftForms: webPartName = Pages.ClientSidePage.ClientSideWebPartEnumToName(Pages.DefaultClientSideWebParts.MicrosoftForms); 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 }; // 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 page.Save(pageName); // Set commenting, ignore on pages of the type Home if (page.LayoutType != Pages.ClientSidePageLayoutType.Home) { // Make it a news page if requested if (clientSidePage.PromoteAsNewsArticle) { page.PromoteAsNewsArticle(); } } if (clientSidePage.EnableComments) { page.EnableComments(); } else { page.DisableComments(); } // Publish page if (clientSidePage.Publish) { page.Publish(); } } } return(parser); }
public override ProvisioningTemplate ExtractObjects(Web web, ProvisioningTemplate template, ProvisioningTemplateCreationInformation creationInfo) { using (var scope = new PnPMonitoredScope(this.Name)) { web.EnsureProperties(w => w.ServerRelativeUrl, w => w.Url); var serverRelativeUrl = web.ServerRelativeUrl; // For each list in the site var lists = web.Lists; web.Context.Load(lists, lc => lc.IncludeWithDefaultProperties( l => l.ContentTypes, l => l.Views, l => l.BaseTemplate, l => l.OnQuickLaunch, l => l.RootFolder.ServerRelativeUrl, l => l.Fields.IncludeWithDefaultProperties( f => f.Id, f => f.Title, f => f.Hidden, f => f.InternalName, f => f.Required))); web.Context.ExecuteQueryRetry(); // Let's see if there are workflow subscriptions Microsoft.SharePoint.Client.WorkflowServices.WorkflowSubscription[] workflowSubscriptions = null; try { workflowSubscriptions = web.GetWorkflowSubscriptions(); } catch (ServerException) { // If there is no workflow service present in the farm this method will throw an error. // Swallow the exception } // Retrieve all not hidden lists and the Workflow History Lists, just in case there are active workflow subscriptions var includeWorkflowSubscriptions = workflowSubscriptions != null && workflowSubscriptions.Length > 0; // var allowedLists = lists.Where(l => !l.Hidden || includeWorkflowSubscriptions && l.BaseTemplate == 140); foreach (var siteList in lists) { ListInstance baseTemplateList = null; if (creationInfo.BaseTemplate != null) { // Check if we need to skip this list...if so let's do it before we gather all the other information for this list...improves performance var index = creationInfo.BaseTemplate.Lists.FindIndex(f => f.Url.Equals(siteList.RootFolder.ServerRelativeUrl.Substring(serverRelativeUrl.Length + 1)) && f.TemplateType.Equals(siteList.BaseTemplate)); if (index != -1) { baseTemplateList = creationInfo.BaseTemplate.Lists[index]; if (siteList.Hidden && !(includeWorkflowSubscriptions && siteList.BaseTemplate == 140)) { continue; } } } var contentTypeFields = new List<FieldRef>(); var list = new ListInstance { Description = siteList.Description, EnableVersioning = siteList.EnableVersioning, TemplateType = siteList.BaseTemplate, Title = siteList.Title, Hidden = siteList.Hidden, EnableFolderCreation = siteList.EnableFolderCreation, DocumentTemplate = Tokenize(siteList.DocumentTemplateUrl, web.Url), ContentTypesEnabled = siteList.ContentTypesEnabled, Url = siteList.RootFolder.ServerRelativeUrl.Substring(serverRelativeUrl.Length).TrimStart('/'), TemplateFeatureID = siteList.TemplateFeatureId, EnableAttachments = siteList.EnableAttachments, OnQuickLaunch = siteList.OnQuickLaunch, MaxVersionLimit = siteList.IsObjectPropertyInstantiated("MajorVersionLimit") ? siteList.MajorVersionLimit : 0, EnableMinorVersions = siteList.EnableMinorVersions, MinorVersionLimit = siteList.IsObjectPropertyInstantiated("MajorWithMinorVersionsLimit") ? siteList.MajorWithMinorVersionsLimit : 0 }; list = ExtractContentTypes(web, siteList, contentTypeFields, list); list = ExtractViews(siteList, list); list = ExtractFields(web, siteList, contentTypeFields, list, lists); list.Security = siteList.GetSecurity(); var logCTWarning = false; if (baseTemplateList != null) { if (!baseTemplateList.Equals(list)) { scope.LogDebug(CoreResources.Provisioning_ObjectHandlers_ListInstances_Adding_list___0_____1_, list.Title, list.Url); template.Lists.Add(list); if (list.ContentTypesEnabled && list.ContentTypeBindings.Any() && web.IsSubSite()) { logCTWarning = true; } } } else { scope.LogDebug(CoreResources.Provisioning_ObjectHandlers_ListInstances_Adding_list___0_____1_, list.Title, list.Url); template.Lists.Add(list); if (list.ContentTypesEnabled && list.ContentTypeBindings.Any() && web.IsSubSite()) { logCTWarning = true; } } if (logCTWarning) { scope.LogWarning("You are extracting a template from a subweb. List '{0}' refers to content types. Content types are not exported when extracting a template from a subweb", list.Title); WriteWarning(string.Format("You are extracting a template from a subweb. List '{0}' refers to content types. Content types are not exported when extracting a template from a subweb", list.Title), ProvisioningMessageType.Warning); } } } return template; }
public override TokenParser ProvisionObjects(Web web, ProvisioningTemplate template, TokenParser parser, ProvisioningTemplateApplyingInformation applyingInformation) { using (var scope = new PnPMonitoredScope(this.Name)) { // Changed by Paolo Pialorsi to embrace the new sub-site attributes to break role inheritance and copy role assignments // if this is a sub site then we're not provisioning security as by default security is inherited from the root site //if (web.IsSubSite() && !template.Security.BreakRoleInheritance) //{ // scope.LogDebug(CoreResources.Provisioning_ObjectHandlers_SiteSecurity_Context_web_is_subweb__skipping_site_security_provisioning); // return parser; //} if (web.IsSubSite() && template.Security.BreakRoleInheritance) { web.BreakRoleInheritance(template.Security.CopyRoleAssignments, template.Security.ClearSubscopes); web.Update(); web.Context.ExecuteQueryRetry(); } var siteSecurity = template.Security; var ownerGroup = web.AssociatedOwnerGroup; var memberGroup = web.AssociatedMemberGroup; var visitorGroup = web.AssociatedVisitorGroup; web.Context.Load(ownerGroup, o => o.Title, o => o.Users); web.Context.Load(memberGroup, o => o.Title, o => o.Users); web.Context.Load(visitorGroup, o => o.Title, o => o.Users); web.Context.Load(web.SiteUsers); web.Context.ExecuteQueryRetry(); if (!ownerGroup.ServerObjectIsNull()) { AddUserToGroup(web, ownerGroup, siteSecurity.AdditionalOwners, scope, parser); } if (!memberGroup.ServerObjectIsNull()) { AddUserToGroup(web, memberGroup, siteSecurity.AdditionalMembers, scope, parser); } if (!visitorGroup.ServerObjectIsNull()) { AddUserToGroup(web, visitorGroup, siteSecurity.AdditionalVisitors, scope, parser); } //sorting groups with respect to possible dependency through Owner property. Groups that are owners of other groups must be processed prior owned groups. for (int i = siteSecurity.SiteGroups.Count - 1; i >= 0; i--) { var currentGroup = siteSecurity.SiteGroups[i]; string currentGroupOwner = parser.ParseString(currentGroup.Owner); string currentGroupTitle = parser.ParseString(currentGroup.Title); if (currentGroupOwner != "SHAREPOINT\\system" && currentGroupOwner != currentGroupTitle && !(currentGroupOwner.StartsWith("{{associated") && currentGroupOwner.EndsWith("group}}"))) { for (int j = 0; j < i; j++) { if (parser.ParseString(siteSecurity.SiteGroups[j].Owner) == currentGroupTitle) { siteSecurity.SiteGroups.RemoveAt(i); siteSecurity.SiteGroups.Insert(j, currentGroup); i++; break; } } } } foreach (var siteGroup in siteSecurity.SiteGroups) { Group group; var allGroups = web.Context.LoadQuery(web.SiteGroups.Include(gr => gr.LoginName)); web.Context.ExecuteQueryRetry(); string parsedGroupTitle = parser.ParseString(siteGroup.Title); string parsedGroupOwner = parser.ParseString(siteGroup.Owner); string parsedGroupDescription = parser.ParseString(siteGroup.Description); bool descriptionHasHtml = HttpUtility.HtmlEncode(parsedGroupDescription) != parsedGroupDescription; if (!web.GroupExists(parsedGroupTitle)) { scope.LogDebug("Creating group {0}", parsedGroupTitle); group = web.AddGroup( parsedGroupTitle, parsedGroupDescription, parsedGroupTitle == parsedGroupOwner); group.AllowMembersEditMembership = siteGroup.AllowMembersEditMembership; group.AllowRequestToJoinLeave = siteGroup.AllowRequestToJoinLeave; group.AutoAcceptRequestToJoinLeave = siteGroup.AutoAcceptRequestToJoinLeave; if (parsedGroupTitle != parsedGroupOwner) { Principal ownerPrincipal = allGroups.FirstOrDefault(gr => gr.LoginName == parsedGroupOwner); if (ownerPrincipal == null) { ownerPrincipal = web.EnsureUser(parsedGroupOwner); } group.Owner = ownerPrincipal; } group.Update(); web.Context.Load(group, g => g.Id, g => g.Title); web.Context.ExecuteQueryRetry(); parser.AddToken(new GroupIdToken(web, group.Title, group.Id)); if (descriptionHasHtml) { var groupItem = web.SiteUserInfoList.GetItemById(group.Id); groupItem["Notes"] = parsedGroupDescription; groupItem.Update(); web.Context.ExecuteQueryRetry(); } } else { group = web.SiteGroups.GetByName(parsedGroupTitle); web.Context.Load(group, g => g.Id, g => g.Title, g => g.Description, g => g.AllowMembersEditMembership, g => g.AllowRequestToJoinLeave, g => g.AutoAcceptRequestToJoinLeave, g => g.Owner.LoginName); web.Context.ExecuteQueryRetry(); var isDirty = false; if (descriptionHasHtml) { var groupItem = web.SiteUserInfoList.GetItemById(group.Id); web.Context.Load(groupItem, g => g["Notes"]); web.Context.ExecuteQueryRetry(); var description = groupItem["Notes"]?.ToString(); if (description != parsedGroupDescription) { groupItem["Notes"] = parsedGroupDescription; groupItem.Update(); isDirty = true; } } else { if (!String.IsNullOrEmpty(group.Description) && group.Description != parsedGroupDescription) { group.Description = parsedGroupDescription; isDirty = true; } } if (group.AllowMembersEditMembership != siteGroup.AllowMembersEditMembership) { group.AllowMembersEditMembership = siteGroup.AllowMembersEditMembership; isDirty = true; } if (group.AllowRequestToJoinLeave != siteGroup.AllowRequestToJoinLeave) { group.AllowRequestToJoinLeave = siteGroup.AllowRequestToJoinLeave; isDirty = true; } if (group.AutoAcceptRequestToJoinLeave != siteGroup.AutoAcceptRequestToJoinLeave) { group.AutoAcceptRequestToJoinLeave = siteGroup.AutoAcceptRequestToJoinLeave; isDirty = true; } if (group.Owner.LoginName != parsedGroupOwner) { if (parsedGroupTitle != parsedGroupOwner) { Principal ownerPrincipal = allGroups.FirstOrDefault(gr => gr.LoginName == parsedGroupOwner); if (ownerPrincipal == null) { ownerPrincipal = web.EnsureUser(parsedGroupOwner); } group.Owner = ownerPrincipal; } else { group.Owner = group; } isDirty = true; } if (isDirty) { scope.LogDebug("Updating existing group {0}", group.Title); group.Update(); web.Context.ExecuteQueryRetry(); } } if (group != null && siteGroup.Members.Any()) { AddUserToGroup(web, group, siteGroup.Members, scope, parser); } } foreach (var admin in siteSecurity.AdditionalAdministrators) { var parsedAdminName = parser.ParseString(admin.Name); try { var user = web.EnsureUser(parsedAdminName); user.IsSiteAdmin = true; user.Update(); web.Context.ExecuteQueryRetry(); } catch (Exception ex) { scope.LogWarning(ex, "Failed to add AdditionalAdministrator {0}", parsedAdminName); } } // With the change from october, manage permission levels on subsites as well if (siteSecurity.SiteSecurityPermissions != null) { var existingRoleDefinitions = web.Context.LoadQuery(web.RoleDefinitions.Include(wr => wr.Name, wr => wr.BasePermissions, wr => wr.Description)); web.Context.ExecuteQueryRetry(); if (siteSecurity.SiteSecurityPermissions.RoleDefinitions.Any()) { foreach (var templateRoleDefinition in siteSecurity.SiteSecurityPermissions.RoleDefinitions) { var roleDefinitions = existingRoleDefinitions as RoleDefinition[] ?? existingRoleDefinitions.ToArray(); var siteRoleDefinition = roleDefinitions.FirstOrDefault(erd => erd.Name == parser.ParseString(templateRoleDefinition.Name)); if (siteRoleDefinition == null) { scope.LogDebug("Creating role definition {0}", parser.ParseString(templateRoleDefinition.Name)); var roleDefinitionCI = new RoleDefinitionCreationInformation(); roleDefinitionCI.Name = parser.ParseString(templateRoleDefinition.Name); roleDefinitionCI.Description = parser.ParseString(templateRoleDefinition.Description); BasePermissions basePermissions = new BasePermissions(); foreach (var permission in templateRoleDefinition.Permissions) { basePermissions.Set(permission); } roleDefinitionCI.BasePermissions = basePermissions; var newRoleDefinition = web.RoleDefinitions.Add(roleDefinitionCI); web.Context.Load(newRoleDefinition, nrd => nrd.Name, nrd => nrd.Id); web.Context.ExecuteQueryRetry(); parser.AddToken(new RoleDefinitionIdToken(web, newRoleDefinition.Name, newRoleDefinition.Id)); } else { var isDirty = false; if (siteRoleDefinition.Description != parser.ParseString(templateRoleDefinition.Description)) { siteRoleDefinition.Description = parser.ParseString(templateRoleDefinition.Description); isDirty = true; } var templateBasePermissions = new BasePermissions(); templateRoleDefinition.Permissions.ForEach(p => templateBasePermissions.Set(p)); if (siteRoleDefinition.BasePermissions != templateBasePermissions) { isDirty = true; foreach (var permission in templateRoleDefinition.Permissions) { siteRoleDefinition.BasePermissions.Set(permission); } } if (isDirty) { scope.LogDebug("Updating role definition {0}", parser.ParseString(templateRoleDefinition.Name)); siteRoleDefinition.Update(); web.Context.ExecuteQueryRetry(); } } } } var webRoleDefinitions = web.Context.LoadQuery(web.RoleDefinitions); var webRoleAssignments = web.Context.LoadQuery(web.RoleAssignments); var groups = web.Context.LoadQuery(web.SiteGroups.Include(g => g.LoginName)); web.Context.ExecuteQueryRetry(); if (siteSecurity.SiteSecurityPermissions.RoleAssignments.Any()) { foreach (var roleAssignment in siteSecurity.SiteSecurityPermissions.RoleAssignments) { if (!roleAssignment.Remove) { var roleDefinition = webRoleDefinitions.FirstOrDefault(r => r.Name == parser.ParseString(roleAssignment.RoleDefinition)); if (roleDefinition != null) { Principal principal = GetPrincipal(web, parser, scope, groups, roleAssignment); if (principal != null) { var roleDefinitionBindingCollection = new RoleDefinitionBindingCollection(web.Context); roleDefinitionBindingCollection.Add(roleDefinition); web.RoleAssignments.Add(principal, roleDefinitionBindingCollection); web.Context.ExecuteQueryRetry(); } } else { scope.LogWarning("Role assignment {0} not found in web", roleAssignment.RoleDefinition); } } else { var principal = GetPrincipal(web, parser, scope, groups, roleAssignment); var assignmentsForPrincipal = webRoleAssignments.Where(t => t.PrincipalId == principal.Id); foreach (var assignmentForPrincipal in assignmentsForPrincipal) { var binding = assignmentForPrincipal.EnsureProperty(r => r.RoleDefinitionBindings).FirstOrDefault(b => b.Name == roleAssignment.RoleDefinition); if (binding != null) { assignmentForPrincipal.DeleteObject(); web.Context.ExecuteQueryRetry(); break; } } } } } } } return(parser); }
private void ExtractMasterPagesAndPageLayouts(Web web, ProvisioningTemplate template, PnPMonitoredScope scope, ProvisioningTemplateCreationInformation creationInfo) { web.EnsureProperty(w => w.Url); String webApplicationUrl = GetWebApplicationUrl(web.Url); if (!String.IsNullOrEmpty(webApplicationUrl)) { // Get the Publishing Feature reference template ProvisioningTemplate publishingFeatureTemplate = GetPublishingFeatureBaseTemplate(); // Get a reference to the root folder of the master page gallery var gallery = web.GetCatalog(116); web.Context.Load(gallery, g => g.RootFolder); web.Context.ExecuteQueryRetry(); var masterPageGalleryFolder = gallery.RootFolder; // Load the files in the master page gallery web.Context.Load(masterPageGalleryFolder.Files); web.Context.ExecuteQueryRetry(); var sourceFiles = masterPageGalleryFolder.Files.AsEnumerable().Where( f => f.Name.EndsWith(".aspx", StringComparison.InvariantCultureIgnoreCase) || f.Name.EndsWith(".html", StringComparison.InvariantCultureIgnoreCase) || f.Name.EndsWith(".master", StringComparison.InvariantCultureIgnoreCase)); foreach (var file in sourceFiles) { var listItem = file.EnsureProperty(f => f.ListItemAllFields); listItem.ContentType.EnsureProperties(ct => ct.Id, ct => ct.StringId); // Check if the content type is of type Master Page or Page Layout if (listItem.ContentType.StringId.StartsWith(MASTER_PAGE_CONTENT_TYPE_ID) || listItem.ContentType.StringId.StartsWith(PAGE_LAYOUT_CONTENT_TYPE_ID) || listItem.ContentType.StringId.StartsWith(HTML_MASTER_PAGE_CONTENT_TYPE_ID) || listItem.ContentType.StringId.StartsWith(HTML_PAGE_LAYOUT_CONTENT_TYPE_ID)) { // Skip any .ASPX or .MASTER file related to an .HTML designer file if ((file.Name.EndsWith(".aspx", StringComparison.InvariantCultureIgnoreCase) && sourceFiles.Any(f => f.Name.Equals(file.Name.ToLower().Replace(".aspx", ".html"), StringComparison.InvariantCultureIgnoreCase))) || (file.Name.EndsWith(".master", StringComparison.InvariantCultureIgnoreCase) && sourceFiles.Any(f => f.Name.Equals(file.Name.ToLower().Replace(".master", ".html"), StringComparison.InvariantCultureIgnoreCase)))) { continue; } // If the file is a custom one, and not one native // and coming out from the publishing feature if (creationInfo.IncludeNativePublishingFiles || !IsPublishingFeatureNativeFile(publishingFeatureTemplate, file.Name)) { var fullUri = new Uri(UrlUtility.Combine(webApplicationUrl, file.ServerRelativeUrl)); var folderPath = fullUri.Segments.Take(fullUri.Segments.Count() - 1).ToArray().Aggregate((i, x) => i + x).TrimEnd('/'); var fileName = fullUri.Segments[fullUri.Segments.Count() - 1]; var publishingFile = new Model.File() { Folder = Tokenize(folderPath, web.Url), Src = HttpUtility.UrlDecode(fileName), Overwrite = true, }; // Add field values to file RetrieveFieldValues(web, file, publishingFile); // Add the file to the template template.Files.Add(publishingFile); // Persist file using connector, if needed if (creationInfo.PersistPublishingFiles) { PersistFile(web, creationInfo, scope, folderPath, fileName, true); } if (listItem.ContentType.StringId.StartsWith(MASTER_PAGE_CONTENT_TYPE_ID)) { scope.LogWarning(String.Format("The file \"{0}\" is a custom MasterPage. Accordingly to the PnP Guidance (http://aka.ms/o365pnpguidancemasterpages) you should try to avoid using custom MasterPages.", file.Name)); } } else { scope.LogWarning(String.Format("Skipping file \"{0}\" because it is native in the publishing feature.", file.Name)); } } } } }
public override TokenParser ProvisionObjects(Web web, ProvisioningTemplate template, TokenParser parser, ProvisioningTemplateApplyingInformation applyingInformation) { using (var scope = new PnPMonitoredScope(this.Name)) { var context = web.Context as ClientContext; web.EnsureProperties(w => w.ServerRelativeUrl, w => w.RootFolder.WelcomePage); // Check if this is not a noscript site as we're not allowed to update some properties bool isNoScriptSite = web.IsNoScriptSite(); foreach (var page in template.Pages) { var url = parser.ParseString(page.Url); if (!url.ToLower().StartsWith(web.ServerRelativeUrl.ToLower())) { url = UrlUtility.Combine(web.ServerRelativeUrl, url); } var exists = true; Microsoft.SharePoint.Client.File file = null; try { file = web.GetFileByServerRelativeUrl(url); web.Context.Load(file); web.Context.ExecuteQueryRetry(); } catch (ServerException ex) { if (ex.ServerErrorTypeName == "System.IO.FileNotFoundException") { exists = false; } } if (exists) { if (page.Overwrite) { try { scope.LogDebug(CoreResources.Provisioning_ObjectHandlers_Pages_Overwriting_existing_page__0_, url); if (page.WelcomePage && url.Contains(web.RootFolder.WelcomePage)) web.SetHomePage(string.Empty); file.DeleteObject(); web.Context.ExecuteQueryRetry(); web.AddWikiPageByUrl(url); if (page.Layout == WikiPageLayout.Custom) { web.AddLayoutToWikiPage(WikiPageLayout.OneColumn, url); } else { web.AddLayoutToWikiPage(page.Layout, url); } } catch (Exception ex) { scope.LogError(CoreResources.Provisioning_ObjectHandlers_Pages_Overwriting_existing_page__0__failed___1_____2_, url, ex.Message, ex.StackTrace); } } } else { try { scope.LogDebug(CoreResources.Provisioning_ObjectHandlers_Pages_Creating_new_page__0_, url); web.AddWikiPageByUrl(url); if (page.Layout == WikiPageLayout.Custom) { web.AddLayoutToWikiPage(WikiPageLayout.OneColumn, url); } else { web.AddLayoutToWikiPage(page.Layout, url); } } catch (Exception ex) { scope.LogError(CoreResources.Provisioning_ObjectHandlers_Pages_Creating_new_page__0__failed___1_____2_, url, ex.Message, ex.StackTrace); } } if (page.WelcomePage) { web.RootFolder.EnsureProperty(p => p.ServerRelativeUrl); var rootFolderRelativeUrl = url.Substring(web.RootFolder.ServerRelativeUrl.Length); web.SetHomePage(rootFolderRelativeUrl); } if (page.WebParts != null & page.WebParts.Any()) { if (!isNoScriptSite) { var existingWebParts = web.GetWebParts(url); foreach (var webpart in page.WebParts) { if (existingWebParts.FirstOrDefault(w => w.WebPart.Title == webpart.Title) == null) { WebPartEntity wpEntity = new WebPartEntity(); wpEntity.WebPartTitle = webpart.Title; wpEntity.WebPartXml = parser.ParseString(webpart.Contents.Trim(new[] { '\n', ' ' })); web.AddWebPartToWikiPage(url, wpEntity, (int)webpart.Row, (int)webpart.Column, false); } } var allWebParts = web.GetWebParts(url); foreach (var webpart in allWebParts) { parser.AddToken(new WebPartIdToken(web, webpart.WebPart.Title, webpart.Id)); } } else { scope.LogWarning(CoreResources.Provisioning_ObjectHandlers_Pages_SkipAddingWebParts, page.Url); } } file = web.GetFileByServerRelativeUrl(url); file.EnsureProperty(f => f.ListItemAllFields); if (page.Fields.Any()) { var item = file.ListItemAllFields; foreach (var fieldValue in page.Fields) { item[fieldValue.Key] = parser.ParseString(fieldValue.Value); } item.Update(); web.Context.ExecuteQueryRetry(); } if (page.Security != null && page.Security.RoleAssignments.Count != 0) { web.Context.Load(file.ListItemAllFields); web.Context.ExecuteQueryRetry(); file.ListItemAllFields.SetSecurity(parser, page.Security); } } } return parser; }
private void UpdateField(Web web, string fieldId, XElement templateFieldElement, PnPMonitoredScope scope) { var existingField = web.Fields.GetById(Guid.Parse(fieldId)); web.Context.Load(existingField, f => f.SchemaXml); web.Context.ExecuteQueryRetry(); XElement existingFieldElement = XElement.Parse(existingField.SchemaXml); XNodeEqualityComparer equalityComparer = new XNodeEqualityComparer(); if (equalityComparer.GetHashCode(existingFieldElement) != equalityComparer.GetHashCode(templateFieldElement)) // Is field different in template? { if (existingFieldElement.Attribute("Type").Value == templateFieldElement.Attribute("Type").Value) // Is existing field of the same type? { var listIdentifier = templateFieldElement.Attribute("List") != null ? templateFieldElement.Attribute("List").Value : null; if (listIdentifier != null) { // Temporary remove list attribute from list templateFieldElement.Attribute("List").Remove(); } foreach (var attribute in templateFieldElement.Attributes()) { if (existingFieldElement.Attribute(attribute.Name) != null) { existingFieldElement.Attribute(attribute.Name).Value = attribute.Value; } else { existingFieldElement.Add(attribute); } } foreach (var element in templateFieldElement.Elements()) { if (existingFieldElement.Element(element.Name) != null) { existingFieldElement.Element(element.Name).Remove(); } existingFieldElement.Add(element); } if (existingFieldElement.Attribute("Version") != null) { existingFieldElement.Attributes("Version").Remove(); } existingField.SchemaXml = existingFieldElement.ToString(); existingField.UpdateAndPushChanges(true); web.Context.ExecuteQueryRetry(); } else { var fieldName = existingFieldElement.Attribute("Name") != null ? existingFieldElement.Attribute("Name").Value : existingFieldElement.Attribute("StaticName").Value; WriteWarning(string.Format(CoreResources.Provisioning_ObjectHandlers_Fields_Field__0____1___exists_but_is_of_different_type__Skipping_field_, fieldName, fieldId), ProvisioningMessageType.Warning); scope.LogWarning(CoreResources.Provisioning_ObjectHandlers_Fields_Field__0____1___exists_but_is_of_different_type__Skipping_field_, fieldName, fieldId); } } }
internal static void UpdateCustomAction(TokenParser parser, PnPMonitoredScope scope, CustomAction customAction, UserCustomAction existingCustomAction, bool isNoScriptSite = false) { var isDirty = false; if (isNoScriptSite) { scope.LogWarning(CoreResources.Provisioning_ObjectHandlers_CustomActions_SkippingAddUpdateDueToNoScript, customAction.Name); return; } // Otherwise we update it if (customAction.CommandUIExtension != null) { if (existingCustomAction.CommandUIExtension != parser.ParseString(customAction.CommandUIExtension.ToString())) { scope.LogPropertyUpdate("CommandUIExtension"); existingCustomAction.CommandUIExtension = parser.ParseString(customAction.CommandUIExtension.ToString()); isDirty = true; } } else { // Required to allow for a delta action to blank out the CommandUIExtension attribute if (existingCustomAction.CommandUIExtension != null) { scope.LogPropertyUpdate("CommandUIExtension"); existingCustomAction.CommandUIExtension = null; isDirty = true; } } if (customAction.ClientSideComponentId != null && customAction.ClientSideComponentId != Guid.Empty) { if (existingCustomAction.ClientSideComponentId != customAction.ClientSideComponentId) { existingCustomAction.ClientSideComponentId = customAction.ClientSideComponentId; isDirty = true; } } if (!String.IsNullOrEmpty(customAction.ClientSideComponentProperties)) { if (existingCustomAction.ClientSideComponentProperties != parser.ParseString(customAction.ClientSideComponentProperties)) { existingCustomAction.ClientSideComponentProperties = parser.ParseString(customAction.ClientSideComponentProperties); isDirty = true; } } if (existingCustomAction.Description != customAction.Description) { scope.LogPropertyUpdate("Description"); existingCustomAction.Description = customAction.Description; isDirty = true; } if (customAction.Description.ContainsResourceToken()) { if (existingCustomAction.DescriptionResource.SetUserResourceValue(customAction.Description, parser)) { isDirty = true; } } if (existingCustomAction.Group != customAction.Group) { scope.LogPropertyUpdate("Group"); existingCustomAction.Group = customAction.Group; isDirty = true; } if (existingCustomAction.ImageUrl != parser.ParseString(customAction.ImageUrl)) { scope.LogPropertyUpdate("ImageUrl"); existingCustomAction.ImageUrl = parser.ParseString(customAction.ImageUrl); isDirty = true; } if (existingCustomAction.Location != customAction.Location) { scope.LogPropertyUpdate("Location"); existingCustomAction.Location = customAction.Location; isDirty = true; } if (existingCustomAction.RegistrationId != parser.ParseString(customAction.RegistrationId)) { scope.LogPropertyUpdate("RegistrationId"); existingCustomAction.RegistrationId = parser.ParseString(customAction.RegistrationId); isDirty = true; } if (existingCustomAction.RegistrationType != customAction.RegistrationType) { scope.LogPropertyUpdate("RegistrationType"); existingCustomAction.RegistrationType = customAction.RegistrationType; isDirty = true; } if (existingCustomAction.ScriptBlock != parser.ParseString(customAction.ScriptBlock)) { scope.LogPropertyUpdate("ScriptBlock"); existingCustomAction.ScriptBlock = parser.ParseString(customAction.ScriptBlock); isDirty = true; } if (existingCustomAction.ScriptSrc != parser.ParseString(customAction.ScriptSrc)) { scope.LogPropertyUpdate("ScriptSrc"); existingCustomAction.ScriptSrc = parser.ParseString(customAction.ScriptSrc); isDirty = true; } if (existingCustomAction.Sequence != customAction.Sequence) { scope.LogPropertyUpdate("Sequence"); existingCustomAction.Sequence = customAction.Sequence; isDirty = true; } if (existingCustomAction.Title != parser.ParseString(customAction.Title)) { scope.LogPropertyUpdate("Title"); existingCustomAction.Title = parser.ParseString(customAction.Title); isDirty = true; } if (customAction.Title.ContainsResourceToken()) { if (existingCustomAction.TitleResource.SetUserResourceValue(customAction.Title, parser)) { isDirty = true; } } if (existingCustomAction.Url != parser.ParseString(customAction.Url)) { scope.LogPropertyUpdate("Url"); existingCustomAction.Url = parser.ParseString(customAction.Url); isDirty = true; } if (isDirty) { existingCustomAction.Update(); existingCustomAction.Context.ExecuteQueryRetry(); } }
private static void LocalizeParts(Web web, TokenParser parser, string url, WebPartCollection webParts, PnPMonitoredScope scope) { if (CanUseAcceptLanguageHeaderForLocalization(web)) { var context = web.Context; var allParts = web.GetWebParts(parser.ParseString(url)).ToList(); foreach (var webPart in webParts) { #if !SP2016 var partOnPage = allParts.FirstOrDefault(w => w.ZoneId == webPart.Zone && w.WebPart.ZoneIndex == webPart.Order); #else var partOnPage = allParts.FirstOrDefault(w => w.WebPart.ZoneIndex == webPart.Order); #endif if (webPart.Title.ContainsResourceToken() && partOnPage != null) { var resourceValues = parser.GetResourceTokenResourceValues(webPart.Title); foreach (var resourceValue in resourceValues) { // Save property with correct locale on the request to make it stick // http://sadomovalex.blogspot.no/2015/09/localize-web-part-titles-via-client.html context.PendingRequest.RequestExecutor.WebRequest.Headers["Accept-Language"] = resourceValue.Item1; partOnPage.WebPart.Properties["Title"] = resourceValue.Item2; partOnPage.SaveWebPartChanges(); context.ExecuteQueryRetry(); } } } context.PendingRequest.RequestExecutor.WebRequest.Headers.Remove("Accept-Language"); } else { // warning scope.LogWarning(CoreResources.Provisioning_Extensions_WebPartLocalization_Skip); } }
private void ProvisionCustomActionImplementation(object parent, CustomActionCollection customActions, TokenParser parser, PnPMonitoredScope scope, bool isNoScriptSite = false) { Web web = null; Site site = null; if (parent is Site) { site = parent as Site; // Switch parser context; parser.Rebase(site.RootWeb); } else { web = parent as Web; // Switch parser context parser.Rebase(web); } foreach (var customAction in customActions) { if (isNoScriptSite && Guid.Empty == customAction.ClientSideComponentId) { scope.LogWarning(CoreResources.Provisioning_ObjectHandlers_CustomActions_SkippingAddUpdateDueToNoScript, customAction.Name); continue; } var caExists = false; if (site != null) { caExists = site.CustomActionExists(customAction.Name); } else { caExists = web.CustomActionExists(customAction.Name); } // If the CustomAction does not exist, we don't have to remove it, and it is enabled if (!caExists && !customAction.Remove && customAction.Enabled) { // Then we add it to the target var customActionEntity = new CustomActionEntity() { ClientSideComponentId = customAction.ClientSideComponentId, ClientSideComponentProperties = customAction.ClientSideComponentProperties != null?parser.ParseString(customAction.ClientSideComponentProperties) : customAction.ClientSideComponentProperties, CommandUIExtension = customAction.CommandUIExtension != null?parser.ParseString(customAction.CommandUIExtension.ToString()) : string.Empty, Description = parser.ParseString(customAction.Description), Group = customAction.Group, ImageUrl = parser.ParseString(customAction.ImageUrl), Location = customAction.Location, Name = customAction.Name, RegistrationId = parser.ParseString(customAction.RegistrationId), RegistrationType = customAction.RegistrationType, Remove = customAction.Remove, Rights = customAction.Rights, ScriptBlock = parser.ParseString(customAction.ScriptBlock), ScriptSrc = parser.ParseString(customAction.ScriptSrc), Sequence = customAction.Sequence, Title = parser.ParseString(customAction.Title), Url = parser.ParseString(customAction.Url) }; if (site != null) { scope.LogDebug(CoreResources.Provisioning_ObjectHandlers_CustomActions_Adding_custom_action___0___to_scope_Site, customActionEntity.Name); site.AddCustomAction(customActionEntity); if ((!string.IsNullOrEmpty(customAction.Title) && customAction.Title.ContainsResourceToken()) || (!string.IsNullOrEmpty(customAction.Description) && customAction.Description.ContainsResourceToken())) { var uca = site.GetCustomActions().FirstOrDefault(uc => uc.Name == customAction.Name); SetCustomActionResourceValues(parser, customAction, uca); } } else { scope.LogDebug(CoreResources.Provisioning_ObjectHandlers_CustomActions_Adding_custom_action___0___to_scope_Web, customActionEntity.Name); web.AddCustomAction(customActionEntity); if (customAction.Title.ContainsResourceToken() || customAction.Description.ContainsResourceToken()) { var uca = web.GetCustomActions().FirstOrDefault(uc => uc.Name == customAction.Name); SetCustomActionResourceValues(parser, customAction, uca); } } } else { UserCustomAction existingCustomAction; if (site != null) { existingCustomAction = site.GetCustomActions().FirstOrDefault(c => c.Name == customAction.Name); } else { existingCustomAction = web.GetCustomActions().FirstOrDefault(c => c.Name == customAction.Name); } if (existingCustomAction != null) { // If we have to remove the existing CustomAction if (customAction.Remove) { // We simply remove it existingCustomAction.DeleteObject(); existingCustomAction.Context.ExecuteQueryRetry(); } else { UpdateCustomAction(parser, scope, customAction, existingCustomAction, isNoScriptSite); } } } } }
private Tuple<List, TokenParser> UpdateList(Web web, List existingList, ListInstance templateList, TokenParser parser, PnPMonitoredScope scope, bool isNoScriptSite = false) { web.Context.Load(existingList, l => l.Title, l => l.Description, l => l.OnQuickLaunch, l => l.Hidden, l => l.ContentTypesEnabled, l => l.EnableAttachments, l => l.EnableVersioning, l => l.EnableFolderCreation, l => l.EnableModeration, l => l.EnableMinorVersions, l => l.ForceCheckout, l => l.DraftVersionVisibility, l => l.Views, l => l.DocumentTemplateUrl, l => l.RootFolder, l => l.BaseType, l => l.BaseTemplate #if !SP2013 , l => l.MajorWithMinorVersionsLimit , l => l.MajorVersionLimit #endif ); web.Context.ExecuteQueryRetry(); if (existingList.BaseTemplate == templateList.TemplateType) { var isDirty = false; if (parser.ParseString(templateList.Title) != existingList.Title) { var oldTitle = existingList.Title; existingList.Title = parser.ParseString(templateList.Title); if (!oldTitle.Equals(existingList.Title, StringComparison.OrdinalIgnoreCase)) { parser.AddToken(new ListIdToken(web, existingList.Title, existingList.Id)); parser.AddToken(new ListUrlToken(web, existingList.Title, existingList.RootFolder.ServerRelativeUrl.Substring(web.ServerRelativeUrl.Length + 1))); } isDirty = true; } if (!string.IsNullOrEmpty(templateList.DocumentTemplate)) { if (existingList.DocumentTemplateUrl != parser.ParseString(templateList.DocumentTemplate)) { existingList.DocumentTemplateUrl = parser.ParseString(templateList.DocumentTemplate); isDirty = true; } } if (!string.IsNullOrEmpty(templateList.Description) && templateList.Description != existingList.Description) { existingList.Description = templateList.Description; isDirty = true; } if (templateList.Hidden != existingList.Hidden) { existingList.Hidden = templateList.Hidden; isDirty = true; } if (templateList.OnQuickLaunch != existingList.OnQuickLaunch) { existingList.OnQuickLaunch = templateList.OnQuickLaunch; isDirty = true; } if (existingList.BaseTemplate != (int)ListTemplateType.Survey && templateList.ContentTypesEnabled != existingList.ContentTypesEnabled) { existingList.ContentTypesEnabled = templateList.ContentTypesEnabled; isDirty = true; } if (existingList.BaseTemplate != (int)ListTemplateType.Survey && existingList.BaseTemplate != (int)ListTemplateType.DocumentLibrary && existingList.BaseTemplate != (int)ListTemplateType.PictureLibrary) { // https://msdn.microsoft.com/EN-US/library/microsoft.sharepoint.splist.enableattachments.aspx // The EnableAttachments property does not apply to any list that has a base type of Survey, DocumentLibrary or PictureLibrary. // If you set this property to true for either type of list, it throws an SPException. if (templateList.EnableAttachments != existingList.EnableAttachments) { existingList.EnableAttachments = templateList.EnableAttachments; isDirty = true; } } if (existingList.BaseTemplate != (int)ListTemplateType.DiscussionBoard) { if (templateList.EnableFolderCreation != existingList.EnableFolderCreation) { existingList.EnableFolderCreation = templateList.EnableFolderCreation; isDirty = true; } } #if !SP2013 if (templateList.Title.ContainsResourceToken()) { if (existingList.TitleResource.SetUserResourceValue(templateList.Title, parser)) { isDirty = true; } } #endif if (existingList.EnableModeration != templateList.EnableModeration) { existingList.EnableModeration = templateList.EnableModeration; isDirty = true; } if (templateList.ForceCheckout != existingList.ForceCheckout) { existingList.ForceCheckout = templateList.ForceCheckout; isDirty = true; } if (templateList.EnableVersioning) { if (existingList.EnableVersioning != templateList.EnableVersioning) { existingList.EnableVersioning = templateList.EnableVersioning; isDirty = true; } #if !SP2013 if (existingList.MajorVersionLimit != templateList.MaxVersionLimit) { existingList.MajorVersionLimit = templateList.MaxVersionLimit; isDirty = true; } #endif if (existingList.BaseType == BaseType.DocumentLibrary) { // Only supported on Document Libraries if (templateList.EnableMinorVersions != existingList.EnableMinorVersions) { existingList.EnableMinorVersions = templateList.EnableMinorVersions; isDirty = true; } if ((DraftVisibilityType)templateList.DraftVersionVisibility != existingList.DraftVersionVisibility) { existingList.DraftVersionVisibility = (DraftVisibilityType)templateList.DraftVersionVisibility; isDirty = true; } if (templateList.EnableMinorVersions) { if (templateList.MinorVersionLimit != existingList.MajorWithMinorVersionsLimit) { existingList.MajorWithMinorVersionsLimit = templateList.MinorVersionLimit; } if (DraftVisibilityType.Approver == (DraftVisibilityType)templateList.DraftVersionVisibility) { if (templateList.EnableModeration) { if ((DraftVisibilityType)templateList.DraftVersionVisibility != existingList.DraftVersionVisibility) { existingList.DraftVersionVisibility = (DraftVisibilityType)templateList.DraftVersionVisibility; isDirty = true; } } } else { if ((DraftVisibilityType)templateList.DraftVersionVisibility != existingList.DraftVersionVisibility) { existingList.DraftVersionVisibility = (DraftVisibilityType)templateList.DraftVersionVisibility; isDirty = true; } } } } } else { if (existingList.EnableVersioning != templateList.EnableVersioning) { existingList.EnableVersioning = templateList.EnableVersioning; isDirty = true; } } if (isDirty) { existingList.Update(); web.Context.ExecuteQueryRetry(); isDirty = false; } #region UserCustomActions if (!isNoScriptSite) { // Add any UserCustomActions var existingUserCustomActions = existingList.UserCustomActions; web.Context.Load(existingUserCustomActions); web.Context.ExecuteQueryRetry(); foreach (CustomAction userCustomAction in templateList.UserCustomActions) { // Check for existing custom actions before adding (compare by custom action name) if (!existingUserCustomActions.AsEnumerable().Any(uca => uca.Name == userCustomAction.Name)) { CreateListCustomAction(existingList, parser, userCustomAction); isDirty = true; } else { var existingCustomAction = existingUserCustomActions.AsEnumerable().FirstOrDefault(uca => uca.Name == userCustomAction.Name); if (existingCustomAction != null) { isDirty = true; // If the custom action already exists if (userCustomAction.Remove) { // And if we need to remove it, we simply delete it existingCustomAction.DeleteObject(); } else { // Otherwise we update it, and before we force the target // registration type and ID to avoid issues userCustomAction.RegistrationType = UserCustomActionRegistrationType.List; userCustomAction.RegistrationId = existingList.Id.ToString("B").ToUpper(); ObjectCustomActions.UpdateCustomAction(parser, scope, userCustomAction, existingCustomAction); // Blank out these values again to avoid inconsistent domain model data userCustomAction.RegistrationType = UserCustomActionRegistrationType.None; userCustomAction.RegistrationId = null; } } } } if (isDirty) { existingList.Update(); web.Context.ExecuteQueryRetry(); isDirty = false; } } else { scope.LogWarning(CoreResources.Provisioning_ObjectHandlers_ListInstances_SkipAddingOrUpdatingCustomActions); } #endregion if (existingList.ContentTypesEnabled) { // Check if we need to add a content type var existingContentTypes = existingList.ContentTypes; web.Context.Load(existingContentTypes, cts => cts.Include(ct => ct.StringId)); web.Context.ExecuteQueryRetry(); var bindingsToAdd = templateList.ContentTypeBindings.Where(ctb => existingContentTypes.All(ct => !ctb.ContentTypeId.Equals(ct.StringId, StringComparison.InvariantCultureIgnoreCase))).ToList(); var defaultCtBinding = templateList.ContentTypeBindings.FirstOrDefault(ctb => ctb.Default == true); var currentDefaultContentTypeId = existingContentTypes.First().StringId; foreach (var ctb in bindingsToAdd) { var tempCT = web.GetContentTypeById(ctb.ContentTypeId, searchInSiteHierarchy: true); if (tempCT != null) { // Get the name of the existing CT var name = tempCT.EnsureProperty(ct => ct.Name); // If the CT does not exist in the target list, and we don't have to remove it if (!existingList.ContentTypeExistsByName(name) && !ctb.Remove) { existingList.AddContentTypeToListById(ctb.ContentTypeId, searchContentTypeInSiteHierarchy: true); } // Else if the CT exists in the target list, and we have to remove it else if (existingList.ContentTypeExistsByName(name) && ctb.Remove) { // Then remove it from the target list existingList.RemoveContentTypeByName(name); } } } // default ContentTypeBinding should be set last because // list extension .SetDefaultContentTypeToList() re-sets // the list.RootFolder UniqueContentTypeOrder property // which may cause missing CTs from the "New Button" if (defaultCtBinding != null) { // Only update the defualt contenttype when we detect a change in default value if (!currentDefaultContentTypeId.Equals(defaultCtBinding.ContentTypeId, StringComparison.InvariantCultureIgnoreCase)) { existingList.SetDefaultContentTypeToList(defaultCtBinding.ContentTypeId); } } } if (templateList.Security != null) { existingList.SetSecurity(parser, templateList.Security); } return Tuple.Create(existingList, parser); } else { scope.LogWarning(CoreResources.Provisioning_ObjectHandlers_ListInstances_List__0____1____2___exists_but_is_of_a_different_type__Skipping_list_, templateList.Title, templateList.Url, existingList.Id); WriteWarning(string.Format(CoreResources.Provisioning_ObjectHandlers_ListInstances_List__0____1____2___exists_but_is_of_a_different_type__Skipping_list_, templateList.Title, templateList.Url, existingList.Id), ProvisioningMessageType.Warning); return null; } }
public override TokenParser ProvisionObjects(Web web, ProvisioningTemplate template, TokenParser parser, ProvisioningTemplateApplyingInformation applyingInformation) { using (var scope = new PnPMonitoredScope(this.Name)) { if (template.WebSettings != null) { // Check if this is not a noscript site as we're not allowed to update some properties bool isNoScriptSite = web.IsNoScriptSite(); web.EnsureProperties( w => w.NoCrawl, w => w.CommentsOnSitePagesDisabled, w => w.ExcludeFromOfflineClient, w => w.MembersCanShare, w => w.DisableFlows, w => w.DisableAppViews, w => w.HorizontalQuickLaunch, w => w.SearchScope, w => w.SearchBoxInNavBar, w => w.RootFolder, w => w.Title, w => w.Description, w => w.AlternateCssUrl, w => w.WebTemplate, w => w.HasUniqueRoleAssignments); var webSettings = template.WebSettings; // Since the IsSubSite function can trigger an executequery ensure it's called before any updates to the web object are done. if (!web.IsSubSite() || (web.IsSubSite() && web.HasUniqueRoleAssignments)) { String requestAccessEmailValue = parser.ParseString(webSettings.RequestAccessEmail); if (!String.IsNullOrEmpty(requestAccessEmailValue) && requestAccessEmailValue.Length >= 255) { requestAccessEmailValue = requestAccessEmailValue.Substring(0, 255); } if (!String.IsNullOrEmpty(requestAccessEmailValue)) { web.RequestAccessEmail = requestAccessEmailValue; web.Update(); web.Context.ExecuteQueryRetry(); } } if (!isNoScriptSite) { web.NoCrawl = webSettings.NoCrawl; } else { scope.LogWarning(CoreResources.Provisioning_ObjectHandlers_WebSettings_SkipNoCrawlUpdate); } if (web.CommentsOnSitePagesDisabled != webSettings.CommentsOnSitePagesDisabled) { web.CommentsOnSitePagesDisabled = webSettings.CommentsOnSitePagesDisabled; } if (web.ExcludeFromOfflineClient != webSettings.ExcludeFromOfflineClient) { web.ExcludeFromOfflineClient = webSettings.ExcludeFromOfflineClient; } if (web.MembersCanShare != webSettings.MembersCanShare) { web.MembersCanShare = webSettings.MembersCanShare; } if (web.DisableFlows != webSettings.DisableFlows) { web.DisableFlows = webSettings.DisableFlows; } if (web.DisableAppViews != webSettings.DisableAppViews) { web.DisableAppViews = webSettings.DisableAppViews; } if (web.HorizontalQuickLaunch != webSettings.HorizontalQuickLaunch) { web.HorizontalQuickLaunch = webSettings.HorizontalQuickLaunch; } if (web.SearchScope.ToString() != webSettings.SearchScope.ToString()) { web.SearchScope = (SearchScopeType)Enum.Parse(typeof(SearchScopeType), webSettings.SearchScope.ToString(), true); } if (web.SearchBoxInNavBar.ToString() != webSettings.SearchBoxInNavBar.ToString()) { web.SearchBoxInNavBar = (SearchBoxInNavBarType)Enum.Parse(typeof(SearchBoxInNavBarType), webSettings.SearchBoxInNavBar.ToString(), true); } string searchCenterUrl = parser.ParseString(webSettings.SearchCenterUrl); if (!string.IsNullOrEmpty(searchCenterUrl) && web.GetWebSearchCenterUrl(true) != webSettings.SearchCenterUrl) { web.SetWebSearchCenterUrl(webSettings.SearchCenterUrl); } var masterUrl = parser.ParseString(webSettings.MasterPageUrl); if (!string.IsNullOrEmpty(masterUrl)) { if (!isNoScriptSite) { web.MasterUrl = masterUrl; } else { scope.LogWarning(CoreResources.Provisioning_ObjectHandlers_WebSettings_SkipMasterPageUpdate); } } var customMasterUrl = parser.ParseString(webSettings.CustomMasterPageUrl); if (!string.IsNullOrEmpty(customMasterUrl)) { if (!isNoScriptSite) { web.CustomMasterUrl = customMasterUrl; } else { scope.LogWarning(CoreResources.Provisioning_ObjectHandlers_WebSettings_SkipCustomMasterPageUpdate); } } if (!String.IsNullOrEmpty(webSettings.Title)) { var newTitle = parser.ParseString(webSettings.Title); if (newTitle != web.Title) { web.Title = newTitle; } } if (!String.IsNullOrEmpty(webSettings.Description)) { var newDescription = parser.ParseString(webSettings.Description); if (newDescription != web.Description) { web.Description = newDescription; } } if (webSettings.SiteLogo != null) { var logoUrl = parser.ParseString(webSettings.SiteLogo); if (template.BaseSiteTemplate == "SITEPAGEPUBLISHING#0" && web.WebTemplate == "GROUP") { // logo provisioning throws when applying across base template IDs; provisioning fails in this case // this is the error that is already (rightly so) shown beforehand in the console: WARNING: The source site from which the template was generated had a base template ID value of SITEPAGEPUBLISHING#0, while the current target site has a base template ID value of GROUP#0. This could cause potential issues while applying the template. WriteMessage("Applying site logo across base template IDs is not possible. Skipping site logo provisioning.", ProvisioningMessageType.Warning); } else { // Modern site? Then we assume the SiteLogo is actually a filepath if (web.WebTemplate == "GROUP") { if (!string.IsNullOrEmpty(logoUrl) && !logoUrl.ToLower().Contains("_api/groupservice/getgroupimage")) { var fileBytes = ConnectorFileHelper.GetFileBytes(template.Connector, logoUrl); if (fileBytes != null && fileBytes.Length > 0) { var mimeType = ""; var imgUrl = logoUrl; if (imgUrl.Contains("?")) { imgUrl = imgUrl.Split(new[] { '?' })[0]; } if (imgUrl.EndsWith(".gif", StringComparison.InvariantCultureIgnoreCase)) { mimeType = "image/gif"; } if (imgUrl.EndsWith(".png", StringComparison.InvariantCultureIgnoreCase)) { mimeType = "image/png"; } if (imgUrl.EndsWith(".jpg", StringComparison.InvariantCultureIgnoreCase)) { mimeType = "image/jpeg"; } Sites.SiteCollection.SetGroupImageAsync((ClientContext)web.Context, fileBytes, mimeType).GetAwaiter().GetResult(); } } } else { web.SiteLogoUrl = logoUrl; } } } var welcomePage = parser.ParseString(webSettings.WelcomePage); if (!string.IsNullOrEmpty(welcomePage)) { if (welcomePage != web.RootFolder.WelcomePage) { web.RootFolder.WelcomePage = welcomePage; web.RootFolder.Update(); } } if (!string.IsNullOrEmpty(webSettings.AlternateCSS)) { var newAlternateCssUrl = parser.ParseString(webSettings.AlternateCSS); if (newAlternateCssUrl != web.AlternateCssUrl) { web.AlternateCssUrl = newAlternateCssUrl; } } // Temporary disabled as this change is a breaking change for folks that have not set this property in their provisioning templates //web.QuickLaunchEnabled = webSettings.QuickLaunchEnabled; web.Update(); web.Context.ExecuteQueryRetry(); if (webSettings.HubSiteUrl != null) { if (TenantExtensions.IsCurrentUserTenantAdmin(web.Context as ClientContext)) { var hubsiteUrl = parser.ParseString(webSettings.HubSiteUrl); try { using (var tenantContext = web.Context.Clone(web.GetTenantAdministrationUrl(), applyingInformation.AccessTokens)) { var tenant = new Tenant(tenantContext); tenant.ConnectSiteToHubSite(web.Url, hubsiteUrl); tenantContext.ExecuteQueryRetry(); } } catch (Exception ex) { WriteMessage($"Hub site association failed: {ex.Message}", ProvisioningMessageType.Warning); } } else { WriteMessage("You need to be a SharePoint admin when associating to a Hub site.", ProvisioningMessageType.Warning); } } } } return(parser); }
private void CreateFolderInList(Microsoft.SharePoint.Client.Folder parentFolder, Model.Folder folder, TokenParser parser, PnPMonitoredScope scope) { // Determine the folder name, parsing any token String targetFolderName = parser.ParseString(folder.Name); // Check if the folder already exists if (parentFolder.FolderExists(targetFolderName)) { // Log a warning if the folder already exists String warningFolderAlreadyExists = String.Format(CoreResources.Provisioning_ObjectHandlers_ListInstances_FolderAlreadyExists, targetFolderName, parentFolder.ServerRelativeUrl); scope.LogWarning(warningFolderAlreadyExists); WriteWarning(warningFolderAlreadyExists, ProvisioningMessageType.Warning); } // Create it or get a reference to it var currentFolder = parentFolder.EnsureFolder(targetFolderName); if (currentFolder != null) { // Handle any child-folder if (folder.Folders != null && folder.Folders.Count > 0) { foreach (var childFolder in folder.Folders) { CreateFolderInList(currentFolder, childFolder, parser, scope); } } // Handle current folder security if (folder.Security != null && folder.Security.RoleAssignments.Count != 0) { var currentFolderItem = currentFolder.ListItemAllFields; parentFolder.Context.Load(currentFolderItem); parentFolder.Context.ExecuteQueryRetry(); currentFolderItem.SetSecurity(parser, folder.Security); } } }
public override TokenParser ProvisionObjects(Web web, ProvisioningTemplate template, TokenParser parser, ProvisioningTemplateApplyingInformation applyingInformation) { using (var scope = new PnPMonitoredScope(this.Name)) { var context = web.Context as ClientContext; web.EnsureProperties(w => w.ServerRelativeUrl, w => w.RootFolder.WelcomePage); // Check if this is not a noscript site as we're not allowed to update some properties bool isNoScriptSite = web.IsNoScriptSite(); foreach (var page in template.Pages) { var url = parser.ParseString(page.Url); if (!url.ToLower().StartsWith(web.ServerRelativeUrl.ToLower())) { url = UrlUtility.Combine(web.ServerRelativeUrl, url); } var exists = true; Microsoft.SharePoint.Client.File file = null; try { file = web.GetFileByServerRelativeUrl(url); web.Context.Load(file); web.Context.ExecuteQueryRetry(); } catch (ServerException ex) { if (ex.ServerErrorTypeName == "System.IO.FileNotFoundException") { exists = false; } } if (exists) { if (page.Overwrite) { try { scope.LogDebug(CoreResources.Provisioning_ObjectHandlers_Pages_Overwriting_existing_page__0_, url); // determine url of current home page string welcomePageUrl = web.RootFolder.WelcomePage; string welcomePageServerRelativeUrl = welcomePageUrl != null ? UrlUtility.Combine(web.ServerRelativeUrl, web.RootFolder.WelcomePage) : null; bool overwriteWelcomePage = string.Equals(url, welcomePageServerRelativeUrl, StringComparison.InvariantCultureIgnoreCase); // temporarily reset home page so we can delete it if (overwriteWelcomePage) { web.SetHomePage(string.Empty); } file.DeleteObject(); web.Context.ExecuteQueryRetry(); web.AddWikiPageByUrl(url); if (page.Layout == WikiPageLayout.Custom) { web.AddLayoutToWikiPage(WikiPageLayout.OneColumn, url); } else { web.AddLayoutToWikiPage(page.Layout, url); } if (overwriteWelcomePage) { // restore welcome page to previous value web.SetHomePage(welcomePageUrl); } } catch (Exception ex) { scope.LogError(CoreResources.Provisioning_ObjectHandlers_Pages_Overwriting_existing_page__0__failed___1_____2_, url, ex.Message, ex.StackTrace); } } } else { try { scope.LogDebug(CoreResources.Provisioning_ObjectHandlers_Pages_Creating_new_page__0_, url); web.AddWikiPageByUrl(url); if (page.Layout == WikiPageLayout.Custom) { web.AddLayoutToWikiPage(WikiPageLayout.OneColumn, url); } else { web.AddLayoutToWikiPage(page.Layout, url); } } catch (Exception ex) { scope.LogError(CoreResources.Provisioning_ObjectHandlers_Pages_Creating_new_page__0__failed___1_____2_, url, ex.Message, ex.StackTrace); } } #pragma warning disable 618 if (page.WelcomePage) #pragma warning restore 618 { web.RootFolder.EnsureProperty(p => p.ServerRelativeUrl); var rootFolderRelativeUrl = url.Substring(web.RootFolder.ServerRelativeUrl.Length); web.SetHomePage(rootFolderRelativeUrl); } #if !SP2013 bool webPartsNeedLocalization = false; #endif if (page.WebParts != null & page.WebParts.Any()) { if (!isNoScriptSite) { var existingWebParts = web.GetWebParts(url); foreach (var webPart in page.WebParts) { if (existingWebParts.FirstOrDefault(w => w.WebPart.Title == parser.ParseString(webPart.Title)) == null) { WebPartEntity wpEntity = new WebPartEntity(); wpEntity.WebPartTitle = parser.ParseString(webPart.Title); wpEntity.WebPartXml = parser.ParseXmlString(webPart.Contents.Trim(new[] { '\n', ' ' }), "~sitecollection", "~site"); var wpd = web.AddWebPartToWikiPage(url, wpEntity, (int)webPart.Row, (int)webPart.Column, false); #if !SP2013 if (webPart.Title.ContainsResourceToken()) { // update data based on where it was added - needed in order to localize wp title #if !SP2016 wpd.EnsureProperties(w => w.ZoneId, w => w.WebPart, w => w.WebPart.Properties); webPart.Zone = wpd.ZoneId; #else wpd.EnsureProperties(w => w.WebPart, w => w.WebPart.Properties); #endif webPart.Order = (uint)wpd.WebPart.ZoneIndex; webPartsNeedLocalization = true; } #endif } } // Remove any existing WebPartIdToken tokens in the parser that were added by other pages. They won't apply to this page, // and they'll cause issues if this page contains web parts with the same name as web parts on other pages. parser.Tokens.RemoveAll(t => t is WebPartIdToken); var allWebParts = web.GetWebParts(url); foreach (var webpart in allWebParts) { parser.AddToken(new WebPartIdToken(web, webpart.WebPart.Title, webpart.Id)); } } else { scope.LogWarning(CoreResources.Provisioning_ObjectHandlers_Pages_SkipAddingWebParts, page.Url); } } #if !SP2013 if (webPartsNeedLocalization) { page.LocalizeWebParts(web, parser, scope); } #endif file = web.GetFileByServerRelativeUrl(url); file.EnsureProperty(f => f.ListItemAllFields); if (page.Fields.Any()) { var item = file.ListItemAllFields; foreach (var fieldValue in page.Fields) { item[fieldValue.Key] = parser.ParseString(fieldValue.Value); } item.Update(); web.Context.ExecuteQueryRetry(); } if (page.Security != null && page.Security.RoleAssignments.Count != 0) { web.Context.Load(file.ListItemAllFields); web.Context.ExecuteQueryRetry(); file.ListItemAllFields.SetSecurity(parser, page.Security); } } } return(parser); }
public override ProvisioningTemplate ExtractObjects(Web web, ProvisioningTemplate template, ProvisioningTemplateCreationInformation creationInfo) { if (template.Workflows == null) { template.Workflows = new Workflows(); } using (var scope = new PnPMonitoredScope(this.Name)) { if (creationInfo.FileConnector == null) { scope.LogWarning("Cannot export Workflow definitions without a FileConnector."); } else { // Retrieve all the lists and libraries var lists = web.Lists; web.Context.Load(lists); web.Context.ExecuteQuery(); // Retrieve the workflow definitions (including unpublished ones) var definitions = web.GetWorkflowDefinitions(false); template.Workflows.WorkflowDefinitions.AddRange( from d in definitions select new Model.WorkflowDefinition(d.Properties.TokenizeWorkflowDefinitionProperties(lists)) { AssociationUrl = d.AssociationUrl, Description = d.Description, DisplayName = d.DisplayName, DraftVersion = d.DraftVersion, FormField = d.FormField, Id = d.Id, InitiationUrl = d.InitiationUrl, Published = d.Published, RequiresAssociationForm = d.RequiresAssociationForm, RequiresInitiationForm = d.RequiresInitiationForm, RestrictToScope = (!String.IsNullOrEmpty(d.RestrictToScope) && Guid.Parse(d.RestrictToScope) != web.Id) ? String.Format("{{listid:{0}}}", lists.First(l => l.Id == Guid.Parse(d.RestrictToScope)).Title) : null, RestrictToType = !String.IsNullOrEmpty(d.RestrictToType) ? d.RestrictToType : "Universal", XamlPath = d.Xaml.SaveXamlToFile(d.Id, creationInfo.FileConnector), } ); // Retrieve the workflow subscriptions var subscriptions = web.GetWorkflowSubscriptions(); #if CLIENTSDKV15 template.Workflows.WorkflowSubscriptions.AddRange( from s in subscriptions select new Model.WorkflowSubscription(s.PropertyDefinitions.TokenizeWorkflowSubscriptionProperties(lists)) { DefinitionId = s.DefinitionId, Enabled = s.Enabled, EventSourceId = s.EventSourceId != web.Id ? String.Format("{{listid:{0}}}", lists.First(l => l.Id == s.EventSourceId).Title) : null, EventTypes = s.EventTypes.ToList(), ManualStartBypassesActivationLimit = s.ManualStartBypassesActivationLimit, Name = s.Name, ListId = s.EventSourceId != web.Id ? String.Format("{{listid:{0}}}", lists.First(l => l.Id == s.EventSourceId).Title) : null, StatusFieldName = s.StatusFieldName, } ); #else template.Workflows.WorkflowSubscriptions.AddRange( from s in subscriptions select new Model.WorkflowSubscription(s.PropertyDefinitions.TokenizeWorkflowSubscriptionProperties(lists)) { DefinitionId = s.DefinitionId, Enabled = s.Enabled, EventSourceId = s.EventSourceId != web.Id ? String.Format("{{listid:{0}}}", lists.First(l => l.Id == s.EventSourceId).Title) : null, EventTypes = s.EventTypes.ToList(), ManualStartBypassesActivationLimit = s.ManualStartBypassesActivationLimit, Name = s.Name, ListId = s.EventSourceId != web.Id ? String.Format("{{listid:{0}}}", lists.First(l => l.Id == s.EventSourceId).Title) : null, ParentContentTypeId = s.ParentContentTypeId, StatusFieldName = s.StatusFieldName, } ); #endif } } return template; }
private Tuple <Guid, TokenParser> CreateTerm <T>(Web web, Model.Term modelTerm, TaxonomyItem parent, TermStore termStore, TokenParser parser, PnPMonitoredScope scope) where T : TaxonomyItem { // If the term is a re-used term and the term is not a source term, skip for now and create later if (modelTerm.IsReused && !modelTerm.IsSourceTerm) { this.reusedTerms.Add(new ReusedTerm() { ModelTerm = modelTerm, Parent = parent, TermStore = termStore }); return(null); } // Create new term Term term; if (modelTerm.Id == Guid.Empty) { modelTerm.Id = Guid.NewGuid(); } if (parent is Term) { term = ((Term)parent).CreateTerm(parser.ParseString(modelTerm.Name), modelTerm.Language ?? termStore.DefaultLanguage, modelTerm.Id); } else { term = ((TermSet)parent).CreateTerm(parser.ParseString(modelTerm.Name), modelTerm.Language ?? termStore.DefaultLanguage, modelTerm.Id); } if (!string.IsNullOrEmpty(modelTerm.Description)) { term.SetDescription(modelTerm.Description, modelTerm.Language ?? termStore.DefaultLanguage); } if (!string.IsNullOrEmpty(modelTerm.Owner)) { term.Owner = modelTerm.Owner; } term.IsAvailableForTagging = modelTerm.IsAvailableForTagging; if (modelTerm.Properties.Any() || modelTerm.Labels.Any() || modelTerm.LocalProperties.Any()) { if (modelTerm.Labels.Any()) { foreach (var label in modelTerm.Labels) { if ((label.IsDefaultForLanguage && label.Language != termStore.DefaultLanguage) || label.IsDefaultForLanguage == false) { term.CreateLabel(parser.ParseString(label.Value), label.Language, label.IsDefaultForLanguage); } else { scope.LogWarning(CoreResources.Provisioning_ObjectHandlers_TermGroups_Skipping_label__0___label_is_to_set_to_default_for_language__1__while_the_default_termstore_language_is_also__1_, label.Value, label.Language); WriteWarning(string.Format(CoreResources.Provisioning_ObjectHandlers_TermGroups_Skipping_label__0___label_is_to_set_to_default_for_language__1__while_the_default_termstore_language_is_also__1_, label.Value, label.Language), ProvisioningMessageType.Warning); } } } if (modelTerm.Properties.Any()) { foreach (var property in modelTerm.Properties) { term.SetCustomProperty(parser.ParseString(property.Key), parser.ParseString(property.Value)); } } if (modelTerm.LocalProperties.Any()) { foreach (var property in modelTerm.LocalProperties) { term.SetLocalCustomProperty(parser.ParseString(property.Key), parser.ParseString(property.Value)); } } } termStore.CommitAll(); web.Context.Load(term); web.Context.ExecuteQueryRetry(); // Deprecate term if needed if (modelTerm.IsDeprecated != term.IsDeprecated) { term.Deprecate(modelTerm.IsDeprecated); web.Context.ExecuteQueryRetry(); } parser = this.CreateChildTerms(web, modelTerm, term, termStore, parser, scope); return(Tuple.Create(modelTerm.Id, parser)); }