public static byte[] GetFileBytes(FileConnectorBase connector, string fileName) { var container = String.Empty; if (fileName.Contains(@"\") || fileName.Contains(@"/")) { var tempFileName = fileName.Replace(@"/", @"\"); container = fileName.Substring(0, tempFileName.LastIndexOf(@"\")); fileName = fileName.Substring(tempFileName.LastIndexOf(@"\") + 1); } // add the default provided container (if any) if (!String.IsNullOrEmpty(container)) { if (!String.IsNullOrEmpty(connector.GetContainer())) { if (container.StartsWith("/")) { container = container.TrimStart("/".ToCharArray()); } container = $@"{connector.GetContainer()}\{container}"; } } else { container = connector.GetContainer(); } var stream = connector.GetFileStream(fileName, container); if (stream == null) { //Decode the URL and try again fileName = WebUtility.UrlDecode(fileName); stream = connector.GetFileStream(fileName, container); } if (stream == null) { throw new ArgumentException($"The specified filename '{fileName}' cannot be found"); } byte[] returnData; using (var memStream = new MemoryStream()) { stream.CopyTo(memStream); memStream.Position = 0; returnData = memStream.ToArray(); } if (stream != null) { stream.Dispose(); } return(returnData); }
private void ProcessFiles(ProvisioningTemplate template, string templateFileName, FileConnectorBase fileSystemConnector) { var templateFile = ProvisioningHelper.LoadSiteTemplateFromFile(templateFileName, null, (e) => { WriteError(new ErrorRecord(e, "TEMPLATENOTVALID", ErrorCategory.SyntaxError, null)); }); if (template.Tenant?.AppCatalog != null) { foreach (var app in template.Tenant.AppCatalog.Packages) { WriteObject($"Processing {app.Src}"); AddFile(app.Src, templateFile, fileSystemConnector); } } if (template.Tenant?.SiteScripts != null) { foreach (var siteScript in template.Tenant.SiteScripts) { WriteObject($"Processing {siteScript.JsonFilePath}"); AddFile(siteScript.JsonFilePath, templateFile, fileSystemConnector); } } if (template.Localizations != null && template.Localizations.Any()) { foreach (var location in template.Localizations) { WriteObject($"Processing {location.ResourceFile}"); AddFile(location.ResourceFile, templateFile, fileSystemConnector); } } if (template.WebSettings != null && !String.IsNullOrEmpty(template.WebSettings.SiteLogo)) { // is it a file? var isFile = false; using (var fileStream = fileSystemConnector.GetFileStream(template.WebSettings.SiteLogo)) { isFile = fileStream != null; } if (isFile) { WriteObject($"Processing {template.WebSettings.SiteLogo}"); AddFile(template.WebSettings.SiteLogo, templateFile, fileSystemConnector); } } if (template.Files.Any()) { foreach (var file in template.Files) { WriteObject($"Processing {file.Src}"); AddFile(file.Src, templateFile, fileSystemConnector); } } if (templateFile.Connector is ICommitableFileConnector) { ((ICommitableFileConnector)templateFile.Connector).Commit(); } }
private void AddResourceTokens(Web web, LocalizationCollection localizations, FileConnectorBase connector) { if (localizations != null && localizations.Any()) { //https://github.com/SharePoint/PnP-Provisioning-Schema/issues/301 //fixing issue to allow multiple resx files in the template. i.e: //<pnp:Localization LCID="1033" Name="core" ResourceFile="core.en-us.resx" /> //<pnp:Localization LCID="3082" Name="core" ResourceFile="core.es-es.resx" /> //<pnp:Localization LCID="1033" Name="intranet" ResourceFile="intranet.en-us.resx" /> //<pnp:Localization LCID="3082" Name="intranet" ResourceFile="intranet.es-es.resx" /> var resourcesFilesCount = localizations.GroupBy(l => l.Name).Count(); // Read all resource keys in a list List <Tuple <string, uint, string> > resourceEntries = new List <Tuple <string, uint, string> >(); foreach (var localizationEntry in localizations) { var filePath = localizationEntry.ResourceFile; using (var stream = connector.GetFileStream(filePath)) { if (stream != null) { #if !NETSTANDARD2_0 using (ResXResourceReader resxReader = new ResXResourceReader(stream)) { foreach (DictionaryEntry entry in resxReader) { // One can have multiple resource files in a single file, by adding tokens with resource file name and without we allow both scenarios to resolve resourceEntries.Add(new Tuple <string, uint, string>($"{localizationEntry.Name}:{entry.Key}", (uint)localizationEntry.LCID, entry.Value.ToString().Replace("\"", """))); resourceEntries.Add(new Tuple <string, uint, string>(entry.Key.ToString(), (uint)localizationEntry.LCID, entry.Value.ToString().Replace("\"", """))); } } #else var xElement = XElement.Load(stream); foreach (var dataElement in xElement.Descendants("data")) { var key = dataElement.Attribute("name").Value; var value = dataElement.Value; resourceEntries.Add(new Tuple <string, uint, string>($"{localizationEntry.Name}:{key}", (uint)localizationEntry.LCID, value.ToString().Replace("\"", """))); resourceEntries.Add(new Tuple <string, uint, string>(key.ToString(), (uint)localizationEntry.LCID, value.ToString().Replace("\"", """))); } #endif } } } var uniqueKeys = resourceEntries.Select(k => k.Item1).Distinct(); foreach (var key in uniqueKeys) { var matches = resourceEntries.Where(k => k.Item1 == key); var entries = matches.Select(k => new ResourceEntry() { LCID = k.Item2, Value = k.Item3 }).ToList(); LocalizationToken token = new LocalizationToken(web, key, entries); _tokens.Add(token); } } }
private void ProcessFiles(string templateFileName, FileConnectorBase fileSystemConnector, FileConnectorBase connector) { var templateFile = ReadTenantTemplate.LoadProvisioningHierarchyFromFile(templateFileName, null); if (Template.Tenant?.AppCatalog != null) { foreach (var app in Template.Tenant.AppCatalog.Packages) { WriteObject($"Processing {app.Src}"); AddFile(app.Src, templateFile, fileSystemConnector, connector); } } if (Template.Tenant?.SiteScripts != null) { foreach (var siteScript in Template.Tenant.SiteScripts) { WriteObject($"Processing {siteScript.JsonFilePath}"); AddFile(siteScript.JsonFilePath, templateFile, fileSystemConnector, connector); } } if (Template.Localizations != null && Template.Localizations.Any()) { foreach (var location in Template.Localizations) { WriteObject($"Processing {location.ResourceFile}"); AddFile(location.ResourceFile, templateFile, fileSystemConnector, connector); } } foreach (var template in Template.Templates) { if (template.WebSettings != null && template.WebSettings.SiteLogo != null) { // is it a file? var isFile = false; using (var fileStream = fileSystemConnector.GetFileStream(template.WebSettings.SiteLogo)) { isFile = fileStream != null; } if (isFile) { WriteObject($"Processing {template.WebSettings.SiteLogo}"); AddFile(template.WebSettings.SiteLogo, templateFile, fileSystemConnector, connector); } } if (template.Files.Any()) { foreach (var file in template.Files) { WriteObject($"Processing {file.Src}"); AddFile(file.Src, templateFile, fileSystemConnector, connector); } } } if (templateFile.Connector is ICommitableFileConnector) { ((ICommitableFileConnector)templateFile.Connector).Commit(); } }
private void AddFile(string sourceName, ProvisioningHierarchy hierarchy, FileConnectorBase fileSystemConnector, FileConnectorBase connector) { using (var fs = fileSystemConnector.GetFileStream(sourceName)) { var fileName = sourceName.IndexOf("\\") > 0 ? sourceName.Substring(sourceName.LastIndexOf("\\") + 1) : sourceName; var folderName = sourceName.IndexOf("\\") > 0 ? sourceName.Substring(0, sourceName.LastIndexOf("\\")) : ""; hierarchy.Connector.SaveFileStream(fileName, folderName, fs); } }
private void AddResourceTokens(Web web, LocalizationCollection localizations, FileConnectorBase connector) { if (localizations != null && localizations.Any()) { // Read all resource keys in a list List <Tuple <string, uint, string> > resourceEntries = new List <Tuple <string, uint, string> >(); foreach (var localizationEntry in localizations) { var filePath = localizationEntry.ResourceFile; using (var stream = connector.GetFileStream(filePath)) { if (stream != null) { #if !NETSTANDARD2_0 using (ResXResourceReader resxReader = new ResXResourceReader(stream)) #else using (ResourceReader resxReader = new ResourceReader(stream)) #endif { foreach (DictionaryEntry entry in resxReader) { resourceEntries.Add(new Tuple <string, uint, string>(entry.Key.ToString(), (uint)localizationEntry.LCID, entry.Value.ToString().Replace("\"", """))); } } } } } var uniqueKeys = resourceEntries.Select(k => k.Item1).Distinct(); foreach (var key in uniqueKeys) { var matches = resourceEntries.Where(k => k.Item1 == key); var entries = matches.Select(k => new ResourceEntry() { LCID = k.Item2, Value = k.Item3 }).ToList(); LocalizationToken token = new LocalizationToken(web, key, entries); _tokens.Add(token); } } }
internal static void ProcessFiles(ProvisioningHierarchy tenantTemplate, string templateFileName, FileConnectorBase fileSystemConnector, FileConnectorBase connector, Action <string> progress) { var templateFile = ReadTenantTemplate.LoadProvisioningHierarchyFromFile(templateFileName, null, null); if (tenantTemplate.Tenant?.AppCatalog != null) { foreach (var app in tenantTemplate.Tenant.AppCatalog.Packages) { progress($"Processing {app.Src}"); AddFile(app.Src, templateFile, fileSystemConnector, connector); } } if (tenantTemplate.Tenant?.SiteScripts != null) { foreach (var siteScript in tenantTemplate.Tenant.SiteScripts) { progress($"Processing {siteScript.JsonFilePath}"); AddFile(siteScript.JsonFilePath, templateFile, fileSystemConnector, connector); } } if (tenantTemplate.Localizations != null && tenantTemplate.Localizations.Any()) { foreach (var location in tenantTemplate.Localizations) { progress($"Processing {location.ResourceFile}"); AddFile(location.ResourceFile, templateFile, fileSystemConnector, connector); } } foreach (var template in tenantTemplate.Templates) { if (template.WebSettings != null && !String.IsNullOrEmpty(template.WebSettings.SiteLogo)) { // is it a file? var isFile = false; try { using (var fileStream = fileSystemConnector.GetFileStream(template.WebSettings.SiteLogo)) { isFile = fileStream != null; } } catch { } if (isFile) { progress($"Processing {template.WebSettings.SiteLogo}"); AddFile(template.WebSettings.SiteLogo, templateFile, fileSystemConnector, connector); } } if (template.Files.Any()) { foreach (var file in template.Files) { progress($"Processing {file.Src}"); AddFile(file.Src, templateFile, fileSystemConnector, connector); } } if (template.Lists.Any()) { foreach (var list in template.Lists) { if (list.DataRows.Any()) { foreach (var dataRow in list.DataRows) { if (dataRow.Attachments.Any()) { progress("List attachments"); foreach (var attachment in dataRow.Attachments) { AddFile(attachment.Src, templateFile, fileSystemConnector, connector); } } } } } } } if (templateFile.Connector is ICommitableFileConnector) { ((ICommitableFileConnector)templateFile.Connector).Commit(); } }
private static Microsoft.SharePoint.Client.ContentType CreateContentType(Web web, ContentType templateContentType, TokenParser parser, FileConnectorBase connector, List <Microsoft.SharePoint.Client.ContentType> existingCTs = null, List <Microsoft.SharePoint.Client.Field> existingFields = null) { var name = parser.ParseString(templateContentType.Name); var description = parser.ParseString(templateContentType.Description); var id = parser.ParseString(templateContentType.Id); var group = parser.ParseString(templateContentType.Group); var createdCT = web.CreateContentType(name, description, id, group); foreach (var fieldRef in templateContentType.FieldRefs) { var field = web.Fields.GetById(fieldRef.Id); web.AddFieldToContentType(createdCT, field, fieldRef.Required, fieldRef.Hidden); } //Reorder the elements so that the new created Content Type has the same order as defined in the //template. The order can be different if the new Content Type inherits from another Content Type. //In this case the new Content Type has all field of the original Content Type and missing fields //will be added at the end. To fix this issue we ordering the fields once more. createdCT.FieldLinks.Reorder(templateContentType.FieldRefs.Select(fld => fld.Name).ToArray()); createdCT.Update(true); web.Context.ExecuteQueryRetry(); createdCT.ReadOnly = templateContentType.ReadOnly; createdCT.Hidden = templateContentType.Hidden; createdCT.Sealed = templateContentType.Sealed; if (!string.IsNullOrEmpty(parser.ParseString(templateContentType.DocumentTemplate))) { createdCT.DocumentTemplate = parser.ParseString(templateContentType.DocumentTemplate); } if (!String.IsNullOrEmpty(templateContentType.NewFormUrl)) { createdCT.NewFormUrl = templateContentType.NewFormUrl; } if (!String.IsNullOrEmpty(templateContentType.EditFormUrl)) { createdCT.EditFormUrl = templateContentType.EditFormUrl; } if (!String.IsNullOrEmpty(templateContentType.DisplayFormUrl)) { createdCT.DisplayFormUrl = templateContentType.DisplayFormUrl; } // If the CT is a DocumentSet if (templateContentType.DocumentSetTemplate != null) { // Retrieve a reference to the DocumentSet Content Type Microsoft.SharePoint.Client.DocumentSet.DocumentSetTemplate documentSetTemplate = Microsoft.SharePoint.Client.DocumentSet.DocumentSetTemplate.GetDocumentSetTemplate(web.Context, createdCT); if (!String.IsNullOrEmpty(templateContentType.DocumentSetTemplate.WelcomePage)) { // TODO: Customize the WelcomePage of the DocumentSet } foreach (String ctId in templateContentType.DocumentSetTemplate.AllowedContentTypes) { Microsoft.SharePoint.Client.ContentType ct = existingCTs.FirstOrDefault(c => c.StringId == ctId); if (ct != null) { documentSetTemplate.AllowedContentTypes.Add(ct.Id); } } foreach (var doc in templateContentType.DocumentSetTemplate.DefaultDocuments) { Microsoft.SharePoint.Client.ContentType ct = existingCTs.FirstOrDefault(c => c.StringId == doc.ContentTypeId); if (ct != null) { using (Stream fileStream = connector.GetFileStream(doc.FileSourcePath)) { documentSetTemplate.DefaultDocuments.Add(doc.Name, ct.Id, ReadFullStream(fileStream)); } } } foreach (var sharedField in templateContentType.DocumentSetTemplate.SharedFields) { Microsoft.SharePoint.Client.Field field = existingFields.FirstOrDefault(f => f.Id == sharedField); if (field != null) { documentSetTemplate.SharedFields.Add(field); } } foreach (var welcomePageField in templateContentType.DocumentSetTemplate.WelcomePageFields) { Microsoft.SharePoint.Client.Field field = existingFields.FirstOrDefault(f => f.Id == welcomePageField); if (field != null) { documentSetTemplate.WelcomePageFields.Add(field); } } documentSetTemplate.Update(true); web.Context.ExecuteQueryRetry(); } web.Context.Load(createdCT); web.Context.ExecuteQueryRetry(); return(createdCT); }
public static byte[] GetFileBytes(FileConnectorBase connector, string fileName) { var container = String.Empty; if (fileName.Contains(@"\") || fileName.Contains(@"/")) { var tempFileName = fileName.Replace(@"/", @"\"); container = fileName.Substring(0, tempFileName.LastIndexOf(@"\")); fileName = fileName.Substring(tempFileName.LastIndexOf(@"\") + 1); } // add the default provided container (if any) if (!String.IsNullOrEmpty(container)) { if (!String.IsNullOrEmpty(connector.GetContainer())) { if (container.StartsWith("/")) { container = container.TrimStart("/".ToCharArray()); } #if !NETSTANDARD2_0 if (connector.GetType() == typeof(Connectors.AzureStorageConnector)) { if (connector.GetContainer().EndsWith("/")) { container = $@"{connector.GetContainer()}{container}"; } else { container = $@"{connector.GetContainer()}/{container}"; } } else { container = $@"{connector.GetContainer()}\{container}"; } #else container = $@"{connector.GetContainer()}\{container}"; #endif } } else { container = connector.GetContainer(); } var stream = connector.GetFileStream(fileName, container); if (stream == null) { //Decode the URL and try again fileName = WebUtility.UrlDecode(fileName); stream = connector.GetFileStream(fileName, container); } byte[] returnData; using (var memStream = new MemoryStream()) { stream.CopyTo(memStream); memStream.Position = 0; returnData = memStream.ToArray(); } if (stream != null) { stream.Dispose(); } return(returnData); }
private static Microsoft.SharePoint.Client.ContentType CreateContentType(Web web, ContentType templateContentType, TokenParser parser, FileConnectorBase connector, PnPMonitoredScope scope, List <Microsoft.SharePoint.Client.ContentType> existingCTs = null, List <Microsoft.SharePoint.Client.Field> existingFields = null, bool isNoScriptSite = false) { var name = parser.ParseString(templateContentType.Name); var description = parser.ParseString(templateContentType.Description); var id = parser.ParseString(templateContentType.Id); var group = parser.ParseString(templateContentType.Group); var createdCT = web.CreateContentType(name, description, id, group); foreach (var fieldRef in templateContentType.FieldRefs) { Microsoft.SharePoint.Client.Field field = null; try { field = web.AvailableFields.GetById(fieldRef.Id); } catch (ArgumentException) { if (!string.IsNullOrEmpty(fieldRef.Name)) { field = web.AvailableFields.GetByInternalNameOrTitle(fieldRef.Name); } } // Add it to the target content type // Notice that this code will fail if the field does not exist web.AddFieldToContentType(createdCT, field, fieldRef.Required, fieldRef.Hidden); } // Add new CTs parser.AddToken(new ContentTypeIdToken(web, name, id)); #if !ONPREMISES // Set resources if (templateContentType.Name.ContainsResourceToken()) { createdCT.NameResource.SetUserResourceValue(templateContentType.Name, parser); } if (templateContentType.Description.ContainsResourceToken()) { createdCT.DescriptionResource.SetUserResourceValue(templateContentType.Description, parser); } #endif //Reorder the elements so that the new created Content Type has the same order as defined in the //template. The order can be different if the new Content Type inherits from another Content Type. //In this case the new Content Type has all field of the original Content Type and missing fields //will be added at the end. To fix this issue we ordering the fields once more. createdCT.FieldLinks.Reorder(templateContentType.FieldRefs.Select(fld => parser.ParseString(fld.Name)).ToArray()); createdCT.ReadOnly = templateContentType.ReadOnly; createdCT.Hidden = templateContentType.Hidden; createdCT.Sealed = templateContentType.Sealed; if (templateContentType.DocumentSetTemplate == null) { // Only apply a document template when the contenttype is not a document set if (!string.IsNullOrEmpty(parser.ParseString(templateContentType.DocumentTemplate))) { createdCT.DocumentTemplate = parser.ParseString(templateContentType.DocumentTemplate); } } // Skipping updates of forms as we can't upload forms to noscript sites if (!isNoScriptSite) { if (!string.IsNullOrEmpty(parser.ParseString(templateContentType.NewFormUrl))) { createdCT.NewFormUrl = parser.ParseString(templateContentType.NewFormUrl); } if (!string.IsNullOrEmpty(parser.ParseString(templateContentType.EditFormUrl))) { createdCT.EditFormUrl = parser.ParseString(templateContentType.EditFormUrl); } if (!string.IsNullOrEmpty(parser.ParseString(templateContentType.DisplayFormUrl))) { createdCT.DisplayFormUrl = parser.ParseString(templateContentType.DisplayFormUrl); } } else { if (!string.IsNullOrEmpty(parser.ParseString(templateContentType.DisplayFormUrl)) || !string.IsNullOrEmpty(parser.ParseString(templateContentType.EditFormUrl)) || !string.IsNullOrEmpty(parser.ParseString(templateContentType.NewFormUrl))) { // log message scope.LogWarning(CoreResources.Provisioning_ObjectHandlers_ContentTypes_SkipCustomFormUrls, name); } } createdCT.Update(true); web.Context.ExecuteQueryRetry(); // If the CT is a DocumentSet if (templateContentType.DocumentSetTemplate != null) { // Retrieve a reference to the DocumentSet Content Type Microsoft.SharePoint.Client.DocumentSet.DocumentSetTemplate documentSetTemplate = Microsoft.SharePoint.Client.DocumentSet.DocumentSetTemplate.GetDocumentSetTemplate(web.Context, createdCT); // Load the collections to allow for deletion scenarions web.Context.Load(documentSetTemplate, d => d.AllowedContentTypes, d => d.DefaultDocuments, d => d.SharedFields, d => d.WelcomePageFields); web.Context.ExecuteQueryRetry(); if (!String.IsNullOrEmpty(templateContentType.DocumentSetTemplate.WelcomePage)) { // TODO: Customize the WelcomePage of the DocumentSet } // Add additional content types to the set of allowed content types bool hasDefaultDocumentContentTypeInTemplate = false; foreach (String ctId in templateContentType.DocumentSetTemplate.AllowedContentTypes) { Microsoft.SharePoint.Client.ContentType ct = existingCTs.FirstOrDefault(c => c.StringId == ctId); if (ct != null) { if (ct.Id.StringValue.Equals("0x0101", StringComparison.InvariantCultureIgnoreCase)) { hasDefaultDocumentContentTypeInTemplate = true; } documentSetTemplate.AllowedContentTypes.Add(ct.Id); } } // If the default document content type (0x0101) is not in our definition then remove it if (!hasDefaultDocumentContentTypeInTemplate) { Microsoft.SharePoint.Client.ContentType ct = existingCTs.FirstOrDefault(c => c.StringId == "0x0101"); if (ct != null) { documentSetTemplate.AllowedContentTypes.Remove(ct.Id); } } if (!isNoScriptSite) { foreach (var doc in templateContentType.DocumentSetTemplate.DefaultDocuments) { Microsoft.SharePoint.Client.ContentType ct = existingCTs.FirstOrDefault(c => c.StringId == doc.ContentTypeId); if (ct != null) { using (Stream fileStream = connector.GetFileStream(doc.FileSourcePath)) { documentSetTemplate.DefaultDocuments.Add(doc.Name, ct.Id, ReadFullStream(fileStream)); } } } } else { if (templateContentType.DocumentSetTemplate.DefaultDocuments.Any()) { scope.LogWarning(CoreResources.Provisioning_ObjectHandlers_ContentTypes_SkipDocumentSetDefaultDocuments, name); } } foreach (var sharedField in templateContentType.DocumentSetTemplate.SharedFields) { Microsoft.SharePoint.Client.Field field = existingFields.FirstOrDefault(f => f.Id == sharedField); if (field != null) { documentSetTemplate.SharedFields.Add(field); } } foreach (var welcomePageField in templateContentType.DocumentSetTemplate.WelcomePageFields) { Microsoft.SharePoint.Client.Field field = existingFields.FirstOrDefault(f => f.Id == welcomePageField); if (field != null) { documentSetTemplate.WelcomePageFields.Add(field); } } documentSetTemplate.Update(true); web.Context.ExecuteQueryRetry(); } web.Context.Load(createdCT); web.Context.ExecuteQueryRetry(); return(createdCT); }
private static Microsoft.SharePoint.Client.ContentType CreateContentType(Web web, ContentType templateContentType, TokenParser parser, FileConnectorBase connector, List <Microsoft.SharePoint.Client.ContentType> existingCTs = null, List <Microsoft.SharePoint.Client.Field> existingFields = null) { var name = parser.ParseString(templateContentType.Name); var description = parser.ParseString(templateContentType.Description); var id = parser.ParseString(templateContentType.Id); var group = parser.ParseString(templateContentType.Group); var createdCT = web.CreateContentType(name, description, id, group); foreach (var fieldRef in templateContentType.FieldRefs) { var field = web.Fields.GetById(fieldRef.Id); web.AddFieldToContentType(createdCT, field, fieldRef.Required, fieldRef.Hidden); } createdCT.ReadOnly = templateContentType.ReadOnly; createdCT.Hidden = templateContentType.Hidden; createdCT.Sealed = templateContentType.Sealed; if (!string.IsNullOrEmpty(parser.ParseString(templateContentType.DocumentTemplate))) { createdCT.DocumentTemplate = parser.ParseString(templateContentType.DocumentTemplate); } if (!String.IsNullOrEmpty(templateContentType.NewFormUrl)) { createdCT.NewFormUrl = templateContentType.NewFormUrl; } if (!String.IsNullOrEmpty(templateContentType.EditFormUrl)) { createdCT.EditFormUrl = templateContentType.EditFormUrl; } if (!String.IsNullOrEmpty(templateContentType.DisplayFormUrl)) { createdCT.DisplayFormUrl = templateContentType.DisplayFormUrl; } // If the CT is a DocumentSet if (templateContentType.DocumentSetTemplate != null) { // Retrieve a reference to the DocumentSet Content Type Microsoft.SharePoint.Client.DocumentSet.DocumentSetTemplate documentSetTemplate = Microsoft.SharePoint.Client.DocumentSet.DocumentSetTemplate.GetDocumentSetTemplate(web.Context, createdCT); if (!String.IsNullOrEmpty(templateContentType.DocumentSetTemplate.WelcomePage)) { // TODO: Customize the WelcomePage of the DocumentSet } foreach (String ctId in templateContentType.DocumentSetTemplate.AllowedContentTypes) { Microsoft.SharePoint.Client.ContentType ct = existingCTs.FirstOrDefault(c => c.StringId == ctId); if (ct != null) { documentSetTemplate.AllowedContentTypes.Add(ct.Id); } } foreach (var doc in templateContentType.DocumentSetTemplate.DefaultDocuments) { Microsoft.SharePoint.Client.ContentType ct = existingCTs.FirstOrDefault(c => c.StringId == doc.ContentTypeId); if (ct != null) { using (Stream fileStream = connector.GetFileStream(doc.FileSourcePath)) { documentSetTemplate.DefaultDocuments.Add(doc.Name, ct.Id, ReadFullStream(fileStream)); } } } foreach (var sharedField in templateContentType.DocumentSetTemplate.SharedFields) { Microsoft.SharePoint.Client.Field field = existingFields.FirstOrDefault(f => f.Id == sharedField); if (field != null) { documentSetTemplate.SharedFields.Add(field); } } foreach (var welcomePageField in templateContentType.DocumentSetTemplate.WelcomePageFields) { Microsoft.SharePoint.Client.Field field = existingFields.FirstOrDefault(f => f.Id == welcomePageField); if (field != null) { documentSetTemplate.WelcomePageFields.Add(field); } } documentSetTemplate.Update(true); web.Context.ExecuteQueryRetry(); } web.Context.Load(createdCT); web.Context.ExecuteQueryRetry(); return(createdCT); }
private Microsoft.SharePoint.Client.ContentType CreateContentType( Web web, ProvisioningTemplate template, ContentType templateContentType, TokenParser parser, FileConnectorBase connector, PnPMonitoredScope scope, List <Microsoft.SharePoint.Client.ContentType> existingCTs = null, List <Microsoft.SharePoint.Client.Field> existingFields = null, bool isNoScriptSite = false) { var name = parser.ParseString(templateContentType.Name); var description = parser.ParseString(templateContentType.Description); var id = parser.ParseString(templateContentType.Id); var group = parser.ParseString(templateContentType.Group); var createdCT = web.CreateContentType(name, description, id, group); var fieldsRefsToProcess = templateContentType.FieldRefs.Select(fr => new { FieldRef = fr, TemplateField = template.SiteFields.FirstOrDefault(tf => (Guid)XElement.Parse(parser.ParseString(tf.SchemaXml)).Attribute("ID") == fr.Id) }).Where(frData => frData.TemplateField == null || // Process fields refs if the target is not defined in the current template frData.TemplateField.GetFieldProvisioningStep(parser) == _step // or process field ref only if the current step is matching ).Select(fr => fr.FieldRef).ToArray(); foreach (var fieldRef in fieldsRefsToProcess) { Microsoft.SharePoint.Client.Field field = null; try { field = web.AvailableFields.GetById(fieldRef.Id); } catch (ArgumentException) { if (!string.IsNullOrEmpty(fieldRef.Name)) { field = web.AvailableFields.GetByInternalNameOrTitle(fieldRef.Name); } } // Add it to the target content type // Notice that this code will fail if the field does not exist web.AddFieldToContentType(createdCT, field, fieldRef.Required, fieldRef.Hidden); } // Add new CTs parser.AddToken(new ContentTypeIdToken(web, name, id)); #if !ONPREMISES // Set resources if (templateContentType.Name.ContainsResourceToken()) { createdCT.NameResource.SetUserResourceValue(templateContentType.Name, parser); } if (templateContentType.Description.ContainsResourceToken()) { createdCT.DescriptionResource.SetUserResourceValue(templateContentType.Description, parser); } #endif //Reorder the elements so that the new created Content Type has the same order as defined in the //template. The order can be different if the new Content Type inherits from another Content Type. //In this case the new Content Type has all field of the original Content Type and missing fields //will be added at the end. To fix this issue we ordering the fields once more. createdCT.FieldLinks.Reorder(templateContentType.FieldRefs.Select(fld => parser.ParseString(fld.Name)).ToArray()); createdCT.ReadOnly = templateContentType.ReadOnly; createdCT.Hidden = templateContentType.Hidden; createdCT.Sealed = templateContentType.Sealed; if (templateContentType.DocumentSetTemplate == null) { // Only apply a document template when the contenttype is not a document set if (!string.IsNullOrEmpty(parser.ParseString(templateContentType.DocumentTemplate))) { createdCT.DocumentTemplate = parser.ParseString(templateContentType.DocumentTemplate); } } // Skipping updates of forms as we can't upload forms to noscript sites if (!isNoScriptSite) { if (!string.IsNullOrEmpty(parser.ParseString(templateContentType.NewFormUrl))) { createdCT.NewFormUrl = parser.ParseString(templateContentType.NewFormUrl); } if (!string.IsNullOrEmpty(parser.ParseString(templateContentType.EditFormUrl))) { createdCT.EditFormUrl = parser.ParseString(templateContentType.EditFormUrl); } if (!string.IsNullOrEmpty(parser.ParseString(templateContentType.DisplayFormUrl))) { createdCT.DisplayFormUrl = parser.ParseString(templateContentType.DisplayFormUrl); } } else { if (!string.IsNullOrEmpty(parser.ParseString(templateContentType.DisplayFormUrl)) || !string.IsNullOrEmpty(parser.ParseString(templateContentType.EditFormUrl)) || !string.IsNullOrEmpty(parser.ParseString(templateContentType.NewFormUrl))) { // log message scope.LogWarning(CoreResources.Provisioning_ObjectHandlers_ContentTypes_SkipCustomFormUrls, name); } } createdCT.Update(true); web.Context.ExecuteQueryRetry(); // If the CT is a DocumentSet if (templateContentType.DocumentSetTemplate != null) { // Retrieve a reference to the DocumentSet Content Type Microsoft.SharePoint.Client.DocumentSet.DocumentSetTemplate documentSetTemplate = Microsoft.SharePoint.Client.DocumentSet.DocumentSetTemplate.GetDocumentSetTemplate(web.Context, createdCT); // Load the collections to allow for deletion scenarions web.Context.Load(documentSetTemplate, d => d.AllowedContentTypes, d => d.DefaultDocuments, d => d.SharedFields, d => d.WelcomePageFields); web.Context.ExecuteQueryRetry(); if (!String.IsNullOrEmpty(templateContentType.DocumentSetTemplate.WelcomePage)) { // TODO: Customize the WelcomePage of the DocumentSet } // Add additional content types to the set of allowed content types bool hasDefaultDocumentContentTypeInTemplate = false; foreach (String ctId in templateContentType.DocumentSetTemplate.AllowedContentTypes) { Microsoft.SharePoint.Client.ContentType ct = existingCTs.FirstOrDefault(c => c.StringId == ctId); if (ct != null) { if (ct.Id.StringValue.Equals("0x0101", StringComparison.InvariantCultureIgnoreCase)) { hasDefaultDocumentContentTypeInTemplate = true; } documentSetTemplate.AllowedContentTypes.Add(ct.Id); } } // If the default document content type (0x0101) is not in our definition then remove it if (!hasDefaultDocumentContentTypeInTemplate) { Microsoft.SharePoint.Client.ContentType ct = existingCTs.FirstOrDefault(c => c.StringId == "0x0101"); if (ct != null) { documentSetTemplate.AllowedContentTypes.Remove(ct.Id); } } if (!isNoScriptSite) { foreach (var doc in templateContentType.DocumentSetTemplate.DefaultDocuments) { Microsoft.SharePoint.Client.ContentType ct = existingCTs.FirstOrDefault(c => c.StringId == doc.ContentTypeId); if (ct != null) { using (Stream fileStream = connector.GetFileStream(doc.FileSourcePath)) { documentSetTemplate.DefaultDocuments.Add(doc.Name, ct.Id, ReadFullStream(fileStream)); } } } } else { if (templateContentType.DocumentSetTemplate.DefaultDocuments.Any()) { scope.LogWarning(CoreResources.Provisioning_ObjectHandlers_ContentTypes_SkipDocumentSetDefaultDocuments, name); } } foreach (var sharedField in templateContentType.DocumentSetTemplate.SharedFields) { Microsoft.SharePoint.Client.Field field = existingFields.FirstOrDefault(f => f.Id == sharedField); if (field != null) { documentSetTemplate.SharedFields.Add(field); } } foreach (var welcomePageField in templateContentType.DocumentSetTemplate.WelcomePageFields) { Microsoft.SharePoint.Client.Field field = existingFields.FirstOrDefault(f => f.Id == welcomePageField); if (field != null) { documentSetTemplate.WelcomePageFields.Add(field); } } documentSetTemplate.Update(true); web.Context.ExecuteQueryRetry(); } else if (templateContentType.Id.StartsWith(BuiltInContentTypeId.Workflow2013Task + "00")) { // If the Workflow Task (SP2013) contains more than one outcomeChoice, the Form UI will not show // the buttons associated each to choices, but fallback to classic Save and Cancel buttons. // +"00" is used to target only inherited content types and not alter OOB var outcomeFields = web.Context.LoadQuery( createdCT.Fields.Where(f => f.TypeAsString == "OutcomeChoice")); web.Context.ExecuteQueryRetry(); if (outcomeFields.Any()) { // 2 OutcomeChoice specified means the user has certainly push its own. // Let's remove the default outcome field var field = outcomeFields.FirstOrDefault(f => f.StaticName == "TaskOutcome"); if (field != null) { var fl = createdCT.FieldLinks.GetById(field.Id); fl.DeleteObject(); createdCT.Update(true); web.Context.ExecuteQueryRetry(); } } } web.Context.Load(createdCT); web.Context.ExecuteQueryRetry(); return(createdCT); }