public void CanProvisionRegionalSettings() { using (var scope = new Core.Diagnostics.PnPMonitoredScope("CanProvisionRegionalSettings")) { using (var ctx = TestCommon.CreateClientContext()) { // Load the base template which will be used for the comparison work var template = new ProvisioningTemplate(); template.RegionalSettings = new Core.Framework.Provisioning.Model.RegionalSettings(); template.RegionalSettings.FirstDayOfWeek = System.DayOfWeek.Monday; template.RegionalSettings.WorkDayEndHour = WorkHour.PM0700; template.RegionalSettings.TimeZone = 5; template.RegionalSettings.Time24 = true; var parser = new TokenParser(ctx.Web, template); new ObjectRegionalSettings().ProvisionObjects(ctx.Web, template, parser, new ProvisioningTemplateApplyingInformation()); ctx.Load(ctx.Web.RegionalSettings); ctx.Load(ctx.Web.RegionalSettings.TimeZone, tz => tz.Id); ctx.ExecuteQueryRetry(); Assert.IsTrue(ctx.Web.RegionalSettings.Time24); Assert.IsTrue(ctx.Web.RegionalSettings.WorkDayEndHour == (short)WorkHour.PM0700); Assert.IsTrue(ctx.Web.RegionalSettings.FirstDayOfWeek == (uint)System.DayOfWeek.Monday); Assert.IsTrue(ctx.Web.RegionalSettings.TimeZone.Id == 5); } } }
public static bool Validate(CustomActions sourceCustomActions, CustomActions targetCustomActions, TokenParser tokenParser, Web web) { if (web.IsNoScriptSite()) { Console.WriteLine("Skipping validation of custom actions due to noscript site."); return true; } Console.WriteLine("Custom Action validation started..."); bool isSiteCustomActionsMatch = false; bool isWebCustomActionsMatch = false; if (sourceCustomActions.SiteCustomActions.Count > 0) { isSiteCustomActionsMatch = ValidateCustomActions(sourceCustomActions.SiteCustomActions, targetCustomActions.SiteCustomActions, tokenParser, web); Console.WriteLine("Site Custom Actions validation " + isSiteCustomActionsMatch); } if (sourceCustomActions.WebCustomActions.Count > 0) { isWebCustomActionsMatch = ValidateCustomActions(sourceCustomActions.WebCustomActions, targetCustomActions.WebCustomActions, tokenParser, web); Console.WriteLine("Web Custom Actions validation " + isWebCustomActionsMatch); } if (!isSiteCustomActionsMatch || !isWebCustomActionsMatch) { return false; } else { return true; } }
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; foreach (var handler in template.ExtensibilityHandlers .Union(template.Providers) .Union(applyingInformation.ExtensibilityHandlers)) { if (handler.Enabled) { try { if (!string.IsNullOrEmpty(handler.Configuration)) { //replace tokens in configuration data handler.Configuration = parser.ParseString(handler.Configuration); } scope.LogDebug(CoreResources.Provisioning_ObjectHandlers_ExtensibilityProviders_Calling_extensibility_callout__0_, handler.Assembly); _extManager.ExecuteExtensibilityProvisionCallOut(context, handler, template, applyingInformation, parser, scope); } catch (Exception ex) { scope.LogError(CoreResources.Provisioning_ObjectHandlers_ExtensibilityProviders_callout_failed___0_____1_, ex.Message, ex.StackTrace); throw; } } } } return parser; }
public bool Validate(ProvisioningTemplate ptSource, ProvisioningTemplate ptTarget, TokenParser sParser, TokenParser tParser) { bool isValid = false; #region SiteFields if (ptTarget.SiteFields.Count > 0) { isValid = ValidateSiteFields(ptSource.SiteFields, ptTarget.SiteFields, sParser, tParser); if (!isValid) { return false; } } #endregion #region ContentTypes if (ptTarget.ContentTypes.Count > 0) { isValid = ValidateContentTypes(ptSource.ContentTypes, ptTarget.ContentTypes, sParser, tParser); if (!isValid) { return false; } } #endregion #region ListInstances isValid = ValidateListInstances(ptSource.Lists, ptTarget.Lists, sParser, tParser); if (!isValid) { return false; } #endregion #if !ONPREMISES #region Custom Action isValid = ValidateCustomActions(ptSource.CustomActions, ptTarget.CustomActions, sParser, tParser, ptTarget.SiteFields.Count > 0); if (!isValid) { return false; } #endregion #endif return isValid; }
public void CanProvisionObjects() { var template = new ProvisioningTemplate(); template.SiteFields.Add(new Core.Framework.Provisioning.Model.Field() { SchemaXml = ElementSchema }); using (var ctx = TestCommon.CreateClientContext()) { var parser = new TokenParser(ctx.Web, template); new ObjectField().ProvisionObjects(ctx.Web, template, parser, new ProvisioningTemplateApplyingInformation()); new ObjectLookupFields().ProvisionObjects(ctx.Web, template, parser, new ProvisioningTemplateApplyingInformation()); var f = ctx.Web.GetFieldById<FieldLookup>(fieldId); Assert.IsNotNull(f); Assert.IsInstanceOfType(f, typeof(FieldLookup)); var schemaXml = f.SchemaXml; // so listId MUST have braces Assert.IsTrue(schemaXml.Contains("List=\""+_listIdWithBraces+"\"")); // web id should NOT have braces Assert.IsTrue(schemaXml.Contains("WebId=\"" + ctx.Web.Id.ToString()+ "\"")); // Source ID MUST have braces Assert.IsTrue(schemaXml.Contains("SourceID=\"" + ctx.Web.Id.ToString("B") + "\"")); } }
public bool Validate(TermGroupCollection sourceCollection, TermGroupCollection targetCollection, TokenParser tokenParser) { // Convert object collections to XML List<SerializedTermGroupInstance> sourceTermGroups = new List<SerializedTermGroupInstance>(); List<SerializedTermGroupInstance> targetTermGroups = new List<SerializedTermGroupInstance>(); foreach (TermGroup termGroup in sourceCollection) { ProvisioningTemplate pt = new ProvisioningTemplate(); pt.TermGroups.Add(termGroup); sourceTermGroups.Add(new SerializedTermGroupInstance() { SchemaXml = ExtractElementXml(pt) }); } foreach (TermGroup termGroup in targetCollection) { ProvisioningTemplate pt = new ProvisioningTemplate(); pt.TermGroups.Add(termGroup); targetTermGroups.Add(new SerializedTermGroupInstance() { SchemaXml = ExtractElementXml(pt) }); } // Use XML validation logic to compare source and target Dictionary<string, string[]> parserSettings = new Dictionary<string, string[]>(); parserSettings.Add("SchemaXml", null); bool isTermGroupsMatch = ValidateObjectsXML(sourceTermGroups, targetTermGroups, "SchemaXml", new List<string> { "Name" }, tokenParser, parserSettings); Console.WriteLine("-- Term group validation " + isTermGroupsMatch); return isTermGroupsMatch; }
public void CanProvisionSupportedUILanguages() { using (var scope = new Core.Diagnostics.PnPMonitoredScope("CanProvisionSupportedUILanguages")) { using (var ctx = TestCommon.CreateClientContext()) { // Load the base template which will be used for the comparison work var template = new ProvisioningTemplate(); template.SupportedUILanguages.Add(new SupportedUILanguage() { LCID = 1033 }); // English template.SupportedUILanguages.Add(new SupportedUILanguage() { LCID = 1032 }); // Greek var parser = new TokenParser(ctx.Web, template); new ObjectSupportedUILanguages().ProvisionObjects(ctx.Web, template, parser, new ProvisioningTemplateApplyingInformation()); ctx.Load(ctx.Web, w => w.SupportedUILanguageIds); ctx.ExecuteQueryRetry(); Assert.IsTrue(ctx.Web.SupportedUILanguageIds.Count() == 2); Assert.IsTrue(ctx.Web.SupportedUILanguageIds.Any(i => i == 1033)); Assert.IsTrue(ctx.Web.SupportedUILanguageIds.Any(i => i == 1032)); } } }
public override TokenParser ProvisionObjects(Web web, ProvisioningTemplate template, TokenParser parser, ProvisioningTemplateApplyingInformation applyingInformation) { using (var scope = new PnPMonitoredScope(this.Name)) { var context = web.Context as ClientContext; var site = context.Site; // Check if this is not a noscript site as we're not allowed to update some properties bool isNoScriptSite = web.IsNoScriptSite(); // if this is a sub site then we're not enabling the site collection scoped custom actions if (!web.IsSubSite()) { var siteCustomActions = template.CustomActions.SiteCustomActions; ProvisionCustomActionImplementation(site, siteCustomActions, parser, scope, isNoScriptSite); } var webCustomActions = template.CustomActions.WebCustomActions; ProvisionCustomActionImplementation(web, webCustomActions, parser, scope, isNoScriptSite); // Switch parser context back to it's original context parser.Rebase(web); } return parser; }
public void CanProvisionObjects() { var template = new ProvisioningTemplate(); FileSystemConnector connector = new FileSystemConnector(resourceFolder, ""); template.Connector = connector; template.Files.Add(new Core.Framework.Provisioning.Model.File() { Overwrite = true, Src = fileName, Folder = folder }); using (var ctx = TestCommon.CreateClientContext()) { var parser = new TokenParser(ctx.Web, template); new ObjectFiles().ProvisionObjects(ctx.Web, template, parser, new ProvisioningTemplateApplyingInformation()); ctx.Web.EnsureProperties(w => w.ServerRelativeUrl); var file = ctx.Web.GetFileByServerRelativeUrl( UrlUtility.Combine(ctx.Web.ServerRelativeUrl, UrlUtility.Combine(folder, fileName))); ctx.Load(file, f => f.Exists); ctx.ExecuteQueryRetry(); Assert.IsTrue(file.Exists); } }
public void CanProvisionObjects() { var template = new ProvisioningTemplate(); foreach (var user in admins) { template.Security.AdditionalMembers.Add(new User() { Name = user.LoginName }); } using (var ctx = TestCommon.CreateClientContext()) { var parser = new TokenParser(ctx.Web, template); new ObjectSiteSecurity().ProvisionObjects(ctx.Web, template, parser, new ProvisioningTemplateApplyingInformation()); var memberGroup = ctx.Web.AssociatedMemberGroup; ctx.Load(memberGroup, g => g.Users); ctx.ExecuteQueryRetry(); foreach (var user in admins) { var existingUser = memberGroup.Users.GetByLoginName(user.LoginName); ctx.Load(existingUser); ctx.ExecuteQueryRetry(); Assert.IsNotNull(existingUser); } } }
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(); if (isNoScriptSite) { return parser; } web.SetPropertyBagValue("_PnP_ProvisioningTemplateId", template.Id != null ? template.Id : ""); web.AddIndexedPropertyBagKey("_PnP_ProvisioningTemplateId"); ProvisioningTemplateInfo info = new ProvisioningTemplateInfo(); info.TemplateId = template.Id != null ? template.Id : ""; info.TemplateVersion = template.Version; info.TemplateSitePolicy = template.SitePolicy; info.Result = true; info.ProvisioningTime = DateTime.Now; string jsonInfo = JsonConvert.SerializeObject(info); web.SetPropertyBagValue("_PnP_ProvisioningTemplateInfo", jsonInfo); } return parser; }
public override ProvisioningTemplate ExtractObjects(Web web, ProvisioningTemplate template, TokenParser parser, ProvisioningTemplateCreationInformation creationInfo) { using (var scope = new PnPMonitoredScope(this.Name)) { web.Context.Load(web.RegionalSettings); web.Context.Load(web.RegionalSettings.TimeZone, tz => tz.Id); web.Context.ExecuteQueryRetry(); Model.RegionalSettings settings = new Model.RegionalSettings(); settings.AdjustHijriDays = web.RegionalSettings.AdjustHijriDays; settings.AlternateCalendarType = (CalendarType)web.RegionalSettings.AlternateCalendarType; settings.Collation = web.RegionalSettings.Collation; settings.FirstDayOfWeek = (DayOfWeek)web.RegionalSettings.FirstDayOfWeek; settings.FirstWeekOfYear = web.RegionalSettings.FirstWeekOfYear; settings.LocaleId = (int)web.RegionalSettings.LocaleId; settings.ShowWeeks = web.RegionalSettings.ShowWeeks; settings.Time24 = web.RegionalSettings.Time24; settings.TimeZone = web.RegionalSettings.TimeZone.Id; settings.WorkDayEndHour = (WorkHour)web.RegionalSettings.WorkDayEndHour; settings.WorkDays = web.RegionalSettings.WorkDays; settings.WorkDayStartHour = (WorkHour)web.RegionalSettings.WorkDayStartHour; template.RegionalSettings = settings; // 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 void CanProvisionAuditSettings() { using (var scope = new Core.Diagnostics.PnPMonitoredScope("CanProvisionAuditSettings")) { using (var ctx = TestCommon.CreateClientContext()) { // Load the base template which will be used for the comparison work var template = new ProvisioningTemplate(); template.AuditSettings = new AuditSettings(); template.AuditSettings.AuditFlags = AuditMaskType.CheckIn; template.AuditSettings.AuditLogTrimmingRetention = 5; template.AuditSettings.TrimAuditLog = true; var parser = new TokenParser(ctx.Web, template); new ObjectAuditSettings().ProvisionObjects(ctx.Web, template, parser, new ProvisioningTemplateApplyingInformation()); var site = ctx.Site; var auditSettings = site.Audit; ctx.Load(auditSettings, af => af.AuditFlags); ctx.Load(site, s => s.AuditLogTrimmingRetention, s => s.TrimAuditLog); ctx.ExecuteQueryRetry(); Assert.IsTrue(auditSettings.AuditFlags == AuditMaskType.CheckIn); Assert.IsTrue(site.AuditLogTrimmingRetention == 5); Assert.IsTrue(site.TrimAuditLog = true); } } }
public static bool Validate(CustomActions sourceCustomActions, CustomActions targetCustomActions, TokenParser tokenParser) { Console.WriteLine("Custom Action validation started..."); bool isSiteCustomActionsMatch = false; bool isWebCustomActionsMatch = false; if (sourceCustomActions.SiteCustomActions.Count > 0) { isSiteCustomActionsMatch = ValidateCustomActions(sourceCustomActions.SiteCustomActions, targetCustomActions.SiteCustomActions, tokenParser); Console.WriteLine("Site Custom Actions validation " + isSiteCustomActionsMatch); } if (sourceCustomActions.WebCustomActions.Count > 0) { isWebCustomActionsMatch = ValidateCustomActions(sourceCustomActions.WebCustomActions, targetCustomActions.WebCustomActions, tokenParser); Console.WriteLine("Web Custom Actions validation " + isWebCustomActionsMatch); } if (!isSiteCustomActionsMatch || !isWebCustomActionsMatch) { return false; } else { return true; } }
public bool Validate(ContentTypeCollection sourceCollection, ContentTypeCollection targetCollection, TokenParser tokenParser) { // Convert object collections to XML List<SerializedContentType> sourceContentTypes = new List<SerializedContentType>(); List<SerializedContentType> targetContentTypes = new List<SerializedContentType>(); foreach (ContentType ct in sourceCollection) { ProvisioningTemplate pt = new ProvisioningTemplate(); pt.ContentTypes.Add(ct); sourceContentTypes.Add(new SerializedContentType() { SchemaXml = ExtractElementXml(pt) }); } foreach (ContentType ct in targetCollection) { ProvisioningTemplate pt = new ProvisioningTemplate(); pt.ContentTypes.Add(ct); targetContentTypes.Add(new SerializedContentType() { SchemaXml = ExtractElementXml(pt) }); } // Use XML validation logic to compare source and target Dictionary<string, string[]> parserSettings = new Dictionary<string, string[]>(); parserSettings.Add("SchemaXml", null); bool isContentTypeMatch = ValidateObjectsXML(sourceContentTypes, targetContentTypes, "SchemaXml", new List<string> { "ID" }, tokenParser, parserSettings); Console.WriteLine("-- Content type validation " + isContentTypeMatch); return isContentTypeMatch; }
public TokenParser AddExtendedTokens(Web web, ProvisioningTemplate template, TokenParser parser, ProvisioningTemplateApplyingInformation applyingInformation) { using (var scope = new PnPMonitoredScope(this.Name)) { var context = web.Context as ClientContext; foreach (var provider in template.Providers) { if (provider.Enabled) { try { if (!string.IsNullOrEmpty(provider.Configuration)) { provider.Configuration = parser.ParseString(provider.Configuration); } scope.LogDebug(CoreResources.Provisioning_ObjectHandlers_ExtensibilityProviders_Calling_tokenprovider_extensibility_callout__0_, provider.Assembly); var _providedTokens = _extManager.ExecuteTokenProviderCallOut(context, provider, template); if (_providedTokens != null) { foreach (var token in _providedTokens) { parser.AddToken(token); } } } catch (Exception ex) { scope.LogError(CoreResources.Provisioning_ObjectHandlers_ExtensibilityProviders_tokenprovider_callout_failed___0_____1_, ex.Message, ex.StackTrace); throw; } } } return parser; } }
public void CanProvisionObjects() { var template = new ProvisioningTemplate(); var contentType = new ContentType() { Id = "0x010100503B9E20E5455344BFAC2292DC6FE805", Name = "Test Content Type", Group = "PnP", Description = "Test Description", Overwrite = true, Hidden = false }; contentType.FieldRefs.Add(new FieldRef() { Id = BuiltInFieldId.Category, DisplayName = "Test Category", }); template.ContentTypes.Add(contentType); using (var ctx = TestCommon.CreateClientContext()) { TokenParser parser = new TokenParser(ctx.Web, template); new ObjectContentType().ProvisionObjects(ctx.Web, template, parser, new ProvisioningTemplateApplyingInformation()); var ct = ctx.Web.GetContentTypeByName("Test Content Type"); Assert.IsNotNull(ct); } }
public override TokenParser ProvisionObjects(Web web, ProvisioningTemplate template, TokenParser parser, ProvisioningTemplateApplyingInformation applyingInformation) { using (var scope = new PnPMonitoredScope(this.Name)) { // if this is a sub site then we're not provisioning content types. Technically this can be done but it's not a recommended practice if (web.IsSubSite()) { scope.LogDebug(CoreResources.Provisioning_ObjectHandlers_ContentTypes_Context_web_is_subweb__Skipping_content_types_); return parser; } // 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(); 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 { 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 { scope.LogDebug(CoreResources.Provisioning_ObjectHandlers_ContentTypes_Updating_existing_Content_Type___0_____1_, ct.Id, ct.Name); UpdateContentType(web, existingCT, ct, parser, scope, isNoScriptSite); } } } } return parser; }
public bool Validate(PropertyBagEntryCollection sourceCollection, PropertyBagEntryCollection targetCollection, TokenParser tokenParser) { Dictionary<string, string[]> parserSettings = new Dictionary<string, string[]>(); parserSettings.Add("Value", null); bool isPropertyBagsMatch = ValidateObjects(sourceCollection, targetCollection, new List<string> { "Key", "Value", "Indexed" }, tokenParser, parserSettings); Console.WriteLine("-- Property Bags validation " + isPropertyBagsMatch); return isPropertyBagsMatch; }
public bool Validate(FieldCollection sourceCollection, FieldCollection targetCollection, TokenParser tokenParser) { Dictionary<string, string[]> parserSettings = new Dictionary<string, string[]>(); parserSettings.Add("SchemaXml", new string[] { "~sitecollection", "~site", "{sitecollectiontermstoreid}", "{termsetid}" }); bool isFieldMatch = ValidateObjectsXML(sourceCollection, targetCollection, "SchemaXml", new List<string> { "ID" }, tokenParser, parserSettings); Console.WriteLine("-- Field validation " + isFieldMatch); return isFieldMatch; }
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)) { 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); var composedLookJson = JsonConvert.SerializeObject(template.ComposedLook); web.SetPropertyBagValue("_PnP_ProvisioningTemplateComposedLookInfo", composedLookJson); } // Persist composed look info in property bag } } return parser; }
/// <summary> /// Check if all tokens where replaced. If the field is a taxonomy field then we will check for the values of the referenced termstore and termset. /// </summary> /// <param name="fieldXml">The xml to parse</param> /// <param name="parser"></param> /// <param name="context"></param> /// <returns></returns> protected static bool IsFieldXmlValid(string fieldXml, TokenParser parser, ClientRuntimeContext context) { var isValid = true; var leftOverTokens = parser.GetLeftOverTokens(fieldXml); if (!leftOverTokens.Any()) { var fieldElement = XElement.Parse(fieldXml); if (fieldElement.Attribute("Type").Value == "TaxonomyFieldType") { var termStoreIdElement = fieldElement.XPathSelectElement("//ArrayOfProperty/Property[Name='SspId']/Value"); if (termStoreIdElement != null) { var termStoreId = Guid.Parse(termStoreIdElement.Value); TaxonomySession taxSession = TaxonomySession.GetTaxonomySession(context); try { taxSession.EnsureProperty(t => t.TermStores); var store = taxSession.TermStores.GetById(termStoreId); context.Load(store); context.ExecuteQueryRetry(); if (store.ServerObjectIsNull.HasValue && !store.ServerObjectIsNull.Value) { var termSetIdElement = fieldElement.XPathSelectElement("//ArrayOfProperty/Property[Name='TermSetId']/Value"); if (termSetIdElement != null) { var termSetId = Guid.Parse(termSetIdElement.Value); try { var termSet = store.GetTermSet(termSetId); context.Load(termSet); context.ExecuteQueryRetry(); isValid = termSet.ServerObjectIsNull.HasValue && !termSet.ServerObjectIsNull.Value; } catch (Exception) { isValid = false; } } } } catch (Exception) { isValid = false; } } else { isValid = false; } } } else { //Some tokens where not replaced isValid = false; } return isValid; }
public override ProvisioningTemplate ExtractObjects(Web web, ProvisioningTemplate template, TokenParser parser, ProvisioningTemplateCreationInformation creationInfo) { using (var scope = new PnPMonitoredScope(this.Name)) { var lists = this.GetListsWithPages(template); template.Pages = new PageCollection(template); var homePageUrl = web.GetHomePageRelativeUrl(); foreach (var list in lists) { try { List splist = web.Lists.GetById(list.ID); web.Context.Load(splist); web.Context.ExecuteQueryRetry(); if (!creationInfo.ExecutePreProvisionEvent<ListInstance, List>(Handlers.Pages, template, list, null)) { continue; } var listItems = GetListPages(web, splist); var fileItems = listItems.AsEnumerable().Where(x => x.IsFile()); foreach (ListItem item in fileItems) { try { IPageModelProvider provider = GetProvider(item, homePageUrl, web, parser); if (null != provider) { provider.AddPage(item, template); } } catch (Exception ex) { var message = string.Format("Error in export page for list: {0}", list.ServerRelativeUrl); scope.LogError(ex, message); } } creationInfo.ExecutePostProvisionEvent<ListInstance, List>(Handlers.Pages, template, list, splist); } catch (Exception exception) { var message = string.Format("Error in export publishing page for list: {0}", list.ServerRelativeUrl); scope.LogError(exception, message); } } // Impossible to return all files in the site currently // 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 void Provision(ClientContext ctx, ProvisioningTemplate template, ProvisioningTemplateApplyingInformation applyingInformation, TokenParser tokenParser, PnPMonitoredScope scope, string configurationData) { bool _urlCheck = ctx.Url.Equals(ExtensibilityTestConstants.MOCK_URL, StringComparison.OrdinalIgnoreCase); if (!_urlCheck) throw new Exception("CTXURLNOTTHESAME"); bool _templateCheck = template.Id.Equals(ExtensibilityTestConstants.PROVISIONINGTEMPLATE_ID, StringComparison.OrdinalIgnoreCase); if (!_templateCheck) throw new Exception("TEMPLATEIDNOTTHESAME"); bool _configDataCheck = configurationData.Equals(ExtensibilityTestConstants.PROVIDER_MOCK_DATA, StringComparison.OrdinalIgnoreCase); if (!_configDataCheck) throw new Exception("CONFIGDATANOTTHESAME"); }
public bool Validate(SupportedUILanguageCollection sourceLanguageSettings, SupportedUILanguageCollection targetLanguageSettings, TokenParser tokenParser) { ProvisioningTemplate sourcePt = new ProvisioningTemplate(); sourcePt.SupportedUILanguages = sourceLanguageSettings; var sourceXml = ExtractElementXml(sourcePt); ProvisioningTemplate targetPt = new ProvisioningTemplate(); targetPt.SupportedUILanguages = targetLanguageSettings; var targetXml = ExtractElementXml(targetPt); return ValidateObjectXML(sourceXml, targetXml, null); }
public bool ValidateContentTypes(Core.Framework.Provisioning.Model.ContentTypeCollection sElements, Core.Framework.Provisioning.Model.ContentTypeCollection tElements, TokenParser sParser, TokenParser tParser) { List<Localization> sColl = LoadContentTypes(sElements); List<Localization> tColl = LoadContentTypes(tElements); if (sColl.Count > 0) { if (!Validatelocalization(sColl, tColl, sParser, tParser)) { return false; } } return true; }
public bool Validate(AuditSettings sourceAuditsettings, AuditSettings targetAuditSettings, TokenParser tokenParser) { ProvisioningTemplate sourcePt = new ProvisioningTemplate(); sourcePt.AuditSettings = sourceAuditsettings; var sourceXml = ExtractElementXml(sourcePt); ProvisioningTemplate targetPt = new ProvisioningTemplate(); targetPt.AuditSettings = targetAuditSettings; var targetXml = ExtractElementXml(targetPt); return ValidateObjectXML(sourceXml, targetXml, null); }
public bool Validate(Core.Framework.Provisioning.Model.RegionalSettings sourceRegionalSettings, Core.Framework.Provisioning.Model.RegionalSettings targetRegionalSettings, TokenParser tokenParser) { ProvisioningTemplate sourcePt = new ProvisioningTemplate(); sourcePt.RegionalSettings = sourceRegionalSettings; var sourceXml = ExtractElementXml(sourcePt); ProvisioningTemplate targetPt = new ProvisioningTemplate(); targetPt.RegionalSettings = targetRegionalSettings; var targetXml = ExtractElementXml(targetPt); return ValidateObjectXML(sourceXml, targetXml, null, null, null); }
public override ProvisioningTemplate ExtractObjects(Web web, ProvisioningTemplate template, TokenParser parser, ProvisioningTemplateCreationInformation creationInfo) { using (var scope = new PnPMonitoredScope(this.Name)) { // 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 bool ValidateSiteFields(FieldCollection sElements, FieldCollection tElements, TokenParser sParser, TokenParser tParser) { List<Localization> sColl = LoadFields(sElements); List<Localization> tColl = LoadFields(tElements); if (sColl.Count > 0) { if (!Validatelocalization(sColl, tColl, sParser, tParser)) { return false; } } return true; }
public void SetFileProperties(File file, IDictionary <string, string> properties, TokenParser parser, bool checkoutIfRequired = true) { var context = file.Context; if (properties != null && properties.Count > 0) { // Get a reference to the target list, if any // and load file item properties var parentList = file.ListItemAllFields.ParentList; context.Load(parentList); context.Load(file.ListItemAllFields); try { context.ExecuteQueryRetry(); } catch (ServerException ex) { // If this throws ServerException (does not belong to list), then shouldn't be trying to set properties) if (ex.ServerErrorCode != -2146232832) { throw; } } ListItemUtilities.UpdateListItem(file.ListItemAllFields, parser, properties, ListItemUtilities.ListItemUpdateType.UpdateOverwriteVersion); } }
public override TokenParser ProvisionObjects(Web web, Model.ProvisioningTemplate template, TokenParser parser, ProvisioningTemplateApplyingInformation applyingInformation) { using (var scope = new PnPMonitoredScope(this.Name)) { this.reusedTerms = new List <ReusedTerm>(); TaxonomySession taxSession = TaxonomySession.GetTaxonomySession(web.Context); TermStore termStore = null; TermGroup siteCollectionTermGroup = null; try { termStore = taxSession.GetDefaultKeywordsTermStore(); web.Context.Load(termStore, ts => ts.Languages, ts => ts.DefaultLanguage, ts => ts.Groups.Include( tg => tg.Name, tg => tg.Id, tg => tg.TermSets.Include( tset => tset.Name, tset => tset.Id))); siteCollectionTermGroup = termStore.GetSiteCollectionGroup((web.Context as ClientContext).Site, false); web.Context.Load(siteCollectionTermGroup); web.Context.ExecuteQueryRetry(); } catch (ServerException) { // If the GetDefaultSiteCollectionTermStore method call fails ... raise a specific Warning WriteMessage(CoreResources.Provisioning_ObjectHandlers_TermGroups_Wrong_Configuration, ProvisioningMessageType.Warning); // and exit skipping the current handler return(parser); } SiteCollectionTermGroupNameToken siteCollectionTermGroupNameToken = new SiteCollectionTermGroupNameToken(web); foreach (var modelTermGroup in template.TermGroups) { #region Group var newGroup = false; var normalizedGroupName = TaxonomyItem.NormalizeName(web.Context, modelTermGroup.Name); web.Context.ExecuteQueryRetry(); TermGroup group = termStore.Groups.FirstOrDefault( g => g.Id == modelTermGroup.Id || g.Name == normalizedGroupName.Value); if (group == null) { var parsedGroupName = parser.ParseString(modelTermGroup.Name); var parsedDescription = parser.ParseString(modelTermGroup.Description); if (modelTermGroup.Name == "Site Collection" || parsedGroupName == siteCollectionTermGroupNameToken.GetReplaceValue() || modelTermGroup.SiteCollectionTermGroup) { var site = (web.Context as ClientContext).Site; group = termStore.GetSiteCollectionGroup(site, true); web.Context.Load(group, g => g.Name, g => g.Id, g => g.TermSets.Include( tset => tset.Name, tset => tset.Id)); web.Context.ExecuteQueryRetry(); } else { var parsedNormalizedGroupName = TaxonomyItem.NormalizeName(web.Context, parsedGroupName); web.Context.ExecuteQueryRetry(); group = termStore.Groups.FirstOrDefault(g => g.Name == parsedNormalizedGroupName.Value); if (group == null) { if (modelTermGroup.Id == Guid.Empty) { modelTermGroup.Id = Guid.NewGuid(); } group = termStore.CreateGroup(parsedGroupName, modelTermGroup.Id); group.Description = parsedDescription; #if !ONPREMISES // Handle TermGroup Contributors, if any if (modelTermGroup.Contributors != null && modelTermGroup.Contributors.Count > 0) { foreach (var c in modelTermGroup.Contributors) { group.AddContributor(c.Name); } } // Handle TermGroup Managers, if any if (modelTermGroup.Managers != null && modelTermGroup.Managers.Count > 0) { foreach (var m in modelTermGroup.Managers) { group.AddGroupManager(m.Name); } } #endif termStore.CommitAll(); web.Context.Load(group); web.Context.ExecuteQueryRetry(); newGroup = true; } } } #endregion #region TermSets foreach (var modelTermSet in modelTermGroup.TermSets) { TermSet set = null; var newTermSet = false; var normalizedTermSetName = TaxonomyItem.NormalizeName(web.Context, modelTermSet.Name); web.Context.ExecuteQueryRetry(); if (!newGroup) { set = group.TermSets.FirstOrDefault( ts => ts.Id == modelTermSet.Id || ts.Name == normalizedTermSetName.Value); } if (set == null) { if (modelTermSet.Id == Guid.Empty) { modelTermSet.Id = Guid.NewGuid(); } set = group.CreateTermSet(parser.ParseString(modelTermSet.Name), modelTermSet.Id, modelTermSet.Language ?? termStore.DefaultLanguage); parser.AddToken(new TermSetIdToken(web, group.Name, modelTermSet.Name, modelTermSet.Id)); if (!siteCollectionTermGroup.ServerObjectIsNull.Value) { if (group.Name == siteCollectionTermGroup.Name) { parser.AddToken((new SiteCollectionTermSetIdToken(web, modelTermSet.Name, modelTermSet.Id))); } } newTermSet = true; set.Description = parser.ParseString(modelTermSet.Description); set.IsOpenForTermCreation = modelTermSet.IsOpenForTermCreation; set.IsAvailableForTagging = modelTermSet.IsAvailableForTagging; foreach (var property in modelTermSet.Properties) { set.SetCustomProperty(property.Key, parser.ParseString(property.Value)); } if (modelTermSet.Owner != null) { set.Owner = modelTermSet.Owner; } termStore.CommitAll(); web.Context.Load(set); web.Context.ExecuteQueryRetry(); } web.Context.Load(set, s => s.Terms.Include(t => t.Id, t => t.Name)); web.Context.ExecuteQueryRetry(); var terms = set.Terms; foreach (var modelTerm in modelTermSet.Terms) { if (!newTermSet) { if (terms.Any()) { var term = terms.FirstOrDefault(t => t.Id == modelTerm.Id); if (term == null) { var normalizedTermName = TaxonomyItem.NormalizeName(web.Context, modelTerm.Name); web.Context.ExecuteQueryRetry(); term = terms.FirstOrDefault(t => t.Name == normalizedTermName.Value); if (term == null) { var returnTuple = CreateTerm <TermSet>(web, modelTerm, set, termStore, parser, scope); if (returnTuple != null) { modelTerm.Id = returnTuple.Item1; parser = returnTuple.Item2; } } else { modelTerm.Id = term.Id; } } else { modelTerm.Id = term.Id; } if (term != null) { CheckChildTerms(web, modelTerm, term, termStore, parser, scope); } } else { var returnTuple = CreateTerm <TermSet>(web, modelTerm, set, termStore, parser, scope); if (returnTuple != null) { modelTerm.Id = returnTuple.Item1; parser = returnTuple.Item2; } } } else { var returnTuple = CreateTerm <TermSet>(web, modelTerm, set, termStore, parser, scope); if (returnTuple != null) { modelTerm.Id = returnTuple.Item1; parser = returnTuple.Item2; } } } // do we need custom sorting? if (modelTermSet.Terms.Any(t => t.CustomSortOrder > -1)) { var sortedTerms = modelTermSet.Terms.OrderBy(t => t.CustomSortOrder); var customSortString = sortedTerms.Aggregate(string.Empty, (a, i) => a + i.Id.ToString() + ":"); customSortString = customSortString.TrimEnd(new[] { ':' }); set.CustomSortOrder = customSortString; termStore.CommitAll(); web.Context.ExecuteQueryRetry(); } } #endregion } foreach (var reusedTerm in this.reusedTerms) { TryReuseTerm(web, reusedTerm.ModelTerm, reusedTerm.Parent, reusedTerm.TermStore, parser, scope); } } return(parser); }
public override TokenParser ProvisionObjects(Tenant tenant, Model.ProvisioningHierarchy hierarchy, string sequenceId, TokenParser tokenParser, ApplyConfiguration configuration) { using (var scope = new PnPMonitoredScope(CoreResources.Provisioning_ObjectHandlers_Provisioning)) { bool nowait = false; if (configuration != null) { nowait = configuration.Tenant.DoNotWaitForSitesToBeFullyCreated; } var sequence = hierarchy.Sequences.FirstOrDefault(s => s.ID == sequenceId); if (sequence != null) { var siteUrls = new Dictionary <Guid, string>(); TokenParser siteTokenParser = null; foreach (var sitecollection in sequence.SiteCollections) { ClientContext siteContext = null; switch (sitecollection) { case TeamSiteCollection t: { TeamSiteCollectionCreationInformation siteInfo = new TeamSiteCollectionCreationInformation() { Alias = tokenParser.ParseString(t.Alias), DisplayName = tokenParser.ParseString(t.Title), Description = tokenParser.ParseString(t.Description), Classification = tokenParser.ParseString(t.Classification), IsPublic = t.IsPublic, Lcid = (uint)t.Language }; if (Guid.TryParse(t.SiteDesign, out Guid siteDesignId)) { siteInfo.SiteDesignId = siteDesignId; } var groupSiteInfo = Sites.SiteCollection.GetGroupInfoAsync(tenant.Context as ClientContext, siteInfo.Alias).GetAwaiter().GetResult(); if (groupSiteInfo == null) { WriteMessage($"Creating Team Site {siteInfo.Alias}", ProvisioningMessageType.Progress); siteContext = Sites.SiteCollection.Create(tenant.Context as ClientContext, siteInfo, configuration.Tenant.DelayAfterModernSiteCreation, noWait: nowait); } else { if (groupSiteInfo.ContainsKey("siteUrl")) { WriteMessage($"Using existing Team Site {siteInfo.Alias}", ProvisioningMessageType.Progress); siteContext = (tenant.Context as ClientContext).Clone(groupSiteInfo["siteUrl"], configuration.AccessTokens); } } if (t.IsHubSite) { siteContext.Load(siteContext.Site, s => s.Id); siteContext.ExecuteQueryRetry(); RegisterAsHubSite(tenant, siteContext.Url, siteContext.Site.Id, t.HubSiteLogoUrl, t.HubSiteTitle, tokenParser); } if (!string.IsNullOrEmpty(t.Theme)) { var parsedTheme = tokenParser.ParseString(t.Theme); tenant.SetWebTheme(parsedTheme, siteContext.Url); tenant.Context.ExecuteQueryRetry(); } if (t.Teamify) { try { WriteMessage($"Teamifying the O365 group connected site at URL - {siteContext.Url}", ProvisioningMessageType.Progress); siteContext.TeamifyAsync().GetAwaiter().GetResult(); } catch (Exception ex) { WriteMessage($"Teamifying site at URL - {siteContext.Url} failed due to an exception:- {ex.Message}", ProvisioningMessageType.Warning); } } if (t.HideTeamify) { try { WriteMessage($"Teamify prompt is now hidden for site at URL - {siteContext.Url}", ProvisioningMessageType.Progress); siteContext.HideTeamifyPrompt().GetAwaiter().GetResult(); } catch (Exception ex) { WriteMessage($"Teamify prompt couldn't be hidden for site at URL - {siteContext.Url} due to an exception:- {ex.Message}", ProvisioningMessageType.Warning); } } siteUrls.Add(t.Id, siteContext.Url); if (!string.IsNullOrEmpty(t.ProvisioningId)) { _additionalTokens.Add(new SequenceSiteUrlUrlToken(null, t.ProvisioningId, siteContext.Url)); siteContext.Web.EnsureProperty(w => w.Id); _additionalTokens.Add(new SequenceSiteIdToken(null, t.ProvisioningId, siteContext.Web.Id)); siteContext.Site.EnsureProperties(s => s.Id, s => s.GroupId); _additionalTokens.Add(new SequenceSiteCollectionIdToken(null, t.ProvisioningId, siteContext.Site.Id)); _additionalTokens.Add(new SequenceSiteGroupIdToken(null, t.ProvisioningId, siteContext.Site.GroupId)); } break; } case CommunicationSiteCollection c: { var siteUrl = tokenParser.ParseString(c.Url); if (!siteUrl.StartsWith("https://", StringComparison.InvariantCultureIgnoreCase)) { var rootSiteUrl = tenant.GetRootSiteUrl(); tenant.Context.ExecuteQueryRetry(); siteUrl = UrlUtility.Combine(rootSiteUrl.Value, siteUrl); } CommunicationSiteCollectionCreationInformation siteInfo = new CommunicationSiteCollectionCreationInformation() { ShareByEmailEnabled = c.AllowFileSharingForGuestUsers, Classification = tokenParser.ParseString(c.Classification), Description = tokenParser.ParseString(c.Description), Lcid = (uint)c.Language, Owner = tokenParser.ParseString(c.Owner), Title = tokenParser.ParseString(c.Title), Url = siteUrl }; if (Guid.TryParse(c.SiteDesign, out Guid siteDesignId)) { siteInfo.SiteDesignId = siteDesignId; } else { if (!string.IsNullOrEmpty(c.SiteDesign)) { siteInfo.SiteDesign = (CommunicationSiteDesign)Enum.Parse(typeof(CommunicationSiteDesign), c.SiteDesign); } else { siteInfo.SiteDesign = CommunicationSiteDesign.Showcase; } } // check if site exists if (tenant.SiteExistsAnywhere(siteInfo.Url) == SiteExistence.Yes) { WriteMessage($"Using existing Communications Site at {siteInfo.Url}", ProvisioningMessageType.Progress); siteContext = (tenant.Context as ClientContext).Clone(siteInfo.Url, configuration.AccessTokens); } else if (tenant.SiteExistsAnywhere(siteInfo.Url) == SiteExistence.Recycled) { var errorMessage = $"The requested Communications Site at {siteInfo.Url} is in the Recycle Bin and cannot be created"; WriteMessage(errorMessage, ProvisioningMessageType.Error); throw new RecycledSiteException(errorMessage); } else { WriteMessage($"Creating Communications Site at {siteInfo.Url}", ProvisioningMessageType.Progress); siteContext = Sites.SiteCollection.Create(tenant.Context as ClientContext, siteInfo, configuration.Tenant.DelayAfterModernSiteCreation, noWait: nowait); } if (c.IsHubSite) { siteContext.Load(siteContext.Site, s => s.Id); siteContext.ExecuteQueryRetry(); RegisterAsHubSite(tenant, siteInfo.Url, siteContext.Site.Id, c.HubSiteLogoUrl, c.HubSiteTitle, tokenParser); } if (!string.IsNullOrEmpty(c.Theme)) { var parsedTheme = tokenParser.ParseString(c.Theme); tenant.SetWebTheme(parsedTheme, siteInfo.Url); tenant.Context.ExecuteQueryRetry(); } siteUrls.Add(c.Id, siteInfo.Url); if (!string.IsNullOrEmpty(c.ProvisioningId)) { _additionalTokens.Add(new SequenceSiteUrlUrlToken(null, c.ProvisioningId, siteInfo.Url)); siteContext.Web.EnsureProperty(w => w.Id); _additionalTokens.Add(new SequenceSiteIdToken(null, c.ProvisioningId, siteContext.Web.Id)); siteContext.Site.EnsureProperties(s => s.Id, s => s.GroupId); _additionalTokens.Add(new SequenceSiteCollectionIdToken(null, c.ProvisioningId, siteContext.Site.Id)); _additionalTokens.Add(new SequenceSiteGroupIdToken(null, c.ProvisioningId, siteContext.Site.GroupId)); } break; } case TeamNoGroupSiteCollection t: { var siteUrl = tokenParser.ParseString(t.Url); TeamNoGroupSiteCollectionCreationInformation siteInfo = new TeamNoGroupSiteCollectionCreationInformation() { Lcid = (uint)t.Language, Url = siteUrl, Title = tokenParser.ParseString(t.Title), Description = tokenParser.ParseString(t.Description), Owner = tokenParser.ParseString(t.Owner) }; if (tenant.SiteExistsAnywhere(siteUrl) == SiteExistence.Yes) { WriteMessage($"Using existing Team Site at {siteUrl}", ProvisioningMessageType.Progress); siteContext = (tenant.Context as ClientContext).Clone(siteUrl, configuration.AccessTokens); } else if (tenant.SiteExistsAnywhere(siteUrl) == SiteExistence.Recycled) { var errorMessage = $"The requested Team Site at {siteUrl} is in the Recycle Bin and cannot be created"; WriteMessage(errorMessage, ProvisioningMessageType.Error); throw new RecycledSiteException(errorMessage); } else { WriteMessage($"Creating Team Site with no Office 365 group at {siteUrl}", ProvisioningMessageType.Progress); siteContext = Sites.SiteCollection.Create(tenant.Context as ClientContext, siteInfo, configuration.Tenant.DelayAfterModernSiteCreation, noWait: nowait); } if (t.Groupify) { if (string.IsNullOrEmpty(t.Alias)) { // We generate the alias, if it is missing t.Alias = t.Title.Replace(" ", string.Empty).ToLower(); } // In case we need to groupify the just created site var groupifyInformation = new TeamSiteCollectionGroupifyInformation { Alias = t.Alias, // Mandatory Classification = t.Classification, // Optional Description = t.Description, DisplayName = t.Title, HubSiteId = Guid.Empty, // Optional, so far we skip it IsPublic = t.IsPublic, // Mandatory KeepOldHomePage = t.KeepOldHomePage, // Optional, but we provide it Lcid = (uint)t.Language, Owners = new string[] { t.Owner }, }; tenant.GroupifySite(siteUrl, groupifyInformation); } if (t.IsHubSite) { siteContext.Load(siteContext.Site, s => s.Id); siteContext.ExecuteQueryRetry(); RegisterAsHubSite(tenant, siteContext.Url, siteContext.Site.Id, t.HubSiteLogoUrl, t.HubSiteTitle, tokenParser); } if (!string.IsNullOrEmpty(t.Theme)) { var parsedTheme = tokenParser.ParseString(t.Theme); tenant.SetWebTheme(parsedTheme, siteContext.Url); tenant.Context.ExecuteQueryRetry(); } siteUrls.Add(t.Id, siteContext.Url); if (!string.IsNullOrEmpty(t.ProvisioningId)) { _additionalTokens.Add(new SequenceSiteUrlUrlToken(null, t.ProvisioningId, siteContext.Url)); siteContext.Web.EnsureProperty(w => w.Id); _additionalTokens.Add(new SequenceSiteIdToken(null, t.ProvisioningId, siteContext.Web.Id)); siteContext.Site.EnsureProperties(s => s.Id, s => s.GroupId); _additionalTokens.Add(new SequenceSiteCollectionIdToken(null, t.ProvisioningId, siteContext.Site.Id)); _additionalTokens.Add(new SequenceSiteGroupIdToken(null, t.ProvisioningId, siteContext.Site.GroupId)); } break; } } var web = siteContext.Web; if (siteTokenParser == null) { siteTokenParser = new TokenParser(tenant, hierarchy, configuration.ToApplyingInformation()); foreach (var token in _additionalTokens) { siteTokenParser.AddToken(token); } } foreach (var subsite in sitecollection.Sites) { var subSiteObject = (TeamNoGroupSubSite)subsite; web.EnsureProperties(w => w.Webs.IncludeWithDefaultProperties(), w => w.ServerRelativeUrl); siteTokenParser = CreateSubSites(hierarchy, siteTokenParser, sitecollection, siteContext, web, subSiteObject); } siteTokenParser = null; } // System.Threading.Thread.Sleep(TimeSpan.FromMinutes(10)); WriteMessage("Applying templates", ProvisioningMessageType.Progress); var currentSite = ""; var provisioningTemplateApplyingInformation = configuration.ToApplyingInformation(); provisioningTemplateApplyingInformation.ProgressDelegate = (string message, int step, int total) => { configuration.ProgressDelegate?.Invoke($"{currentSite} : {message}", step, total); }; foreach (var sitecollection in sequence.SiteCollections) { currentSite = sitecollection.ProvisioningId != null ? sitecollection.ProvisioningId : sitecollection.Title; siteUrls.TryGetValue(sitecollection.Id, out string siteUrl); if (siteUrl != null) { using (var clonedContext = tenant.Context.Clone(siteUrl, configuration.AccessTokens)) { var web = clonedContext.Web; foreach (var templateRef in sitecollection.Templates) { var provisioningTemplate = hierarchy.Templates.FirstOrDefault(t => t.Id == templateRef); if (provisioningTemplate != null) { provisioningTemplate.Connector = hierarchy.Connector; //if (siteTokenParser == null) //{ siteTokenParser = new TokenParser(web, provisioningTemplate, configuration.ToApplyingInformation()); foreach (var token in _additionalTokens) { siteTokenParser.AddToken(token); } //} //else //{ // siteTokenParser.Rebase(web, provisioningTemplate); //} WriteMessage($"Applying Template", ProvisioningMessageType.Progress); new SiteToTemplateConversion().ApplyRemoteTemplate(web, provisioningTemplate, provisioningTemplateApplyingInformation, true, siteTokenParser); } else { WriteMessage($"Referenced template ID {templateRef} not found", ProvisioningMessageType.Error); } } if (siteTokenParser == null) { siteTokenParser = new TokenParser(tenant, hierarchy, configuration.ToApplyingInformation()); foreach (var token in _additionalTokens) { siteTokenParser.AddToken(token); } } foreach (var subsite in sitecollection.Sites) { var subSiteObject = (TeamNoGroupSubSite)subsite; web.EnsureProperties(w => w.Webs.IncludeWithDefaultProperties(), w => w.ServerRelativeUrl); siteTokenParser = ApplySubSiteTemplates(hierarchy, siteTokenParser, sitecollection, clonedContext, web, subSiteObject, provisioningTemplateApplyingInformation); } if (sitecollection.IsHubSite) { RESTUtilities.ExecuteGet(web, "/_api/web/hubsitedata(true)").GetAwaiter().GetResult(); } } } } } return(tokenParser); } }
public override TokenParser ProvisionObjects(Web web, ProvisioningTemplate template, TokenParser parser, ProvisioningTemplateApplyingInformation applyingInformation) { #if !ONPREMISES using (var scope = new PnPMonitoredScope(this.Name)) { var context = web.Context as ClientContext; var parsedName = parser.ParseString(template.Theme.Name); if (Enum.TryParse <SharePointTheme>(parsedName, out SharePointTheme builtInTheme)) { ThemeManager.ApplyTheme(web, builtInTheme); } else { web.EnsureProperty(w => w.Url); if (!string.IsNullOrEmpty(template.Theme.Palette)) { var parsedPalette = parser.ParseString(template.Theme.Palette); ThemeManager.ApplyTheme(web, parsedPalette, template.Theme.Name ?? parsedPalette); } } } #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()); 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); } } }
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)) { 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); var composedLookJson = JsonConvert.SerializeObject(template.ComposedLook); web.SetPropertyBagValue("_PnP_ProvisioningTemplateComposedLookInfo", composedLookJson); } // Persist composed look info in property bag } } return(parser); }
private static void CreateField(Web web, XElement templateFieldElement, PnPMonitoredScope scope, TokenParser parser, string originalFieldXml) { var listIdentifier = templateFieldElement.Attribute("List") != null?templateFieldElement.Attribute("List").Value : null; if (listIdentifier != null) { // Temporary remove list attribute from list templateFieldElement.Attribute("List").Remove(); } var fieldXml = parser.ParseXmlString(templateFieldElement.ToString(), "~sitecollection", "~site"); if (IsFieldXmlValid(fieldXml, parser, web.Context)) { var field = web.Fields.AddFieldAsXml(fieldXml, false, AddFieldOptions.AddFieldInternalNameHint); web.Context.Load(field, f => f.TypeAsString, f => f.DefaultValue, f => f.InternalName, f => f.Title); web.Context.ExecuteQueryRetry(); // Add newly created field to token set, this allows to create a field + use it in a formula in the same provisioning template parser.AddToken(new FieldTitleToken(web, field.InternalName, field.Title)); 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()) { field.TitleResource.SetUserResourceValue(nameAttributeValue, parser); isDirty = true; } var descriptionAttributeValue = originalFieldElement.Attribute("Description") != null?originalFieldElement.Attribute("Description").Value : ""; if (descriptionAttributeValue.ContainsResourceToken()) { field.DescriptionResource.SetUserResourceValue(descriptionAttributeValue, parser); isDirty = true; } } #endif if (isDirty) { field.Update(); web.Context.ExecuteQueryRetry(); } if ((field.TypeAsString == "TaxonomyFieldType" || field.TypeAsString == "TaxonomyFieldTypeMulti")) { var taxField = web.Context.CastTo <TaxonomyField>(field); if (!string.IsNullOrEmpty(field.DefaultValue)) { ValidateTaxonomyFieldDefaultValue(taxField); } SetTaxonomyFieldOpenValue(taxField, originalFieldXml); } } else { // The field Xml was found invalid var tokenString = parser.GetLeftOverTokens(fieldXml).Aggregate(String.Empty, (acc, i) => acc + " " + i); scope.LogError("The field was found invalid: {0}", tokenString); throw new Exception($"The field was found invalid: {tokenString}"); } }
public override TokenParser ProvisionObjects(Web web, ProvisioningTemplate template, TokenParser parser, ProvisioningTemplateApplyingInformation applyingInformation) { using (var scope = new PnPMonitoredScope(this.Name)) { // if this is a sub site then we're not provisioning fields. Technically this can be done but it's not a recommended practice if (web.IsSubSite() && !applyingInformation.ProvisionFieldsToSubWebs) { scope.LogDebug(CoreResources.Provisioning_ObjectHandlers_Fields_Context_web_is_subweb__skipping_site_columns); WriteMessage("This template contains fields and you are provisioning to a subweb. If you still want to provision these fields, set the ProvisionFieldsToSubWebs property to true.", ProvisioningMessageType.Warning); return(parser); } var existingFields = web.Fields; web.Context.Load(existingFields, fs => fs.Include(f => f.Id)); web.Context.ExecuteQueryRetry(); var existingFieldIds = existingFields.AsEnumerable <SPField>().Select(l => l.Id).ToList(); var fields = template.SiteFields; var currentFieldIndex = 0; foreach (var field in fields) { currentFieldIndex++; XElement templateFieldElement = XElement.Parse(parser.ParseXmlString(field.SchemaXml, "~sitecollection", "~site")); var fieldId = templateFieldElement.Attribute("ID").Value; var fieldInternalName = templateFieldElement.Attribute("InternalName") != null?templateFieldElement.Attribute("InternalName").Value : ""; WriteMessage($"Field|{(!string.IsNullOrWhiteSpace(fieldInternalName) ? fieldInternalName : fieldId)}|{currentFieldIndex}|{fields.Count}", ProvisioningMessageType.Progress); if (!existingFieldIds.Contains(Guid.Parse(fieldId))) { try { scope.LogDebug(CoreResources.Provisioning_ObjectHandlers_Fields_Adding_field__0__to_site, fieldId); CreateField(web, templateFieldElement, scope, parser, field.SchemaXml); } catch (Exception ex) { scope.LogError(CoreResources.Provisioning_ObjectHandlers_Fields_Adding_field__0__failed___1_____2_, fieldId, ex.Message, ex.StackTrace); throw; } } else { try { scope.LogDebug(CoreResources.Provisioning_ObjectHandlers_Fields_Updating_field__0__in_site, fieldId); UpdateField(web, fieldId, templateFieldElement, scope, parser, field.SchemaXml); } catch (Exception ex) { scope.LogError(CoreResources.Provisioning_ObjectHandlers_Fields_Updating_field__0__failed___1_____2_, fieldId, ex.Message, ex.StackTrace); throw; } } } } WriteMessage($"Done processing fields", ProvisioningMessageType.Completed); return(parser); }
public override ProvisioningTemplate ExtractObjects(Web web, ProvisioningTemplate template, ProvisioningTemplateCreationInformation creationInfo) { using (var scope = new PnPMonitoredScope(this.Name)) { scope.LogInfo(CoreResources.Provisioning_ObjectHandlers_ComposedLooks_ExtractObjects_Retrieving_current_composed_look); // Ensure that we have URL property loaded for web and site web.EnsureProperty(w => w.Url); Site site = (web.Context as ClientContext).Site; site.EnsureProperty(s => s.Url); SharePointConnector spConnector = new SharePointConnector(web.Context, web.Url, "dummy"); // to get files from theme catalog we need a connector linked to the root site SharePointConnector spConnectorRoot; if (!site.Url.Equals(web.Url, StringComparison.InvariantCultureIgnoreCase)) { spConnectorRoot = new SharePointConnector(web.Context.Clone(site.Url), site.Url, "dummy"); } else { spConnectorRoot = spConnector; } // Check if we have composed look info in the property bag, if so, use that, otherwise try to detect the current composed look if (web.PropertyBagContainsKey("_PnP_ProvisioningTemplateComposedLookInfo")) { scope.LogInfo(CoreResources.Provisioning_ObjectHandlers_ComposedLooks_ExtractObjects_Using_ComposedLookInfoFromPropertyBag); try { var composedLook = JsonConvert.DeserializeObject <ComposedLook>(web.GetPropertyBagValueString("_PnP_ProvisioningTemplateComposedLookInfo", "")); if (composedLook.Name == null || composedLook.BackgroundFile == null || composedLook.FontFile == null) { scope.LogError(CoreResources.Provisioning_ObjectHandlers_ComposedLooks_ExtractObjects_ComposedLookInfoFailedToDeserialize); throw new JsonSerializationException(); } composedLook.BackgroundFile = Tokenize(composedLook.BackgroundFile, web.Url); composedLook.FontFile = Tokenize(composedLook.FontFile, web.Url); composedLook.ColorFile = Tokenize(composedLook.ColorFile, web.Url); template.ComposedLook = composedLook; if (!web.IsSubSite() && creationInfo != null && creationInfo.PersistBrandingFiles && creationInfo.FileConnector != null) { scope.LogDebug(CoreResources.Provisioning_ObjectHandlers_ComposedLooks_ExtractObjects_Creating_SharePointConnector); // Let's create a SharePoint connector since our files anyhow are in SharePoint at this moment TokenParser parser = new TokenParser(web, template); DownLoadFile(spConnector, spConnectorRoot, creationInfo.FileConnector, web.Url, parser.ParseString(composedLook.BackgroundFile), scope); DownLoadFile(spConnector, spConnectorRoot, creationInfo.FileConnector, web.Url, parser.ParseString(composedLook.ColorFile), scope); DownLoadFile(spConnector, spConnectorRoot, creationInfo.FileConnector, web.Url, parser.ParseString(composedLook.FontFile), scope); } // Create file entries for the custom theme files if (!string.IsNullOrEmpty(template.ComposedLook.BackgroundFile)) { var f = GetComposedLookFile(template.ComposedLook.BackgroundFile); f.Folder = Tokenize(f.Folder, web.Url); template.Files.Add(f); } if (!string.IsNullOrEmpty(template.ComposedLook.ColorFile)) { var f = GetComposedLookFile(template.ComposedLook.ColorFile); f.Folder = Tokenize(f.Folder, web.Url); template.Files.Add(f); } if (!string.IsNullOrEmpty(template.ComposedLook.FontFile)) { var f = GetComposedLookFile(template.ComposedLook.FontFile); f.Folder = Tokenize(f.Folder, web.Url); template.Files.Add(f); } } catch (JsonSerializationException) { // cannot deserialize the object, fall back to composed look detection template = DetectComposedLook(web, template, creationInfo, scope, spConnector, spConnectorRoot); } } else { template = DetectComposedLook(web, template, creationInfo, scope, spConnector, spConnectorRoot); } if (creationInfo != null && 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)) { // 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 = 0; i < siteSecurity.SiteGroups.Count; i++) { var currentGroup = siteSecurity.SiteGroups[i]; string currentGroupOwner = currentGroup.Owner; string currentGroupTitle = parser.ParseString(currentGroup.Title); if (currentGroupOwner != "SHAREPOINT\\system" && currentGroupOwner != currentGroupTitle && !(currentGroupOwner.StartsWith("{{associated") && currentGroupOwner.EndsWith("group}}"))) { for (int j = i + 1; j < siteSecurity.SiteGroups.Count; j++) { if (siteSecurity.SiteGroups[j].Title == currentGroupOwner) { siteSecurity.SiteGroups.Insert(i, siteSecurity.SiteGroups[j]); siteSecurity.SiteGroups.RemoveAt(j); 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); if (!web.GroupExists(parsedGroupTitle)) { scope.LogDebug("Creating group {0}", parsedGroupTitle); group = web.AddGroup( parsedGroupTitle, //If the description is more than 512 characters long a server exception will be thrown. PnPHttpUtility.ConvertSimpleHtmlToText(parsedGroupDescription, int.MaxValue), parsedGroupTitle == parsedGroupOwner); group.AllowMembersEditMembership = siteGroup.AllowMembersEditMembership; group.AllowRequestToJoinLeave = siteGroup.AllowRequestToJoinLeave; group.AutoAcceptRequestToJoinLeave = siteGroup.AutoAcceptRequestToJoinLeave; group.OnlyAllowMembersViewMembership = siteGroup.OnlyAllowMembersViewMembership; group.RequestToJoinLeaveEmailSetting = siteGroup.RequestToJoinLeaveEmailSetting; 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)); 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.OnlyAllowMembersViewMembership, g => g.RequestToJoinLeaveEmailSetting, g => g.Owner.LoginName); web.Context.ExecuteQueryRetry(); var groupNeedsUpdate = false; var executeQuery = false; if (!String.IsNullOrEmpty(parsedGroupDescription)) { 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(); executeQuery = true; } var plainTextDescription = PnPHttpUtility.ConvertSimpleHtmlToText(parsedGroupDescription, int.MaxValue); if (group.Description != plainTextDescription) { //If the description is more than 512 characters long a server exception will be thrown. group.Description = plainTextDescription; groupNeedsUpdate = true; } } if (group.AllowMembersEditMembership != siteGroup.AllowMembersEditMembership) { group.AllowMembersEditMembership = siteGroup.AllowMembersEditMembership; groupNeedsUpdate = true; } if (group.AllowRequestToJoinLeave != siteGroup.AllowRequestToJoinLeave) { group.AllowRequestToJoinLeave = siteGroup.AllowRequestToJoinLeave; groupNeedsUpdate = true; } if (group.AutoAcceptRequestToJoinLeave != siteGroup.AutoAcceptRequestToJoinLeave) { group.AutoAcceptRequestToJoinLeave = siteGroup.AutoAcceptRequestToJoinLeave; groupNeedsUpdate = true; } if (group.OnlyAllowMembersViewMembership != siteGroup.OnlyAllowMembersViewMembership) { group.OnlyAllowMembersViewMembership = siteGroup.OnlyAllowMembersViewMembership; groupNeedsUpdate = true; } if (!String.IsNullOrEmpty(group.RequestToJoinLeaveEmailSetting) && group.RequestToJoinLeaveEmailSetting != siteGroup.RequestToJoinLeaveEmailSetting) { group.RequestToJoinLeaveEmailSetting = siteGroup.RequestToJoinLeaveEmailSetting; groupNeedsUpdate = 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; } groupNeedsUpdate = true; } if (groupNeedsUpdate) { scope.LogDebug("Updating existing group {0}", group.Title); group.Update(); executeQuery = true; } if (executeQuery) { 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 parsedRoleDefinitionName = parser.ParseString(templateRoleDefinition.Name); var parsedTemplateRoleDefinitionDesc = parser.ParseString(templateRoleDefinition.Description); var siteRoleDefinition = roleDefinitions.FirstOrDefault(erd => erd.Name == parsedRoleDefinitionName); if (siteRoleDefinition == null) { scope.LogDebug("Creating role definition {0}", parsedRoleDefinitionName); var roleDefinitionCI = new RoleDefinitionCreationInformation(); roleDefinitionCI.Name = parsedRoleDefinitionName; roleDefinitionCI.Description = parsedTemplateRoleDefinitionDesc; 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 != parsedTemplateRoleDefinitionDesc) { siteRoleDefinition.Description = parsedTemplateRoleDefinitionDesc; 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}", parsedRoleDefinitionName); 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) { var parsedRoleDefinition = parser.ParseString(roleAssignment.RoleDefinition); if (!roleAssignment.Remove) { var roleDefinition = webRoleDefinitions.FirstOrDefault(r => r.Name == parsedRoleDefinition); 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 == parsedRoleDefinition); if (binding != null) { assignmentForPrincipal.DeleteObject(); web.Context.ExecuteQueryRetry(); break; } } } } } } } return(parser); }
private static void RegisterAsHubSite(Tenant tenant, string siteUrl, Guid siteId, string logoUrl, string hubsiteTitle, TokenParser parser) { siteUrl = parser.ParseString(siteUrl); var hubSiteProperties = tenant.GetHubSitePropertiesByUrl(siteUrl); tenant.Context.Load <HubSiteProperties>(hubSiteProperties); tenant.Context.ExecuteQueryRetry(); if (hubSiteProperties.ServerObjectIsNull == true) { var ci = new HubSiteCreationInformation(); ci.SiteId = siteId; if (!string.IsNullOrEmpty(logoUrl)) { ci.LogoUrl = parser.ParseString(logoUrl); } if (!string.IsNullOrEmpty(hubsiteTitle)) { ci.Title = parser.ParseString(hubsiteTitle); } tenant.RegisterHubSiteWithCreationInformation(siteUrl, ci); //tenant.Context.Load(hubSiteProperties); tenant.Context.ExecuteQueryRetry(); } else { bool isDirty = false; if (!string.IsNullOrEmpty(logoUrl)) { logoUrl = parser.ParseString(logoUrl); hubSiteProperties.LogoUrl = logoUrl; isDirty = true; } if (!string.IsNullOrEmpty(hubsiteTitle)) { hubsiteTitle = parser.ParseString(hubsiteTitle); hubSiteProperties.Title = hubsiteTitle; isDirty = true; } if (isDirty) { hubSiteProperties.Update(); tenant.Context.ExecuteQueryRetry(); } } }
public override TokenParser ProvisionObjects(Web web, ProvisioningTemplate template, TokenParser parser, ProvisioningTemplateApplyingInformation applyingInformation) { using (var scope = new PnPMonitoredScope(this.Name)) { if (template.ApplicationLifecycleManagement != null) { var manager = new AppManager(web.Context as ClientContext); // The ALM API do not support the local Site Collection App Catalog // Thus, so far we skip the AppCatalog section // NOOP if (template.ApplicationLifecycleManagement.Apps != null && template.ApplicationLifecycleManagement.Apps.Count > 0) { // Get the apps already installed in the site var siteApps = manager.GetAvailable()?.Where(a => a.InstalledVersion != null)?.ToList(); foreach (var app in template.ApplicationLifecycleManagement.Apps) { var appId = Guid.Parse(parser.ParseString(app.AppId)); var alreadyExists = siteApps.Any(a => a.Id == appId); var working = false; if (app.Action == AppAction.Install && !alreadyExists) { manager.Install(appId); working = true; } else if (app.Action == AppAction.Install && alreadyExists) { WriteMessage($"App with ID {appId} already exists in the target site and it will be skipped!", ProvisioningMessageType.Warning); } else if (app.Action == AppAction.Uninstall && alreadyExists) { manager.Uninstall(appId); working = true; } else if (app.Action == AppAction.Uninstall && !alreadyExists) { WriteMessage($"App with ID {appId} does not exist in the target site and cannot be uninstalled!", ProvisioningMessageType.Warning); } else if (app.Action == AppAction.Update && alreadyExists) { manager.Upgrade(appId); working = true; } else if (app.Action == AppAction.Update && !alreadyExists) { WriteMessage($"App with ID {appId} does not exist in the target site and cannot be updated!", ProvisioningMessageType.Warning); } if (app.SyncMode == SyncMode.Synchronously && working) { // We need to wait for the app management // to be completed before proceeding } } } } } return(parser); }
/// <summary> /// Actual implementation of the apply templates /// </summary> /// <param name="web"></param> /// <param name="template"></param> /// <param name="provisioningInfo"></param> internal void ApplyRemoteTemplate(Web web, ProvisioningTemplate template, ProvisioningTemplateApplyingInformation provisioningInfo) { using (var scope = new PnPMonitoredScope(CoreResources.Provisioning_ObjectHandlers_Provisioning)) { ProvisioningProgressDelegate progressDelegate = null; ProvisioningMessagesDelegate messagesDelegate = 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); } } else { // When no provisioning info was passed then we want to execute all handlers provisioningInfo = new ProvisioningTemplateApplyingInformation(); provisioningInfo.HandlersToProcess = Handlers.All; } 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()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.Fields) || provisioningInfo.HandlersToProcess.HasFlag(Handlers.Lists)) { objectHandlers.Add(new ObjectField()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.ContentTypes)) { objectHandlers.Add(new ObjectContentType()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.Lists)) { objectHandlers.Add(new ObjectListInstance()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.Fields) || provisioningInfo.HandlersToProcess.HasFlag(Handlers.Lists)) { objectHandlers.Add(new ObjectLookupFields()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.Fields) || provisioningInfo.HandlersToProcess.HasFlag(Handlers.Lists)) { objectHandlers.Add(new ObjectListInstanceDataRows()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.Files)) { objectHandlers.Add(new ObjectFiles()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.Pages)) { objectHandlers.Add(new ObjectPages()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.PageContents)) { objectHandlers.Add(new ObjectPageContents()); } 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.Workflows)) { objectHandlers.Add(new ObjectWorkflows()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.PropertyBagEntries)) { objectHandlers.Add(new ObjectPropertyBagEntry()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.ExtensibilityProviders)) { objectHandlers.Add(new ObjectExtensibilityHandlers()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.WebSettings)) { objectHandlers.Add(new ObjectWebSettings()); } objectHandlers.Add(new ObjectPersistTemplateInfo()); var 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 = 1; var count = objectHandlers.Count(o => o.ReportProgress && o.WillProvision(web, template)); foreach (var handler in objectHandlers) { if (handler.WillProvision(web, template)) { if (messagesDelegate != null) { handler.MessagesDelegate = messagesDelegate; } if (handler.ReportProgress && progressDelegate != null) { progressDelegate(handler.Name, step, count); step++; } tokenParser = handler.ProvisionObjects(web, template, tokenParser, provisioningInfo); } } } }
public override TokenParser ProvisionObjects(Web web, ProvisioningTemplate template, TokenParser parser, ProvisioningTemplateApplyingInformation applyingInformation) { using (var scope = new PnPMonitoredScope(this.Name)) { // if this is a sub site then we're not provisioning fields. Technically this can be done but it's not a recommended practice if (web.IsSubSite()) { scope.LogDebug(CoreResources.Provisioning_ObjectHandlers_Fields_Context_web_is_subweb__skipping_site_columns); return(parser); } var existingFields = web.Fields; web.Context.Load(existingFields, fs => fs.Include(f => f.Id)); web.Context.ExecuteQueryRetry(); var existingFieldIds = existingFields.AsEnumerable <SPField>().Select(l => l.Id).ToList(); var fields = template.SiteFields; foreach (var field in fields) { XElement templateFieldElement = XElement.Parse(parser.ParseString(field.SchemaXml, "~sitecollection", "~site")); var fieldId = templateFieldElement.Attribute("ID").Value; if (!existingFieldIds.Contains(Guid.Parse(fieldId))) { try { scope.LogDebug(CoreResources.Provisioning_ObjectHandlers_Fields_Adding_field__0__to_site, fieldId); CreateField(web, templateFieldElement, scope, parser); } catch (Exception ex) { scope.LogError(CoreResources.Provisioning_ObjectHandlers_Fields_Adding_field__0__failed___1_____2_, fieldId, ex.Message, ex.StackTrace); throw; } } else { try { scope.LogDebug(CoreResources.Provisioning_ObjectHandlers_Fields_Updating_field__0__in_site, fieldId); UpdateField(web, fieldId, templateFieldElement, scope, parser); } catch (Exception ex) { scope.LogError(CoreResources.Provisioning_ObjectHandlers_Fields_Updating_field__0__failed___1_____2_, fieldId, ex.Message, ex.StackTrace); throw; } } } } return(parser); }
private TokenParser CheckChildTerms(Web web, Model.Term modelTerm, Term parentTerm, TermStore termStore, TokenParser parser, PnPMonitoredScope scope) { if (modelTerm.Terms.Any()) { parentTerm.Context.Load(parentTerm, s => s.Terms.Include(t => t.Id, t => t.Name)); parentTerm.Context.ExecuteQueryRetry(); var terms = parentTerm.Terms; foreach (var childTerm in modelTerm.Terms) { if (terms.Any()) { var term = terms.FirstOrDefault(t => t.Id == childTerm.Id); if (term == null) { var normalizedTermName = TaxonomyItem.NormalizeName(web.Context, childTerm.Name); web.Context.ExecuteQueryRetry(); term = terms.FirstOrDefault(t => t.Name == normalizedTermName.Value); if (term == null) { var returnTuple = CreateTerm <TermSet>(web, childTerm, parentTerm, termStore, parser, scope); if (returnTuple != null) { childTerm.Id = returnTuple.Item1; parser = returnTuple.Item2; } } else { childTerm.Id = term.Id; } } else { childTerm.Id = term.Id; } if (term != null) { parser = CheckChildTerms(web, childTerm, term, termStore, parser, scope); } } else { var returnTuple = CreateTerm <TermSet>(web, childTerm, parentTerm, termStore, parser, scope); if (returnTuple != null) { childTerm.Id = returnTuple.Item1; parser = returnTuple.Item2; } } } } return(parser); }
/// <summary> /// Attempts to reuse the model term. If the term does not yet exists it will return /// false for the first part of the the return tuple. this will notify the system /// that the term should be created instead of re-used. /// </summary> /// <param name="web"></param> /// <param name="modelTerm"></param> /// <param name="parent"></param> /// <param name="termStore"></param> /// <param name="parser"></param> /// <param name="scope"></param> /// <returns></returns> private TryReuseTermResult TryReuseTerm(Web web, Model.Term modelTerm, TaxonomyItem parent, TermStore termStore, TokenParser parser, PnPMonitoredScope scope) { if (!modelTerm.IsReused) { return new TryReuseTermResult() { Success = false, UpdatedParser = parser } } ; if (modelTerm.Id == Guid.Empty) { return new TryReuseTermResult() { Success = false, UpdatedParser = parser } } ; // Since we're reusing terms ensure the previous terms are committed termStore.CommitAll(); web.Context.ExecuteQueryRetry(); // Try to retrieve a matching term from the website also marked from re-use. var taxonomySession = TaxonomySession.GetTaxonomySession(web.Context); web.Context.Load(taxonomySession); web.Context.ExecuteQueryRetry(); if (taxonomySession.ServerObjectIsNull()) { return(new TryReuseTermResult() { Success = false, UpdatedParser = parser }); } var freshTermStore = taxonomySession.GetDefaultKeywordsTermStore(); Term preExistingTerm = freshTermStore.GetTerm(modelTerm.Id); try { web.Context.Load(preExistingTerm); web.Context.ExecuteQueryRetry(); if (preExistingTerm.ServerObjectIsNull()) { preExistingTerm = null; } } catch (Exception) { preExistingTerm = null; } // If the matching term is not found, return false... we can't re-use just yet if (preExistingTerm == null) { return(new TryReuseTermResult() { Success = false, UpdatedParser = parser }); } // if the matching term is found re-use, create child terms, and return true else { // Reuse term Term createdTerm = null; if (parent is TermSet) { createdTerm = ((TermSet)parent).ReuseTerm(preExistingTerm, false); } else if (parent is Term) { createdTerm = ((Term)parent).ReuseTerm(preExistingTerm, false); } if (modelTerm.IsSourceTerm) { preExistingTerm.ReassignSourceTerm(createdTerm); } // Set labels and shared properties just in case we're on the source term if (modelTerm.IsSourceTerm) { if (modelTerm.Labels.Any()) { CreateTermLabels(modelTerm, termStore, parser, scope, createdTerm); } if (modelTerm.Properties.Any()) { SetTermCustomProperties(modelTerm, parser, createdTerm); } } if (modelTerm.LocalProperties.Any()) { SetTermLocalCustomProperties(modelTerm, parser, createdTerm); } termStore.CommitAll(); web.Context.Load(createdTerm); web.Context.ExecuteQueryRetry(); // Create any child terms parser = this.CreateChildTerms(web, modelTerm, createdTerm, termStore, parser, scope); // Return true, because our TryReuseTerm attempt succeeded! return(new TryReuseTermResult() { Success = true, UpdatedParser = parser }); } }
private static void CreateField(Web web, XElement templateFieldElement, PnPMonitoredScope scope, TokenParser parser) { var listIdentifier = templateFieldElement.Attribute("List") != null?templateFieldElement.Attribute("List").Value : null; if (listIdentifier != null) { // Temporary remove list attribute from list templateFieldElement.Attribute("List").Remove(); } var fieldXml = parser.ParseString(templateFieldElement.ToString()); web.Fields.AddFieldAsXml(fieldXml, false, AddFieldOptions.AddFieldInternalNameHint); web.Context.ExecuteQueryRetry(); }
public override void ProvisionObjects(Web web, ProvisioningTemplate template) { Log.Info(Constants.LOGGING_SOURCE_FRAMEWORK_PROVISIONING, CoreResources.Provisioning_ObjectHandlers_ListInstances); if (template.Lists.Any()) { var rootWeb = (web.Context as ClientContext).Site.RootWeb; if (!web.IsPropertyAvailable("ServerRelativeUrl")) { web.Context.Load(web, w => w.ServerRelativeUrl); web.Context.ExecuteQueryRetry(); } 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; var createdLists = new List <ListInfo>(); #region Lists foreach (var list in template.Lists) { if (existingLists.FindIndex(x => x.Equals(UrlUtility.Combine(serverRelativeUrl, list.Url), StringComparison.OrdinalIgnoreCase)) == -1) { var listCreate = new ListCreationInformation(); listCreate.Description = list.Description; listCreate.TemplateType = list.TemplateType; listCreate.Title = 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 = list.Url.ToParsedString(); 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 = list.DocumentTemplate.ToParsedString(); } // 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; createdList.EnableVersioning = list.EnableVersioning; if (list.EnableVersioning) { createdList.MajorVersionLimit = list.MaxVersionLimit; if (createdList.BaseTemplate == (int)ListTemplateType.DocumentLibrary) { // Only supported on Document Libraries createdList.EnableMinorVersions = list.EnableMinorVersions; createdList.DraftVersionVisibility = (DraftVisibilityType)list.DraftVersionVisibility; // TODO: User should be notified that MinorVersionLimit and DraftVersionVisibility will not be applied 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 { // TODO: User should be notified that DraftVersionVisibility is not applied because .EnableModeration is false } } 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 List <Microsoft.SharePoint.Client.ContentType> contentTypesToRemove = new List <Microsoft.SharePoint.Client.ContentType>(); if (list.RemoveExistingContentTypes && list.ContentTypeBindings.Count > 0) { foreach (var ct in createdList.ContentTypes) { contentTypesToRemove.Add(ct); } } ContentTypeBinding defaultCtBinding = null; foreach (var ctBinding in list.ContentTypeBindings) { 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(); } createdLists.Add(new ListInfo { CreatedList = createdList, ListInstance = list }); TokenParser.AddToken(new ListIdToken(web, list.Title, createdList.Id)); TokenParser.AddToken(new ListUrlToken(web, list.Title, createdList.RootFolder.ServerRelativeUrl.Substring(web.ServerRelativeUrl.Length + 1))); } } #endregion #region FieldRefs foreach (var listInfo in createdLists) { if (listInfo.ListInstance.FieldRefs.Any()) { foreach (var fieldRef in listInfo.ListInstance.FieldRefs) { var field = rootWeb.GetFieldById <Field>(fieldRef.Id); if (field != null) { if (!listInfo.CreatedList.FieldExistsById(fieldRef.Id)) { var createdField = listInfo.CreatedList.Fields.Add(field); if (!string.IsNullOrEmpty(fieldRef.DisplayName)) { createdField.Title = fieldRef.DisplayName; } createdField.Hidden = fieldRef.Hidden; createdField.Required = fieldRef.Required; createdField.Update(); } } } listInfo.CreatedList.Update(); web.Context.ExecuteQueryRetry(); } } #endregion #region Fields foreach (var listInfo in createdLists) { if (listInfo.ListInstance.Fields.Any()) { foreach (var field in listInfo.ListInstance.Fields) { XElement fieldElement = XElement.Parse(field.SchemaXml.ToParsedString()); var id = fieldElement.Attribute("ID").Value; Guid fieldGuid = Guid.Empty; if (Guid.TryParse(id, out fieldGuid)) { if (!listInfo.CreatedList.FieldExistsById(fieldGuid)) { var listIdentifier = fieldElement.Attribute("List") != null?fieldElement.Attribute("List").Value : null; if (listIdentifier != null) { // Temporary remove list attribute from fieldElement fieldElement.Attribute("List").Remove(); } var fieldXml = fieldElement.ToString(); listInfo.CreatedList.Fields.AddFieldAsXml(fieldXml, false, AddFieldOptions.DefaultValue); } } } } listInfo.CreatedList.Update(); web.Context.ExecuteQueryRetry(); } #endregion #region Views foreach (var listInfo in createdLists) { var list = listInfo.ListInstance; var createdList = listInfo.CreatedList; if (list.Views.Any() && list.RemoveExistingViews) { while (createdList.Views.Any()) { createdList.Views[0].DeleteObject(); } web.Context.ExecuteQueryRetry(); } foreach (var view in list.Views) { var viewDoc = XDocument.Parse(view.SchemaXml); var displayNameXml = viewDoc.Root.Attribute("DisplayName"); if (displayNameXml == null) { throw new ApplicationException("Invalid View element, missing a valid value for the attribute DisplayName."); } var viewTitle = displayNameXml.Value; // Type var viewTypeString = viewDoc.Root.Attribute("Type") != null?viewDoc.Root.Attribute("Type").Value : "None"; viewTypeString = viewTypeString[0].ToString().ToUpper() + viewTypeString.Substring(1).ToLower(); var viewType = (ViewType)Enum.Parse(typeof(ViewType), viewTypeString); // Fields string[] viewFields = null; var viewFieldsElement = viewDoc.Descendants("ViewFields").FirstOrDefault(); if (viewFieldsElement != null) { viewFields = (from field in viewDoc.Descendants("ViewFields").Descendants("FieldRef") select field.Attribute("Name").Value).ToArray(); } // Default view var viewDefault = viewDoc.Root.Attribute("DefaultView") != null && Boolean.Parse(viewDoc.Root.Attribute("DefaultView").Value); // Row limit bool viewPaged = true; uint viewRowLimit = 30; var rowLimitElement = viewDoc.Descendants("RowLimit").FirstOrDefault(); if (rowLimitElement != null) { if (rowLimitElement.Attribute("Paged") != null) { viewPaged = bool.Parse(rowLimitElement.Attribute("Paged").Value); } viewRowLimit = uint.Parse(rowLimitElement.Value); } // Query var viewQuery = new StringBuilder(); foreach (var queryElement in viewDoc.Descendants("Query").Elements()) { viewQuery.Append(queryElement.ToString()); } var viewCI = new ViewCreationInformation { ViewFields = viewFields, RowLimit = viewRowLimit, Paged = viewPaged, Title = viewTitle, Query = viewQuery.ToString(), ViewTypeKind = viewType, PersonalView = false, SetAsDefaultView = viewDefault }; createdList.Views.Add(viewCI); createdList.Update(); web.Context.ExecuteQueryRetry(); } // Removing existing views set the OnQuickLaunch option to false and need to be re-set. if (list.OnQuickLaunch && list.RemoveExistingViews && list.Views.Count > 0) { createdList.RefreshLoad(); web.Context.ExecuteQueryRetry(); createdList.OnQuickLaunch = list.OnQuickLaunch; createdList.Update(); web.Context.ExecuteQueryRetry(); } } #endregion #region DataRows foreach (var listInfo in createdLists) { var listInstance = listInfo.ListInstance; if (listInstance.DataRows != null && listInstance.DataRows.Any()) { var list = listInfo.CreatedList; foreach (var dataRow in listInfo.ListInstance.DataRows) { ListItemCreationInformation listitemCI = new ListItemCreationInformation(); var listitem = list.AddItem(listitemCI); foreach (var dataValue in dataRow.Values) { listitem[dataValue.Key.ToParsedString()] = dataValue.Value.ToParsedString(); } listitem.Update(); web.Context.ExecuteQueryRetry(); // TODO: Run in batches? } } } #endregion } }
public override TokenParser ProvisionObjects(Web web, ProvisioningTemplate template, TokenParser parser, ProvisioningTemplateApplyingInformation applyingInformation) { using (var scope = new PnPMonitoredScope(this.Name)) { web.EnsureProperties(w => w.ServerRelativeUrl); 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; 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) { // 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); } // 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; } 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); // Make it a news page if requested if (clientSidePage.PromoteAsNewsArticle) { page.PromoteAsNewsArticle(); } } } return(parser); }
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() { #if !ONPREMISES ClientSideComponentId = customAction.ClientSideComponentId, ClientSideComponentProperties = customAction.ClientSideComponentProperties != null?parser.ParseString(customAction.ClientSideComponentProperties) : customAction.ClientSideComponentProperties, #endif 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, "~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().FirstOrDefault(uc => uc.Name == customAction.Name); 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().FirstOrDefault(uc => uc.Name == customAction.Name); SetCustomActionResourceValues(parser, customAction, uca); } #endif } } 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); } } } } }
/// <summary> /// Creates child terms for the current model term if any exist /// </summary> /// <param name="web"></param> /// <param name="modelTerm"></param> /// <param name="term"></param> /// <param name="termStore"></param> /// <param name="parser"></param> /// <param name="scope"></param> /// <returns>Updated parser object</returns> private TokenParser CreateChildTerms(Web web, Model.Term modelTerm, Term term, TermStore termStore, TokenParser parser, PnPMonitoredScope scope) { if (modelTerm.Terms.Any()) { foreach (var modelTermTerm in modelTerm.Terms) { web.Context.Load(term.Terms); web.Context.ExecuteQueryRetry(); var termTerms = term.Terms; if (termTerms.Any()) { var termTerm = termTerms.FirstOrDefault(t => t.Id == modelTermTerm.Id); if (termTerm == null) { termTerm = termTerms.FirstOrDefault(t => t.Name == modelTermTerm.Name); if (termTerm == null) { var returnTuple = CreateTerm <Term>(web, modelTermTerm, term, termStore, parser, scope); if (returnTuple != null) { modelTermTerm.Id = returnTuple.Item1; parser = returnTuple.Item2; } } else { modelTermTerm.Id = termTerm.Id; } } else { modelTermTerm.Id = termTerm.Id; } } else { var returnTuple = CreateTerm <Term>(web, modelTermTerm, term, termStore, parser, scope); if (returnTuple != null) { modelTermTerm.Id = returnTuple.Item1; parser = returnTuple.Item2; } } } if (modelTerm.Terms.Any(t => t.CustomSortOrder > -1)) { var sortedTerms = modelTerm.Terms.OrderBy(t => t.CustomSortOrder); var customSortString = sortedTerms.Aggregate(string.Empty, (a, i) => a + i.Id.ToString() + ":"); customSortString = customSortString.TrimEnd(new[] { ':' }); term.CustomSortOrder = customSortString; termStore.CommitAll(); } } return(parser); }
public override TokenParser ProvisionObjects(Web web, ProvisioningTemplate template, TokenParser parser, ProvisioningTemplateApplyingInformation applyingInformation) { using (var scope = new PnPMonitoredScope(this.Name)) { var context = web.Context as ClientContext; var site = context.Site; // Check if this is not a noscript site as we're not allowed to update some properties bool isNoScriptSite = web.IsNoScriptSite(); // if this is a sub site then we're not enabling the site collection scoped custom actions if (!web.IsSubSite()) { var siteCustomActions = template.CustomActions.SiteCustomActions; ProvisionCustomActionImplementation(site, siteCustomActions, parser, scope, isNoScriptSite); } var webCustomActions = template.CustomActions.WebCustomActions; ProvisionCustomActionImplementation(web, webCustomActions, parser, scope, isNoScriptSite); // Switch parser context back to it's original context parser.Rebase(web); } return(parser); }
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 != null && modelTerm.Language != 0 ? modelTerm.Language.Value : termStore.DefaultLanguage, modelTerm.Id); } else { term = ((TermSet)parent).CreateTerm(parser.ParseString(modelTerm.Name), modelTerm.Language != null && modelTerm.Language != 0 ? modelTerm.Language.Value : termStore.DefaultLanguage, modelTerm.Id); } if (!string.IsNullOrEmpty(modelTerm.Description)) { term.SetDescription(parser.ParseString(modelTerm.Description), modelTerm.Language != null && modelTerm.Language != 0 ? modelTerm.Language.Value : 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()) { CreateTermLabels(modelTerm, termStore, parser, scope, term); //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()) { SetTermCustomProperties(modelTerm, parser, term); //foreach (var property in modelTerm.Properties) //{ // term.SetCustomProperty(parser.ParseString(property.Key), parser.ParseString(property.Value)); //} } if (modelTerm.LocalProperties.Any()) { SetTermLocalCustomProperties(modelTerm, parser, term); //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)); }
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 !ONPREMISES if (customAction.ClientSideComponentId != null && customAction.ClientSideComponentId != Guid.Empty) { if (existingCustomAction.ClientSideComponentId != customAction.ClientSideComponentId) { existingCustomAction.ClientSideComponentId = customAction.ClientSideComponentId; } } if (!String.IsNullOrEmpty(customAction.ClientSideComponentProperties)) { if (existingCustomAction.ClientSideComponentProperties != parser.ParseString(customAction.ClientSideComponentProperties)) { existingCustomAction.ClientSideComponentProperties = parser.ParseString(customAction.ClientSideComponentProperties); } } #endif 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 != 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, "~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(); } }
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(listInstance.Title); web.Context.Load(list); // Retrieve the fields' types from the list 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 var lookupValue = new FieldLookupValue { LookupId = Int32.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 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; default: listitem[parser.ParseString(dataValue.Key)] = fieldValue; break; } } listitem.Update(); } web.Context.ExecuteQueryRetry(); // TODO: Run in batches? if (dataRow.Security != null) { listitem.SetSecurity(parser, dataRow.Security); } } catch (Exception ex) { scope.LogError(CoreResources.Provisioning_ObjectHandlers_ListInstancesDataRows_Creating_listitem_failed___0_____1_, ex.Message, ex.StackTrace); throw; } } } } #endregion } } return(parser); }
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.Url); foreach (var file in template.Files) { var folderName = parser.ParseString(file.Folder); if (folderName.ToLower().StartsWith((web.ServerRelativeUrl.ToLower()))) { folderName = folderName.Substring(web.ServerRelativeUrl.Length); } var folder = web.EnsureFolderPath(folderName); File targetFile = null; var checkedOut = false; 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 = template.Connector.GetFileStream(file.Src)) { targetFile = folder.UploadFile(template.Connector.GetFilenamePart(file.Src), stream, file.Overwrite); } } else { checkedOut = CheckOutIfNeeded(web, targetFile); } } else { using (var stream = template.Connector.GetFileStream(file.Src)) { scope.LogDebug(CoreResources.Provisioning_ObjectHandlers_Files_Uploading_file__0_, file.Src); targetFile = folder.UploadFile(template.Connector.GetFilenamePart(file.Src), stream, file.Overwrite); } 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)); targetFile.SetFileProperties(transformedProperties, false); // if needed, the file is already checked out } if (file.WebParts != null && file.WebParts.Any()) { targetFile.EnsureProperties(f => f.ServerRelativeUrl); var existingWebParts = web.GetWebParts(targetFile.ServerRelativeUrl); foreach (var webpart in file.WebParts) { // check if the webpart is already set on the page if (existingWebParts.FirstOrDefault(w => w.WebPart.Title == webpart.Title) == null) { scope.LogDebug(CoreResources.Provisioning_ObjectHandlers_Files_Adding_webpart___0___to_page, webpart.Title); var wpEntity = new WebPartEntity(); wpEntity.WebPartTitle = webpart.Title; wpEntity.WebPartXml = parser.ParseString(webpart.Contents).Trim(new[] { '\n', ' ' }); wpEntity.WebPartZone = webpart.Zone; wpEntity.WebPartIndex = (int)webpart.Order; web.AddWebPartToWebPartPage(targetFile.ServerRelativeUrl, wpEntity); } } } if (checkedOut) { targetFile.CheckIn("", CheckinType.MajorCheckIn); web.Context.ExecuteQueryRetry(); } // 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 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++; WriteMessage($"File|{targetFileName}|{currentFileIndex}|{filesToProcess.Length}", ProvisioningMessageType.Progress); 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); 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 = GetFileStream(template, file)) { targetFile = UploadFile(folder, stream, targetFileName, file.Overwrite); } } else { checkedOut = CheckOutIfNeeded(web, targetFile); } } else { using (var stream = 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 #if !SP2013 targetFile.EnsureProperties(p => p.UniqueId, p => p.ServerRelativeUrl); parser.AddToken(new FileUniqueIdToken(web, targetFile.ServerRelativeUrl.Substring(web.ServerRelativeUrl.Length).TrimStart("/".ToCharArray()), targetFile.UniqueId)); parser.AddToken(new FileUniqueIdEncodedToken(web, targetFile.ServerRelativeUrl.Substring(web.ServerRelativeUrl.Length).TrimStart("/".ToCharArray()), targetFile.UniqueId)); #endif #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.ParseXmlString(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 wpd.EnsureProperties(w => w.ZoneId, w => w.WebPart, w => w.WebPart.Properties); webPart.Zone = wpd.ZoneId; 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); } 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); } } web = originalWeb; // restore context in case files are provisioned to the master page gallery #1059 } } WriteMessage("Done processing files", ProvisioningMessageType.Completed); return(parser); }
public override TokenParser ProvisionObjects(Web web, ProvisioningTemplate template, TokenParser parser, ProvisioningTemplateApplyingInformation applyingInformation) { using (var scope = new PnPMonitoredScope(this.Name)) { var context = web.Context as ClientContext; foreach (var handler in template.ExtensibilityHandlers .Union(template.Providers) .Union(applyingInformation.ExtensibilityHandlers)) { if (handler.Enabled) { try { if (!string.IsNullOrEmpty(handler.Configuration)) { //replace tokens in configuration data handler.Configuration = parser.ParseString(handler.Configuration); } scope.LogDebug(CoreResources.Provisioning_ObjectHandlers_ExtensibilityProviders_Calling_extensibility_callout__0_, handler.Assembly); _extManager.ExecuteExtensibilityProvisionCallOut(context, handler, template, applyingInformation, parser, scope); } catch (Exception ex) { scope.LogError(CoreResources.Provisioning_ObjectHandlers_ExtensibilityProviders_callout_failed___0_____1_, ex.Message, ex.StackTrace); throw; } } } } return(parser); }
private static void AddUserToGroup(Web web, Group group, IEnumerable <User> members, PnPMonitoredScope scope, TokenParser parser) { if (members.Any()) { scope.LogDebug("Adding users to group {0}", group.Title); try { foreach (var user in members) { var parsedUserName = parser.ParseString(user.Name); scope.LogDebug("Adding user {0}", parsedUserName); if (parsedUserName.Contains("#ext#")) { var externalUser = web.SiteUsers.FirstOrDefault(u => u.LoginName.Equals(parsedUserName)); if (externalUser == null) { scope.LogInfo($"Skipping external user {parsedUserName}"); } else { group.Users.AddUser(externalUser); } } else { try { var existingUser = web.EnsureUser(parsedUserName); web.Context.ExecuteQueryRetry(); group.Users.AddUser(existingUser); } catch (Exception ex) { scope.LogWarning(ex, "Failed to EnsureUser {0}", parsedUserName); } } } web.Context.ExecuteQueryRetry(); } catch (Exception ex) { scope.LogError(CoreResources.Provisioning_ObjectHandlers_SiteSecurity_Add_users_failed_for_group___0_____1_____2_, group.Title, ex.Message, ex.StackTrace); throw; } } }
public override TokenParser ProvisionObjects(Web web, ProvisioningTemplate template, TokenParser parser, ProvisioningTemplateApplyingInformation applyingInformation) { using (var scope = new PnPMonitoredScope(this.Name)) { if (template.WebSettings != null) { web.EnsureProperty(w => w.HasUniqueRoleAssignments); var webSettings = template.WebSettings; #if !ONPREMISES web.NoCrawl = webSettings.NoCrawl; 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; } } #endif var masterUrl = parser.ParseString(webSettings.MasterPageUrl); if (!string.IsNullOrEmpty(masterUrl)) { web.MasterUrl = masterUrl; } var customMasterUrl = parser.ParseString(webSettings.CustomMasterPageUrl); if (!string.IsNullOrEmpty(customMasterUrl)) { web.CustomMasterUrl = customMasterUrl; } if (!string.IsNullOrEmpty(parser.ParseString(webSettings.Title))) { web.Title = parser.ParseString(webSettings.Title); } web.Description = parser.ParseString(webSettings.Description); web.SiteLogoUrl = parser.ParseString(webSettings.SiteLogo); var welcomePage = parser.ParseString(webSettings.WelcomePage); if (!string.IsNullOrEmpty(welcomePage)) { web.RootFolder.WelcomePage = welcomePage; web.RootFolder.Update(); } web.AlternateCssUrl = parser.ParseString(webSettings.AlternateCSS); web.Update(); web.Context.ExecuteQueryRetry(); } } return(parser); }