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 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, 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; } } } return parser; }
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; } }
internal void PersistFile(Web web, ProvisioningTemplateCreationInformation creationInfo, PnPMonitoredScope scope, string folderPath, string fileName, Boolean decodeFileName = false) { if (creationInfo.FileConnector != null) { SharePointConnector connector = new SharePointConnector(web.Context, web.Url, "dummy"); Uri u = new Uri(web.Url); if (folderPath.IndexOf(u.PathAndQuery, StringComparison.InvariantCultureIgnoreCase) > -1) { folderPath = folderPath.Replace(u.PathAndQuery, ""); } using (Stream s = connector.GetFileStream(fileName, folderPath)) { if (s != null) { creationInfo.FileConnector.SaveFileStream(decodeFileName ? HttpUtility.UrlDecode(fileName) : fileName, s); } } } else { WriteWarning("No connector present to persist homepage.", ProvisioningMessageType.Error); scope.LogError("No connector present to persist homepage"); } }
// This function will be triggered based on the schedule you have set for this WebJob public static void VerifyDocLib() { var url = ConfigurationManager.AppSettings["SpUrl"].ToString(); var user = ConfigurationManager.AppSettings["SpUserName"].ToString(); var pw = ConfigurationManager.AppSettings["SpPassword"].ToString(); using (PnPMonitoredScope p = new PnPMonitoredScope()) { p.LogInfo("Gathering connect info from web.config"); p.LogInfo("SharePoint url is " + url); p.LogInfo("SharePoint user is " + user); try { ClientContext cc = new ClientContext(url); cc.AuthenticationMode = ClientAuthenticationMode.Default; cc.Credentials = new SharePointOnlineCredentials(user, GetPassword(pw)); using (cc) { if (cc != null) { string listName = "Site Pages"; p.LogInfo("This is what a Monitored Scope log entry looks like in PNP, more to come as we try to validate a lists existence."); p.LogInfo("Connect to Sharepoint"); ListCollection lists = cc.Web.Lists; IEnumerable<List> results = cc.LoadQuery<List>(lists.Where(lst => lst.Title == listName)); p.LogInfo("Executing query to find the Site Pages library"); cc.ExecuteQuery(); p.LogInfo("Query Executed successfully."); List list = results.FirstOrDefault(); if (list == null) { p.LogError("Site Pages library not found."); } else { p.LogInfo("Site Pages library found."); ListItemCollection items = list.GetItems(new CamlQuery()); cc.Load(items, itms => itms.Include(item => item.DisplayName)); cc.ExecuteQueryRetry(); string pgs = "These pages were found, " + string.Join(", ", items.Select(x => x.DisplayName)); p.LogInfo(pgs); } } } } catch (System.Exception ex) { p.LogInfo("We had a problem: " + ex.Message); } } }
public override TokenParser ProvisionObjects(Web web, ProvisioningTemplate template, TokenParser parser, ProvisioningTemplateApplyingInformation applyingInformation) { using (var scope = new PnPMonitoredScope(this.Name)) { try { parser = ProcessLookupFields(web, template, parser, scope); } catch (Exception ex) { scope.LogError(CoreResources.Provisioning_ObjectHandlers_LookupFields_Processing_lookup_fields_failed___0_____1_, ex.Message, ex.StackTrace); //throw; } } return parser; }
public override ProvisioningTemplate ExtractObjects(Web web, ProvisioningTemplate template, ProvisioningTemplateCreationInformation creationInfo) { using (var scope = new PnPMonitoredScope(this.Name)) { var context = web.Context as ClientContext; foreach (var handler in creationInfo.ExtensibilityHandlers) { if (handler.Enabled) { try { scope.LogDebug(CoreResources.Provisioning_ObjectHandlers_ExtensibilityProviders_Calling_extensibility_callout__0_, handler.Assembly); template = _extManager.ExecuteExtensibilityExtractionCallOut(context, handler, template, creationInfo, scope); } catch (Exception ex) { scope.LogError(CoreResources.Provisioning_ObjectHandlers_ExtensibilityProviders_callout_failed___0_____1_, ex.Message, ex.StackTrace); throw; } } } } return template; }
internal void PersistFile(Web web, ProvisioningTemplateCreationInformation creationInfo, PnPMonitoredScope scope, string folderPath, string fileName, Boolean decodeFileName = false) { if (creationInfo.FileConnector != null) { SharePointConnector connector = new SharePointConnector(web.Context, web.Url, "dummy"); if (folderPath.StartsWith( web.ServerRelativeUrl, StringComparison.OrdinalIgnoreCase ) ) { folderPath = folderPath.Substring(web.ServerRelativeUrl.Length); } using (Stream s = connector.GetFileStream(fileName, folderPath)) { if (s != null) { creationInfo.FileConnector.SaveFileStream(decodeFileName ? HttpUtility.UrlDecode(fileName) : fileName, s); } } } else { WriteWarning("No connector present to persist homepage.", ProvisioningMessageType.Error); scope.LogError("No connector present to persist homepage"); } }
private static void UpdateContentType(Web web, Microsoft.SharePoint.Client.ContentType existingContentType, ContentType templateContentType, TokenParser parser, PnPMonitoredScope scope, bool isNoScriptSite = false) { var isDirty = false; var reOrderFields = false; if (existingContentType.Hidden != templateContentType.Hidden) { scope.LogPropertyUpdate("Hidden"); existingContentType.Hidden = templateContentType.Hidden; isDirty = true; } if (existingContentType.ReadOnly != templateContentType.ReadOnly) { scope.LogPropertyUpdate("ReadOnly"); existingContentType.ReadOnly = templateContentType.ReadOnly; isDirty = true; } if (existingContentType.Sealed != templateContentType.Sealed) { scope.LogPropertyUpdate("Sealed"); existingContentType.Sealed = templateContentType.Sealed; isDirty = true; } if (templateContentType.Description != null && existingContentType.Description != parser.ParseString(templateContentType.Description)) { scope.LogPropertyUpdate("Description"); existingContentType.Description = parser.ParseString(templateContentType.Description); isDirty = true; } if (templateContentType.DocumentTemplate != null && existingContentType.DocumentTemplate != parser.ParseString(templateContentType.DocumentTemplate)) { scope.LogPropertyUpdate("DocumentTemplate"); existingContentType.DocumentTemplate = parser.ParseString(templateContentType.DocumentTemplate); isDirty = true; } if (existingContentType.Name != parser.ParseString(templateContentType.Name)) { scope.LogPropertyUpdate("Name"); existingContentType.Name = parser.ParseString(templateContentType.Name); isDirty = true; // CT is being renamed, add an extra token to the tokenparser parser.AddToken(new ContentTypeIdToken(web, existingContentType.Name, existingContentType.StringId)); } if (templateContentType.Group != null && existingContentType.Group != parser.ParseString(templateContentType.Group)) { scope.LogPropertyUpdate("Group"); existingContentType.Group = parser.ParseString(templateContentType.Group); isDirty = true; } if (!isNoScriptSite) { if (templateContentType.DisplayFormUrl != null && existingContentType.DisplayFormUrl != parser.ParseString(templateContentType.DisplayFormUrl)) { scope.LogPropertyUpdate("DisplayFormUrl"); existingContentType.DisplayFormUrl = parser.ParseString(templateContentType.DisplayFormUrl); isDirty = true; } if (templateContentType.EditFormUrl != null && existingContentType.EditFormUrl != parser.ParseString(templateContentType.EditFormUrl)) { scope.LogPropertyUpdate("EditFormUrl"); existingContentType.EditFormUrl = parser.ParseString(templateContentType.EditFormUrl); isDirty = true; } if (templateContentType.NewFormUrl != null && existingContentType.NewFormUrl != parser.ParseString(templateContentType.NewFormUrl)) { scope.LogPropertyUpdate("NewFormUrl"); existingContentType.NewFormUrl = parser.ParseString(templateContentType.NewFormUrl); isDirty = true; } } else { if (!string.IsNullOrEmpty(parser.ParseString(templateContentType.DisplayFormUrl)) || !string.IsNullOrEmpty(parser.ParseString(templateContentType.EditFormUrl)) || !string.IsNullOrEmpty(parser.ParseString(templateContentType.NewFormUrl))) { // log message scope.LogWarning(CoreResources.Provisioning_ObjectHandlers_ContentTypes_SkipCustomFormUrls, existingContentType.Name); } } #if !SP2013 if (templateContentType.Name.ContainsResourceToken()) { existingContentType.NameResource.SetUserResourceValue(templateContentType.Name, parser); isDirty = true; } if (templateContentType.Description.ContainsResourceToken()) { existingContentType.DescriptionResource.SetUserResourceValue(templateContentType.Description, parser); isDirty = true; } #endif if (isDirty) { existingContentType.Update(true); web.Context.ExecuteQueryRetry(); } // Set flag to reorder fields CT fields are not equal to template fields var existingFieldNames = existingContentType.FieldLinks.AsEnumerable().Select(fld => fld.Name).ToArray(); var ctFieldNames = templateContentType.FieldRefs.Select(fld => parser.ParseString(fld.Name)).ToArray(); reOrderFields = !existingFieldNames.SequenceEqual(ctFieldNames); // Delta handling existingContentType.EnsureProperty(c => c.FieldLinks); var targetIds = existingContentType.FieldLinks.AsEnumerable().Select(c1 => c1.Id).ToList(); var sourceIds = templateContentType.FieldRefs.Select(c1 => c1.Id).ToList(); var fieldsNotPresentInTarget = sourceIds.Except(targetIds).ToArray(); if (fieldsNotPresentInTarget.Any()) { // Set flag to reorder fields when new fields are added. reOrderFields = true; foreach (var fieldId in fieldsNotPresentInTarget) { var fieldRef = templateContentType.FieldRefs.Find(fr => fr.Id == fieldId); var field = web.AvailableFields.GetById(fieldRef.Id); scope.LogDebug(CoreResources.Provisioning_ObjectHandlers_ContentTypes_Adding_field__0__to_content_type, fieldId); web.AddFieldToContentType(existingContentType, field, fieldRef.Required, fieldRef.Hidden); } } // Reorder fields if (reOrderFields) { existingContentType.FieldLinks.Reorder(ctFieldNames); isDirty = true; } foreach (var fieldId in targetIds.Intersect(sourceIds)) { var fieldLink = existingContentType.FieldLinks.FirstOrDefault(fl => fl.Id == fieldId); var fieldRef = templateContentType.FieldRefs.Find(fr => fr.Id == fieldId); if (fieldRef != null) { scope.LogDebug(CoreResources.Provisioning_ObjectHandlers_ContentTypes_Field__0__exists_in_content_type, fieldId); if (fieldLink.Required != fieldRef.Required) { scope.LogPropertyUpdate("Required"); fieldLink.Required = fieldRef.Required; isDirty = true; } if (fieldLink.Hidden != fieldRef.Hidden) { scope.LogPropertyUpdate("Hidden"); fieldLink.Hidden = fieldRef.Hidden; isDirty = true; } } } // The new CT is a DocumentSet, and the target should be, as well if (templateContentType.DocumentSetTemplate != null) { if (!Microsoft.SharePoint.Client.DocumentSet.DocumentSetTemplate.IsChildOfDocumentSetContentType(web.Context, existingContentType).Value) { scope.LogError(CoreResources.Provisioning_ObjectHandlers_ContentTypes_InvalidDocumentSet_Update_Request, existingContentType.Id, existingContentType.Name); } else { Microsoft.SharePoint.Client.DocumentSet.DocumentSetTemplate templateToUpdate = Microsoft.SharePoint.Client.DocumentSet.DocumentSetTemplate.GetDocumentSetTemplate(web.Context, existingContentType); // TODO: Implement Delta Handling scope.LogWarning(CoreResources.Provisioning_ObjectHandlers_ContentTypes_DocumentSet_DeltaHandling_OnHold, existingContentType.Id, existingContentType.Name); } } if (isDirty) { existingContentType.Update(true); web.Context.ExecuteQueryRetry(); } }
public void UpdateLookups(Func<Guid, ListItemsProvider> fnGetLookupDependentProvider, PnPMonitoredScope scope) { if (null != m_lookups) { bool valueUpdated = false; foreach (KeyValuePair<string, LookupDataRef> pair in m_lookups) { LookupDataRef lookupData = pair.Value; if (0 < lookupData.ItemLookupValues.Count) { Guid sourceListId = Guid.Empty; try { sourceListId = new Guid(lookupData.Field.LookupList); } catch (Exception ex) { scope.LogError(ex, "Failed to get source list for lookup field. Field Name: {0}, Source List: {1}.", lookupData.Field.InternalName, lookupData.Field.LookupList); } if (!Guid.Empty.Equals(sourceListId)) { ListItemsProvider sourceProvider = fnGetLookupDependentProvider(sourceListId); if ((null != sourceProvider) && (null != sourceProvider.m_mappingIDs)) { foreach (KeyValuePair<ListItem, object> lookupPair in lookupData.ItemLookupValues) { ListItem item = lookupPair.Key; object newItemValue = null; object oldItemValue = lookupPair.Value; FieldLookupValue oldLookupValue = oldItemValue as FieldLookupValue; if (null != oldLookupValue) { int lookupId = oldLookupValue.LookupId; int newId; if (sourceProvider.m_mappingIDs.TryGetValue(lookupId, out newId) && (0 < newId)) { newItemValue = new FieldLookupValue() { LookupId = newId }; } } else { List<FieldLookupValue> newLookupValues = new List<FieldLookupValue>(); FieldLookupValue[] oldLookupValues = oldItemValue as FieldLookupValue[]; if ((null != oldLookupValues) && (0 < oldLookupValues.Length)) { foreach (FieldLookupValue val in oldLookupValues) { int newId; if (sourceProvider.m_mappingIDs.TryGetValue(val.LookupId, out newId) && (0 < newId)) { newLookupValues.Add(new FieldLookupValue() { LookupId = newId }); } } } if (0 < newLookupValues.Count) { newItemValue = newLookupValues.ToArray(); } } if (null != newItemValue) { item[lookupData.Field.InternalName] = newItemValue; item.Update(); valueUpdated = true; } } } } } } if (valueUpdated) { try { this.Context.ExecuteQueryRetry(); } catch (Exception ex) { string lookupFieldNames = string.Join(", ", m_lookups.Select(pair => pair.Value.Field.InternalName).ToArray()); scope.LogError(ex, "Failed to set lookup values. List: '{0}', Lookup Fields: {1}.", this.List.Title, lookupFieldNames); } } } }
private TokenParser ProcessLookupFields(Web web, ProvisioningTemplate template, TokenParser parser, PnPMonitoredScope scope) { var rootWeb = (web.Context as ClientContext).Site.RootWeb; rootWeb.Context.Load(rootWeb.Lists, lists => lists.Include(l => l.Id, l => l.RootFolder.ServerRelativeUrl, l => l.Fields).Where(l => l.Hidden == false)); rootWeb.Context.ExecuteQueryRetry(); foreach (var siteField in template.SiteFields) { var fieldElement = XElement.Parse(siteField.SchemaXml); if (fieldElement.Attribute("List") != null) { var fieldId = Guid.Parse(fieldElement.Attribute("ID").Value); var listIdentifier = parser.ParseString(fieldElement.Attribute("List").Value); var relationshipDeleteBehavior = fieldElement.Attribute("RelationshipDeleteBehavior") != null ? fieldElement.Attribute("RelationshipDeleteBehavior").Value : string.Empty; var webId = string.Empty; var field = rootWeb.Fields.GetById(fieldId); rootWeb.Context.Load(field, f => f.SchemaXmlWithResourceTokens); rootWeb.Context.ExecuteQueryRetry(); List sourceList = FindSourceList(listIdentifier, web, rootWeb); if (sourceList != null) { rootWeb.Context.Load(sourceList.ParentWeb); rootWeb.Context.ExecuteQueryRetry(); webId = sourceList.ParentWeb.Id.ToString(); ProcessField(field, sourceList.Id, webId, relationshipDeleteBehavior); } } } web.Context.Load(web.Lists, lists => lists.Include(l => l.Id, l => l.RootFolder.ServerRelativeUrl, l => l.Fields).Where(l => l.Hidden == false)); web.Context.ExecuteQueryRetry(); foreach (var listInstance in template.Lists) { foreach (var listField in listInstance.Fields) { var fieldElement = XElement.Parse(listField.SchemaXml); if (fieldElement.Attribute("List") == null) continue; var fieldId = Guid.Parse(fieldElement.Attribute("ID").Value); var listIdentifier = parser.ParseString(fieldElement.Attribute("List").Value); var relationshipDeleteBehavior = fieldElement.Attribute("RelationshipDeleteBehavior") != null ? fieldElement.Attribute("RelationshipDeleteBehavior").Value : string.Empty; var webId = string.Empty; var listUrl = UrlUtility.Combine(web.ServerRelativeUrl, parser.ParseString(listInstance.Url)); var createdList = web.Lists.FirstOrDefault(l => l.RootFolder.ServerRelativeUrl.Equals(listUrl, StringComparison.OrdinalIgnoreCase)); if (createdList != null) { try { var field = createdList.Fields.GetById(fieldId); web.Context.Load(field, f => f.SchemaXmlWithResourceTokens); web.Context.ExecuteQueryRetry(); List sourceList = FindSourceList(listIdentifier, web, rootWeb); if (sourceList != null) { web.Context.Load(sourceList.ParentWeb); web.Context.ExecuteQueryRetry(); webId = sourceList.ParentWeb.Id.ToString(); ProcessField(field, sourceList.Id, webId, relationshipDeleteBehavior); } } catch (ArgumentException ex) { // We skip and log any issues related to not existing lookup fields scope.LogError(String.Format("Exception searching for field! {0}", ex.Message)); } } } } return parser; }
private Field UpdateField(ClientObject web, ListInfo listInfo, Guid fieldId, XElement templateFieldElement, Field existingField, PnPMonitoredScope scope, TokenParser parser, string originalFieldXml) { Field field = null; web.Context.Load(existingField, f => f.SchemaXmlWithResourceTokens); web.Context.ExecuteQueryRetry(); var existingFieldElement = XElement.Parse(existingField.SchemaXmlWithResourceTokens); var equalityComparer = new XNodeEqualityComparer(); // Is field different in template? if (equalityComparer.GetHashCode(existingFieldElement) != equalityComparer.GetHashCode(templateFieldElement)) { // Is existing field of the same type? if (existingFieldElement.Attribute("Type").Value == templateFieldElement.Attribute("Type").Value) { templateFieldElement = PrepareField(templateFieldElement); if (IsFieldXmlValid(parser.ParseString(templateFieldElement.ToString()), parser, web.Context)) { foreach (var attribute in templateFieldElement.Attributes()) { if (existingFieldElement.Attribute(attribute.Name) != null) { existingFieldElement.Attribute(attribute.Name).Value = attribute.Value; } else { existingFieldElement.Add(attribute); } } foreach (var element in templateFieldElement.Elements()) { if (existingFieldElement.Element(element.Name) != null) { existingFieldElement.Element(element.Name).Remove(); } existingFieldElement.Add(element); } if (existingFieldElement.Attribute("Version") != null) { existingFieldElement.Attributes("Version").Remove(); } existingField.SchemaXml = parser.ParseString(existingFieldElement.ToString(), "~sitecollection", "~site"); existingField.UpdateAndPushChanges(true); web.Context.ExecuteQueryRetry(); bool isDirty = false; #if !SP2013 if (originalFieldXml.ContainsResourceToken()) { var originalFieldElement = XElement.Parse(originalFieldXml); var nameAttributeValue = originalFieldElement.Attribute("DisplayName") != null ? originalFieldElement.Attribute("DisplayName").Value : ""; if (nameAttributeValue.ContainsResourceToken()) { if (existingField.TitleResource.SetUserResourceValue(nameAttributeValue, parser)) { isDirty = true; } } var descriptionAttributeValue = originalFieldElement.Attribute("Description") != null ? originalFieldElement.Attribute("Description").Value : ""; if (descriptionAttributeValue.ContainsResourceToken()) { if (existingField.DescriptionResource.SetUserResourceValue(descriptionAttributeValue, parser)) { isDirty = true; } } } #endif if (isDirty) { existingField.Update(); web.Context.ExecuteQueryRetry(); field = existingField; } } else { // The field Xml was found invalid var tokenString = parser.GetLeftOverTokens(originalFieldXml).Aggregate(String.Empty, (acc, i) => acc + " " + i); scope.LogError("The field was found invalid: {0}", tokenString); throw new Exception(string.Format("The field was found invalid: {0}", tokenString)); } } else { var fieldName = existingFieldElement.Attribute("Name") != null ? existingFieldElement.Attribute("Name").Value : existingFieldElement.Attribute("StaticName").Value; scope.LogWarning(CoreResources.Provisioning_ObjectHandlers_ListInstances_Field__0____1___exists_in_list__2____3___but_is_of_different_type__Skipping_field_, fieldName, fieldId, listInfo.TemplateList.Title, listInfo.SiteList.Id); WriteWarning(string.Format(CoreResources.Provisioning_ObjectHandlers_ListInstances_Field__0____1___exists_in_list__2____3___but_is_of_different_type__Skipping_field_, fieldName, fieldId, listInfo.TemplateList.Title, listInfo.SiteList.Id), ProvisioningMessageType.Warning); } } return field; }
public override TokenParser ProvisionObjects(Web web, ProvisioningTemplate template, TokenParser parser, ProvisioningTemplateApplyingInformation applyingInformation) { using (var scope = new PnPMonitoredScope(this.Name)) { var context = web.Context as ClientContext; web.EnsureProperties(w => w.ServerRelativeUrl, w => w.RootFolder.WelcomePage); foreach (var page in template.Pages) { var url = parser.ParseString(page.Url); if (!url.ToLower().StartsWith(web.ServerRelativeUrl.ToLower())) { url = UrlUtility.Combine(web.ServerRelativeUrl, url); } var exists = true; Microsoft.SharePoint.Client.File file = null; try { file = web.GetFileByServerRelativeUrl(url); web.Context.Load(file); web.Context.ExecuteQuery(); } catch (ServerException ex) { if (ex.ServerErrorTypeName == "System.IO.FileNotFoundException") { exists = false; } } if (exists) { if (page.Overwrite) { try { scope.LogDebug(CoreResources.Provisioning_ObjectHandlers_Pages_Overwriting_existing_page__0_, url); if (page.WelcomePage && url.Contains(web.RootFolder.WelcomePage)) web.SetHomePage(string.Empty); file.DeleteObject(); web.Context.ExecuteQueryRetry(); web.AddWikiPageByUrl(url); if (page.Layout == WikiPageLayout.Custom) { web.AddLayoutToWikiPage(WikiPageLayout.OneColumn, url); } else { web.AddLayoutToWikiPage(page.Layout, url); } } catch (Exception ex) { scope.LogError(CoreResources.Provisioning_ObjectHandlers_Pages_Overwriting_existing_page__0__failed___1_____2_, url, ex.Message, ex.StackTrace); } } } else { try { scope.LogDebug(CoreResources.Provisioning_ObjectHandlers_Pages_Creating_new_page__0_, url); web.AddWikiPageByUrl(url); web.AddLayoutToWikiPage(page.Layout, url); } catch (Exception ex) { scope.LogError(CoreResources.Provisioning_ObjectHandlers_Pages_Creating_new_page__0__failed___1_____2_, url, ex.Message, ex.StackTrace); } } if (page.WelcomePage) { web.RootFolder.EnsureProperty(p => p.ServerRelativeUrl); var rootFolderRelativeUrl = url.Substring(web.RootFolder.ServerRelativeUrl.Length); web.SetHomePage(rootFolderRelativeUrl); } if (page.WebParts != null & page.WebParts.Any()) { var existingWebParts = web.GetWebParts(url); foreach (var webpart in page.WebParts) { if (existingWebParts.FirstOrDefault(w => w.WebPart.Title == webpart.Title) == null) { WebPartEntity wpEntity = new WebPartEntity(); wpEntity.WebPartTitle = webpart.Title; wpEntity.WebPartXml = parser.ParseString(webpart.Contents.Trim(new[] { '\n', ' ' })); web.AddWebPartToWikiPage(url, wpEntity, (int)webpart.Row, (int)webpart.Column, false); } } var allWebParts = web.GetWebParts(url); foreach (var webpart in allWebParts) { parser.AddToken(new WebPartIdToken(web, webpart.WebPart.Title, webpart.Id)); } } file = web.GetFileByServerRelativeUrl(url); file.EnsureProperty(f => f.ListItemAllFields); if (page.Fields.Any()) { var item = file.ListItemAllFields; foreach (var fieldValue in page.Fields) { item[fieldValue.Key] = parser.ParseString(fieldValue.Value); } item.Update(); web.Context.ExecuteQueryRetry(); } if (page.Security != null && page.Security.RoleAssignments.Count != 0) { web.Context.Load(file.ListItemAllFields); web.Context.ExecuteQuery(); file.ListItemAllFields.SetSecurity(parser, page.Security); } } } return parser; }
private void UpdateField(Web web, string fieldId, XElement templateFieldElement, PnPMonitoredScope scope, TokenParser parser, string originalFieldXml) { var existingField = web.Fields.GetById(Guid.Parse(fieldId)); web.Context.Load(existingField, f => f.SchemaXml); web.Context.ExecuteQueryRetry(); XElement existingFieldElement = XElement.Parse(existingField.SchemaXml); XNodeEqualityComparer equalityComparer = new XNodeEqualityComparer(); if (equalityComparer.GetHashCode(existingFieldElement) != equalityComparer.GetHashCode(templateFieldElement)) // Is field different in template? { if (existingFieldElement.Attribute("Type").Value == templateFieldElement.Attribute("Type").Value) // Is existing field of the same type? { if (IsFieldXmlValid(parser.ParseString(originalFieldXml), parser, web.Context)) { var listIdentifier = templateFieldElement.Attribute("List") != null ? templateFieldElement.Attribute("List").Value : null; if (listIdentifier != null) { // Temporary remove list attribute from list templateFieldElement.Attribute("List").Remove(); } foreach (var attribute in templateFieldElement.Attributes()) { if (existingFieldElement.Attribute(attribute.Name) != null) { existingFieldElement.Attribute(attribute.Name).Value = attribute.Value; } else { existingFieldElement.Add(attribute); } } foreach (var element in templateFieldElement.Elements()) { if (existingFieldElement.Element(element.Name) != null) { existingFieldElement.Element(element.Name).Remove(); } existingFieldElement.Add(element); } if (existingFieldElement.Attribute("Version") != null) { existingFieldElement.Attributes("Version").Remove(); } existingField.SchemaXml = parser.ParseString(existingFieldElement.ToString(), "~sitecollection", "~site"); existingField.UpdateAndPushChanges(true); web.Context.Load(existingField, f => f.TypeAsString, f => f.DefaultValue); web.Context.ExecuteQueryRetry(); bool isDirty = false; #if !CLIENTSDKV15 if (originalFieldXml.ContainsResourceToken()) { var originalFieldElement = XElement.Parse(originalFieldXml); var nameAttributeValue = originalFieldElement.Attribute("Title") != null ? originalFieldElement.Attribute("Title").Value : ""; if (nameAttributeValue.ContainsResourceToken()) { existingField.TitleResource.SetUserResourceValue(nameAttributeValue, parser); isDirty = true; } var descriptionAttributeValue = originalFieldElement.Attribute("Description") != null ? originalFieldElement.Attribute("Description").Value : ""; if (descriptionAttributeValue.ContainsResourceToken()) { existingField.DescriptionResource.SetUserResourceValue(descriptionAttributeValue, parser); isDirty = true; } } #endif if (isDirty) { existingField.Update(); web.Context.ExecuteQuery(); } if ((existingField.TypeAsString == "TaxonomyFieldType" || existingField.TypeAsString == "TaxonomyFieldTypeMulti") && !string.IsNullOrEmpty(existingField.DefaultValue)) { var taxField = web.Context.CastTo<TaxonomyField>(existingField); ValidateTaxonomyFieldDefaultValue(taxField); } } else { // The field Xml was found invalid var tokenString = parser.GetLeftOverTokens(originalFieldXml).Aggregate(String.Empty, (acc, i) => acc + " " + i); scope.LogError("The field was found invalid: {0}", tokenString); throw new Exception(string.Format("The field was found invalid: {0}", tokenString)); } } else { var fieldName = existingFieldElement.Attribute("Name") != null ? existingFieldElement.Attribute("Name").Value : existingFieldElement.Attribute("StaticName").Value; WriteWarning(string.Format(CoreResources.Provisioning_ObjectHandlers_Fields_Field__0____1___exists_but_is_of_different_type__Skipping_field_, fieldName, fieldId), ProvisioningMessageType.Warning); scope.LogWarning(CoreResources.Provisioning_ObjectHandlers_Fields_Field__0____1___exists_but_is_of_different_type__Skipping_field_, fieldName, fieldId); } } }
public override ProvisioningTemplate ExtractObjects(Web web, ProvisioningTemplate template, ProvisioningTemplateCreationInformation creationInfo) { using (var scope = new PnPMonitoredScope(this.Name)) { web.EnsureProperties(w => w.HasUniqueRoleAssignments, w => w.Title); // Changed by Paolo Pialorsi to embrace the new sub-site attributes for break role inheritance and copy role assignments // if this is a sub site then we're not creating security entities as by default security is inherited from the root site if (web.IsSubSite() && !web.HasUniqueRoleAssignments) { return(template); } var ownerGroup = web.AssociatedOwnerGroup; var memberGroup = web.AssociatedMemberGroup; var visitorGroup = web.AssociatedVisitorGroup; web.Context.ExecuteQueryRetry(); if (!ownerGroup.ServerObjectIsNull.Value) { web.Context.Load(ownerGroup, o => o.Id, o => o.Users, o => o.Title); } if (!memberGroup.ServerObjectIsNull.Value) { web.Context.Load(memberGroup, o => o.Id, o => o.Users, o => o.Title); } if (!visitorGroup.ServerObjectIsNull.Value) { web.Context.Load(visitorGroup, o => o.Id, o => o.Users, o => o.Title); } web.Context.ExecuteQueryRetry(); List <int> associatedGroupIds = new List <int>(); var owners = new List <User>(); var members = new List <User>(); var visitors = new List <User>(); var siteSecurity = new SiteSecurity(); if (!ownerGroup.ServerObjectIsNull.Value) { siteSecurity.AssociatedOwnerGroup = ownerGroup.Title; associatedGroupIds.Add(ownerGroup.Id); foreach (var member in ownerGroup.Users) { owners.Add(new User() { Name = member.LoginName }); } } if (!memberGroup.ServerObjectIsNull.Value) { siteSecurity.AssociatedMemberGroup = memberGroup.Title; associatedGroupIds.Add(memberGroup.Id); foreach (var member in memberGroup.Users) { members.Add(new User() { Name = member.LoginName }); } } if (!visitorGroup.ServerObjectIsNull.Value) { siteSecurity.AssociatedVisitorGroup = visitorGroup.Title; associatedGroupIds.Add(visitorGroup.Id); foreach (var member in visitorGroup.Users) { visitors.Add(new User() { Name = member.LoginName }); } } siteSecurity.AdditionalOwners.AddRange(owners); siteSecurity.AdditionalMembers.AddRange(members); siteSecurity.AdditionalVisitors.AddRange(visitors); var query = from user in web.SiteUsers where user.IsSiteAdmin select user; var allUsers = web.Context.LoadQuery(query); web.Context.ExecuteQueryRetry(); var admins = new List <User>(); foreach (var member in allUsers) { admins.Add(new User() { Name = member.LoginName }); } siteSecurity.AdditionalAdministrators.AddRange(admins); if (creationInfo.IncludeSiteGroups) { web.Context.Load(web.SiteGroups, o => o.IncludeWithDefaultProperties( gr => gr.Id, gr => gr.Title, gr => gr.AllowMembersEditMembership, gr => gr.AutoAcceptRequestToJoinLeave, gr => gr.AllowRequestToJoinLeave, gr => gr.Description, gr => gr.Users.Include(u => u.LoginName), gr => gr.OnlyAllowMembersViewMembership, gr => gr.Owner.LoginName, gr => gr.RequestToJoinLeaveEmailSetting )); web.Context.ExecuteQueryRetry(); if (web.IsSubSite()) { WriteMessage("You are requesting to export sitegroups from a subweb. Notice that ALL sitegroups from the site collection are included in the result.", ProvisioningMessageType.Warning); } foreach (var group in web.SiteGroups.AsEnumerable().Where(o => !associatedGroupIds.Contains(o.Id))) { try { scope.LogDebug("Processing group {0}", group.Title); var siteGroup = new SiteGroup() { Title = !string.IsNullOrEmpty(web.Title) ? group.Title.Replace(web.Title, "{sitename}") : group.Title, AllowMembersEditMembership = group.AllowMembersEditMembership, AutoAcceptRequestToJoinLeave = group.AutoAcceptRequestToJoinLeave, AllowRequestToJoinLeave = group.AllowRequestToJoinLeave, Description = group.Description, OnlyAllowMembersViewMembership = group.OnlyAllowMembersViewMembership, Owner = ReplaceGroupTokens(web, group.Owner.LoginName), RequestToJoinLeaveEmailSetting = group.RequestToJoinLeaveEmailSetting }; if (String.IsNullOrEmpty(siteGroup.Description)) { var groupItem = web.SiteUserInfoList.GetItemById(group.Id); web.Context.Load(groupItem); web.Context.ExecuteQueryRetry(); var groupNotes = (String)groupItem["Notes"]; if (!String.IsNullOrEmpty(groupNotes)) { siteGroup.Description = groupNotes; } } foreach (var member in group.Users) { scope.LogDebug("Processing member {0} of group {0}", member.LoginName, group.Title); siteGroup.Members.Add(new User() { Name = member.LoginName }); } siteSecurity.SiteGroups.Add(siteGroup); } catch (Exception ee) { scope.LogError(ee.StackTrace); scope.LogError(ee.Message); scope.LogError(ee.InnerException.StackTrace); } } } var webRoleDefinitions = web.Context.LoadQuery(web.RoleDefinitions.Include(r => r.Name, r => r.Description, r => r.BasePermissions, r => r.RoleTypeKind)); web.Context.ExecuteQueryRetry(); if (web.HasUniqueRoleAssignments) { var permissionKeys = Enum.GetNames(typeof(PermissionKind)); if (!web.IsSubSite()) { foreach (var webRoleDefinition in webRoleDefinitions) { if (webRoleDefinition.RoleTypeKind == RoleType.None) { scope.LogDebug("Processing custom role definition {0}", webRoleDefinition.Name); var modelRoleDefinitions = new Model.RoleDefinition(); modelRoleDefinitions.Description = webRoleDefinition.Description; modelRoleDefinitions.Name = webRoleDefinition.Name; foreach (var permissionKey in permissionKeys) { scope.LogDebug("Processing custom permissionKey definition {0}", permissionKey); var permissionKind = (PermissionKind)Enum.Parse(typeof(PermissionKind), permissionKey); if (webRoleDefinition.BasePermissions.Has(permissionKind)) { modelRoleDefinitions.Permissions.Add(permissionKind); } } siteSecurity.SiteSecurityPermissions.RoleDefinitions.Add(modelRoleDefinitions); } else { scope.LogDebug("Skipping OOTB role definition {0}", webRoleDefinition.Name); } } } var webRoleAssignments = web.Context.LoadQuery(web.RoleAssignments.Include( r => r.RoleDefinitionBindings.Include( rd => rd.Name, rd => rd.RoleTypeKind), r => r.Member.LoginName, r => r.Member.PrincipalType)); web.Context.ExecuteQueryRetry(); foreach (var webRoleAssignment in webRoleAssignments) { scope.LogDebug("Processing Role Assignment {0}", webRoleAssignment.ToString()); if (webRoleAssignment.Member.PrincipalType == PrincipalType.SharePointGroup && !creationInfo.IncludeSiteGroups) { continue; } if (webRoleAssignment.Member.LoginName != "Excel Services Viewers") { foreach (var roleDefinition in webRoleAssignment.RoleDefinitionBindings) { if (roleDefinition.RoleTypeKind != RoleType.Guest) { var modelRoleAssignment = new Model.RoleAssignment(); var roleDefinitionValue = roleDefinition.Name; if (roleDefinition.RoleTypeKind != RoleType.None) { // Replace with token roleDefinitionValue = $"{{roledefinition:{roleDefinition.RoleTypeKind}}}"; } modelRoleAssignment.RoleDefinition = roleDefinitionValue; if (webRoleAssignment.Member.PrincipalType == PrincipalType.SharePointGroup) { modelRoleAssignment.Principal = ReplaceGroupTokens(web, webRoleAssignment.Member.LoginName); } else { modelRoleAssignment.Principal = webRoleAssignment.Member.LoginName; } siteSecurity.SiteSecurityPermissions.RoleAssignments.Add(modelRoleAssignment); } } } } } template.Security = siteSecurity; // 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); }
/// <summary> /// Public method to send a Webhook notification /// </summary> /// <param name="webhook">The reference webhook to notify</param> /// <param name="httpClient">The HttpClient instance to use to send the notification</param> /// <param name="kind">The Kind of webhook</param> /// <param name="parser">The parser to use for parsing parameters, optional</param> /// <param name="objectHandler">The objectHandler name, optional</param> /// <param name="exception">The exception, optional</param> /// <param name="scope">The PnP Provisioning Scope, if any, optional</param> public static void InvokeWebhook(ProvisioningWebhookBase webhook, HttpClient httpClient, ProvisioningTemplateWebhookKind kind, TokenParser parser = null, string objectHandler = null, Exception exception = null, PnPMonitoredScope scope = null) { var requestParameters = new Dictionary <String, String>(); if (exception != null) { // For GET requests we limit the size of the exception to avoid issues requestParameters["__exception"] = webhook.Method == ProvisioningTemplateWebhookMethod.GET ? exception.Message : exception.ToString(); } SimpleTokenParser internalParser = new SimpleTokenParser(); if (webhook.Parameters != null) { foreach (var webhookparam in webhook.Parameters) { requestParameters.Add(webhookparam.Key, parser != null ? parser.ParseString(webhookparam.Value) : webhookparam.Value); internalParser.AddToken(new WebhookParameter(webhookparam.Key, requestParameters[webhookparam.Key])); } } var url = parser != null?parser.ParseString(webhook.Url) : webhook.Url; // parse for template scoped parameters url = internalParser.ParseString(url); // parse for webhook scoped parameters // Fix URL if it does not contain ? if (!url.Contains("?")) { url += "?"; } switch (webhook.Method) { case ProvisioningTemplateWebhookMethod.GET: { url += $"&__webhookKind={kind.ToString()}"; // add the webhook kind to the REST request URL foreach (var k in requestParameters.Keys) { url += $"&{HttpUtility.UrlEncode(k)}={HttpUtility.UrlEncode(requestParameters[k])}"; } if ((kind == ProvisioningTemplateWebhookKind.ObjectHandlerProvisioningStarted || kind == ProvisioningTemplateWebhookKind.ObjectHandlerProvisioningCompleted || kind == ProvisioningTemplateWebhookKind.ExceptionOccurred) && objectHandler != null) { url += $"&__handler={HttpUtility.UrlEncode(objectHandler)}"; // add the handler name to the REST request URL } try { if (webhook.Async) { Task.Factory.StartNew(async() => { await httpClient.GetAsync(url); }); } else { httpClient.GetAsync(url).GetAwaiter().GetResult(); } } catch (HttpRequestException ex) { scope?.LogError(ex, "Error calling provisioning template webhook"); } break; } case ProvisioningTemplateWebhookMethod.POST: { requestParameters.Add("__webhookKind", kind.ToString()); // add the webhook kind to the parameters of the request body if ((kind == ProvisioningTemplateWebhookKind.ObjectHandlerProvisioningCompleted || kind == ProvisioningTemplateWebhookKind.ObjectHandlerProvisioningStarted || kind == ProvisioningTemplateWebhookKind.ExceptionOccurred) && objectHandler != null) { requestParameters.Add("__handler", objectHandler); // add the handler name to the parameters of the request body } try { if (webhook.Async) { Task.Factory.StartNew(async() => { switch (webhook.BodyFormat) { case ProvisioningTemplateWebhookBodyFormat.Json: using (var stringContent = new StringContent(JsonConvert.SerializeObject(requestParameters), Encoding.UTF8, "application/json")) { await httpClient.PostAsync(url, stringContent); } break; case ProvisioningTemplateWebhookBodyFormat.Xml: using (var stringContent = new StringContent(SerializeXml(requestParameters), Encoding.UTF8, "application/xml")) { await httpClient.PostAsync(url, stringContent); } break; case ProvisioningTemplateWebhookBodyFormat.FormUrlEncoded: using (var content = new FormUrlEncodedContent(requestParameters)) { await httpClient.PostAsync(url, content); } break; } }); } else { switch (webhook.BodyFormat) { case ProvisioningTemplateWebhookBodyFormat.Json: using (var stringContent = new StringContent(JsonConvert.SerializeObject(requestParameters), Encoding.UTF8, "application/json")) { httpClient.PostAsync(url, stringContent).GetAwaiter().GetResult(); } break; case ProvisioningTemplateWebhookBodyFormat.Xml: using (var stringContent = new StringContent(SerializeXml(requestParameters), Encoding.UTF8, "application/xml")) { httpClient.PostAsync(url, stringContent); } break; case ProvisioningTemplateWebhookBodyFormat.FormUrlEncoded: using (var content = new FormUrlEncodedContent(requestParameters)) { httpClient.PostAsync(url, content).GetAwaiter().GetResult(); } break; } } } catch (HttpRequestException ex) { scope?.LogError(ex, "Error calling provisioning template webhook"); } break; } } }
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)) { if (!template.Lists.Any()) { return(parser); } web.EnsureProperties(w => w.ServerRelativeUrl); web.Context.Load(web.Lists, lc => lc.IncludeWithDefaultProperties(l => l.RootFolder.ServerRelativeUrl)); web.Context.ExecuteQueryRetry(); #region DataRows foreach (var listInstance in template.Lists) { if (listInstance.DataRows == null || !listInstance.DataRows.Any()) { continue; } scope.LogDebug(CoreResources.Provisioning_ObjectHandlers_ListInstancesDataRows_Processing_data_rows_for__0_, listInstance.Title); // Retrieve the target list var list = web.Lists.GetByTitle(parser.ParseString(listInstance.Title)); web.Context.Load(list); // Retrieve the fields' types from the list Microsoft.SharePoint.Client.FieldCollection fields = list.Fields; web.Context.Load(fields, fs => fs.Include(f => f.InternalName, f => f.FieldTypeKind, f => f.TypeAsString, f => f.ReadOnlyField, f => f.Title)); web.Context.ExecuteQueryRetry(); var keyColumnType = "Text"; var parsedKeyColumn = parser.ParseString(listInstance.DataRows.KeyColumn); if (!string.IsNullOrEmpty(parsedKeyColumn)) { var keyColumn = fields.FirstOrDefault(f => f.InternalName.Equals(parsedKeyColumn, StringComparison.InvariantCultureIgnoreCase)); if (keyColumn != null) { switch (keyColumn.FieldTypeKind) { case FieldType.User: case FieldType.Lookup: keyColumnType = "Lookup"; break; case FieldType.URL: keyColumnType = "Url"; break; case FieldType.DateTime: keyColumnType = "DateTime"; break; case FieldType.Number: case FieldType.Counter: keyColumnType = "Number"; break; } } } foreach (var dataRow in listInstance.DataRows) { try { scope.LogDebug(CoreResources.Provisioning_ObjectHandlers_ListInstancesDataRows_Creating_list_item__0_, listInstance.DataRows.IndexOf(dataRow) + 1); bool processItem = true; ListItem listitem = null; var updateValues = new List <FieldUpdateValue>(); if (!string.IsNullOrEmpty(listInstance.DataRows.KeyColumn)) { // Get value from key column var dataRowValues = dataRow.Values.Where(v => v.Key == listInstance.DataRows.KeyColumn).ToList(); // if it is empty, skip the check if (dataRowValues.Any()) { var query = $@"<View><Query><Where><Eq><FieldRef Name=""{parsedKeyColumn}""/><Value Type=""{keyColumnType}"">{parser.ParseString(dataRowValues.FirstOrDefault().Value)}</Value></Eq></Where></Query><RowLimit>1</RowLimit></View>"; var camlQuery = new CamlQuery() { ViewXml = query }; var existingItems = list.GetItems(camlQuery); list.Context.Load(existingItems); list.Context.ExecuteQueryRetry(); if (existingItems.Count > 0) { if (listInstance.DataRows.UpdateBehavior == UpdateBehavior.Skip) { processItem = false; } else { listitem = existingItems[0]; processItem = true; } } } } if (!processItem) { continue; } if (listitem == null) { var listitemCI = new ListItemCreationInformation(); listitem = list.AddItem(listitemCI); } foreach (var dataValue in dataRow.Values) { Field dataField = fields.FirstOrDefault( f => f.InternalName == parser.ParseString(dataValue.Key)); if (dataField != null && dataField.ReadOnlyField && !dataField.InternalName.Equals("ContentTypeId", StringComparison.OrdinalIgnoreCase)) { // skip read only fields, except ContentTypeId continue; } if (dataField == null) { continue; } if (dataValue.Value == null) { updateValues.Add(dataField.FieldTypeKind == FieldType.Invalid ? new FieldUpdateValue(dataValue.Key, null, dataField.TypeAsString) : new FieldUpdateValue(dataValue.Key, null)); } else { 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]), }; updateValues.Add(new FieldUpdateValue(dataValue.Key, geolocationValue)); } else { updateValues.Add(new FieldUpdateValue(dataValue.Key, fieldValue)); } break; case FieldType.Lookup: // FieldLookupValue - Expected format: LookupID or LookupID,LookupID,LookupID... if (fieldValue.Contains(",")) { var lookupValues = new List <FieldLookupValue>(); fieldValue.Split(',').All(value => { lookupValues.Add(new FieldLookupValue { LookupId = int.Parse(value), }); return(true); }); updateValues.Add(new FieldUpdateValue(dataValue.Key, lookupValues.ToArray())); } else { var lookupValue = new FieldLookupValue { LookupId = int.Parse(fieldValue), }; updateValues.Add(new FieldUpdateValue(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]; } updateValues.Add(new FieldUpdateValue(dataValue.Key, linkValue)); break; case FieldType.User: // FieldUserValue - Expected format: loginName or loginName,loginName,loginName... if (fieldValue.Contains(",")) { var userValues = new List <FieldUserValue>(); fieldValue.Split(',').All(value => { var user = web.EnsureUser(value); web.Context.Load(user); web.Context.ExecuteQueryRetry(); if (user != null) { userValues.Add(new FieldUserValue { LookupId = user.Id, });; } return(true); }); updateValues.Add(new FieldUpdateValue(dataValue.Key, userValues.ToArray())); } else { var user = web.EnsureUser(fieldValue); web.Context.Load(user); web.Context.ExecuteQueryRetry(); if (user != null) { var userValue = new FieldUserValue { LookupId = user.Id, }; updateValues.Add(new FieldUpdateValue(dataValue.Key, userValue)); } else { updateValues.Add(new FieldUpdateValue(dataValue.Key, fieldValue)); } } break; case FieldType.DateTime: var dateTime = DateTime.MinValue; if (DateTime.TryParse(fieldValue, out dateTime)) { updateValues.Add(new FieldUpdateValue(dataValue.Key, dateTime)); } break; case FieldType.Invalid: switch (dataField.TypeAsString) { case "TaxonomyFieldType": // Single value field - Expected format: term label|term GUID case "TaxonomyFieldTypeMulti": // Multi value field - Expected format: term label|term GUID;term label|term GUID;term label|term GUID;... { if (fieldValue != null) { var termStrings = new List <string>(); var termsArray = fieldValue.Split(new char[] { ';' }); foreach (var term in termsArray) { termStrings.Add($"-1;#{term}"); } updateValues.Add(new FieldUpdateValue(dataValue.Key, termStrings, dataField.TypeAsString)); } break; } default: { //Publishing image case, but can be others too updateValues.Add(new FieldUpdateValue(dataValue.Key, fieldValue)); break; } } break; default: updateValues.Add(new FieldUpdateValue(dataValue.Key, fieldValue)); break; } } } foreach (var itemValue in updateValues.Where(u => u.FieldTypeString != "TaxonomyFieldTypeMulti" && u.FieldTypeString != "TaxonomyFieldType")) { if (string.IsNullOrEmpty(itemValue.FieldTypeString)) { listitem[itemValue.Key] = itemValue.Value; } } listitem.Update(); web.Context.Load(listitem); web.Context.ExecuteQueryRetry(); foreach (var itemValue in updateValues.Where(u => u.FieldTypeString == "TaxonomyFieldTypeMulti" || u.FieldTypeString == "TaxonomyFieldType")) { switch (itemValue.FieldTypeString) { case "TaxonomyFieldTypeMulti": { var field = fields.FirstOrDefault(f => f.InternalName == itemValue.Key as string || f.Title == itemValue.Key as string); var taxField = web.Context.CastTo <TaxonomyField>(field); if (itemValue.Value != null) { var valueCollection = new TaxonomyFieldValueCollection(web.Context, string.Join(";#", itemValue.Value as List <string>), taxField); taxField.SetFieldValueByValueCollection(listitem, valueCollection); } else { var valueCollection = new TaxonomyFieldValueCollection(web.Context, null, taxField); taxField.SetFieldValueByValueCollection(listitem, valueCollection); } listitem.Update(); web.Context.Load(listitem); web.Context.ExecuteQueryRetry(); break; } case "TaxonomyFieldType": { var field = fields.FirstOrDefault(f => f.InternalName == itemValue.Key as string || f.Title == itemValue.Key as string); var taxField = web.Context.CastTo <TaxonomyField>(field); taxField.EnsureProperty(f => f.TextField); var taxValue = new TaxonomyFieldValue(); if (itemValue.Value != null) { var termString = (itemValue.Value as List <string>).First(); taxValue.Label = termString.Split(new string[] { ";#" }, StringSplitOptions.None)[1].Split(new char[] { '|' })[0]; taxValue.TermGuid = termString.Split(new string[] { ";#" }, StringSplitOptions.None)[1].Split(new char[] { '|' })[1]; taxValue.WssId = -1; taxField.SetFieldValueByValue(listitem, taxValue); } else { taxValue.Label = string.Empty; taxValue.TermGuid = "11111111-1111-1111-1111-111111111111"; taxValue.WssId = -1; Field hiddenField = list.Fields.GetById(taxField.TextField); listitem.Context.Load(hiddenField, tf => tf.InternalName); listitem.Context.ExecuteQueryRetry(); taxField.SetFieldValueByValue(listitem, taxValue); // this order of updates is important. listitem[hiddenField.InternalName] = string.Empty; // this order of updates is important. } listitem.Update(); web.Context.Load(listitem); web.Context.ExecuteQueryRetry(); break; } } } if (dataRow.Security != null && (dataRow.Security.ClearSubscopes == true || dataRow.Security.CopyRoleAssignments == true || dataRow.Security.RoleAssignments.Count > 0)) { listitem.SetSecurity(parser, dataRow.Security); } } catch (Exception ex) { if (ex.GetType().Equals(typeof(ServerException)) && (ex as ServerException).ServerErrorTypeName.Equals("Microsoft.SharePoint.SPDuplicateValuesFoundException", StringComparison.InvariantCultureIgnoreCase) && applyingInformation.IgnoreDuplicateDataRowErrors) { scope.LogWarning(CoreResources.Provisioning_ObjectHandlers_ListInstancesDataRows_Creating_listitem_duplicate); continue; } else { scope.LogError(CoreResources.Provisioning_ObjectHandlers_ListInstancesDataRows_Creating_listitem_failed___0_____1_, ex.Message, ex.StackTrace); throw; } } } } #endregion } return(parser); }
private bool PersistFile(Web web, ProvisioningTemplateCreationInformation creationInfo, PnPMonitoredScope scope, string serverRelativeUrl) { var success = false; if (creationInfo.PersistBrandingFiles) { if (creationInfo.FileConnector != null) { if (UrlUtility.IsIisVirtualDirectory(serverRelativeUrl)) { scope.LogWarning("File is not located in the content database. Not retrieving {0}", serverRelativeUrl); return(success); } try { var file = web.GetFileByServerRelativeUrl(serverRelativeUrl); string fileName = string.Empty; if (serverRelativeUrl.IndexOf("/") > -1) { fileName = serverRelativeUrl.Substring(serverRelativeUrl.LastIndexOf("/") + 1); } else { fileName = serverRelativeUrl; } web.Context.Load(file); web.Context.ExecuteQueryRetry(); ClientResult <Stream> stream = file.OpenBinaryStream(); web.Context.ExecuteQueryRetry(); using (Stream memStream = new MemoryStream()) { CopyStream(stream.Value, memStream); memStream.Position = 0; creationInfo.FileConnector.SaveFileStream(fileName, memStream); } success = true; } catch (ServerException ex1) { // If we are referring a file from a location outside of the current web or at a location where we cannot retrieve the file an exception is thrown. We swallow this exception. if (ex1.ServerErrorCode != -2147024809) { throw; } else { scope.LogWarning("File is not necessarily located in the current web. Not retrieving {0}", serverRelativeUrl); } } } else { WriteMessage("No connector present to persist homepage.", ProvisioningMessageType.Error); scope.LogError("No connector present to persist homepage"); } } else { success = true; } return(success); }
public override TokenParser ProvisionObjects(Web web, ProvisioningTemplate template, TokenParser parser, ProvisioningTemplateApplyingInformation applyingInformation) { using (var scope = new PnPMonitoredScope(this.Name)) { if (template.Lists.Any()) { var rootWeb = (web.Context as ClientContext).Site.RootWeb; web.EnsureProperties(w => w.ServerRelativeUrl); web.Context.Load(web.Lists, lc => lc.IncludeWithDefaultProperties(l => l.RootFolder.ServerRelativeUrl)); web.Context.ExecuteQueryRetry(); var existingLists = web.Lists.AsEnumerable <List>().Select(existingList => existingList.RootFolder.ServerRelativeUrl).ToList(); var serverRelativeUrl = web.ServerRelativeUrl; #region DataRows foreach (var listInstance in template.Lists) { if (listInstance.DataRows != null && listInstance.DataRows.Any()) { scope.LogDebug(CoreResources.Provisioning_ObjectHandlers_ListInstancesDataRows_Processing_data_rows_for__0_, listInstance.Title); // Retrieve the target list var list = web.Lists.GetByTitle(parser.ParseString(listInstance.Title)); web.Context.Load(list); // Retrieve the fields' types from the list Microsoft.SharePoint.Client.FieldCollection fields = list.Fields; web.Context.Load(fields, fs => fs.Include(f => f.InternalName, f => f.FieldTypeKind, f => f.TypeAsString)); web.Context.ExecuteQueryRetry(); var keyColumnType = "Text"; var parsedKeyColumn = parser.ParseString(listInstance.DataRows.KeyColumn); if (!string.IsNullOrEmpty(parsedKeyColumn)) { var keyColumn = fields.FirstOrDefault(f => f.InternalName.Equals(parsedKeyColumn, StringComparison.InvariantCultureIgnoreCase)); if (keyColumn != null) { switch (keyColumn.FieldTypeKind) { case FieldType.User: case FieldType.Lookup: keyColumnType = "Lookup"; break; case FieldType.URL: keyColumnType = "Url"; break; case FieldType.DateTime: keyColumnType = "DateTime"; break; case FieldType.Number: case FieldType.Counter: keyColumnType = "Number"; break; } } } foreach (var dataRow in listInstance.DataRows) { try { scope.LogDebug(CoreResources.Provisioning_ObjectHandlers_ListInstancesDataRows_Creating_list_item__0_, listInstance.DataRows.IndexOf(dataRow) + 1); bool create = true; ListItem listitem = null; if (!string.IsNullOrEmpty(listInstance.DataRows.KeyColumn)) { // if it is empty, skip the check if (!string.IsNullOrEmpty(dataRow.Key)) { var query = $@"<View><Query><Where><Eq><FieldRef Name=""{parsedKeyColumn}""/><Value Type=""{keyColumnType}"">{parser.ParseString(dataRow.Key)}</Value></Eq></Where></Query><RowLimit>1</RowLimit></View>"; var camlQuery = new CamlQuery() { ViewXml = query }; var existingItems = list.GetItems(camlQuery); list.Context.Load(existingItems); list.Context.ExecuteQueryRetry(); if (existingItems.Count > 0) { if (listInstance.DataRows.UpdateBehavior == UpdateBehavior.Skip) { create = false; } else { listitem = existingItems[0]; create = true; } } } } if (create) { if (listitem == null) { var listitemCI = new ListItemCreationInformation(); listitem = list.AddItem(listitemCI); } foreach (var dataValue in dataRow.Values) { Field dataField = fields.FirstOrDefault( f => f.InternalName == parser.ParseString(dataValue.Key)); if (dataField != null) { String fieldValue = parser.ParseString(dataValue.Value); switch (dataField.FieldTypeKind) { case FieldType.Geolocation: // FieldGeolocationValue - Expected format: Altitude,Latitude,Longitude,Measure var geolocationArray = fieldValue.Split(','); if (geolocationArray.Length == 4) { var geolocationValue = new FieldGeolocationValue { Altitude = Double.Parse(geolocationArray[0]), Latitude = Double.Parse(geolocationArray[1]), Longitude = Double.Parse(geolocationArray[2]), Measure = Double.Parse(geolocationArray[3]), }; listitem[parser.ParseString(dataValue.Key)] = geolocationValue; } else { listitem[parser.ParseString(dataValue.Key)] = fieldValue; } break; case FieldType.Lookup: // FieldLookupValue - Expected format: LookupID or LookupID,LookupID,LookupID... if (fieldValue.Contains(",")) { var lookupValues = new List <FieldLookupValue>(); fieldValue.Split(',').All(value => { lookupValues.Add(new FieldLookupValue { LookupId = int.Parse(value), }); return(true); }); listitem[parser.ParseString(dataValue.Key)] = lookupValues.ToArray(); } else { var lookupValue = new FieldLookupValue { LookupId = int.Parse(fieldValue), }; listitem[parser.ParseString(dataValue.Key)] = lookupValue; } break; case FieldType.URL: // FieldUrlValue - Expected format: URL,Description var urlArray = fieldValue.Split(','); var linkValue = new FieldUrlValue(); if (urlArray.Length == 2) { linkValue.Url = urlArray[0]; linkValue.Description = urlArray[1]; } else { linkValue.Url = urlArray[0]; linkValue.Description = urlArray[0]; } listitem[parser.ParseString(dataValue.Key)] = linkValue; break; case FieldType.User: // FieldUserValue - Expected format: loginName or loginName,loginName,loginName... if (fieldValue.Contains(",")) { var userValues = new List <FieldUserValue>(); fieldValue.Split(',').All(value => { var user = web.EnsureUser(value); web.Context.Load(user); web.Context.ExecuteQueryRetry(); if (user != null) { userValues.Add(new FieldUserValue { LookupId = user.Id, });; } return(true); }); listitem[parser.ParseString(dataValue.Key)] = userValues.ToArray(); } else { var user = web.EnsureUser(fieldValue); web.Context.Load(user); web.Context.ExecuteQueryRetry(); if (user != null) { var userValue = new FieldUserValue { LookupId = user.Id, }; listitem[parser.ParseString(dataValue.Key)] = userValue; } else { listitem[parser.ParseString(dataValue.Key)] = fieldValue; } } break; case FieldType.DateTime: var dateTime = DateTime.MinValue; if (DateTime.TryParse(fieldValue, out dateTime)) { listitem[parser.ParseString(dataValue.Key)] = dateTime; } break; default: listitem[parser.ParseString(dataValue.Key)] = fieldValue; break; } } } listitem.Update(); web.Context.ExecuteQueryRetry(); // TODO: Run in batches? if (dataRow.Security != null && (dataRow.Security.ClearSubscopes == true || dataRow.Security.CopyRoleAssignments == true || dataRow.Security.RoleAssignments.Count > 0)) { listitem.SetSecurity(parser, dataRow.Security); } } } catch (Exception ex) { if (ex.GetType().Equals(typeof(ServerException)) && (ex as ServerException).ServerErrorTypeName.Equals("Microsoft.SharePoint.SPDuplicateValuesFoundException", StringComparison.InvariantCultureIgnoreCase) && applyingInformation.IgnoreDuplicateDataRowErrors) { scope.LogWarning(CoreResources.Provisioning_ObjectHandlers_ListInstancesDataRows_Creating_listitem_duplicate); continue; } else { scope.LogError(CoreResources.Provisioning_ObjectHandlers_ListInstancesDataRows_Creating_listitem_failed___0_____1_, ex.Message, ex.StackTrace); throw; } } } } } #endregion } } return(parser); }
private static void UpdateContentType(Web web, Microsoft.SharePoint.Client.ContentType existingContentType, ContentType templateContentType, TokenParser parser, PnPMonitoredScope scope, bool isNoScriptSite = false) { var isDirty = false; if (existingContentType.Hidden != templateContentType.Hidden) { scope.LogPropertyUpdate("Hidden"); existingContentType.Hidden = templateContentType.Hidden; isDirty = true; } if (existingContentType.ReadOnly != templateContentType.ReadOnly) { scope.LogPropertyUpdate("ReadOnly"); existingContentType.ReadOnly = templateContentType.ReadOnly; isDirty = true; } if (existingContentType.Sealed != templateContentType.Sealed) { scope.LogPropertyUpdate("Sealed"); existingContentType.Sealed = templateContentType.Sealed; isDirty = true; } if (templateContentType.Description != null && existingContentType.Description != parser.ParseString(templateContentType.Description)) { scope.LogPropertyUpdate("Description"); existingContentType.Description = parser.ParseString(templateContentType.Description); isDirty = true; } if (templateContentType.DocumentTemplate != null && existingContentType.DocumentTemplate != parser.ParseString(templateContentType.DocumentTemplate)) { scope.LogPropertyUpdate("DocumentTemplate"); existingContentType.DocumentTemplate = parser.ParseString(templateContentType.DocumentTemplate); isDirty = true; } if (existingContentType.Name != parser.ParseString(templateContentType.Name)) { scope.LogPropertyUpdate("Name"); existingContentType.Name = parser.ParseString(templateContentType.Name); isDirty = true; // CT is being renamed, add an extra token to the tokenparser parser.AddToken(new ContentTypeIdToken(web, existingContentType.Name, existingContentType.StringId)); } if (templateContentType.Group != null && existingContentType.Group != parser.ParseString(templateContentType.Group)) { scope.LogPropertyUpdate("Group"); existingContentType.Group = parser.ParseString(templateContentType.Group); isDirty = true; } if (!isNoScriptSite) { if (templateContentType.DisplayFormUrl != null && existingContentType.DisplayFormUrl != parser.ParseString(templateContentType.DisplayFormUrl)) { scope.LogPropertyUpdate("DisplayFormUrl"); existingContentType.DisplayFormUrl = parser.ParseString(templateContentType.DisplayFormUrl); isDirty = true; } if (templateContentType.EditFormUrl != null && existingContentType.EditFormUrl != parser.ParseString(templateContentType.EditFormUrl)) { scope.LogPropertyUpdate("EditFormUrl"); existingContentType.EditFormUrl = parser.ParseString(templateContentType.EditFormUrl); isDirty = true; } if (templateContentType.NewFormUrl != null && existingContentType.NewFormUrl != parser.ParseString(templateContentType.NewFormUrl)) { scope.LogPropertyUpdate("NewFormUrl"); existingContentType.NewFormUrl = parser.ParseString(templateContentType.NewFormUrl); isDirty = true; } } else { if (!String.IsNullOrEmpty(parser.ParseString(templateContentType.DisplayFormUrl)) || !String.IsNullOrEmpty(parser.ParseString(templateContentType.EditFormUrl)) || !String.IsNullOrEmpty(parser.ParseString(templateContentType.NewFormUrl))) { // log message scope.LogWarning(CoreResources.Provisioning_ObjectHandlers_ContentTypes_SkipCustomFormUrls, existingContentType.Name); } } #if !SP2013 if (templateContentType.Name.ContainsResourceToken()) { existingContentType.NameResource.SetUserResourceValue(templateContentType.Name, parser); isDirty = true; } if (templateContentType.Description.ContainsResourceToken()) { existingContentType.DescriptionResource.SetUserResourceValue(templateContentType.Description, parser); isDirty = true; } #endif if (isDirty) { existingContentType.Update(true); web.Context.ExecuteQueryRetry(); } // Delta handling existingContentType.EnsureProperty(c => c.FieldLinks); List<Guid> targetIds = existingContentType.FieldLinks.AsEnumerable().Select(c1 => c1.Id).ToList(); List<Guid> sourceIds = templateContentType.FieldRefs.Select(c1 => c1.Id).ToList(); var fieldsNotPresentInTarget = sourceIds.Except(targetIds).ToArray(); if (fieldsNotPresentInTarget.Any()) { foreach (var fieldId in fieldsNotPresentInTarget) { var fieldRef = templateContentType.FieldRefs.Find(fr => fr.Id == fieldId); var field = web.Fields.GetById(fieldId); scope.LogDebug(CoreResources.Provisioning_ObjectHandlers_ContentTypes_Adding_field__0__to_content_type, fieldId); web.AddFieldToContentType(existingContentType, field, fieldRef.Required, fieldRef.Hidden); } } isDirty = false; foreach (var fieldId in targetIds.Intersect(sourceIds)) { var fieldLink = existingContentType.FieldLinks.FirstOrDefault(fl => fl.Id == fieldId); var fieldRef = templateContentType.FieldRefs.Find(fr => fr.Id == fieldId); if (fieldRef != null) { scope.LogDebug(CoreResources.Provisioning_ObjectHandlers_ContentTypes_Field__0__exists_in_content_type, fieldId); if (fieldLink.Required != fieldRef.Required) { scope.LogPropertyUpdate("Required"); fieldLink.Required = fieldRef.Required; isDirty = true; } if (fieldLink.Hidden != fieldRef.Hidden) { scope.LogPropertyUpdate("Hidden"); fieldLink.Hidden = fieldRef.Hidden; isDirty = true; } } } // The new CT is a DocumentSet, and the target should be, as well if (templateContentType.DocumentSetTemplate != null) { if (!Microsoft.SharePoint.Client.DocumentSet.DocumentSetTemplate.IsChildOfDocumentSetContentType(web.Context, existingContentType).Value) { scope.LogError(CoreResources.Provisioning_ObjectHandlers_ContentTypes_InvalidDocumentSet_Update_Request, existingContentType.Id, existingContentType.Name); } else { Microsoft.SharePoint.Client.DocumentSet.DocumentSetTemplate templateToUpdate = Microsoft.SharePoint.Client.DocumentSet.DocumentSetTemplate.GetDocumentSetTemplate(web.Context, existingContentType); // TODO: Implement Delta Handling scope.LogWarning(CoreResources.Provisioning_ObjectHandlers_ContentTypes_DocumentSet_DeltaHandling_OnHold, existingContentType.Id, existingContentType.Name); } } if (isDirty) { existingContentType.Update(true); web.Context.ExecuteQueryRetry(); } }
private bool PersistFile(Web web, ProvisioningTemplateCreationInformation creationInfo, PnPMonitoredScope scope, string serverRelativeUrl) { var success = false; if (creationInfo.PersistBrandingFiles) { if (creationInfo.FileConnector != null) { if (UrlUtility.IsIisVirtualDirectory(serverRelativeUrl)) { scope.LogWarning("File is not located in the content database. Not retrieving {0}", serverRelativeUrl); return(success); } try { var file = web.GetFileByServerRelativeUrl(serverRelativeUrl); string fileName = string.Empty; if (serverRelativeUrl.IndexOf("/") > -1) { fileName = serverRelativeUrl.Substring(serverRelativeUrl.LastIndexOf("/") + 1); } else { fileName = serverRelativeUrl; } web.Context.Load(file); web.Context.ExecuteQueryRetry(); ClientResult <Stream> stream = file.OpenBinaryStream(); web.Context.ExecuteQueryRetry(); var baseUri = new Uri(web.Url); var fullUri = new Uri(baseUri, file.ServerRelativeUrl); var folderPath = HttpUtility.UrlDecode(fullUri.Segments.Take(fullUri.Segments.Count() - 1).ToArray().Aggregate((i, x) => i + x).TrimEnd('/')); // Configure the filename to use fileName = HttpUtility.UrlDecode(fullUri.Segments[fullUri.Segments.Count() - 1]); // Build up a site relative container URL...might end up empty as well String container = HttpUtility.UrlDecode(folderPath.Replace(web.ServerRelativeUrl, "")).Trim('/').Replace("/", "\\"); using (Stream memStream = new MemoryStream()) { CopyStream(stream.Value, memStream); memStream.Position = 0; if (!string.IsNullOrEmpty(container)) { creationInfo.FileConnector.SaveFileStream(fileName, container, memStream); } else { creationInfo.FileConnector.SaveFileStream(fileName, memStream); } } success = true; } catch (ServerException ex1) { // If we are referring a file from a location outside of the current web or at a location where we cannot retrieve the file an exception is thrown. We swallow this exception. if (ex1.ServerErrorCode != -2147024809) { throw; } else { scope.LogWarning("File is not necessarily located in the current web. Not retrieving {0}", serverRelativeUrl); } } } else { WriteMessage("No connector present to persist footer logo.", ProvisioningMessageType.Error); scope.LogError("No connector present to persist footer logo."); } } else { success = true; } return(success); }
private void UpdateField(Web web, string fieldId, XElement templateFieldElement, PnPMonitoredScope scope, TokenParser parser, string originalFieldXml) { var existingField = web.Fields.GetById(Guid.Parse(fieldId)); web.Context.Load(existingField, f => f.SchemaXml); web.Context.ExecuteQueryRetry(); XElement existingFieldElement = XElement.Parse(existingField.SchemaXml); XNodeEqualityComparer equalityComparer = new XNodeEqualityComparer(); if (equalityComparer.GetHashCode(existingFieldElement) != equalityComparer.GetHashCode(templateFieldElement)) // Is field different in template? { if (existingFieldElement.Attribute("Type").Value == templateFieldElement.Attribute("Type").Value) // Is existing field of the same type? { if (IsFieldXmlValid(parser.ParseString(originalFieldXml), parser, web.Context)) { var listIdentifier = templateFieldElement.Attribute("List") != null?templateFieldElement.Attribute("List").Value : null; if (listIdentifier != null) { // Temporary remove list attribute from list templateFieldElement.Attribute("List").Remove(); } foreach (var attribute in templateFieldElement.Attributes()) { if (existingFieldElement.Attribute(attribute.Name) != null) { existingFieldElement.Attribute(attribute.Name).Value = attribute.Value; } else { existingFieldElement.Add(attribute); } } foreach (var element in templateFieldElement.Elements()) { if (existingFieldElement.Element(element.Name) != null) { existingFieldElement.Element(element.Name).Remove(); } existingFieldElement.Add(element); } if (string.Equals(templateFieldElement.Attribute("Type").Value, "Calculated", StringComparison.OrdinalIgnoreCase)) { var fieldRefsElement = existingFieldElement.Descendants("FieldRefs").FirstOrDefault(); if (fieldRefsElement != null) { fieldRefsElement.Remove(); } } if (existingFieldElement.Attribute("Version") != null) { existingFieldElement.Attributes("Version").Remove(); } existingField.SchemaXml = parser.ParseString(existingFieldElement.ToString(), "~sitecollection", "~site"); existingField.UpdateAndPushChanges(true); web.Context.Load(existingField, f => f.TypeAsString, f => f.DefaultValue); web.Context.ExecuteQueryRetry(); bool isDirty = false; #if !SP2013 if (originalFieldXml.ContainsResourceToken()) { var originalFieldElement = XElement.Parse(originalFieldXml); var nameAttributeValue = originalFieldElement.Attribute("DisplayName") != null?originalFieldElement.Attribute("DisplayName").Value : ""; if (nameAttributeValue.ContainsResourceToken()) { existingField.TitleResource.SetUserResourceValue(nameAttributeValue, parser); isDirty = true; } var descriptionAttributeValue = originalFieldElement.Attribute("Description") != null?originalFieldElement.Attribute("Description").Value : ""; if (descriptionAttributeValue.ContainsResourceToken()) { existingField.DescriptionResource.SetUserResourceValue(descriptionAttributeValue, parser); isDirty = true; } } #endif if (isDirty) { existingField.Update(); web.Context.ExecuteQueryRetry(); } if ((existingField.TypeAsString == "TaxonomyFieldType" || existingField.TypeAsString == "TaxonomyFieldTypeMulti") && !string.IsNullOrEmpty(existingField.DefaultValue)) { var taxField = web.Context.CastTo <TaxonomyField>(existingField); ValidateTaxonomyFieldDefaultValue(taxField); } } else { // The field Xml was found invalid var tokenString = parser.GetLeftOverTokens(originalFieldXml).Aggregate(String.Empty, (acc, i) => acc + " " + i); scope.LogError("The field was found invalid: {0}", tokenString); throw new Exception(string.Format("The field was found invalid: {0}", tokenString)); } } else { var fieldName = existingFieldElement.Attribute("Name") != null?existingFieldElement.Attribute("Name").Value : existingFieldElement.Attribute("StaticName").Value; WriteWarning(string.Format(CoreResources.Provisioning_ObjectHandlers_Fields_Field__0____1___exists_but_is_of_different_type__Skipping_field_, fieldName, fieldId), ProvisioningMessageType.Warning); scope.LogWarning(CoreResources.Provisioning_ObjectHandlers_Fields_Field__0____1___exists_but_is_of_different_type__Skipping_field_, fieldName, fieldId); } } }
private void ProcessApps(Web web, ProvisioningTemplate template, TokenParser parser, PnPMonitoredScope scope) { if (template.Tenant.AppCatalog != null && template.Tenant.AppCatalog.Packages.Count > 0) { var manager = new AppManager(web.Context as ClientContext); var appCatalogUri = web.GetAppCatalog(); if (appCatalogUri != null) { foreach (var app in template.Tenant.AppCatalog.Packages) { AppMetadata appMetadata = null; if (app.Action == PackageAction.Upload || app.Action == PackageAction.UploadAndPublish) { var appBytes = GetFileBytes(template, app.Src); var appFilename = app.Src.Substring(app.Src.LastIndexOf('\\') + 1); appMetadata = manager.Add(appBytes, appFilename, app.Overwrite); parser.Tokens.Add(new AppPackageIdToken(web, appFilename, appMetadata.Id)); } if (app.Action == PackageAction.Publish || app.Action == PackageAction.UploadAndPublish) { if (appMetadata == null) { appMetadata = manager.GetAvailable() .FirstOrDefault(a => a.Id == Guid.Parse(parser.ParseString(app.PackageId))); } if (appMetadata != null) { manager.Deploy(appMetadata, app.SkipFeatureDeployment); } else { scope.LogError("Referenced App Package {0} not available", app.PackageId); throw new Exception($"Referenced App Package {app.PackageId} not available"); } } if (app.Action == PackageAction.Remove) { var appId = Guid.Parse(parser.ParseString(app.PackageId)); // Get the apps already installed in the site var appExists = manager.GetAvailable()?.Any(a => a.Id == appId); if (appExists.HasValue && appExists.Value) { manager.Remove(appId); } else { WriteMessage($"App Package with ID {appId} does not exist in the AppCatalog and cannot be removed!", ProvisioningMessageType.Warning); } } } } else { WriteMessage($"Tenant app catalog doesn't exist. ALM step will be skipped!", ProvisioningMessageType.Warning); } } }
public List<DataRow> ExtractItems( ProvisioningTemplateCreationInformation creationInfo, TokenParser parser, PnPMonitoredScope scope) { List<DataRow> dataRows = new List<DataRow>(); bool isPageLib = (List.BaseTemplate == (int)ListTemplateType.WebPageLibrary) || (List.BaseTemplate == (int)ListTemplateType.HomePageLibrary) || (List.BaseTemplate == (int)ListTemplateType.PublishingPages); CamlQuery query = isPageLib ? CamlQuery.CreateAllFoldersQuery() : CamlQuery.CreateAllItemsQuery(); query.DatesInUtc = true; ListItemCollection items = this.List.GetItems(query); this.Context.Load(items, col => col.IncludeWithDefaultProperties(i => i.HasUniqueRoleAssignments)); this.Context.Load(this.List.Fields); this.Context.Load(this.List, l=> l.RootFolder.ServerRelativeUrl, l=> l.BaseType); this.Context.ExecuteQueryRetry(); ItemPathProvider itemPathProvider = new ItemPathProvider(this.List, this.Web); List<Field> fields = GetListContentSerializableFields(true); foreach (ListItem item in items) { try { Dictionary<string, string> values = new Dictionary<string, string>(); foreach (Field field in fields) { if (CanFieldContentBeIncluded(field, true)) { string str = ""; object value = null; ; try { value = item[field.InternalName]; } catch (Exception ex) { scope.LogWarning(ex, "Failed to read item field value. List:{0}, Item ID:{1}, Field: {2}", this.List.Title, item.Id, field.InternalName); } if (null != value) { try { FieldValueProvider provider = GetFieldValueProvider(field, this.Web); str = provider.GetValidatedValue(value); } catch (Exception ex) { scope.LogWarning(ex, "Failed to serialize item field value. List:{0}, Item ID:{1}, Field: {2}", this.List.Title, item.Id, field.InternalName); } if (!string.IsNullOrEmpty(str)) { values.Add(field.InternalName, str); } } } } string fileSrc; itemPathProvider.ExtractItemPathValues(item, values, creationInfo, out fileSrc); if (values.Any()) { ObjectSecurity security = null; if (item.HasUniqueRoleAssignments) { try { security = item.GetSecurity(parser); security.ClearSubscopes = true; } catch (Exception ex) { scope.LogWarning(ex, "Failed to get item security. Item ID: {0}, List: '{1}'.", item.Id, this.List.Title); } } DataRow row = new DataRow(values, security, fileSrc); dataRows.Add(row); } } catch (Exception ex) { scope.LogError(ex, "Failed to save item in template. Item ID: {0}, List: '{1}'.", item.Id, this.List.Title); } } return dataRows; }
private static TokenParser ProvisionFeaturesImplementation <T>(T parent, IEnumerable <Feature> features, TokenParser parser, PnPMonitoredScope scope) { var activeFeatures = new List <Microsoft.SharePoint.Client.Feature>(); Web web = null; Site site = null; if (parent is Site) { site = parent as Site; site.Context.Load(site.Features, fs => fs.Include(f => f.DefinitionId)); site.Context.ExecuteQueryRetry(); activeFeatures = site.Features.ToList(); } else { web = parent as Web; web.Context.Load(web.Features, fs => fs.Include(f => f.DefinitionId)); web.Context.ExecuteQueryRetry(); activeFeatures = web.Features.ToList(); } if (features != null) { foreach (var feature in features) { if (!feature.Deactivate) { if (activeFeatures.FirstOrDefault(f => f.DefinitionId == feature.Id) == null) { scope.LogDebug(CoreResources.Provisioning_ObjectHandlers_Features_Activating__0__scoped_feature__1_, site != null ? "site" : "web", feature.Id); if (site != null) { try { site.ActivateFeature(feature.Id); } catch (ServerException ex) { scope.LogError("Error activating feature {0}: {1}", feature.Id, ex.Message); } } else { try { web.ActivateFeature(feature.Id); } catch (ServerException ex) { scope.LogError("Error activating feature {0}: {1}", feature.Id, ex.Message); } } } } else { if (activeFeatures.FirstOrDefault(f => f.DefinitionId == feature.Id) != null) { scope.LogDebug(CoreResources.Provisioning_ObjectHandlers_Features_Deactivating__0__scoped_feature__1_, site != null ? "site" : "web", feature.Id); if (site != null) { try { site.DeactivateFeature(feature.Id); } catch (ServerException ex) { scope.LogError("Error deactivating feature {0}: {1}", feature.Id, ex.Message); } } else { try { web.DeactivateFeature(feature.Id); } catch (ServerException ex) { scope.LogError("Error deactivating feature {0}: {1}", feature.Id, ex.Message); } } } } } } if (parent is Site) { parser.RebuildListTokens((parent as Site).RootWeb); } else { parser.RebuildListTokens(parent as Web); } return(parser); }
private static void AddUserToGroup(Web web, Group group, List<User> members, PnPMonitoredScope scope) { if (members.Any()) { scope.LogDebug("Adding users to group {0}", group.Title); try { foreach (var user in members) { scope.LogDebug("Adding user {0}", user.Name); var existingUser = web.EnsureUser(user.Name); group.Users.AddUser(existingUser); } 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.Lists.Any()) { return(parser); } web.EnsureProperties(w => w.ServerRelativeUrl); web.Context.Load(web.Lists, lc => lc.IncludeWithDefaultProperties(l => l.RootFolder.ServerRelativeUrl)); web.Context.ExecuteQueryRetry(); #region DataRows foreach (var listInstance in template.Lists) { if (listInstance.DataRows != null && listInstance.DataRows.Any()) { scope.LogDebug(CoreResources.Provisioning_ObjectHandlers_ListInstancesDataRows_Processing_data_rows_for__0_, listInstance.Title); // Retrieve the target list var list = web.Lists.GetByTitle(parser.ParseString(listInstance.Title)); web.Context.Load(list); // Retrieve the fields' types from the list Microsoft.SharePoint.Client.FieldCollection fields = list.Fields; web.Context.Load(fields, fs => fs.Include(f => f.InternalName, f => f.FieldTypeKind, f => f.TypeAsString, f => f.ReadOnlyField, f => f.Title)); web.Context.ExecuteQueryRetry(); var keyColumnType = "Text"; var parsedKeyColumn = parser.ParseString(listInstance.DataRows.KeyColumn); if (!string.IsNullOrEmpty(parsedKeyColumn)) { var keyColumn = fields.FirstOrDefault(f => f.InternalName.Equals(parsedKeyColumn, StringComparison.InvariantCultureIgnoreCase)); if (keyColumn != null) { switch (keyColumn.FieldTypeKind) { case FieldType.User: case FieldType.Lookup: keyColumnType = "Lookup"; break; case FieldType.URL: keyColumnType = "Url"; break; case FieldType.DateTime: keyColumnType = "DateTime"; break; case FieldType.Number: case FieldType.Counter: keyColumnType = "Number"; break; } } } foreach (var dataRow in listInstance.DataRows) { try { scope.LogDebug(CoreResources.Provisioning_ObjectHandlers_ListInstancesDataRows_Creating_list_item__0_, listInstance.DataRows.IndexOf(dataRow) + 1); bool processItem = true; ListItem listitem = null; if (!string.IsNullOrEmpty(listInstance.DataRows.KeyColumn)) { // Get value from key column var dataRowValues = dataRow.Values.Where(v => v.Key == listInstance.DataRows.KeyColumn).ToList(); // if it is empty, skip the check if (dataRowValues.Any()) { var query = $@"<View><Query><Where><Eq><FieldRef Name=""{parsedKeyColumn}""/><Value Type=""{keyColumnType}"">{parser.ParseString(dataRowValues.FirstOrDefault().Value)}</Value></Eq></Where></Query><RowLimit>1</RowLimit></View>"; var camlQuery = new CamlQuery() { ViewXml = query }; var existingItems = list.GetItems(camlQuery); list.Context.Load(existingItems); list.Context.ExecuteQueryRetry(); if (existingItems.Count > 0) { if (listInstance.DataRows.UpdateBehavior == UpdateBehavior.Skip) { processItem = false; } else { listitem = existingItems[0]; processItem = true; } } } } if (processItem) { bool IsNewItem = false; if (listitem == null) { var listitemCI = new ListItemCreationInformation(); listitem = list.AddItem(listitemCI); IsNewItem = true; } ListItemUtilities.UpdateListItem(listitem, parser, dataRow.Values, ListItemUtilities.ListItemUpdateType.UpdateOverwriteVersion, IsNewItem); if (dataRow.Security != null && (dataRow.Security.ClearSubscopes || dataRow.Security.CopyRoleAssignments || dataRow.Security.RoleAssignments.Count > 0)) { listitem.SetSecurity(parser, dataRow.Security); } if (dataRow.Attachments != null && dataRow.Attachments.Count > 0) { foreach (var attachment in dataRow.Attachments) { attachment.Name = parser.ParseString(attachment.Name); attachment.Src = parser.ParseString(attachment.Src); if (!IsNewItem) { var overwrite = attachment.Overwrite; listitem.EnsureProperty(l => l.AttachmentFiles); Attachment existingItem = null; if (listitem.AttachmentFiles.Count > 0) { existingItem = listitem.AttachmentFiles.FirstOrDefault(a => a.FileName.Equals(attachment.Name, StringComparison.OrdinalIgnoreCase)); } if (existingItem != null) { if (overwrite) { existingItem.DeleteObject(); web.Context.ExecuteQueryRetry(); AddAttachment(template, listitem, attachment); } } else { AddAttachment(template, listitem, attachment); } } else { AddAttachment(template, listitem, attachment, IsNewItem); } } if (IsNewItem) { listitem.Context.ExecuteQueryRetry(); } } } } catch (ServerException ex) { if (ex.ServerErrorTypeName.Equals("Microsoft.SharePoint.SPDuplicateValuesFoundException", StringComparison.InvariantCultureIgnoreCase) && applyingInformation.IgnoreDuplicateDataRowErrors) { scope.LogWarning(CoreResources.Provisioning_ObjectHandlers_ListInstancesDataRows_Creating_listitem_duplicate); continue; } if (ex.ServerErrorTypeName.Equals("Microsoft.SharePoint.SPException", StringComparison.InvariantCultureIgnoreCase) && ex.Message.Equals("To add an item to a document library, use SPFileCollection.Add()", StringComparison.InvariantCultureIgnoreCase)) { // somebody tries to add new items to a document library var warning = string.Format(CoreResources.Provisioning_ObjectHandlers_ListInstancesDataRows_Creating_listitem_notsupported_0, listInstance.Title); scope.LogWarning(warning); WriteMessage(warning, ProvisioningMessageType.Warning); continue; } } catch (Exception ex) { scope.LogError(CoreResources.Provisioning_ObjectHandlers_ListInstancesDataRows_Creating_listitem_failed___0_____1_, ex.Message, ex.StackTrace); throw; } } } } #endregion DataRows } return(parser); }
public override 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; }
private void ExtractFileSettings(Web web, List siteList, string fileServerRelativeUrl, ref Model.File pnpFile, PnPMonitoredScope scope) #endif { try { #if !SP2013 && !SP2016 var file = web.GetFileById(fileUniqueId); #else var file = web.GetFileByServerRelativeUrl(fileServerRelativeUrl); #endif web.Context.Load(file, f => f.Level, f => f.ServerRelativeUrl, #if !SP2013 && !SP2016 f => f.Properties, #endif f => f.ListItemAllFields, f => f.ListItemAllFields.RoleAssignments, f => f.ListItemAllFields.RoleAssignments.Include(r => r.Member, r => r.RoleDefinitionBindings), f => f.ListItemAllFields.HasUniqueRoleAssignments, f => f.ListItemAllFields.ParentList, f => f.ListItemAllFields.ContentType.StringId); web.Context.ExecuteQueryRetry(); //export PnPFile FieldValues if (file.ListItemAllFields.FieldValues.Any()) { var fieldValues = file.ListItemAllFields.FieldValues; var fieldValuesAsText = file.ListItemAllFields.EnsureProperty(li => li.FieldValuesAsText).FieldValues; #region //**** get correct Content Type string ctId = string.Empty; foreach (var ct in web.ContentTypes.OrderByDescending(c => c.StringId.Length)) { if (file.ListItemAllFields.ContentType.StringId.StartsWith(ct.StringId)) { pnpFile.Properties.Add("ContentTypeId", ct.StringId); break; } } #endregion //**** get correct Content Type foreach (var fieldValue in fieldValues) { if (fieldValue.Value != null && !string.IsNullOrEmpty(fieldValue.Value.ToString())) { var field = siteList.Fields.FirstOrDefault(fs => fs.InternalName == fieldValue.Key); string value = string.Empty; //ignore read only fields if (!field.ReadOnlyField || WriteableReadOnlyField.Contains(field.InternalName.ToLower())) { value = TokenizeValue(web, field.TypeAsString, fieldValue, fieldValuesAsText[field.InternalName]); if (fieldValue.Key == "ContentTypeId") { value = null; //it's already in Properties - we can ignore here } } // We process real values only if (value != null && !String.IsNullOrEmpty(value) && value != "[]") { pnpFile.Properties.Add(fieldValue.Key, value); } } } } } catch (Exception ex) { #if !SP2013 && !SP2016 scope.LogError(ex, "Extract of File with uniqueId {0} failed", fileUniqueId); #else scope.LogError(ex, "Extract of File with url {0} failed", fileServerRelativeUrl); #endif } }
private static Field CreateField(XElement fieldElement, ListInfo listInfo, TokenParser parser, string originalFieldXml, ClientRuntimeContext context, PnPMonitoredScope scope) { Field field = null; fieldElement = PrepareField(fieldElement); var fieldXml = parser.ParseString(fieldElement.ToString(), "~sitecollection", "~site"); if (IsFieldXmlValid(parser.ParseString(originalFieldXml), parser, context)) { field = listInfo.SiteList.Fields.AddFieldAsXml(fieldXml, false, AddFieldOptions.AddFieldInternalNameHint); listInfo.SiteList.Context.Load(field); listInfo.SiteList.Context.ExecuteQueryRetry(); bool isDirty = false; #if !SP2013 if (originalFieldXml.ContainsResourceToken()) { var originalFieldElement = XElement.Parse(originalFieldXml); var nameAttributeValue = originalFieldElement.Attribute("DisplayName") != null ? originalFieldElement.Attribute("DisplayName").Value : ""; if (nameAttributeValue.ContainsResourceToken()) { if (field.TitleResource.SetUserResourceValue(nameAttributeValue, parser)) { isDirty = true; } } var descriptionAttributeValue = originalFieldElement.Attribute("Description") != null ? originalFieldElement.Attribute("Description").Value : ""; if (descriptionAttributeValue.ContainsResourceToken()) { if (field.DescriptionResource.SetUserResourceValue(descriptionAttributeValue, parser)) { isDirty = true; } } } #endif if (isDirty) { field.Update(); listInfo.SiteList.Context.ExecuteQueryRetry(); } } else { // The field Xml was found invalid var tokenString = parser.GetLeftOverTokens(originalFieldXml).Aggregate(String.Empty, (acc, i) => acc + " " + i); scope.LogError("The field was found invalid: {0}", tokenString); throw new Exception(string.Format("The field was found invalid: {0}", tokenString)); } return field; }
public Model.Folder ExtractFolderSettings(Web web, List siteList, string serverRelativePathToFolder, PnPMonitoredScope scope, Model.Configuration.Lists.Lists.ExtractQueryConfiguration queryConfig) { Model.Folder pnpFolder = null; try { Microsoft.SharePoint.Client.Folder spFolder = web.GetFolderByServerRelativeUrl(serverRelativePathToFolder); web.Context.Load(spFolder, f => f.Name, f => f.ServerRelativeUrl, f => f.Properties, f => f.ListItemAllFields, f => f.ListItemAllFields.RoleAssignments, f => f.ListItemAllFields.RoleAssignments.Include(r => r.Member, r => r.RoleDefinitionBindings), f => f.ListItemAllFields.HasUniqueRoleAssignments, f => f.ListItemAllFields.ParentList, f => f.ListItemAllFields.ContentType.StringId); web.Context.Load(web, w => w.AssociatedOwnerGroup, w => w.AssociatedMemberGroup, w => w.AssociatedVisitorGroup, w => w.Title, w => w.Url, w => w.RoleDefinitions.Include(r => r.RoleTypeKind, r => r.Name), w => w.ContentTypes.Include(c => c.Id, c => c.Name, c => c.StringId)); web.Context.ExecuteQueryRetry(); pnpFolder = new Model.Folder(spFolder.Name); //export PnPFolder Properties if (spFolder.Properties.FieldValues.Any()) { foreach (var propKey in spFolder.Properties.FieldValues.Keys.Where(k => !k.StartsWith("vti_") && !k.StartsWith("docset_"))) { pnpFolder.PropertyBagEntries.Add(new PropertyBagEntry() { Key = propKey, Value = spFolder.Properties.FieldValues[propKey].ToString() }); } } //export PnPFolder FieldValues if (spFolder.ListItemAllFields.FieldValues.Any()) { var list = spFolder.ListItemAllFields.ParentList; var fields = list.Fields; web.Context.Load(fields, fs => fs.IncludeWithDefaultProperties(f => f.TypeAsString, f => f.InternalName, f => f.Title)); web.Context.ExecuteQueryRetry(); var fieldValues = spFolder.ListItemAllFields.FieldValues; var fieldValuesAsText = spFolder.ListItemAllFields.EnsureProperty(li => li.FieldValuesAsText).FieldValues; #region //**** get correct Content Type string ctId = string.Empty; foreach (var ct in web.ContentTypes.OrderByDescending(c => c.StringId.Length)) { if (spFolder.ListItemAllFields.ContentType.StringId.StartsWith(ct.StringId)) { pnpFolder.ContentTypeID = ct.StringId; break; } } #endregion //**** get correct Content Type var filteredFieldValues = fieldValues.ToList(); if (queryConfig != null && queryConfig.ViewFields != null && queryConfig.ViewFields.Count > 0) { filteredFieldValues = fieldValues.Where(f => queryConfig.ViewFields.Contains(f.Key)).ToList(); } foreach (var fieldValue in filteredFieldValues) { if (fieldValue.Value != null && !string.IsNullOrEmpty(fieldValue.Value.ToString())) { var field = siteList.Fields.FirstOrDefault(fs => fs.InternalName == fieldValue.Key); string value = string.Empty; //ignore read only fields if (!field.ReadOnlyField || WriteableReadOnlyField.Contains(field.InternalName.ToLower())) { value = TokenizeValue(web, field.TypeAsString, fieldValue, fieldValuesAsText[field.InternalName]); } if (fieldValue.Key.Equals("ContentTypeId", StringComparison.CurrentCultureIgnoreCase)) { value = null; //ignore here since already in dataRow } if (fieldValue.Key.Equals("HTML_x0020_File_x0020_Type", StringComparison.CurrentCultureIgnoreCase) && fieldValuesAsText["HTML_x0020_File_x0020_Type"] == "OneNote.Notebook") { pnpFolder.Properties.Add("File_x0020_Type", "OneNote.Notebook"); pnpFolder.Properties.Add(fieldValue.Key, "OneNote.Notebook"); value = null; } // We process real values only if (!string.IsNullOrWhiteSpace(value) && value != "[]") { pnpFolder.Properties.Add(fieldValue.Key, value); } } } } } catch (Exception ex) { scope.LogError(ex, "Extract of Folder {0} failed", serverRelativePathToFolder); } return(pnpFolder); }
private void CallWebHooks(ProvisioningTemplate template, TokenParser parser, ProvisioningTemplateWebhookKind kind, String objectHandler = null, Exception exception = null) { if (template != null) { using (var scope = new PnPMonitoredScope("ProvisioningTemplate WebHook Call")) { var webhooks = new List <ProvisioningWebhookBase>(); // Merge the webhooks at template level with those at global level if (template.ProvisioningTemplateWebhooks != null && template.ProvisioningTemplateWebhooks.Any()) { webhooks.AddRange(template.ProvisioningTemplateWebhooks); } if (template.ParentHierarchy?.ProvisioningWebhooks != null && template.ParentHierarchy.ProvisioningWebhooks.Any()) { webhooks.AddRange(template.ParentHierarchy.ProvisioningWebhooks); } // If there is any webhook if (webhooks.Count > 0) { foreach (var webhook in webhooks.Where(w => w.Kind == kind)) { var requestParameters = new Dictionary <String, String>(); if (exception != null) { // For GET requests we limit the size of the exception to avoid issues requestParameters["__exception"] = webhook.Method == ProvisioningTemplateWebhookMethod.GET ? exception.Message : exception.ToString(); } SimpleTokenParser internalParser = new SimpleTokenParser(); foreach (var webhookparam in webhook.Parameters) { requestParameters.Add(webhookparam.Key, parser.ParseString(webhookparam.Value)); internalParser.AddToken(new WebhookParameter(webhookparam.Key, requestParameters[webhookparam.Key])); } var url = parser.ParseString(webhook.Url); // parse for template scoped parameters url = internalParser.ParseString(url); // parse for webhook scoped parameters switch (webhook.Method) { case ProvisioningTemplateWebhookMethod.GET: { url += $"&__webhookKind={kind.ToString()}"; // add the webhook kind to the REST request URL foreach (var k in requestParameters.Keys) { url += $"&{HttpUtility.UrlEncode(k)}={HttpUtility.UrlEncode(requestParameters[k])}"; } if (kind == ProvisioningTemplateWebhookKind.ObjectHandlerProvisioningStarted || kind == ProvisioningTemplateWebhookKind.ObjectHandlerProvisioningCompleted || kind == ProvisioningTemplateWebhookKind.ExceptionOccurred) { url += $"&__handler={HttpUtility.UrlEncode(objectHandler)}"; // add the handler name to the REST request URL } try { if (webhook.Async) { Task.Factory.StartNew(async() => { await httpClient.GetAsync(url); }); } else { httpClient.GetAsync(url).GetAwaiter().GetResult(); } } catch (HttpRequestException ex) { scope.LogError(ex, "Error calling provisioning template webhook"); } break; } case ProvisioningTemplateWebhookMethod.POST: { requestParameters.Add("__webhookKind", kind.ToString()); // add the webhook kind to the parameters of the request body if (kind == ProvisioningTemplateWebhookKind.ObjectHandlerProvisioningCompleted || kind == ProvisioningTemplateWebhookKind.ObjectHandlerProvisioningStarted || kind == ProvisioningTemplateWebhookKind.ExceptionOccurred) { requestParameters.Add("__handler", objectHandler); // add the handler name to the parameters of the request body } try { if (webhook.Async) { Task.Factory.StartNew(async() => { switch (webhook.BodyFormat) { case ProvisioningTemplateWebhookBodyFormat.Json: await httpClient.PostAsJsonAsync(url, requestParameters); break; case ProvisioningTemplateWebhookBodyFormat.Xml: await httpClient.PostAsXmlAsync(url, requestParameters); break; case ProvisioningTemplateWebhookBodyFormat.FormUrlEncoded: var content = new FormUrlEncodedContent(requestParameters); await httpClient.PostAsync(url, content); break; } }); } else { switch (webhook.BodyFormat) { case ProvisioningTemplateWebhookBodyFormat.Json: httpClient.PostAsJsonAsync(url, requestParameters).GetAwaiter().GetResult(); break; case ProvisioningTemplateWebhookBodyFormat.Xml: httpClient.PostAsXmlAsync(url, requestParameters).GetAwaiter().GetResult(); break; case ProvisioningTemplateWebhookBodyFormat.FormUrlEncoded: var content = new FormUrlEncodedContent(requestParameters); httpClient.PostAsync(url, content).GetAwaiter().GetResult(); break; } } } catch (HttpRequestException ex) { scope.LogError(ex, "Error calling provisioning template webhook"); } break; } } } } } } }
private static void UpdateContentType(Web web, Microsoft.SharePoint.Client.ContentType existingContentType, ContentType templateContentType, TokenParser parser, PnPMonitoredScope scope) { var isDirty = false; if (existingContentType.Hidden != templateContentType.Hidden) { scope.LogPropertyUpdate("Hidden"); existingContentType.Hidden = templateContentType.Hidden; isDirty = true; } if (existingContentType.ReadOnly != templateContentType.ReadOnly) { scope.LogPropertyUpdate("ReadOnly"); existingContentType.ReadOnly = templateContentType.ReadOnly; isDirty = true; } if (existingContentType.Sealed != templateContentType.Sealed) { scope.LogPropertyUpdate("Sealed"); existingContentType.Sealed = templateContentType.Sealed; isDirty = true; } if (templateContentType.Description != null && existingContentType.Description != parser.ParseString(templateContentType.Description)) { scope.LogPropertyUpdate("Description"); existingContentType.Description = parser.ParseString(templateContentType.Description); isDirty = true; } if (templateContentType.DocumentTemplate != null && existingContentType.DocumentTemplate != parser.ParseString(templateContentType.DocumentTemplate)) { scope.LogPropertyUpdate("DocumentTemplate"); existingContentType.DocumentTemplate = parser.ParseString(templateContentType.DocumentTemplate); isDirty = true; } if (existingContentType.Name != parser.ParseString(templateContentType.Name)) { scope.LogPropertyUpdate("Name"); existingContentType.Name = parser.ParseString(templateContentType.Name); isDirty = true; } if (templateContentType.Group != null && existingContentType.Group != parser.ParseString(templateContentType.Group)) { scope.LogPropertyUpdate("Group"); existingContentType.Group = parser.ParseString(templateContentType.Group); isDirty = true; } if (isDirty) { existingContentType.Update(true); web.Context.ExecuteQueryRetry(); } // Delta handling List<Guid> targetIds = existingContentType.FieldLinks.AsEnumerable().Select(c1 => c1.Id).ToList(); List<Guid> sourceIds = templateContentType.FieldRefs.Select(c1 => c1.Id).ToList(); var fieldsNotPresentInTarget = sourceIds.Except(targetIds).ToArray(); if (fieldsNotPresentInTarget.Any()) { foreach (var fieldId in fieldsNotPresentInTarget) { var fieldRef = templateContentType.FieldRefs.Find(fr => fr.Id == fieldId); var field = web.Fields.GetById(fieldId); scope.LogDebug(CoreResources.Provisioning_ObjectHandlers_ContentTypes_Adding_field__0__to_content_type, fieldId); web.AddFieldToContentType(existingContentType, field, fieldRef.Required, fieldRef.Hidden); } } isDirty = false; foreach (var fieldId in targetIds.Intersect(sourceIds)) { var fieldLink = existingContentType.FieldLinks.FirstOrDefault(fl => fl.Id == fieldId); var fieldRef = templateContentType.FieldRefs.Find(fr => fr.Id == fieldId); if (fieldRef != null) { scope.LogDebug(CoreResources.Provisioning_ObjectHandlers_ContentTypes_Field__0__exists_in_content_type, fieldId); if (fieldLink.Required != fieldRef.Required) { scope.LogPropertyUpdate("Required"); fieldLink.Required = fieldRef.Required; isDirty = true; } if (fieldLink.Hidden != fieldRef.Hidden) { scope.LogPropertyUpdate("Hidden"); fieldLink.Hidden = fieldRef.Hidden; isDirty = true; } } } // The new CT is a DocumentSet, and the target should be, as well if (templateContentType.DocumentSetTemplate != null) { if (!Microsoft.SharePoint.Client.DocumentSet.DocumentSetTemplate.IsChildOfDocumentSetContentType(web.Context, existingContentType).Value) { scope.LogError(CoreResources.Provisioning_ObjectHandlers_ContentTypes_InvalidDocumentSet_Update_Request, existingContentType.Id, existingContentType.Name); } else { Microsoft.SharePoint.Client.DocumentSet.DocumentSetTemplate templateToUpdate = Microsoft.SharePoint.Client.DocumentSet.DocumentSetTemplate.GetDocumentSetTemplate(web.Context, existingContentType); // TODO: Implement Delta Handling scope.LogWarning(CoreResources.Provisioning_ObjectHandlers_ContentTypes_DocumentSet_DeltaHandling_OnHold, existingContentType.Id, existingContentType.Name); } } if (isDirty) { existingContentType.Update(true); web.Context.ExecuteQueryRetry(); } }
private TokenParser ProcessLookupFields(Web web, ProvisioningTemplate template, TokenParser parser, PnPMonitoredScope scope) { var rootWeb = (web.Context as ClientContext).Site.RootWeb; rootWeb.Context.Load(rootWeb.Lists, lists => lists.Include(l => l.Id, l => l.RootFolder.ServerRelativeUrl, l => l.Fields).Where(l => l.Hidden == false)); rootWeb.Context.ExecuteQueryRetry(); foreach (var siteField in template.SiteFields) { var fieldElement = XElement.Parse(siteField.SchemaXml); if (fieldElement.Attribute("List") != null) { var fieldId = Guid.Parse(fieldElement.Attribute("ID").Value); var listIdentifier = parser.ParseString(fieldElement.Attribute("List").Value); var relationshipDeleteBehavior = fieldElement.Attribute("RelationshipDeleteBehavior") != null?fieldElement.Attribute("RelationshipDeleteBehavior").Value : string.Empty; var webId = string.Empty; var field = rootWeb.Fields.GetById(fieldId); rootWeb.Context.Load(field, f => f.SchemaXmlWithResourceTokens); rootWeb.Context.ExecuteQueryRetry(); List sourceList = FindSourceList(listIdentifier, web, rootWeb); if (sourceList != null) { rootWeb.Context.Load(sourceList.ParentWeb); rootWeb.Context.ExecuteQueryRetry(); webId = sourceList.ParentWeb.Id.ToString(); ProcessField(field, sourceList.Id, webId, relationshipDeleteBehavior); } } } web.Context.Load(web.Lists, lists => lists.Include(l => l.Id, l => l.RootFolder.ServerRelativeUrl, l => l.Fields).Where(l => l.Hidden == false)); web.Context.ExecuteQueryRetry(); foreach (var listInstance in template.Lists) { foreach (var listField in listInstance.Fields) { var fieldElement = XElement.Parse(listField.SchemaXml); if (fieldElement.Attribute("List") == null) { continue; } var fieldId = Guid.Parse(fieldElement.Attribute("ID").Value); var listIdentifier = parser.ParseString(fieldElement.Attribute("List").Value); var relationshipDeleteBehavior = fieldElement.Attribute("RelationshipDeleteBehavior") != null?fieldElement.Attribute("RelationshipDeleteBehavior").Value : string.Empty; var webId = string.Empty; var listUrl = UrlUtility.Combine(web.ServerRelativeUrl, parser.ParseString(listInstance.Url)); var createdList = web.Lists.FirstOrDefault(l => l.RootFolder.ServerRelativeUrl.Equals(listUrl, StringComparison.OrdinalIgnoreCase)); if (createdList != null) { try { var field = createdList.Fields.GetById(fieldId); web.Context.Load(field, f => f.SchemaXmlWithResourceTokens); web.Context.ExecuteQueryRetry(); List sourceList = FindSourceList(listIdentifier, web, rootWeb); if (sourceList != null) { web.Context.Load(sourceList.ParentWeb); web.Context.ExecuteQueryRetry(); webId = sourceList.ParentWeb.Id.ToString(); ProcessField(field, sourceList.Id, webId, relationshipDeleteBehavior); } } catch (ArgumentException ex) { // We skip and log any issues related to not existing lookup fields scope.LogError($"Exception searching for field! {ex.Message}"); } } } } return(parser); }
private void ExtractMasterPagesAndPageLayouts(Web web, ProvisioningTemplate template, TokenParser parser, PnPMonitoredScope scope, ProvisioningTemplateCreationInformation creationInfo) { String webApplicationUrl = TokenParser.GetWebApplicationUrl(web); if (!String.IsNullOrEmpty(webApplicationUrl)) { // Get the Publishing Feature reference template ProvisioningTemplate publishingFeatureTemplate = GetPublishingFeatureBaseTemplate(); // Get a reference to the root folder of the master page gallery var gallery = web.GetCatalog(116); web.Context.Load(gallery, g => g.RootFolder); web.Context.ExecuteQueryRetry(); var masterPageGalleryFolder = gallery.RootFolder; // Load the files in the master page gallery web.Context.Load(masterPageGalleryFolder.Files); web.Context.ExecuteQueryRetry(); var sourceFiles = masterPageGalleryFolder.Files.AsEnumerable().Where( f => f.Name.EndsWith(".aspx", StringComparison.InvariantCultureIgnoreCase) || f.Name.EndsWith(".html", StringComparison.InvariantCultureIgnoreCase) || f.Name.EndsWith(".master", StringComparison.InvariantCultureIgnoreCase)); foreach (var file in sourceFiles) { try { var listItem = file.EnsureProperty(f => f.ListItemAllFields); listItem.ContentType.EnsureProperties(ct => ct.Id, ct => ct.StringId); // Check if the content type is of type Master Page or Page Layout if (listItem.ContentType.StringId.StartsWith(MASTER_PAGE_CONTENT_TYPE_ID) || listItem.ContentType.StringId.StartsWith(PAGE_LAYOUT_CONTENT_TYPE_ID) || listItem.ContentType.StringId.StartsWith(HTML_MASTER_PAGE_CONTENT_TYPE_ID) || listItem.ContentType.StringId.StartsWith(HTML_PAGE_LAYOUT_CONTENT_TYPE_ID)) { // Skip any .ASPX or .MASTER file related to an .HTML designer file if ((file.Name.EndsWith(".aspx", StringComparison.InvariantCultureIgnoreCase) && sourceFiles.Any(f => f.Name.Equals(file.Name.ToLower().Replace(".aspx", ".html"), StringComparison.InvariantCultureIgnoreCase))) || (file.Name.EndsWith(".master", StringComparison.InvariantCultureIgnoreCase) && sourceFiles.Any(f => f.Name.Equals(file.Name.ToLower().Replace(".master", ".html"), StringComparison.InvariantCultureIgnoreCase)))) { continue; } // If the file is a custom one, and not one native // and coming out from the publishing feature if (creationInfo.IncludeNativePublishingFiles || !IsPublishingFeatureNativeFile(publishingFeatureTemplate, file.Name)) { var fullUri = new Uri(UrlUtility.Combine(webApplicationUrl, file.ServerRelativeUrl)); var folderPath = fullUri.Segments.Take(fullUri.Segments.Count() - 1).ToArray().Aggregate((i, x) => i + x).TrimEnd('/'); var fileName = fullUri.Segments[fullUri.Segments.Count() - 1]; string fileSrc = (null != template.Connector) ? Path.Combine(template.Connector.GetConnectionString(), fileName) : fileName; var publishingFile = new Model.File() { Folder = TokenizeUrl(folderPath, parser), Src = HttpUtility.UrlDecode(fileSrc), Overwrite = true, }; // Add field values to file RetrieveFieldValues(web, file, publishingFile, parser); // Add the file to the template template.Files.Add(publishingFile); // Persist file using connector, if needed if (creationInfo.PersistPublishingFiles) { PersistFile(web, creationInfo, scope, folderPath, fileName, true); } if (listItem.ContentType.StringId.StartsWith(MASTER_PAGE_CONTENT_TYPE_ID)) { scope.LogWarning(String.Format("The file \"{0}\" is a custom MasterPage. Accordingly to the PnP Guidance (http://aka.ms/o365pnpguidancemasterpages) you should try to avoid using custom MasterPages.", file.Name)); } } else { scope.LogWarning(String.Format("Skipping file \"{0}\" because it is native in the publishing feature.", file.Name)); } } } catch (Exception ex) { scope.LogError(String.Format("Could not extract master page or layout: {0} - {1}", ex.Message, ex.StackTrace)); } } } }
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 ProvisioningTemplate ExtractObjects(Web web, ProvisioningTemplate template, ProvisioningTemplateCreationInformation creationInfo) { using (var scope = new PnPMonitoredScope(this.Name)) { // Load object if not there #if !CLIENTSDKV15 web.EnsureProperties(w => w.Url, w => w.MasterUrl, w => w.AlternateCssUrl, w => w.SiteLogoUrl); #else web.EnsureProperties(w => w.Url, w => w.MasterUrl); #endif // Information coming from the site template.ComposedLook.MasterPage = Tokenize(web.MasterUrl, web.Url); #if !CLIENTSDKV15 template.ComposedLook.AlternateCSS = Tokenize(web.AlternateCssUrl, web.Url); template.ComposedLook.SiteLogo = Tokenize(web.SiteLogoUrl, web.Url); #else template.ComposedLook.AlternateCSS = null; template.ComposedLook.SiteLogo = null; #endif scope.LogInfo(CoreResources.Provisioning_ObjectHandlers_ComposedLooks_ExtractObjects_Retrieving_current_composed_look); Site site = (web.Context as ClientContext).Site; if (!site.IsObjectPropertyInstantiated("Url")) { web.Context.Load(site); web.Context.ExecuteQueryRetry(); } 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 || composedLook.MasterPage == null || composedLook.SiteLogo == null) { scope.LogError(CoreResources.Provisioning_ObjectHandlers_ComposedLooks_ExtractObjects_ComposedLookInfoFailedToDeserialize); throw new JsonSerializationException(); } template.ComposedLook = composedLook; if (creationInfo != null && creationInfo.PersistComposedLookFiles && 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 // Download the theme/branding specific files #if !CLIENTSDKV15 DownLoadFile(spConnector, spConnectorRoot, creationInfo.FileConnector, web.Url, web.AlternateCssUrl, scope); DownLoadFile(spConnector, spConnectorRoot, creationInfo.FileConnector, web.Url, web.SiteLogoUrl, scope); #endif 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)) { template.Files.Add(GetComposedLookFile(template.ComposedLook.BackgroundFile)); } if (!string.IsNullOrEmpty(template.ComposedLook.ColorFile)) { template.Files.Add(GetComposedLookFile(template.ComposedLook.ColorFile)); } if (!string.IsNullOrEmpty(template.ComposedLook.FontFile)) { template.Files.Add(GetComposedLookFile(template.ComposedLook.FontFile)); } if (!string.IsNullOrEmpty(template.ComposedLook.SiteLogo)) { template.Files.Add(GetComposedLookFile(template.ComposedLook.SiteLogo)); } } 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; }
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.ParseString(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") && !string.IsNullOrEmpty(field.DefaultValue)) { var taxField = web.Context.CastTo <TaxonomyField>(field); ValidateTaxonomyFieldDefaultValue(taxField); } } 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(string.Format("The field was found invalid: {0}", tokenString)); } }
public override TokenParser ProvisionObjects(Web web, ProvisioningTemplate template, TokenParser parser, ProvisioningTemplateApplyingInformation applyingInformation) { web.EnsureProperty(w => w.Url); using (var scope = new PnPMonitoredScope(this.Name)) { if (template.Tenant != null) { ProcessCdns(web, template.Tenant, parser, scope); var manager = new AppManager(web.Context as ClientContext); if (template.Tenant.AppCatalog != null && template.Tenant.AppCatalog.Packages.Count > 0) { var appCatalogUri = web.GetAppCatalog(); if (appCatalogUri != null) { foreach (var app in template.Tenant.AppCatalog.Packages) { AppMetadata appMetadata = null; if (app.Action == PackageAction.Upload || app.Action == PackageAction.UploadAndPublish) { using (var packageStream = GetPackageStream(template, app)) { var memStream = new MemoryStream(); packageStream.CopyTo(memStream); memStream.Position = 0; var appFilename = app.Src.Substring(app.Src.LastIndexOf('\\') + 1); appMetadata = manager.Add(memStream.ToArray(), appFilename, app.Overwrite); parser.Tokens.Add(new AppPackageIdToken(web, appFilename, appMetadata.Id)); } } if (app.Action == PackageAction.Publish || app.Action == PackageAction.UploadAndPublish) { if (appMetadata == null) { appMetadata = manager.GetAvailable() .FirstOrDefault(a => a.Id == Guid.Parse(parser.ParseString(app.PackageId))); } if (appMetadata != null) { manager.Deploy(appMetadata, app.SkipFeatureDeployment); } else { scope.LogError("Referenced App Package {0} not available", app.PackageId); throw new Exception($"Referenced App Package {app.PackageId} not available"); } } if (app.Action == PackageAction.Remove) { var appId = Guid.Parse(parser.ParseString(app.PackageId)); // Get the apps already installed in the site var appExists = manager.GetAvailable()?.Any(a => a.Id == appId); if (appExists.HasValue && appExists.Value) { manager.Remove(appId); } else { WriteMessage($"App Package with ID {appId} does not exist in the AppCatalog and cannot be removed!", ProvisioningMessageType.Warning); } } } } else { WriteMessage($"Tenant app catalog doesn't exist. ALM step will be skipped!", ProvisioningMessageType.Warning); } } // So far we do not provision CDN settings // It will come in the near future // NOOP on CDN } } return(parser); }
private bool PersistFile(Web web, ProvisioningTemplateCreationInformation creationInfo, PnPMonitoredScope scope, string serverRelativeUrl) { var success = false; if (creationInfo.PersistBrandingFiles) { if (creationInfo.FileConnector != null) { try { var file = web.GetFileByServerRelativeUrl(serverRelativeUrl); string fileName = string.Empty; if (serverRelativeUrl.IndexOf("/") > -1) { fileName = serverRelativeUrl.Substring(serverRelativeUrl.LastIndexOf("/") + 1); } else { fileName = serverRelativeUrl; } web.Context.Load(file); web.Context.ExecuteQueryRetry(); ClientResult<Stream> stream = file.OpenBinaryStream(); web.Context.ExecuteQueryRetry(); using (Stream memStream = new MemoryStream()) { CopyStream(stream.Value, memStream); memStream.Position = 0; creationInfo.FileConnector.SaveFileStream(fileName, memStream); } success = true; } catch (ServerException ex1) { // If we are referring a file from a location outside of the current web or at a location where we cannot retrieve the file an exception is thrown. We swallow this exception. if (ex1.ServerErrorCode != -2147024809) { throw; } else { scope.LogWarning("File is not necessarily located in the current web. Not retrieving {0}", serverRelativeUrl); } } } else { WriteWarning("No connector present to persist homepage.", ProvisioningMessageType.Error); scope.LogError("No connector present to persist homepage"); } } else { success = true; } return success; }
public override 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 Microsoft.SharePoint.Client.FieldCollection fields = list.Fields; web.Context.Load(fields, fs => fs.Include(f => f.InternalName, f => f.FieldTypeKind)); web.Context.ExecuteQueryRetry(); foreach (var dataRow in listInstance.DataRows) { try { scope.LogDebug(CoreResources.Provisioning_ObjectHandlers_ListInstancesDataRows_Creating_list_item__0_, listInstance.DataRows.IndexOf(dataRow) + 1); var listitemCI = new ListItemCreationInformation(); var listitem = list.AddItem(listitemCI); foreach (var dataValue in dataRow.Values) { Field dataField = fields.FirstOrDefault( f => f.InternalName == parser.ParseString(dataValue.Key)); if (dataField != null) { String fieldValue = parser.ParseString(dataValue.Value); switch (dataField.FieldTypeKind) { case FieldType.Geolocation: // FieldGeolocationValue - Expected format: Altitude,Latitude,Longitude,Measure var geolocationArray = fieldValue.Split(','); if (geolocationArray.Length == 4) { var geolocationValue = new FieldGeolocationValue { Altitude = Double.Parse(geolocationArray[0]), Latitude = Double.Parse(geolocationArray[1]), Longitude = Double.Parse(geolocationArray[2]), Measure = Double.Parse(geolocationArray[3]), }; listitem[parser.ParseString(dataValue.Key)] = geolocationValue; } else { listitem[parser.ParseString(dataValue.Key)] = fieldValue; } break; case FieldType.Lookup: // FieldLookupValue - Expected format: LookupID or LookupID,LookupID,LookupID... if (fieldValue.Contains(",")) { var lookupValues = new List <FieldLookupValue>(); fieldValue.Split(',').All(value => { lookupValues.Add(new FieldLookupValue { LookupId = int.Parse(value), }); return(true); }); listitem[parser.ParseString(dataValue.Key)] = lookupValues.ToArray(); } else { var lookupValue = new FieldLookupValue { LookupId = int.Parse(fieldValue), }; listitem[parser.ParseString(dataValue.Key)] = lookupValue; } break; case FieldType.URL: // FieldUrlValue - Expected format: URL,Description var urlArray = fieldValue.Split(','); var linkValue = new FieldUrlValue(); if (urlArray.Length == 2) { linkValue.Url = urlArray[0]; linkValue.Description = urlArray[1]; } else { linkValue.Url = urlArray[0]; linkValue.Description = urlArray[0]; } listitem[parser.ParseString(dataValue.Key)] = linkValue; break; case FieldType.User: // FieldUserValue - Expected format: loginName or loginName,loginName,loginName... if (fieldValue.Contains(",")) { var userValues = new List <FieldUserValue>(); fieldValue.Split(',').All(value => { var user = web.EnsureUser(value); web.Context.Load(user); web.Context.ExecuteQueryRetry(); if (user != null) { userValues.Add(new FieldUserValue { LookupId = user.Id, });; } return(true); }); listitem[parser.ParseString(dataValue.Key)] = userValues.ToArray(); } else { var user = web.EnsureUser(fieldValue); web.Context.Load(user); web.Context.ExecuteQueryRetry(); if (user != null) { var userValue = new FieldUserValue { LookupId = user.Id, }; listitem[parser.ParseString(dataValue.Key)] = userValue; } else { listitem[parser.ParseString(dataValue.Key)] = fieldValue; } } break; case FieldType.DateTime: var dateTime = DateTime.MinValue; if (DateTime.TryParse(fieldValue, out dateTime)) { listitem[parser.ParseString(dataValue.Key)] = dateTime; } break; default: listitem[parser.ParseString(dataValue.Key)] = fieldValue; break; } } listitem.Update(); } web.Context.ExecuteQueryRetry(); // TODO: Run in batches? if (dataRow.Security != null && dataRow.Security.RoleAssignments.Count != 0) { listitem.SetSecurity(parser, dataRow.Security); } } catch (Exception ex) { scope.LogError(CoreResources.Provisioning_ObjectHandlers_ListInstancesDataRows_Creating_listitem_failed___0_____1_, ex.Message, ex.StackTrace); throw; } } } } #endregion } } return(parser); }
public static TokenParser ProcessApps(Tenant tenant, ProvisioningTenant provisioningTenant, FileConnectorBase connector, TokenParser parser, PnPMonitoredScope scope, ApplyConfiguration configuration, ProvisioningMessagesDelegate messagesDelegate) { if (provisioningTenant.AppCatalog != null && provisioningTenant.AppCatalog.Packages.Count > 0) { var rootSiteUrl = tenant.GetRootSiteUrl(); tenant.Context.ExecuteQueryRetry(); using (var context = ((ClientContext)tenant.Context).Clone(rootSiteUrl.Value, configuration.AccessTokens)) { var web = context.Web; Uri appCatalogUri = null; try { appCatalogUri = web.GetAppCatalog(); } catch (System.Net.WebException ex) { if (ex.Response != null) { var httpResponse = ex.Response as System.Net.HttpWebResponse; if (httpResponse != null && httpResponse.StatusCode == HttpStatusCode.Unauthorized) { // Ignore any security exception and simply keep // the AppCatalog URI null } else { throw ex; } } else { throw ex; } } if (appCatalogUri != null) { var manager = new AppManager(context); foreach (var app in provisioningTenant.AppCatalog.Packages) { AppMetadata appMetadata = null; if (app.Action == PackageAction.Upload || app.Action == PackageAction.UploadAndPublish) { var appSrc = parser.ParseString(app.Src); var appBytes = ConnectorFileHelper.GetFileBytes(connector, appSrc); var hash = string.Empty; using (var memoryStream = new MemoryStream(appBytes)) { hash = CalculateHash(memoryStream); } var exists = false; var appId = Guid.Empty; using (var appCatalogContext = ((ClientContext)tenant.Context).Clone(appCatalogUri, configuration.AccessTokens)) { // check if the app already is present var appList = appCatalogContext.Web.GetListByUrl("AppCatalog"); var camlQuery = new CamlQuery { ViewXml = string.Format(appExistsQuery, hash) }; var items = appList.GetItems(camlQuery); appCatalogContext.Load(items, i => i.IncludeWithDefaultProperties()); appCatalogContext.ExecuteQueryRetry(); if (items.Count > 0) { exists = true; appId = Guid.Parse(items[0].FieldValues["UniqueId"].ToString()); } } var appFilename = appSrc.Substring(appSrc.LastIndexOf('\\') + 1); if (!exists) { messagesDelegate?.Invoke($"Processing solution {app.Src}", ProvisioningMessageType.Progress); appMetadata = manager.Add(appBytes, appFilename, app.Overwrite, timeoutSeconds: 500); } else { messagesDelegate?.Invoke($"Skipping existing solution {app.Src}", ProvisioningMessageType.Progress); appMetadata = manager.GetAvailable().FirstOrDefault(a => a.Id == appId); } if (appMetadata != null) { parser.AddToken(new AppPackageIdToken(web, appFilename, appMetadata.Id)); parser.AddToken(new AppPackageIdToken(web, appMetadata.Title, appMetadata.Id)); } } if (app.Action == PackageAction.Publish || app.Action == PackageAction.UploadAndPublish) { if (appMetadata == null) { appMetadata = manager.GetAvailable() .FirstOrDefault(a => a.Id == Guid.Parse(parser.ParseString(app.PackageId))); } if (appMetadata != null) { manager.Deploy(appMetadata, app.SkipFeatureDeployment); } else { scope.LogError("Referenced App Package {0} not available", app.PackageId); throw new Exception($"Referenced App Package {app.PackageId} not available"); } } if (app.Action == PackageAction.Remove) { var appId = Guid.Parse(parser.ParseString(app.PackageId)); // Get the apps already installed in the site var appExists = manager.GetAvailable()?.Any(a => a.Id == appId); if (appExists.HasValue && appExists.Value) { manager.Remove(appId); } else { messagesDelegate?.Invoke($"App Package with ID {appId} does not exist in the AppCatalog and cannot be removed!", ProvisioningMessageType.Warning); } } } } else { messagesDelegate?.Invoke($"Tenant app catalog doesn't exist. ALM step will be skipped!", ProvisioningMessageType.Warning); } } } return(parser); }
/// <summary> /// Helper method to create or update an object through the Microsoft Graph /// </summary> /// <param name="scope">The PnP Provisioning Scope</param> /// <param name="method">The HTTP method to use</param> /// <param name="uri">The URI for the Graph request</param> /// <param name="content">The content of the Graph request</param> /// <param name="contentType">The content type of the Graph request</param> /// <param name="accessToken">The OAuth 2.0 Access Token</param> /// <param name="alreadyExistsErrorMessage">The error message token that identifies an already existing item</param> /// <param name="warningMessage">The warning message to log when the target item already exists</param> /// <param name="matchingFieldName">The name of a field to match an already existing instance of the target item</param> /// <param name="matchingFieldValue">The value of a field to match an already existing instance of the target item</param> /// <param name="errorMessage">The error message to log when the create or update action fails</param> /// <param name="canPatch">Defines whether a Patch HTTP request can be executed to update an already existing target item</param> /// <returns>The ID of the create or updated target item</returns> public static String CreateOrUpdateGraphObject( PnPMonitoredScope scope, HttpMethodVerb method, String uri, Object content, String contentType, String accessToken, String alreadyExistsErrorMessage, String warningMessage, String matchingFieldName, String matchingFieldValue, String errorMessage, Boolean canPatch ) { try { String itemId = null; String json = null; HttpResponseHeaders responseHeaders; // Try to create the Graph object switch (method) { case HttpMethodVerb.POST: json = HttpHelper.MakePostRequestForString(uri, content, contentType, accessToken); if (!string.IsNullOrEmpty(json)) { itemId = JToken.Parse(json).Value <String>("id"); } break; case HttpMethodVerb.PUT: json = HttpHelper.MakePutRequestForString(uri, content, contentType, accessToken); if (!string.IsNullOrEmpty(json)) { itemId = JToken.Parse(json).Value <String>("id"); } break; case HttpMethodVerb.POST_WITH_RESPONSE_HEADERS: responseHeaders = HttpHelper.MakePostRequestForHeaders(uri, content, contentType, accessToken); itemId = responseHeaders.Location.ToString().Split('\'')[1]; break; } // Return the ID of the just created item return(itemId); } catch (Exception ex) { // In case of exception, let's see if the target item already exists if (!String.IsNullOrEmpty(alreadyExistsErrorMessage) && !String.IsNullOrEmpty(matchingFieldName) && !String.IsNullOrEmpty(matchingFieldValue) && ex.InnerException.Message.Contains(alreadyExistsErrorMessage)) { try { if (!String.IsNullOrEmpty(warningMessage)) { scope.LogWarning(warningMessage); } // If it's a POST we need to look for any existing item String id = null; // In case of PUT we already have the id if (method == HttpMethodVerb.POST || method == HttpMethodVerb.POST_WITH_RESPONSE_HEADERS) { // Filter by field and value specified id = ItemAlreadyExists(uri, matchingFieldName, matchingFieldValue, accessToken); uri = $"{uri}/{id}"; } else { id = matchingFieldValue; } // Patch the item, if supported if (canPatch) { HttpHelper.MakePatchRequestForString(uri, content, contentType, accessToken); } return(id); } catch (Exception exUpdate) { if (!String.IsNullOrEmpty(errorMessage)) { scope.LogError(errorMessage, exUpdate.Message); } return(null); } } else { return(null); } } }
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.ParseString(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); web.Context.ExecuteQueryRetry(); bool isDirty = false; #if !CLIENTSDKV15 if (originalFieldXml.ContainsResourceToken()) { var originalFieldElement = XElement.Parse(originalFieldXml); var nameAttributeValue = originalFieldElement.Attribute("Name") != null ? originalFieldElement.Attribute("Name").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.ExecuteQuery(); } if ((field.TypeAsString == "TaxonomyFieldType" || field.TypeAsString == "TaxonomyFieldTypeMulti") && !string.IsNullOrEmpty(field.DefaultValue)) { var taxField = web.Context.CastTo<TaxonomyField>(field); ValidateTaxonomyFieldDefaultValue(taxField); } } 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(string.Format("The field was found invalid: {0}", tokenString)); } }
private void CallWebHooks(ProvisioningTemplate template, TokenParser parser, ProvisioningTemplateWebhookKind kind, ObjectHandlerBase objectHandler = null) { using (var scope = new PnPMonitoredScope("ProvisioningTemplate WebHook Call")) { if (template.ProvisioningTemplateWebhooks != null && template.ProvisioningTemplateWebhooks.Any()) { foreach (var webhook in template.ProvisioningTemplateWebhooks.Where(w => w.Kind == kind)) { var requestParameters = new Dictionary <String, String>(); SimpleTokenParser internalParser = new SimpleTokenParser(); foreach (var webhookparam in webhook.Parameters) { requestParameters.Add(webhookparam.Key, parser.ParseString(webhookparam.Value)); internalParser.AddToken(new WebhookParameter(webhookparam.Key, requestParameters[webhookparam.Key])); } var url = parser.ParseString(webhook.Url); // parse for template scoped parameters url = internalParser.ParseString(url); // parse for webhook scoped parameters switch (webhook.Method) { case ProvisioningTemplateWebhookMethod.GET: { if (kind == ProvisioningTemplateWebhookKind.ObjectHandlerProvisioningStarted || kind == ProvisioningTemplateWebhookKind.ObjectHandlerProvisioningCompleted) { url += $"&__handler={objectHandler.InternalName}"; // add the handler name to the REST request URL url += $"&__webhookKind={kind.ToString()}"; // add the webhook kind to the REST request URL } try { if (webhook.Async) { Task.Factory.StartNew(async() => { await httpClient.GetAsync(url); }); } else { httpClient.GetAsync(url).GetAwaiter().GetResult(); } } catch (HttpRequestException ex) { scope.LogError(ex, "Error calling provisioning template webhook"); } break; } case ProvisioningTemplateWebhookMethod.POST: { requestParameters.Add("__webhookKind", kind.ToString()); // add the webhook kind to the parameters of the request body if (kind == ProvisioningTemplateWebhookKind.ObjectHandlerProvisioningCompleted || kind == ProvisioningTemplateWebhookKind.ObjectHandlerProvisioningStarted) { requestParameters.Add("__handler", objectHandler.InternalName); // add the handler name to the parameters of the request body } try { if (webhook.Async) { Task.Factory.StartNew(async() => { switch (webhook.BodyFormat) { case ProvisioningTemplateWebhookBodyFormat.Json: await httpClient.PostAsJsonAsync(url, requestParameters); break; case ProvisioningTemplateWebhookBodyFormat.Xml: await httpClient.PostAsXmlAsync(url, requestParameters); break; case ProvisioningTemplateWebhookBodyFormat.FormUrlEncoded: var content = new FormUrlEncodedContent(requestParameters); await httpClient.PostAsync(url, content); break; } }); } else { switch (webhook.BodyFormat) { case ProvisioningTemplateWebhookBodyFormat.Json: httpClient.PostAsJsonAsync(url, requestParameters).GetAwaiter().GetResult(); break; case ProvisioningTemplateWebhookBodyFormat.Xml: httpClient.PostAsXmlAsync(url, requestParameters).GetAwaiter().GetResult(); break; case ProvisioningTemplateWebhookBodyFormat.FormUrlEncoded: var content = new FormUrlEncodedContent(requestParameters); httpClient.PostAsync(url, content).GetAwaiter().GetResult(); break; } } } catch (HttpRequestException ex) { scope.LogError(ex, "Error calling provisioning template webhook"); } break; } } } } } }
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().Select(existingList => existingList.RootFolder.ServerRelativeUrl).ToList(); var serverRelativeUrl = web.ServerRelativeUrl; var processedLists = new List<ListInfo>(); #region Lists foreach (var templateList in template.Lists) { // Check for the presence of the references content types and throw an exception if not present or in template if (templateList.ContentTypesEnabled) { var existingCts = web.Context.LoadQuery(web.AvailableContentTypes); web.Context.ExecuteQueryRetry(); foreach (var ct in templateList.ContentTypeBindings) { var found = template.ContentTypes.Any(t => t.Id.ToUpperInvariant() == ct.ContentTypeId.ToUpperInvariant()); if (found == false) { found = existingCts.Any(t => t.StringId.ToUpperInvariant() == ct.ContentTypeId.ToUpperInvariant()); } if (!found) { scope.LogError("Referenced content type {0} not available in site or in template", ct.ContentTypeId); throw new Exception(string.Format("Referenced content type {0} not available in site or in template", ct.ContentTypeId)); } } } var index = existingLists.FindIndex(x => x.Equals(UrlUtility.Combine(serverRelativeUrl, templateList.Url), StringComparison.OrdinalIgnoreCase)); if (index == -1) { try { scope.LogDebug(CoreResources.Provisioning_ObjectHandlers_ListInstances_Creating_list__0_, templateList.Title); var returnTuple = CreateList(web, templateList, parser, scope); var createdList = returnTuple.Item1; parser = returnTuple.Item2; processedLists.Add(new ListInfo { SiteList = createdList, TemplateList = templateList }); parser.AddToken(new ListIdToken(web, templateList.Title, createdList.Id)); parser.AddToken(new ListUrlToken(web, templateList.Title, createdList.RootFolder.ServerRelativeUrl.Substring(web.ServerRelativeUrl.Length + 1))); } catch (Exception ex) { scope.LogDebug(CoreResources.Provisioning_ObjectHandlers_ListInstances_Creating_list__0__failed___1_____2_, templateList.Title, ex.Message, ex.StackTrace); throw; } } else { try { scope.LogDebug(CoreResources.Provisioning_ObjectHandlers_ListInstances_Updating_list__0_, templateList.Title); var existingList = web.Lists[index]; var returnTuple = UpdateList(web, existingList, templateList, parser, scope); var updatedList = returnTuple.Item1; parser = returnTuple.Item2; if (updatedList != null) { processedLists.Add(new ListInfo { SiteList = updatedList, TemplateList = templateList }); } } catch (Exception ex) { scope.LogDebug(CoreResources.Provisioning_ObjectHandlers_ListInstances_Updating_list__0__failed___1_____2_, templateList.Title, ex.Message, ex.StackTrace); throw; } } } #endregion #region FieldRefs foreach (var listInfo in processedLists) { if (listInfo.TemplateList.FieldRefs.Any()) { foreach (var fieldRef in listInfo.TemplateList.FieldRefs) { var field = rootWeb.GetFieldById<Field>(fieldRef.Id); if (field != null) { if (!listInfo.SiteList.FieldExistsById(fieldRef.Id)) { CreateFieldRef(listInfo, field, fieldRef); } else { UpdateFieldRef(listInfo.SiteList, field.Id, fieldRef); } } } listInfo.SiteList.Update(); web.Context.ExecuteQueryRetry(); } } #endregion #region Fields foreach (var listInfo in processedLists) { if (listInfo.TemplateList.Fields.Any()) { foreach (var field in listInfo.TemplateList.Fields) { var fieldElement = XElement.Parse(parser.ParseString(field.SchemaXml, "~sitecollection", "~site")); if (fieldElement.Attribute("ID") == null) { scope.LogError(CoreResources.Provisioning_ObjectHandlers_ListInstances_Field_schema_has_no_ID_attribute___0_, field.SchemaXml); throw new Exception(string.Format(CoreResources.Provisioning_ObjectHandlers_ListInstances_Field_schema_has_no_ID_attribute___0_, field.SchemaXml)); } var id = fieldElement.Attribute("ID").Value; Guid fieldGuid; if (!Guid.TryParse(id, out fieldGuid)) { scope.LogError(CoreResources.Provisioning_ObjectHandlers_ListInstances_ID_for_field_is_not_a_valid_Guid___0_, field.SchemaXml); throw new Exception(string.Format(CoreResources.Provisioning_ObjectHandlers_ListInstances_ID_for_field_is_not_a_valid_Guid___0_, id)); } else { var fieldFromList = listInfo.SiteList.GetFieldById<Field>(fieldGuid); if (fieldFromList == null) { try { scope.LogDebug(CoreResources.Provisioning_ObjectHandlers_ListInstances_Creating_field__0_, fieldGuid); CreateField(fieldElement, listInfo, parser); } catch (Exception ex) { scope.LogError(CoreResources.Provisioning_ObjectHandlers_ListInstances_Creating_field__0__failed___1_____2_, fieldGuid, ex.Message, ex.StackTrace); throw; } } else { try { scope.LogDebug(CoreResources.Provisioning_ObjectHandlers_ListInstances_Updating_field__0_, fieldGuid); UpdateField(web, listInfo, fieldGuid, fieldElement, fieldFromList, scope, parser); } catch (Exception ex) { scope.LogError(CoreResources.Provisioning_ObjectHandlers_ListInstances_Updating_field__0__failed___1_____2_, fieldGuid, ex.Message, ex.StackTrace); throw; } } } } } listInfo.SiteList.Update(); web.Context.ExecuteQueryRetry(); } #endregion #region Default Field Values foreach (var listInfo in processedLists) { if (listInfo.TemplateList.FieldDefaults.Any()) { foreach (var fieldDefault in listInfo.TemplateList.FieldDefaults) { var field = listInfo.SiteList.Fields.GetByInternalNameOrTitle(fieldDefault.Key); field.DefaultValue = fieldDefault.Value; field.Update(); web.Context.ExecuteQueryRetry(); } } } #endregion #region Views foreach (var listInfo in processedLists) { var list = listInfo.TemplateList; var createdList = listInfo.SiteList; if (list.Views.Any() && list.RemoveExistingViews) { while (createdList.Views.Any()) { createdList.Views[0].DeleteObject(); } web.Context.ExecuteQueryRetry(); } var existingViews = createdList.Views; web.Context.Load(existingViews, vs => vs.Include(v => v.Title, v => v.Id)); web.Context.ExecuteQueryRetry(); foreach (var view in list.Views) { CreateView(web, view, existingViews, createdList, scope); } //// 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 // If an existing view is updated, and the list is to be listed on the QuickLaunch, it is removed because the existing view will be deleted and recreated from scratch. foreach (var listInfo in processedLists) { listInfo.SiteList.OnQuickLaunch = listInfo.TemplateList.OnQuickLaunch; listInfo.SiteList.Update(); } web.Context.ExecuteQueryRetry(); } } return parser; }
public static TokenParser ProcessO365GroupSettings(Tenant tenant, ProvisioningTenant provisioningTenant, TokenParser parser, PnPMonitoredScope scope, ProvisioningMessagesDelegate messagesDelegate) { if (provisioningTenant.Office365GroupsSettings != null && provisioningTenant.Office365GroupsSettings.Properties.Any()) { messagesDelegate?.Invoke("Processing Office 365 Group Settings", ProvisioningMessageType.Progress); bool siteClassificationSettingsExists = false; if (PnPProvisioningContext.Current != null) { string accessToken = string.Empty; try { // Get a fresh Access Token for every request accessToken = PnPProvisioningContext.Current.AcquireToken(GraphHelper.MicrosoftGraphBaseURI, "Directory.ReadWrite.All"); if (accessToken != null) { try { var siteClassificationSettings = tenant.GetSiteClassificationsSettings(accessToken); siteClassificationSettingsExists = true; } catch (Exception) { // Tenant classification doesn't exist, just swallow the exception. } var azureEnvironment = AzureEnvironment.Production; if (PnPProvisioningContext.Current != null) { azureEnvironment = PnPProvisioningContext.Current.AzureEnvironment; } if (siteClassificationSettingsExists) { // Tenant classification exists, update the necessary values for Group Settings. try { string directorySettingTemplatesUrl = $"{GraphHttpClient.GetGraphEndPointUrl(azureEnvironment)}groupSettings"; var directorySettingTemplatesJson = GraphHttpClient.MakeGetRequestForString(directorySettingTemplatesUrl, accessToken); var directorySettingTemplates = JsonConvert.DeserializeObject <DirectorySettingTemplates>(directorySettingTemplatesJson); // Retrieve the setinngs for "Group.Unified" var unifiedGroupSetting = directorySettingTemplates.Templates.FirstOrDefault(t => t.DisplayName == "Group.Unified"); if (unifiedGroupSetting != null) { var props = provisioningTenant.Office365GroupsSettings.Properties; foreach (var v in unifiedGroupSetting.SettingValues) { var item = props.Where(p => p.Key == v.Name).FirstOrDefault(); if (!string.IsNullOrEmpty(item.Key)) { v.Value = parser.ParseString(item.Value); } } string updateDirectorySettingUrl = $"{GraphHttpClient.GetGraphEndPointUrl(azureEnvironment)}groupSettings/{unifiedGroupSetting.Id}"; var updateDirectorySettingResult = GraphHttpClient.MakePatchRequestForString( updateDirectorySettingUrl, content: new { templateId = unifiedGroupSetting.Id, values = from v in unifiedGroupSetting.SettingValues select new { name = v.Name, value = v.Value }, }, contentType: "application/json", accessToken: accessToken); } else { throw new ApplicationException("Missing DirectorySettingTemplate for \"Group.Unified\""); } } catch (Exception ex) { scope.LogError($"Error occurred processing O365 Group settings ${ex.Message}"); } } else { // Tenant classification doesn't exist, create the necessary template for Group Settings. try { string directorySettingTemplatesUrl = $"{GraphHttpClient.GetGraphEndPointUrl(azureEnvironment)}groupSettingTemplates"; var directorySettingTemplatesJson = GraphHttpClient.MakeGetRequestForString(directorySettingTemplatesUrl, accessToken); var directorySettingTemplates = JsonConvert.DeserializeObject <DirectorySettingTemplates>(directorySettingTemplatesJson); // Retrieve the setinngs for "Group.Unified" var unifiedGroupSetting = directorySettingTemplates.Templates.FirstOrDefault(t => t.DisplayName == "Group.Unified"); if (unifiedGroupSetting != null) { var props = provisioningTenant.Office365GroupsSettings.Properties; foreach (var v in unifiedGroupSetting.SettingValues) { var item = props.Where(p => p.Key == v.Name).FirstOrDefault(); if (!string.IsNullOrEmpty(item.Key)) { v.Value = parser.ParseString(item.Value); } else { // Set default value because null is not supported // It only accepts entire collection and not individual properties v.Value = v.DefaultValue; } } string updateDirectorySettingUrl = $"{GraphHttpClient.GetGraphEndPointUrl(azureEnvironment)}groupSettings"; var updateDirectorySettingResult = GraphHttpClient.MakePostRequestForString( updateDirectorySettingUrl, content: new { templateId = unifiedGroupSetting.Id, values = from v in unifiedGroupSetting.SettingValues select new { name = v.Name, value = v.Value }, }, contentType: "application/json", accessToken: accessToken); } else { throw new ApplicationException("Missing DirectorySettingTemplate for \"Group.Unified\""); } } catch (Exception ex) { scope.LogError($"Error occurred processing O365 Group settings ${ex.Message}"); } } } } catch (Exception ex) { scope.LogError($"Error occurred processing O365 Group settings ${ex.Message}"); } } } 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; }
/// <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; } // Check if scope is present and if so, matches the current site. When scope was not set the returned value will be ProvisioningTemplateScope.Undefined if (template.Scope == ProvisioningTemplateScope.RootSite) { if (web.IsSubSite()) { scope.LogError(CoreResources.SiteToTemplateConversion_ScopeOfTemplateDoesNotMatchTarget); throw new Exception(CoreResources.SiteToTemplateConversion_ScopeOfTemplateDoesNotMatchTarget); } } var currentCultureInfoValue = System.Threading.Thread.CurrentThread.CurrentCulture.LCID; if (!string.IsNullOrEmpty(template.TemplateCultureInfo)) { int cultureInfoValue = System.Threading.Thread.CurrentThread.CurrentCulture.LCID; if (int.TryParse(template.TemplateCultureInfo, out cultureInfoValue)) { System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo(cultureInfoValue); } else { System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo(template.TemplateCultureInfo); } } // Check if the target site shares the same base template with the template's source site var targetSiteTemplateId = web.GetBaseTemplateId(); if (!String.IsNullOrEmpty(targetSiteTemplateId) && !String.IsNullOrEmpty(template.BaseSiteTemplate)) { if (!targetSiteTemplateId.Equals(template.BaseSiteTemplate, StringComparison.InvariantCultureIgnoreCase)) { var templatesNotMatchingWarning = String.Format(CoreResources.Provisioning_Asymmetric_Base_Templates, template.BaseSiteTemplate, targetSiteTemplateId); scope.LogWarning(templatesNotMatchingWarning); if (provisioningInfo.MessagesDelegate != null) { provisioningInfo.MessagesDelegate(templatesNotMatchingWarning, ProvisioningMessageType.Warning); } } } // Always ensure the Url property is loaded. In the tokens we need this and we don't want to call ExecuteQuery as this can // impact delta scenarions (calling ExecuteQuery before the planned update is called) web.EnsureProperty(w => w.Url); List <ObjectHandlerBase> objectHandlers = new List <ObjectHandlerBase>(); if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.RegionalSettings)) { objectHandlers.Add(new ObjectRegionalSettings()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.SupportedUILanguages)) { objectHandlers.Add(new ObjectSupportedUILanguages()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.AuditSettings)) { objectHandlers.Add(new ObjectAuditSettings()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.SitePolicy)) { objectHandlers.Add(new ObjectSitePolicy()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.SiteSecurity)) { objectHandlers.Add(new ObjectSiteSecurity()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.Features)) { objectHandlers.Add(new ObjectFeatures()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.TermGroups)) { objectHandlers.Add(new ObjectTermGroups()); } // Process 3 times these providers to handle proper ordering of artefact creation when dealing with lookup fields // 1st. create fields, content and list without lookup fields if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.Fields) || provisioningInfo.HandlersToProcess.HasFlag(Handlers.Lists)) { objectHandlers.Add(new ObjectField(FieldAndListProvisioningStepHelper.Step.ListAndStandardFields)); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.ContentTypes)) { objectHandlers.Add(new ObjectContentType(FieldAndListProvisioningStepHelper.Step.ListAndStandardFields)); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.Lists)) { objectHandlers.Add(new ObjectListInstance(FieldAndListProvisioningStepHelper.Step.ListAndStandardFields)); } // 2nd. create lookup fields (which requires lists to be present if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.Fields) || provisioningInfo.HandlersToProcess.HasFlag(Handlers.Lists)) { objectHandlers.Add(new ObjectField(FieldAndListProvisioningStepHelper.Step.LookupFields)); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.ContentTypes)) { objectHandlers.Add(new ObjectContentType(FieldAndListProvisioningStepHelper.Step.LookupFields)); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.Lists)) { objectHandlers.Add(new ObjectListInstance(FieldAndListProvisioningStepHelper.Step.LookupFields)); } // 3rd. Create remaining objects in lists (views, user custom actions, ...) if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.Lists)) { objectHandlers.Add(new ObjectListInstance(FieldAndListProvisioningStepHelper.Step.ListSettings)); } //if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.Fields) || provisioningInfo.HandlersToProcess.HasFlag(Handlers.Lists)) objectHandlers.Add(new ObjectLookupFields()); if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.Fields) || provisioningInfo.HandlersToProcess.HasFlag(Handlers.Lists)) { objectHandlers.Add(new ObjectListInstanceDataRows()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.Workflows)) { objectHandlers.Add(new ObjectWorkflows()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.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 !ONPREMISES if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.Tenant)) { objectHandlers.Add(new ObjectTenant()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.ApplicationLifecycleManagement)) { objectHandlers.Add(new ObjectApplicationLifecycleManagement()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.WebApiPermissions)) { objectHandlers.Add(new ObjectWebApiPermissions()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.Pages)) { objectHandlers.Add(new ObjectClientSidePages()); } #endif if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.CustomActions)) { objectHandlers.Add(new ObjectCustomActions()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.Publishing)) { objectHandlers.Add(new ObjectPublishing()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.ComposedLook)) { objectHandlers.Add(new ObjectComposedLook()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.SearchSettings)) { objectHandlers.Add(new ObjectSearchSettings()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.PropertyBagEntries)) { objectHandlers.Add(new ObjectPropertyBagEntry()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.WebSettings)) { objectHandlers.Add(new ObjectWebSettings()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.Navigation)) { objectHandlers.Add(new ObjectNavigation()); } if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.ImageRenditions)) { objectHandlers.Add(new ObjectImageRenditions()); } objectHandlers.Add(new ObjectLocalization()); // Always add this one, check is done in the handler if (provisioningInfo.HandlersToProcess.HasFlag(Handlers.ExtensibilityProviders)) { objectHandlers.Add(new ObjectExtensibilityHandlers()); } // Only persist template information in case this flag is set: this will allow the engine to // work with lesser permissions if (provisioningInfo.PersistTemplateInfo) { objectHandlers.Add(new ObjectPersistTemplateInfo()); } var count = objectHandlers.Count(o => o.ReportProgress && o.WillProvision(web, template, provisioningInfo)) + 1; if (progressDelegate != null) { progressDelegate("Initializing engine", 1, count); // handlers + initializing message) } 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 = 2; // Remove potentially unsupported artifacts var cleaner = new NoScriptTemplateCleaner(web); if (messagesDelegate != null) { cleaner.MessagesDelegate = messagesDelegate; } template = cleaner.CleanUpBeforeProvisioning(template); foreach (var handler in objectHandlers) { if (handler.WillProvision(web, template, provisioningInfo)) { if (messagesDelegate != null) { handler.MessagesDelegate = messagesDelegate; } if (handler.ReportProgress && progressDelegate != null) { progressDelegate(handler.Name, step, count); step++; } tokenParser = handler.ProvisionObjects(web, template, tokenParser, provisioningInfo); } } System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo(currentCultureInfoValue); } }
public override TokenParser ProvisionObjects(Web web, ProvisioningTemplate template, TokenParser parser, ProvisioningTemplateApplyingInformation applyingInformation) { using (var scope = new PnPMonitoredScope(CoreResources.Provisioning_ObjectHandlers_Pages)) { var context = web.Context as ClientContext; if (!web.IsPropertyAvailable("ServerRelativeUrl")) { context.Load(web, w => w.ServerRelativeUrl); context.ExecuteQueryRetry(); } foreach (var page in template.Pages) { var url = parser.ParseString(page.Url); if (!url.ToLower().StartsWith(web.ServerRelativeUrl.ToLower())) { url = UrlUtility.Combine(web.ServerRelativeUrl, url); } var exists = true; Microsoft.SharePoint.Client.File file = null; try { file = web.GetFileByServerRelativeUrl(url); web.Context.Load(file); web.Context.ExecuteQuery(); } catch (ServerException ex) { if (ex.ServerErrorTypeName == "System.IO.FileNotFoundException") { exists = false; } } if (exists) { if (page.Overwrite) { try { scope.LogDebug(CoreResources.Provisioning_ObjectHandlers_Pages_Overwriting_existing_page__0_, url); file.DeleteObject(); web.Context.ExecuteQueryRetry(); web.AddWikiPageByUrl(url); web.AddLayoutToWikiPage(page.Layout, url); } catch (Exception ex) { scope.LogError(CoreResources.Provisioning_ObjectHandlers_Pages_Overwriting_existing_page__0__failed___1_____2_,url,ex.Message,ex.StackTrace); } } } else { try { scope.LogDebug(CoreResources.Provisioning_ObjectHandlers_Pages_Creating_new_page__0_, url); web.AddWikiPageByUrl(url); web.AddLayoutToWikiPage(page.Layout, url); } catch (Exception ex) { scope.LogError(CoreResources.Provisioning_ObjectHandlers_Pages_Creating_new_page__0__failed___1_____2_,url, ex.Message,ex.StackTrace); } } if (page.WelcomePage) { if (!web.IsPropertyAvailable("RootFolder")) { web.Context.Load(web.RootFolder); web.Context.ExecuteQueryRetry(); } var rootFolderRelativeUrl = url.Substring(web.RootFolder.ServerRelativeUrl.Length); web.SetHomePage(rootFolderRelativeUrl); } if (page.WebParts != null & page.WebParts.Any()) { var existingWebParts = web.GetWebParts(url); foreach (var webpart in page.WebParts) { if (existingWebParts.FirstOrDefault(w => w.WebPart.Title == webpart.Title) == null) { WebPartEntity wpEntity = new WebPartEntity(); wpEntity.WebPartTitle = webpart.Title; wpEntity.WebPartXml = parser.ParseString(webpart.Contents).Trim(new[] {'\n', ' '}); web.AddWebPartToWikiPage(url, wpEntity, (int) webpart.Row, (int) webpart.Column, false); } } } } } 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.RootFolder.WelcomePage); foreach (var page in template.Pages) { var url = parser.ParseString(page.Url); if (!url.ToLower().StartsWith(web.ServerRelativeUrl.ToLower())) { url = UrlUtility.Combine(web.ServerRelativeUrl, url); } var exists = true; Microsoft.SharePoint.Client.File file = null; try { file = web.GetFileByServerRelativeUrl(url); web.Context.Load(file); web.Context.ExecuteQuery(); } catch (ServerException ex) { if (ex.ServerErrorTypeName == "System.IO.FileNotFoundException") { exists = false; } } if (exists) { if (page.Overwrite) { try { scope.LogDebug(CoreResources.Provisioning_ObjectHandlers_Pages_Overwriting_existing_page__0_, url); if (page.WelcomePage && url.Contains(web.RootFolder.WelcomePage)) { web.SetHomePage(string.Empty); } file.DeleteObject(); web.Context.ExecuteQueryRetry(); web.AddWikiPageByUrl(url); web.AddLayoutToWikiPage(page.Layout, url); } catch (Exception ex) { scope.LogError(CoreResources.Provisioning_ObjectHandlers_Pages_Overwriting_existing_page__0__failed___1_____2_, url, ex.Message, ex.StackTrace); } } } else { try { scope.LogDebug(CoreResources.Provisioning_ObjectHandlers_Pages_Creating_new_page__0_, url); web.AddWikiPageByUrl(url); web.AddLayoutToWikiPage(page.Layout, url); } catch (Exception ex) { scope.LogError(CoreResources.Provisioning_ObjectHandlers_Pages_Creating_new_page__0__failed___1_____2_, url, ex.Message, ex.StackTrace); } } if (page.WelcomePage) { web.RootFolder.EnsureProperty(p => p.ServerRelativeUrl); var rootFolderRelativeUrl = url.Substring(web.RootFolder.ServerRelativeUrl.Length); web.SetHomePage(rootFolderRelativeUrl); } if (page.WebParts != null & page.WebParts.Any()) { var existingWebParts = web.GetWebParts(url); foreach (var webpart in page.WebParts) { if (existingWebParts.FirstOrDefault(w => w.WebPart.Title == webpart.Title) == null) { WebPartEntity wpEntity = new WebPartEntity(); wpEntity.WebPartTitle = webpart.Title; wpEntity.WebPartXml = parser.ParseString(webpart.Contents).Trim(new[] { '\n', ' ' }); web.AddWebPartToWikiPage(url, wpEntity, (int)webpart.Row, (int)webpart.Column, false); } } } if (page.Security != null && page.Security.RoleAssignments.Count != 0) { file = web.GetFileByServerRelativeUrl(url); web.Context.Load(file.ListItemAllFields); web.Context.ExecuteQuery(); file.ListItemAllFields.SetSecurity(parser, page.Security); } } } return(parser); }
private void CreateView(Web web, View view, Microsoft.SharePoint.Client.ViewCollection existingViews, List createdList, PnPMonitoredScope monitoredScope) { try { var viewElement = XElement.Parse(view.SchemaXml); var displayNameElement = viewElement.Attribute("DisplayName"); if (displayNameElement == null) { throw new ApplicationException("Invalid View element, missing a valid value for the attribute DisplayName."); } monitoredScope.LogDebug(CoreResources.Provisioning_ObjectHandlers_ListInstances_Creating_view__0_, displayNameElement.Value); var existingView = existingViews.FirstOrDefault(v => v.Title == displayNameElement.Value); if (existingView != null) { existingView.DeleteObject(); web.Context.ExecuteQueryRetry(); } var viewTitle = displayNameElement.Value; // Type var viewTypeString = viewElement.Attribute("Type") != null ? viewElement.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 = viewElement.Descendants("ViewFields").FirstOrDefault(); if (viewFieldsElement != null) { viewFields = (from field in viewElement.Descendants("ViewFields").Descendants("FieldRef") select field.Attribute("Name").Value).ToArray(); } // Default view var viewDefault = viewElement.Attribute("DefaultView") != null && Boolean.Parse(viewElement.Attribute("DefaultView").Value); // Row limit var viewPaged = true; uint viewRowLimit = 30; var rowLimitElement = viewElement.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 viewElement.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, }; // Allow to specify a custom view url. View url is taken from title, so we first set title to the view url value we need, // create the view and then set title back to the original value var urlAttribute = viewElement.Attribute("Url"); var urlHasValue = urlAttribute != null && !string.IsNullOrEmpty(urlAttribute.Value); if (urlHasValue) { //set Title to be equal to url (in order to generate desired url) viewCI.Title = Path.GetFileNameWithoutExtension(urlAttribute.Value); } var createdView = createdList.Views.Add(viewCI); web.Context.Load(createdView, v => v.Scope, v => v.JSLink, v => v.Title); web.Context.ExecuteQueryRetry(); if (urlHasValue) { //restore original title createdView.Title = viewTitle; createdView.Update(); } // ContentTypeID var contentTypeID = viewElement.Attribute("ContentTypeID") != null ? viewElement.Attribute("ContentTypeID").Value : null; if (!string.IsNullOrEmpty(contentTypeID) && (contentTypeID != BuiltInContentTypeId.System)) { ContentTypeId childContentTypeId = null; if (contentTypeID == BuiltInContentTypeId.RootOfList) { var childContentType = web.GetContentTypeById(contentTypeID); childContentTypeId = childContentType != null ? childContentType.Id : null; } else { childContentTypeId = createdList.ContentTypes.BestMatch(contentTypeID); } if (childContentTypeId != null) { createdView.ContentTypeId = childContentTypeId; createdView.Update(); } } // Default for content type bool parsedDefaultViewForContentType; var defaultViewForContentType = viewElement.Attribute("DefaultViewForContentType") != null ? viewElement.Attribute("DefaultViewForContentType").Value : null; if (!string.IsNullOrEmpty(defaultViewForContentType) && bool.TryParse(defaultViewForContentType, out parsedDefaultViewForContentType)) { createdView.DefaultViewForContentType = parsedDefaultViewForContentType; createdView.Update(); } // Scope var scope = viewElement.Attribute("Scope") != null ? viewElement.Attribute("Scope").Value : null; ViewScope parsedScope = ViewScope.DefaultValue; if (!string.IsNullOrEmpty(scope) && Enum.TryParse<ViewScope>(scope, out parsedScope)) { createdView.Scope = parsedScope; createdView.Update(); } // JSLink var jslinkElement = viewElement.Descendants("JSLink").FirstOrDefault(); if (jslinkElement != null) { var jslink = jslinkElement.Value; if (createdView.JSLink != jslink) { createdView.JSLink = jslink; createdView.Update(); } } createdList.Update(); web.Context.ExecuteQueryRetry(); } catch (Exception ex) { monitoredScope.LogError(CoreResources.Provisioning_ObjectHandlers_ListInstances_Creating_view_failed___0_____1_, ex.Message, ex.StackTrace); throw; } }
public void AddListItems(DataRowCollection dataRows, ProvisioningTemplate template, TokenParser parser, PnPMonitoredScope scope) { Microsoft.SharePoint.Client.FieldCollection fields = this.List.Fields; this.Context.Load(fields); this.Context.Load(this.List, l => l.RootFolder.ServerRelativeUrl); this.Context.ExecuteQueryRetry(); ItemPathProvider itemPathProvider = new ItemPathProvider(this.List, this.Web); bool isDocLib = ( this.List.BaseType == BaseType.DocumentLibrary ); var items = new List<ListItemInfo>(); this.Context.ExecuteQueryBatch(dataRows.ToList(), (dataRow) => { scope.LogDebug(CoreResources.Provisioning_ObjectHandlers_ListInstancesDataRows_Creating_list_item__0_, dataRows.IndexOf(dataRow) + 1); var listitem = itemPathProvider.CreateListItem(dataRow, template); if (null != listitem) { foreach (var dataValue in dataRow.Values) { Field dataField = fields.FirstOrDefault( f => f.InternalName == parser.ParseString(dataValue.Key)); if ((dataField != null) && CanFieldContentBeIncluded(dataField, false)) { string fieldValue = parser.ParseString(dataValue.Value); if (!string.IsNullOrEmpty(fieldValue)) { FieldValueProvider valueProvider = GetFieldValueProvider(dataField, this.Web); if (null != valueProvider) { object itemValue = valueProvider.GetFieldValueTyped(fieldValue); if (null != itemValue) { if (dataField.FieldTypeKind == FieldType.Lookup) { FieldLookup lookupField = (FieldLookup)dataField; RegisterLookupReference(lookupField, listitem, itemValue); } else { listitem[dataField.InternalName] = itemValue; } } } } } } listitem.Update(); this.Context.Load(listitem); if (isDocLib) { this.Context.Load(listitem.File); } items.Add(new ListItemInfo() { Item = listitem, Row = dataRow }); } }, (error, dataRow) => { for (var i = items.Count - 1; i >= 0; i--) { if (items[i].Row == dataRow) { items.RemoveAt(i); } } scope.LogError(CoreResources.Provisioning_ObjectHandlers_ListInstancesDataRows_Creating_listitem_failed___0_____1_, error, ""); }, isDocLib ? 1 : BATCH_SIZE); //Ensure files CheckIn if (isDocLib) { this.Context.ExecuteQueryBatch(items, (itemInfo) => { Microsoft.SharePoint.Client.File file = itemInfo.Item.File; if ((null != file.ServerObjectIsNull) && (!(bool)file.ServerObjectIsNull) && (file.CheckOutType != CheckOutType.None)) { file.CheckIn("", CheckinType.MajorCheckIn); } }, BATCH_SIZE); } foreach (ListItemInfo itemInfo in items) { try { var listitem = itemInfo.Item; var dataRow = itemInfo.Row; if (0 < listitem.Id) { AddIDMappingEntry(listitem, dataRow); if (dataRow.Security != null && dataRow.Security.RoleAssignments.Count != 0) { //Should be optimized (run in batch) listitem.SetSecurity(parser, dataRow.Security); } } } catch (Exception ex) { } } }
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().ToList(); var serverRelativeUrl = web.ServerRelativeUrl; var processedLists = new List<ListInfo>(); // Check if this is not a noscript site as we're not allowed to update some properties bool isNoScriptSite = web.IsNoScriptSite(); #region Lists foreach (var templateList in template.Lists) { // Check for the presence of the references content types and throw an exception if not present or in template if (templateList.ContentTypesEnabled) { var existingCts = web.Context.LoadQuery(web.AvailableContentTypes); web.Context.ExecuteQueryRetry(); foreach (var ct in templateList.ContentTypeBindings) { var found = template.ContentTypes.Any(t => t.Id.ToUpperInvariant() == ct.ContentTypeId.ToUpperInvariant()); if (found == false) { found = existingCts.Any(t => t.StringId.ToUpperInvariant() == ct.ContentTypeId.ToUpperInvariant()); } if (!found) { scope.LogError("Referenced content type {0} not available in site or in template", ct.ContentTypeId); throw new Exception(string.Format("Referenced content type {0} not available in site or in template", ct.ContentTypeId)); } } } // check if the List exists by url or by title var index = existingLists.FindIndex(x => x.Title.Equals(templateList.Title, StringComparison.OrdinalIgnoreCase) || x.RootFolder.ServerRelativeUrl.Equals(UrlUtility.Combine(serverRelativeUrl, templateList.Url), StringComparison.OrdinalIgnoreCase)); if (index == -1) { try { scope.LogDebug(CoreResources.Provisioning_ObjectHandlers_ListInstances_Creating_list__0_, templateList.Title); var returnTuple = CreateList(web, templateList, parser, scope, isNoScriptSite); var createdList = returnTuple.Item1; parser = returnTuple.Item2; processedLists.Add(new ListInfo { SiteList = createdList, TemplateList = templateList }); parser.AddToken(new ListIdToken(web, templateList.Title, createdList.Id)); parser.AddToken(new ListUrlToken(web, templateList.Title, createdList.RootFolder.ServerRelativeUrl.Substring(web.ServerRelativeUrl.Length + 1))); } catch (Exception ex) { scope.LogDebug(CoreResources.Provisioning_ObjectHandlers_ListInstances_Creating_list__0__failed___1_____2_, templateList.Title, ex.Message, ex.StackTrace); throw; } } else { try { scope.LogDebug(CoreResources.Provisioning_ObjectHandlers_ListInstances_Updating_list__0_, templateList.Title); var existingList = web.Lists[index]; var returnTuple = UpdateList(web, existingList, templateList, parser, scope, isNoScriptSite); var updatedList = returnTuple.Item1; parser = returnTuple.Item2; if (updatedList != null) { processedLists.Add(new ListInfo { SiteList = updatedList, TemplateList = templateList }); } } catch (Exception ex) { scope.LogDebug(CoreResources.Provisioning_ObjectHandlers_ListInstances_Updating_list__0__failed___1_____2_, templateList.Title, ex.Message, ex.StackTrace); throw; } } } #endregion #region FieldRefs foreach (var listInfo in processedLists) { if (listInfo.TemplateList.FieldRefs.Any()) { foreach (var fieldRef in listInfo.TemplateList.FieldRefs) { var field = rootWeb.GetFieldById<Field>(fieldRef.Id); if (field == null) { // log missing referenced field this.WriteWarning(string.Format(CoreResources.Provisioning_ObjectHandlers_ListInstances_InvalidFieldReference, listInfo.TemplateList.Title, fieldRef.Name, fieldRef.Id), ProvisioningMessageType.Error); // move onto next field reference continue; } if (!listInfo.SiteList.FieldExistsById(fieldRef.Id)) { field = CreateFieldRef(listInfo, field, fieldRef); } else { field = UpdateFieldRef(listInfo.SiteList, field.Id, fieldRef); } field.EnsureProperties(f => f.InternalName, f => f.Title); parser.AddToken(new FieldTitleToken(web, field.InternalName, field.Title)); #if !SP2013 var siteField = template.SiteFields.FirstOrDefault(f => Guid.Parse(XElement.Parse(f.SchemaXml).Attribute("ID").Value).Equals(field.Id)); if (siteField != null && siteField.SchemaXml.ContainsResourceToken()) { var isDirty = false; var originalFieldElement = XElement.Parse(siteField.SchemaXml); var nameAttributeValue = originalFieldElement.Attribute("DisplayName") != null ? originalFieldElement.Attribute("DisplayName").Value : ""; if (nameAttributeValue.ContainsResourceToken()) { if (field.TitleResource.SetUserResourceValue(nameAttributeValue, parser)) { isDirty = true; } } var descriptionAttributeValue = originalFieldElement.Attribute("Description") != null ? originalFieldElement.Attribute("Description").Value : ""; if (descriptionAttributeValue.ContainsResourceToken()) { if (field.DescriptionResource.SetUserResourceValue(descriptionAttributeValue, parser)) { isDirty = true; } } if (isDirty) { field.Update(); field.Context.ExecuteQueryRetry(); } } #endif } listInfo.SiteList.Update(); web.Context.ExecuteQueryRetry(); } } #endregion #region Fields foreach (var listInfo in processedLists) { if (listInfo.TemplateList.Fields.Any()) { foreach (var field in listInfo.TemplateList.Fields) { var fieldElement = XElement.Parse(parser.ParseString(field.SchemaXml, "~sitecollection", "~site")); if (fieldElement.Attribute("ID") == null) { scope.LogError(CoreResources.Provisioning_ObjectHandlers_ListInstances_Field_schema_has_no_ID_attribute___0_, field.SchemaXml); throw new Exception(string.Format(CoreResources.Provisioning_ObjectHandlers_ListInstances_Field_schema_has_no_ID_attribute___0_, field.SchemaXml)); } var id = fieldElement.Attribute("ID").Value; Guid fieldGuid; if (!Guid.TryParse(id, out fieldGuid)) { scope.LogError(CoreResources.Provisioning_ObjectHandlers_ListInstances_ID_for_field_is_not_a_valid_Guid___0_, field.SchemaXml); throw new Exception(string.Format(CoreResources.Provisioning_ObjectHandlers_ListInstances_ID_for_field_is_not_a_valid_Guid___0_, id)); } else { var fieldFromList = listInfo.SiteList.GetFieldById<Field>(fieldGuid); if (fieldFromList == null) { try { scope.LogDebug(CoreResources.Provisioning_ObjectHandlers_ListInstances_Creating_field__0_, fieldGuid); var createdField = CreateField(fieldElement, listInfo, parser, field.SchemaXml, web.Context, scope); if (createdField != null) { createdField.EnsureProperties(f => f.InternalName, f => f.Title); parser.AddToken(new FieldTitleToken(web, createdField.InternalName, createdField.Title)); } } catch (Exception ex) { scope.LogError(CoreResources.Provisioning_ObjectHandlers_ListInstances_Creating_field__0__failed___1_____2_, fieldGuid, ex.Message, ex.StackTrace); throw; } } else { try { scope.LogDebug(CoreResources.Provisioning_ObjectHandlers_ListInstances_Updating_field__0_, fieldGuid); var updatedField = UpdateField(web, listInfo, fieldGuid, fieldElement, fieldFromList, scope, parser, field.SchemaXml); if (updatedField != null) { updatedField.EnsureProperties(f => f.InternalName, f => f.Title); parser.AddToken(new FieldTitleToken(web, updatedField.InternalName, updatedField.Title)); } } catch (Exception ex) { scope.LogError(CoreResources.Provisioning_ObjectHandlers_ListInstances_Updating_field__0__failed___1_____2_, fieldGuid, ex.Message, ex.StackTrace); throw; } } } } } listInfo.SiteList.Update(); web.Context.ExecuteQueryRetry(); } #endregion #region Default Field Values foreach (var listInfo in processedLists) { if (listInfo.TemplateList.FieldDefaults.Any()) { foreach (var fieldDefault in listInfo.TemplateList.FieldDefaults) { var field = listInfo.SiteList.Fields.GetByInternalNameOrTitle(fieldDefault.Key); field.DefaultValue = fieldDefault.Value; field.Update(); web.Context.ExecuteQueryRetry(); } } } #endregion #region Views foreach (var listInfo in processedLists) { var list = listInfo.TemplateList; var createdList = listInfo.SiteList; if (list.Views.Any() && list.RemoveExistingViews) { while (createdList.Views.Any()) { createdList.Views[0].DeleteObject(); } web.Context.ExecuteQueryRetry(); } var existingViews = createdList.Views; web.Context.Load(existingViews, vs => vs.Include(v => v.Title, v => v.Id)); web.Context.ExecuteQueryRetry(); foreach (var view in list.Views) { CreateView(web, view, existingViews, createdList, scope); } //// 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 Folders // Folders are supported for document libraries and generic lists only foreach (var list in processedLists) { list.SiteList.EnsureProperties(l => l.BaseType); if ((list.SiteList.BaseType == BaseType.DocumentLibrary | list.SiteList.BaseType == BaseType.GenericList) && list.TemplateList.Folders != null && list.TemplateList.Folders.Count > 0) { list.SiteList.EnableFolderCreation = true; list.SiteList.Update(); web.Context.ExecuteQueryRetry(); var rootFolder = list.SiteList.RootFolder; foreach (var folder in list.TemplateList.Folders) { CreateFolderInList(rootFolder, folder, parser, scope); } } } #endregion // If an existing view is updated, and the list is to be listed on the QuickLaunch, it is removed because the existing view will be deleted and recreated from scratch. foreach (var listInfo in processedLists) { listInfo.SiteList.OnQuickLaunch = listInfo.TemplateList.OnQuickLaunch; listInfo.SiteList.Update(); } web.Context.ExecuteQueryRetry(); } } return parser; }
/// <summary> /// Creates or updates a Team object via Graph /// </summary> /// <param name="scope">The PnP Provisioning Scope</param> /// <param name="team">The Team to create</param> /// <param name="parser">The PnP Token Parser</param> /// <param name="accessToken">The OAuth 2.0 Access Token</param> /// <returns>The ID of the created or update Team</returns> private static string CreateOrUpdateTeam(PnPMonitoredScope scope, Team team, TokenParser parser, string accessToken) { var parsedMailNickname = !string.IsNullOrEmpty(team.MailNickname) ? parser.ParseString(team.MailNickname).ToLower() : null; if (string.IsNullOrEmpty(parsedMailNickname)) { parsedMailNickname = CreateMailNicknameFromDisplayName(team.DisplayName); } // Check if the Group/Team already exists var alreadyExistingGroupId = GetGroupIdByMailNickname(scope, parsedMailNickname, accessToken); // If the Group already exists, we don't need to create it if (String.IsNullOrEmpty(alreadyExistingGroupId)) { // Otherwise we create the Group, first // Prepare the IDs for owners and members String[] desideredOwnerIds; String[] desideredMemberIds; try { var userIdsByUPN = team.Security.Owners .Select(o => o.UserPrincipalName) .Concat(team.Security.Members.Select(m => m.UserPrincipalName)) .Distinct(StringComparer.OrdinalIgnoreCase) .ToDictionary(k => k, k => { var jsonUser = HttpHelper.MakeGetRequestForString($"{GraphHelper.MicrosoftGraphBaseURI}v1.0/users/{k}?$select=id", accessToken); return(JToken.Parse(jsonUser).Value <string>("id")); }); desideredOwnerIds = team.Security.Owners.Select(o => userIdsByUPN[o.UserPrincipalName]).ToArray(); desideredMemberIds = team.Security.Members.Select(o => userIdsByUPN[o.UserPrincipalName]).Union(desideredOwnerIds).ToArray(); } catch (Exception ex) { scope.LogError(CoreResources.Provisioning_ObjectHandlers_Teams_Team_FetchingUserError, ex.Message); return(null); } var groupCreationRequest = new { displayName = parser.ParseString(team.DisplayName), description = parser.ParseString(team.Description), groupTypes = new String[] { "Unified" }, mailEnabled = true, mailNickname = parsedMailNickname, securityEnabled = false, visibility = team.Visibility.ToString(), owners_odata_bind = (from o in desideredOwnerIds select $"{GraphHelper.MicrosoftGraphBaseURI}v1.0/users/{o}").ToArray(), members_odata_bind = (from m in desideredMemberIds select $"{GraphHelper.MicrosoftGraphBaseURI}v1.0/users/{m}").ToArray() }; // Make the Graph request to create the Office 365 Group var createdGroupJson = HttpHelper.MakePostRequestForString($"{GraphHelper.MicrosoftGraphBaseURI}v1.0/groups", groupCreationRequest, HttpHelper.JsonContentType, accessToken); var createdGroupId = JToken.Parse(createdGroupJson).Value <string>("id"); // Wait for the Group to be ready Boolean wait = true; Int32 iterations = 0; while (wait) { iterations++; try { var jsonGroup = HttpHelper.MakeGetRequestForString($"{GraphHelper.MicrosoftGraphBaseURI}v1.0/groups/{createdGroupId}", accessToken); if (!String.IsNullOrEmpty(jsonGroup)) { wait = false; } } catch (Exception) { // In case of exception wait for 5 secs System.Threading.Thread.Sleep(TimeSpan.FromSeconds(5)); } // Don't wait more than 1 minute if (iterations > 12) { wait = false; } } team.GroupId = createdGroupId; } else { // Otherwise use the already existing Group ID team.GroupId = alreadyExistingGroupId; } // Then we Teamify the Group var teamId = CreateOrUpdateTeamFromGroup(scope, team, parser, team.GroupId, accessToken); return(teamId); }
/// <summary> /// Creates a new Team from a PnP Provisioning Schema definition /// </summary> /// <param name="scope">The PnP Provisioning Scope</param> /// <param name="parser">The PnP Token Parser</param> /// <param name="connector">The PnP File connector</param> /// <param name="team">The Team to provision</param> /// <param name="accessToken">The OAuth 2.0 Access Token</param> /// <returns>The provisioned Team as a JSON object</returns> private static JToken CreateTeamFromProvisioningSchema(PnPMonitoredScope scope, TokenParser parser, FileConnectorBase connector, Team team, string accessToken) { String teamId = null; // If we have to Clone an existing Team if (!String.IsNullOrWhiteSpace(team.CloneFrom)) { teamId = CloneTeam(scope, team, parser, accessToken); } // If we start from an already existing Group else if (!String.IsNullOrEmpty(team.GroupId)) { // We need to parse the GroupId, if it is a token var parsedGroupId = parser.ParseString(team.GroupId); // Check if the Group exists if (GroupExistsById(scope, parsedGroupId, accessToken)) { // Then promote the Group into a Team or update it, if it already exists. Patching a team doesn't return an ID, so use the parsedGroupId directly (teamId and groupId are the same). teamId = CreateOrUpdateTeamFromGroup(scope, team, parser, parsedGroupId, accessToken) ?? parsedGroupId; } else { // Log the exception and return NULL (i.e. cancel) scope.LogError(CoreResources.Provisioning_ObjectHandlers_Teams_Team_GroupDoesNotExists, parsedGroupId); return(null); } } // Otherwise create a Team from scratch else { teamId = CreateOrUpdateTeam(scope, team, parser, accessToken); } if (!String.IsNullOrEmpty(teamId)) { // Wait to be sure that the Team is ready before configuring it WaitForTeamToBeReady(accessToken, teamId); // And now we configure security, channels, and apps if (!SetGroupSecurity(scope, team, teamId, accessToken)) { return(null); } if (!SetTeamChannels(scope, parser, team, teamId, accessToken)) { return(null); } if (!SetTeamApps(scope, team, teamId, accessToken)) { return(null); } // So far the Team's photo cannot be set if we don't have an already existing mailbox // if (!SetTeamPhoto(scope, parser, connector, team, teamId, accessToken)) return null; // Call Archive or Unarchive for the current Team ArchiveTeam(scope, teamId, team.Archived, accessToken); try { // Get the whole Team that we just created and return it back as the method result return(JToken.Parse(HttpHelper.MakeGetRequestForString($"{GraphHelper.MicrosoftGraphBaseURI}v1.0/teams/{teamId}", accessToken))); } catch (Exception ex) { scope.LogError(CoreResources.Provisioning_ObjectHandlers_Teams_Team_FetchingError, ex.Message); } } return(null); }
/// <summary> /// Synchronizes Owners and Members with Team settings /// </summary> /// <param name="scope">The PnP Provisioning Scope</param> /// <param name="team">The Team settings, including security settings</param> /// <param name="teamId">The ID of the target Team</param> /// <param name="accessToken">The OAuth 2.0 Access Token</param> /// <returns>Whether the Security settings have been provisioned or not</returns> private static bool SetGroupSecurity(PnPMonitoredScope scope, Team team, string teamId, string accessToken) { String[] desideredOwnerIds; String[] desideredMemberIds; String[] finalOwnerIds; try { var userIdsByUPN = team.Security.Owners .Select(o => o.UserPrincipalName) .Concat(team.Security.Members.Select(m => m.UserPrincipalName)) .Distinct(StringComparer.OrdinalIgnoreCase) .ToDictionary(k => k, k => { var jsonUser = HttpHelper.MakeGetRequestForString($"{GraphHelper.MicrosoftGraphBaseURI}v1.0/users/{k}?$select=id", accessToken); return(JToken.Parse(jsonUser).Value <string>("id")); }); desideredOwnerIds = team.Security.Owners.Select(o => userIdsByUPN[o.UserPrincipalName]).ToArray(); desideredMemberIds = team.Security.Members.Select(o => userIdsByUPN[o.UserPrincipalName]).Union(desideredOwnerIds).ToArray(); } catch (Exception ex) { scope.LogError(CoreResources.Provisioning_ObjectHandlers_Teams_Team_FetchingUserError, ex.Message); return(false); } String[] ownerIdsToAdd; String[] ownerIdsToRemove; try { // Get current group owners var jsonOwners = HttpHelper.MakeGetRequestForString($"{GraphHelper.MicrosoftGraphBaseURI}v1.0/groups/{teamId}/owners?$select=id", accessToken); string[] currentOwnerIds = GraphHelper.GetIdsFromList(jsonOwners); // Exclude owners already into the group ownerIdsToAdd = desideredOwnerIds.Except(currentOwnerIds).ToArray(); if (team.Security.ClearExistingOwners) { ownerIdsToRemove = currentOwnerIds.Except(desideredOwnerIds).ToArray(); } else { ownerIdsToRemove = new string[0]; } // Define the complete set of owners finalOwnerIds = currentOwnerIds.Union(ownerIdsToAdd).Except(ownerIdsToRemove).ToArray(); } catch (Exception ex) { scope.LogError(CoreResources.Provisioning_ObjectHandlers_Teams_Team_ListingOwnersError, ex.Message); return(false); } // Add new owners foreach (string ownerId in ownerIdsToAdd) { try { object content = new JObject { ["@odata.id"] = $"{GraphHelper.MicrosoftGraphBaseURI}v1.0/users/{ownerId}" }; HttpHelper.MakePostRequest($"{GraphHelper.MicrosoftGraphBaseURI}v1.0/groups/{teamId}/owners/$ref", content, "application/json", accessToken); } catch (Exception ex) { scope.LogError(CoreResources.Provisioning_ObjectHandlers_Teams_Team_AddingOwnerError, ex.Message); return(false); } } // Remove exceeding owners foreach (string ownerId in ownerIdsToRemove) { try { HttpHelper.MakeDeleteRequest($"{GraphHelper.MicrosoftGraphBaseURI}v1.0/groups/{teamId}/owners/{ownerId}/$ref", accessToken); } catch (Exception ex) { scope.LogError(CoreResources.Provisioning_ObjectHandlers_Teams_Team_RemovingOwnerError, ex.Message); return(false); } } String[] memberIdsToAdd; String[] memberIdsToRemove; try { // Get current group members var jsonMembers = HttpHelper.MakeGetRequestForString($"{GraphHelper.MicrosoftGraphBaseURI}v1.0/groups/{teamId}/members?$select=id", accessToken); string[] currentMemberIds = GraphHelper.GetIdsFromList(jsonMembers); // Exclude members already into the group memberIdsToAdd = desideredMemberIds.Except(currentMemberIds).ToArray(); if (team.Security.ClearExistingMembers) { memberIdsToRemove = currentMemberIds.Except(desideredMemberIds.Union(finalOwnerIds)).ToArray(); } else { memberIdsToRemove = new string[0]; } } catch (Exception ex) { scope.LogError(CoreResources.Provisioning_ObjectHandlers_Teams_Team_ListingMembersError, ex.Message); return(false); } // Add new members foreach (string memberId in memberIdsToAdd) { try { object content = new JObject { ["@odata.id"] = $"{GraphHelper.MicrosoftGraphBaseURI}v1.0/users/{memberId}" }; HttpHelper.MakePostRequest($"{GraphHelper.MicrosoftGraphBaseURI}v1.0/groups/{teamId}/members/$ref", content, "application/json", accessToken); } catch (Exception ex) { scope.LogError(CoreResources.Provisioning_ObjectHandlers_Teams_Team_AddingMemberError, ex.Message); return(false); } } // Remove exceeding members foreach (string memberId in memberIdsToRemove) { try { HttpHelper.MakeDeleteRequest($"{GraphHelper.MicrosoftGraphBaseURI}v1.0/groups/{teamId}/members/{memberId}/$ref", accessToken); } catch (Exception ex) { scope.LogError(CoreResources.Provisioning_ObjectHandlers_Teams_Team_RemovingMemberError, ex.Message); return(false); } } 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; web.EnsureProperties(w => w.ServerRelativeUrl, w => w.RootFolder.WelcomePage); // Check if this is not a noscript site as we're not allowed to update some properties bool isNoScriptSite = web.IsNoScriptSite(); foreach (var page in template.Pages) { var url = parser.ParseString(page.Url); if (!url.ToLower().StartsWith(web.ServerRelativeUrl.ToLower())) { url = UrlUtility.Combine(web.ServerRelativeUrl, url); } var exists = true; Microsoft.SharePoint.Client.File file = null; try { file = web.GetFileByServerRelativeUrl(url); web.Context.Load(file); web.Context.ExecuteQueryRetry(); } catch (ServerException ex) { if (ex.ServerErrorTypeName == "System.IO.FileNotFoundException") { exists = false; } } if (exists) { if (page.Overwrite) { try { scope.LogDebug(CoreResources.Provisioning_ObjectHandlers_Pages_Overwriting_existing_page__0_, url); // determine url of current home page string welcomePageUrl = web.RootFolder.WelcomePage; string welcomePageServerRelativeUrl = welcomePageUrl != null ? UrlUtility.Combine(web.ServerRelativeUrl, web.RootFolder.WelcomePage) : null; bool overwriteWelcomePage = string.Equals(url, welcomePageServerRelativeUrl, StringComparison.InvariantCultureIgnoreCase); // temporarily reset home page so we can delete it if (overwriteWelcomePage) { web.SetHomePage(string.Empty); } file.DeleteObject(); web.Context.ExecuteQueryRetry(); web.AddWikiPageByUrl(url); if (page.Layout == WikiPageLayout.Custom) { web.AddLayoutToWikiPage(WikiPageLayout.OneColumn, url); } else { web.AddLayoutToWikiPage(page.Layout, url); } if (overwriteWelcomePage) { // restore welcome page to previous value web.SetHomePage(welcomePageUrl); } } catch (Exception ex) { scope.LogError(CoreResources.Provisioning_ObjectHandlers_Pages_Overwriting_existing_page__0__failed___1_____2_, url, ex.Message, ex.StackTrace); } } } else { try { scope.LogDebug(CoreResources.Provisioning_ObjectHandlers_Pages_Creating_new_page__0_, url); web.AddWikiPageByUrl(url); if (page.Layout == WikiPageLayout.Custom) { web.AddLayoutToWikiPage(WikiPageLayout.OneColumn, url); } else { web.AddLayoutToWikiPage(page.Layout, url); } } catch (Exception ex) { scope.LogError(CoreResources.Provisioning_ObjectHandlers_Pages_Creating_new_page__0__failed___1_____2_, url, ex.Message, ex.StackTrace); } } #pragma warning disable 618 if (page.WelcomePage) #pragma warning restore 618 { web.RootFolder.EnsureProperty(p => p.ServerRelativeUrl); var rootFolderRelativeUrl = url.Substring(web.RootFolder.ServerRelativeUrl.Length); web.SetHomePage(rootFolderRelativeUrl); } #if !SP2013 bool webPartsNeedLocalization = false; #endif if (page.WebParts != null & page.WebParts.Any()) { if (!isNoScriptSite) { var existingWebParts = web.GetWebParts(url); foreach (var webPart in page.WebParts) { if (existingWebParts.FirstOrDefault(w => w.WebPart.Title == parser.ParseString(webPart.Title)) == null) { WebPartEntity wpEntity = new WebPartEntity { WebPartTitle = parser.ParseString(webPart.Title), WebPartXml = parser.ParseXmlStringWebpart(webPart.Contents.Trim(new[] { '\n', ' ' }), web) }; var wpd = web.AddWebPartToWikiPage(url, wpEntity, (int)webPart.Row, (int)webPart.Column, false); #if !SP2013 if (webPart.Title.ContainsResourceToken()) { // update data based on where it was added - needed in order to localize wp title 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 } } // Remove any existing WebPartIdToken tokens in the parser that were added by other pages. They won't apply to this page, // and they'll cause issues if this page contains web parts with the same name as web parts on other pages. parser.Tokens.RemoveAll(t => t is WebPartIdToken); var allWebParts = web.GetWebParts(url); foreach (var webpart in allWebParts) { parser.AddToken(new WebPartIdToken(web, webpart.WebPart.Title, webpart.Id)); } } else { scope.LogWarning(CoreResources.Provisioning_ObjectHandlers_Pages_SkipAddingWebParts, page.Url); } } #if !SP2013 if (webPartsNeedLocalization) { page.LocalizeWebParts(web, parser, scope); } #endif file = web.GetFileByServerRelativeUrl(url); file.EnsureProperty(f => f.ListItemAllFields); if (page.Fields.Any()) { var item = file.ListItemAllFields; foreach (var fieldValue in page.Fields) { item[fieldValue.Key] = parser.ParseString(fieldValue.Value); } item.Update(); web.Context.ExecuteQueryRetry(); } if (page.Security != null && page.Security.RoleAssignments.Count != 0) { web.Context.Load(file.ListItemAllFields); web.Context.ExecuteQueryRetry(); file.ListItemAllFields.SetSecurity(parser, page.Security); } } } return(parser); }
private void CallWebHooks(ProvisioningTemplate template, TokenParser parser, ProvisioningTemplateWebhookKind kind, ObjectHandlerBase objectHandler = null) { using (var scope = new PnPMonitoredScope("ProvisioningTemplate WebHook Call")) { if (template.ProvisioningTemplateWebhooks != null && template.ProvisioningTemplateWebhooks.Any()) { foreach (var webhook in template.ProvisioningTemplateWebhooks.Where(w => w.Kind == kind)) { SimpleTokenParser internalParser = new SimpleTokenParser(); foreach (var webhookparam in webhook.Parameters) { internalParser.AddToken(new WebhookParameter(parser.ParseString(webhookparam.Key), parser.ParseString(webhookparam.Value))); } var url = parser.ParseString(webhook.Url); // parse for template scoped parameters url = internalParser.ParseString(url); // parse for webhook scoped parameters switch (webhook.Method) { case ProvisioningTemplateWebhookMethod.GET: { if (kind == ProvisioningTemplateWebhookKind.ObjectHandlerProvisioningStarted || kind == ProvisioningTemplateWebhookKind.ObjectHandlerProvisioningCompleted) { url += $"&__handler={objectHandler.InternalName}"; } try { using (var client = new HttpClient()) { if (webhook.Async) { client.GetAsync(url); } else { client.GetAsync(url).GetAwaiter().GetResult(); } } } catch (HttpRequestException ex) { scope.LogError(ex, "Error calling provisioning template webhook"); } break; } case ProvisioningTemplateWebhookMethod.POST: { if (kind == ProvisioningTemplateWebhookKind.ObjectHandlerProvisioningCompleted || kind == ProvisioningTemplateWebhookKind.ObjectHandlerProvisioningStarted) { webhook.Parameters.Add("__handler", objectHandler.InternalName); } try { using (var client = new HttpClient()) { if (webhook.Async) { switch (webhook.BodyFormat) { case ProvisioningTemplateWebhookBodyFormat.Json: client.PostAsJsonAsync(url, webhook.Parameters); break; case ProvisioningTemplateWebhookBodyFormat.Xml: client.PostAsXmlAsync(url, webhook.Parameters); break; case ProvisioningTemplateWebhookBodyFormat.FormUrlEncoded: var content = new FormUrlEncodedContent(webhook.Parameters); client.PostAsync(url, content); break; } } else { switch (webhook.BodyFormat) { case ProvisioningTemplateWebhookBodyFormat.Json: client.PostAsJsonAsync(url, webhook.Parameters).GetAwaiter().GetResult(); break; case ProvisioningTemplateWebhookBodyFormat.Xml: client.PostAsXmlAsync(url, webhook.Parameters).GetAwaiter().GetResult(); break; case ProvisioningTemplateWebhookBodyFormat.FormUrlEncoded: var content = new FormUrlEncodedContent(webhook.Parameters); client.PostAsync(url, content).GetAwaiter().GetResult(); break; } } } } catch (HttpRequestException ex) { scope.LogError(ex, "Error calling provisioning template webhook"); } break; } } } } } }