private void CleanFields(SharePointSession session, FieldCollection fields) { if (this.FieldGroup == null) { return; } ClientContext clientContext = session.ClientContext; clientContext.Load(fields, c => c.Include(t => t.Group, t => t.StaticName)); session.ExecuteQuery(); List <Field> tbdFields = new List <Field>(); foreach (Field f in fields) { if (f.Group == this.FieldGroup) { tbdFields.Add(f); } } if (tbdFields.Count > 0) { foreach (Field f in tbdFields) { f.DeleteObject(); } session.ExecuteQuery(); } }
private void ApplyMetadata(FolderInfo folder, ProgressTracker tracker) { // Apply the actual metadata to the folder, including permissions, attributes, etc. using (ObjectPool <SharePointSession> .Ref sessionRef = this.ImportContext.SessionFactory.GetSession()) { SharePointSession session = sessionRef.Target; ClientContext clientContext = session.ClientContext; XElement xml = XElement.Load(folder.Location); XNamespace ns = xml.GetDefaultNamespace(); Folder f = clientContext.Web.GetFolderByServerRelativeUrl(folder.Url); tracker.TrackProgress("Gathering metadata and permissions for folder at [{0}]", folder.SafeFullPath); ContentType contentType = ResolveContentType(folder.Type); if (contentType != null) { f.ListItemAllFields["ContentTypeId"] = contentType.Id; } FolderInfo parent = ResolveFolder(folder.Path); bool individualAcl = (parent == null || (folder.Acl != parent.Acl)); ApplyMetadata(f.ListItemAllFields, xml); string aclResult = "inherited"; if (individualAcl) { aclResult = "independent"; f.ListItemAllFields.BreakRoleInheritance(false, false); ApplyPermissions(f.ListItemAllFields, xml); } tracker.TrackProgress("The ACL for [{0}] will be {1} from its parent's", folder.SafeFullPath, aclResult); SetAuthorAndEditor(f.ListItemAllFields, xml); if (individualAcl) { ApplyOwnerPermission(f.ListItemAllFields, xml); } f.ListItemAllFields.Update(); f.Update(); tracker.TrackProgress("Applying metadata and permissions on folder at [{0}]", folder.SafeFullPath); session.ExecuteQuery(); ShowProgress(); } }
public static int MainLoop(string[] args) { ILog log = null; string baseDir = Directory.GetCurrentDirectory(); // Initialize log4j Configuration options = new Configuration(baseDir, args); if (options.help) { Console.Error.WriteLine(options.GetUsage()); return(1); } List <string> errors = options.ValidateConfiguration(); if (errors.Count > 0) { Console.Error.WriteLine(string.Format("{0} Configuration Errors detected:", errors.Count)); foreach (string e in errors) { Console.Error.WriteLine(string.Format("\t* {0}", e)); } return(2); } System.IO.Directory.CreateDirectory(options.caches); string logDir = string.Format("{0}\\logs", baseDir); System.IO.Directory.CreateDirectory(logDir); Environment.SetEnvironmentVariable("CMF_LOGDATE", string.Format("{0:yyyyMMdd-HHmmss}", DateTime.Now)); Environment.SetEnvironmentVariable("CMF_LOGDIR", logDir); XmlConfigurator.Configure(new FileInfo(string.Format("{0}\\log4net.xml", baseDir))); LOG = log = LogManager.GetLogger(typeof(Launcher)); log.Info("Initializing Application"); if (options.indexOnly) { ImportContext importContext = new ImportContext(null, options.content, options.metadata, options.caches); FormatResolver formatResolver = new FormatResolver(importContext); new DocumentImporter(new FolderImporter(importContext), formatResolver, options.locationMode, options.fixExtensions).StoreLocationIndex(); return(0); } ServicePointManager.MaxServicePointIdleTime = (int)SharePointSession.TIME_OUT.TotalMilliseconds; ServicePointManager.SetTcpKeepAlive(true, (int)SharePointSession.TIME_OUT.TotalMilliseconds, 60000); ServicePointManager.DefaultConnectionLimit = options.threads * 10; using (DirectoryEntry ldapDirectory = BindToLDAP(options)) { log.Info(string.Format("Using SharePoint at [{0}]", options.siteUrl)); string userString = options.user; if (!string.IsNullOrWhiteSpace(options.domain)) { userString = string.Format("{0}@{1}", userString, options.domain); } SecureString userPassword = null; if (!string.IsNullOrWhiteSpace(options.user)) { if (options.password == null) { Console.Write(string.Format("Enter The Sharepoint Password for [{0}]: ", userString)); userPassword = Tools.ReadPassword(); } else { String pass = CRYPT.Decrypt(options.password); pass = CRYPT.Encrypt(pass); log.Info(string.Format("Using stored credentials for [{0}] = [{1}]", userString, pass)); userPassword = new SecureString(); foreach (char c in CRYPT.Decrypt(pass)) { userPassword.AppendChar(c); } } } using (SharePointSessionFactory sessionFactory = new SharePointSessionFactory(new SharePointSessionInfo(options.siteUrl, options.user, userPassword, options.domain, options.applicationId, options.certificateKey, options.certificatePass, options.library, options.reuseCount))) { ImportContext importContext = new ImportContext(sessionFactory, options.content, options.metadata, options.caches); using (ObjectPool <SharePointSession> .Ref sessionRef = sessionFactory.GetSession()) { SharePointSession session = sessionRef.Target; ClientContext clientContext = session.ClientContext; List documentLibrary = sessionRef.Target.DocumentLibrary; // We configure the document library as required documentLibrary.EnableVersioning = true; documentLibrary.EnableMinorVersions = true; documentLibrary.ForceCheckout = false; documentLibrary.ContentTypesEnabled = true; // documentLibrary.MajorVersionLimit = 50000; // documentLibrary.MajorWithMinorVersionsLimit = 50000; documentLibrary.Update(); session.ExecuteQuery(); } FormatResolver formatResolver = new FormatResolver(importContext); ContentTypeImporter contentTypeImporter = null; for (int i = 0; i <= options.retries; i++) { try { contentTypeImporter = new ContentTypeImporter(importContext, options.library, options.cleanTypes); break; } catch (Exception e) { contentTypeImporter = null; log.Warn("WARNING: ContentTypeImporter failed to initialize due to an exception", e); } } if (contentTypeImporter == null) { log.Error(string.Format("ContentTypeImporter failed to initialize after {0} attempts", options.retries + 1)); return(3); } UserGroupImporter userGroupImporter = null; for (int i = 0; i <= options.retries; i++) { try { userGroupImporter = new UserGroupImporter(importContext, ldapDirectory, options.ldapSyncDomain, options.fallbackUser, options.internalUser, options.fallbackGroup, options.internalGroup); break; } catch (Exception e) { userGroupImporter = null; log.Warn("WARNING: UserGroupImporter failed to initialize due to an exception", e); } } if (userGroupImporter == null) { log.Error(string.Format("UserGroupImporter failed to initialize after {0} attempts", options.retries + 1)); return(4); } PermissionsImporter permissionsImporter = new PermissionsImporter(userGroupImporter); FolderImporter folderImporter = new FolderImporter(contentTypeImporter, permissionsImporter); DocumentImporter documentImporter = new DocumentImporter(folderImporter, formatResolver, options.locationMode, options.fixExtensions); bool aborted = false; Console.CancelKeyPress += delegate(object sender, ConsoleCancelEventArgs e) { if (aborted) { return; } aborted = true; e.Cancel = true; documentImporter.Abort = true; folderImporter.Abort = true; string msg = "Program Interrupted (hit Ctrl-C again to terminate immediately)"; if (log == null) { Console.WriteLine(msg); } else { log.Warn(msg); } }; try { documentImporter.StoreDocuments(options.threads, options.simulationMode, options.locationMode, options.autoPublish, options.retries); folderImporter.FinalizeFolders(options.threads, options.retries); documentImporter.StoreLocationIndex(); } finally { log.Info(documentImporter.ProcessingReport); log.Info(folderImporter.ProcessingReport); } return(aborted ? 1 : 0); } } }
public async Task SaveSharePointSession(Guid sessionId, SharePointSession sharePointSession) { await SetAsync(sessionId.ToString(), sharePointSession, AuthenticationParameters.CacheSessionDurationInMinutes); }
private void ProcessAccumulatedFolders(SharePointSession session, Dictionary <string, List <FolderInfo> > folders) { // This allows for the case where we're only creating indexes, and don't want to touch the repository if (session == null) { return; } ClientContext clientContext = session.ClientContext; Folder rootFolder = session.RootFolder; // We know all of these folders are at the same depth, so for all of these we only need // to find their parent folder(s), and add the new folders Web web = clientContext.Web; // Step 1: gather all the parent folders in this batch Dictionary <string, Folder> spFolders = new Dictionary <string, Folder>(); List <FolderInfo> processed = new List <FolderInfo>(); foreach (string parent in folders.Keys) { Folder f = null; if (parent == "") { f = rootFolder; } else { f = web.GetFolderByServerRelativeUrl(rootFolder.ServerRelativeUrl + parent); } clientContext.Load(f, r => r.ServerRelativeUrl); spFolders[parent] = f; } // Now get all the parent folders in a single query session.ExecuteQuery(); // Step 2: go through all the parent folders, and create their children int batch = 0; foreach (string parent in folders.Keys) { Folder parentFolder = spFolders[parent]; foreach (FolderInfo f in folders[parent]) { ProgressTracker tracker = new ProgressTracker(f.Location, this.Log); if (tracker.Completed) { f.SPObj = parentFolder.Folders.GetByUrl(f.SafeName); f.Exists = true; Log.Info(string.Format("Loaded existing folder [{0}] from [{1}]", f.FullPath, f.SafeFullPath)); } else { f.SPObj = parentFolder.Folders.Add(f.SafeName); f.Modified = true; Log.Info(string.Format("Added folder [{0}] for creation as [{1}]", f.FullPath, f.SafeFullPath)); } clientContext.Load(f.SPObj, r => r.ServerRelativeUrl); processed.Add(f); // Do them in bunches of 50 if (++batch >= 50) { Log.Info(string.Format("Executing the creation of the last {0} folders", batch)); session.ExecuteQuery(); batch = 0; } } } // Now, create all the children in a single query if (batch > 0) { Log.Info(string.Format("Executing the creation of the last {0} folders", batch)); session.ExecuteQuery(); } foreach (FolderInfo f in processed) { // Update the server relative URLs for each of them f.Url = f.SPObj.ServerRelativeUrl; } }
private FolderImporter(ImportContext importContext, ContentTypeImporter contentTypeImporter, PermissionsImporter permissionsImporter) : base("folders", importContext, contentTypeImporter, permissionsImporter) { Dictionary <string, FolderInfo> folderDictionary = new Dictionary <string, FolderInfo>(); using (XmlReader folders = this.ImportContext.LoadIndex("folders")) { int currentDepth = 0; Dictionary <string, List <FolderInfo> > accumulated = new Dictionary <string, List <FolderInfo> >(); int accumulatedCount = 0; using (ObjectPool <SharePointSession> .Ref sessionRef = this.ImportContext.SessionFactory?.GetSession()) { SharePointSession session = sessionRef?.Target; outer : while (folders.ReadToFollowing("folder")) { string location = null; string path = null; using (XmlReader folder = folders.ReadSubtree()) { // We're only interested in the <location> and <path> elements, so if they're not there // we simply move on to the next folder if (!folder.ReadToFollowing("path")) { goto outer; } path = "/" + folder.ReadElementContentAsString(); if (!folder.ReadToFollowing("location")) { goto outer; } location = folder.ReadElementContentAsString(); } int thisDepth = (path == "/" ? 0 : thisDepth = Tools.CountChars(path, '/')); // If we've changed depths, we process what we've accumulated so far if (thisDepth > currentDepth) { if (session != null) { Log.Info(string.Format("Creating {0} folders in the target environment, depth {1}", accumulatedCount, thisDepth)); try { ProcessAccumulatedFolders(session, accumulated); } catch (Exception e) { Log.Error("Failed to process the current accumulated folder batch"); throw e; } } accumulated.Clear(); accumulatedCount = 0; currentDepth = thisDepth; } // A new folder to handle... FolderInfo f = new FolderInfo(this.ImportContext.FormatMetadataLocation(location)); List <FolderInfo> l = null; if (!accumulated.ContainsKey(f.SafePath)) { l = new List <FolderInfo>(); accumulated[f.SafePath] = l; } else { l = accumulated[f.SafePath]; } /* * if (thisDepth == 0) * { * // Check to see if this is a cabinet we want to avoid * if (XmlConvert.ToBoolean(XmlTools.GetAttributeValue(xml, "dctm:is_private"))) * { * Log.Info(string.Format("Skipping private cabinet [{0}]", f.FullPath)); * continue; * } * } */ l.Add(f); accumulatedCount++; folderDictionary[f.FullPath] = f; } if ((session != null) && accumulatedCount > 0) { Log.Info(string.Format("Creating {0} folders in the target environment, depth {1}", accumulated.Count, currentDepth + 1)); try { ProcessAccumulatedFolders(session, accumulated); } catch (Exception e) { Log.Error("Failed to process the last accumulated folder batch"); throw e; } } } } this.Folders = folderDictionary; }
private void CleanContentTypes(SharePointSession session, ContentTypeCollection contentTypes) { if (this.TypeGroup == null) { return; } ClientContext clientContext = session.ClientContext; clientContext.Load(contentTypes, c => c.Include(t => t.Id, t => t.Name, t => t.Group, t => t.Parent, t => t.Parent.Name, t => t.Parent.Group)); session.ExecuteQuery(); Dictionary <string, ContentType> tbdTypes = new Dictionary <string, ContentType>(); foreach (ContentType type in contentTypes) { if (type.Group == this.TypeGroup) { tbdTypes[type.Name] = type; } } if (tbdTypes.Count > 0) { // TODO: we have an inheritance issue here, in that parent types can't be // deleted prior to their subtypes...so build the tree... Dictionary <int, List <ContentType> > tree = new Dictionary <int, List <ContentType> >(); int maxDepth = -1; foreach (ContentType type in tbdTypes.Values) { // Calculate the depth for this item int depth = 0; ContentType current = type; while (current.Parent != null && current.Parent.Name != current.Name && current.Parent.Group == this.TypeGroup) { depth++; if (!tbdTypes.ContainsKey(current.Parent.Name)) { break; } current = tbdTypes[current.Parent.Name]; } List <ContentType> l = null; if (tree.ContainsKey(depth)) { l = tree[depth]; } else { l = new List <ContentType>(); tree[depth] = l; } l.Add(type); if (depth > maxDepth) { maxDepth = depth; } } for (int d = maxDepth; d >= 0; d--) { foreach (ContentType type in tree[d]) { type.DeleteObject(); } } session.ExecuteQuery(); } }
public ContentTypeImporter(ImportContext importContext, String documentLibraryName, bool clearFirst) : base("content types", importContext) { this.Log.Info(string.Format("Mapping the object types to content types and columns to the site and the library [{0}]...", documentLibraryName)); // TODO: Make these two configurable this.TypeGroup = TYPE_GROUP; this.FieldGroup = FIELD_GROUP; using (ObjectPool <SharePointSession> .Ref sessionRef = this.ImportContext.SessionFactory.GetSession()) { SharePointSession session = sessionRef.Target; ClientContext clientContext = session.ClientContext; List documentLibrary = clientContext.Web.Lists.GetByTitle(documentLibraryName); if (clearFirst) { try { Log.Warn("Cleaning out document library content types..."); CleanContentTypes(sessionRef.Target, documentLibrary.ContentTypes); Log.Warn("Cleaning out document library fields..."); CleanFields(sessionRef.Target, documentLibrary.Fields); Log.Warn("Cleaning out site content types..."); CleanContentTypes(sessionRef.Target, clientContext.Web.ContentTypes); Log.Warn("Cleaning out site fields..."); CleanFields(sessionRef.Target, clientContext.Web.Fields); Log.Warn("Fields and content types cleared!"); } catch (Exception e) { Log.Warn("Tried to remove the existing content types, but failed", e); } } ContentTypeCollection contentTypeCollection = clientContext.Web.ContentTypes; clientContext.Load(contentTypeCollection, c => c.Include(t => t.Id, t => t.Name, t => t.Group, t => t.Parent, t => t.FieldLinks)); clientContext.Load(documentLibrary.ContentTypes, c => c.Include(t => t.Id, t => t.Name, t => t.Parent)); clientContext.Load(clientContext.Web, w => w.Fields, w => w.AvailableFields); session.ExecuteQuery(); // First we gather up whatever's already there Dictionary <string, ImportedContentType> siteContentTypes = new Dictionary <string, ImportedContentType>(); Dictionary <string, ImportedContentType> libraryContentTypes = new Dictionary <string, ImportedContentType>(); Dictionary <string, ImportedContentType> contentTypesById = new Dictionary <string, ImportedContentType>(); Dictionary <string, ContentType> allTypes = new Dictionary <string, ContentType>(); foreach (ContentType type in contentTypeCollection) { ImportedContentType ct = new ImportedContentType(this, type); siteContentTypes[type.Name] = ct; contentTypesById[type.Id.StringValue] = ct; } Dictionary <string, Field> existingFields = new Dictionary <string, Field>(); foreach (Field f in clientContext.Web.Fields) { existingFields[f.StaticName] = f; } HashSet <string> documentLibraryTypes = new HashSet <string>(); foreach (ContentType ct in documentLibrary.ContentTypes) { documentLibraryTypes.Add(ct.Name); ImportedContentType ict = new ImportedContentType(this, ct); libraryContentTypes[ct.Name] = ict; contentTypesById[ct.Id.StringValue] = ict; } // Now we go over the XML declarations HashSet <string> newTypes = new HashSet <string>(); XElement types = XElement.Load(this.ImportContext.LoadIndex("types")); XNamespace ns = types.GetDefaultNamespace(); foreach (XElement type in types.Elements(ns + "type")) { string typeName = (string)type.Element(ns + "name"); ImportedContentType finalType = null; HashSet <string> linkNames = new HashSet <string>(); bool skipInherited = true; bool patchFields = false; bool versionableType = false; bool containerType = false; if (siteContentTypes.ContainsKey(typeName)) { finalType = siteContentTypes[typeName]; foreach (FieldLink link in finalType.Type.FieldLinks) { linkNames.Add(link.Name); } if (typeName == "dm_sysobject" || typeName == "dm_folder") { patchFields = true; versionableType = (typeName == "dm_sysobject"); containerType = (typeName == "dm_folder"); } } else { // New type...create it ImportedContentType superType = null; XElement superTypeElement = type.Element(ns + "superType"); if ((superTypeElement != null) && (typeName != "dm_folder")) { string stName = (string)superTypeElement; if (siteContentTypes.ContainsKey(stName)) { superType = siteContentTypes[stName]; } } if (superType == null) { switch (typeName) { case "dm_sysobject": superType = siteContentTypes["Document"]; // skipInherited = false; patchFields = true; versionableType = true; break; case "dm_folder": superType = siteContentTypes["Folder"]; // skipInherited = false; patchFields = true; containerType = true; break; default: // This isn't a type we're intereseted in, so we skip it continue; } } Log.Info(string.Format("Creating content type {0} (descended from [{1}]])", typeName, superType.Name)); ContentTypeCreationInformation ctInfo = new ContentTypeCreationInformation(); ctInfo.Description = string.Format("Documentum Type {0}", typeName); ctInfo.Name = typeName; ctInfo.ParentContentType = (superType != null ? superType.Type : null); ctInfo.Group = this.TypeGroup; ContentType contentTypeObj = contentTypeCollection.Add(ctInfo); clientContext.Load(contentTypeObj, t => t.Id); session.ExecuteQuery(); finalType = new ImportedContentType(this, contentTypeObj, superType.Id); siteContentTypes[typeName] = finalType; contentTypesById[finalType.Id.StringValue] = finalType; } // Now we link the type to its fields, as needed int updateCount = 0; XElement attributeContainer = type.Element(ns + "attributes"); if (patchFields) { XElement versionAtt = new XElement(ns + "attribute"); versionAtt.SetAttributeValue("length", "32"); versionAtt.SetAttributeValue("repeating", "false"); versionAtt.SetAttributeValue("inherited", "false"); versionAtt.SetAttributeValue("sourceName", "version"); versionAtt.SetAttributeValue("name", "cmf:version"); versionAtt.SetAttributeValue("dataType", "STRING"); attributeContainer.AddFirst(versionAtt); versionAtt = new XElement(ns + "attribute"); versionAtt.SetAttributeValue("length", "400"); versionAtt.SetAttributeValue("repeating", "false"); versionAtt.SetAttributeValue("inherited", "false"); versionAtt.SetAttributeValue("sourceName", "title"); versionAtt.SetAttributeValue("name", "cmis:description"); versionAtt.SetAttributeValue("dataType", "STRING"); attributeContainer.AddFirst(versionAtt); versionAtt = new XElement(ns + "attribute"); versionAtt.SetAttributeValue("length", "128"); versionAtt.SetAttributeValue("repeating", "false"); versionAtt.SetAttributeValue("inherited", "false"); versionAtt.SetAttributeValue("sourceName", "author_name"); versionAtt.SetAttributeValue("name", "shpt:authorName"); versionAtt.SetAttributeValue("dataType", "STRING"); attributeContainer.AddFirst(versionAtt); versionAtt = new XElement(ns + "attribute"); versionAtt.SetAttributeValue("length", "0"); versionAtt.SetAttributeValue("repeating", "false"); versionAtt.SetAttributeValue("inherited", "false"); versionAtt.SetAttributeValue("sourceName", "author"); versionAtt.SetAttributeValue("name", "shpt:author"); versionAtt.SetAttributeValue("dataType", "USER"); attributeContainer.AddFirst(versionAtt); versionAtt = new XElement(ns + "attribute"); versionAtt.SetAttributeValue("length", "128"); versionAtt.SetAttributeValue("repeating", "false"); versionAtt.SetAttributeValue("inherited", "false"); versionAtt.SetAttributeValue("sourceName", "editor_name"); versionAtt.SetAttributeValue("name", "shpt:editorName"); versionAtt.SetAttributeValue("dataType", "STRING"); attributeContainer.AddFirst(versionAtt); versionAtt = new XElement(ns + "attribute"); versionAtt.SetAttributeValue("length", "0"); versionAtt.SetAttributeValue("repeating", "false"); versionAtt.SetAttributeValue("inherited", "false"); versionAtt.SetAttributeValue("sourceName", "editor"); versionAtt.SetAttributeValue("name", "shpt:editor"); versionAtt.SetAttributeValue("dataType", "USER"); attributeContainer.AddFirst(versionAtt); versionAtt = new XElement(ns + "attribute"); versionAtt.SetAttributeValue("length", "16"); versionAtt.SetAttributeValue("repeating", "false"); versionAtt.SetAttributeValue("inherited", "false"); versionAtt.SetAttributeValue("sourceName", "object_id"); versionAtt.SetAttributeValue("name", "cmis:objectId"); versionAtt.SetAttributeValue("dataType", "STRING"); attributeContainer.AddFirst(versionAtt); versionAtt = new XElement(ns + "attribute"); versionAtt.SetAttributeValue("length", "256"); versionAtt.SetAttributeValue("repeating", "false"); versionAtt.SetAttributeValue("inherited", "false"); versionAtt.SetAttributeValue("sourceName", "location"); versionAtt.SetAttributeValue("name", "cmf:location"); versionAtt.SetAttributeValue("dataType", "STRING"); attributeContainer.AddFirst(versionAtt); versionAtt = new XElement(ns + "attribute"); versionAtt.SetAttributeValue("length", "256"); versionAtt.SetAttributeValue("repeating", "false"); versionAtt.SetAttributeValue("inherited", "false"); versionAtt.SetAttributeValue("sourceName", "path"); versionAtt.SetAttributeValue("name", "cmis:path"); versionAtt.SetAttributeValue("dataType", "STRING"); attributeContainer.AddFirst(versionAtt); versionAtt = new XElement(ns + "attribute"); versionAtt.SetAttributeValue("length", "256"); versionAtt.SetAttributeValue("repeating", "false"); versionAtt.SetAttributeValue("inherited", "false"); versionAtt.SetAttributeValue("sourceName", "name"); versionAtt.SetAttributeValue("name", "cmis:name"); versionAtt.SetAttributeValue("dataType", "STRING"); attributeContainer.AddFirst(versionAtt); versionAtt = new XElement(ns + "attribute"); versionAtt.SetAttributeValue("length", "1024"); versionAtt.SetAttributeValue("repeating", "true"); versionAtt.SetAttributeValue("inherited", "false"); versionAtt.SetAttributeValue("sourceName", "keywords"); versionAtt.SetAttributeValue("name", "dctm:keywords"); versionAtt.SetAttributeValue("dataType", "STRING"); attributeContainer.AddFirst(versionAtt); versionAtt = new XElement(ns + "attribute"); versionAtt.SetAttributeValue("length", "16"); versionAtt.SetAttributeValue("repeating", "false"); versionAtt.SetAttributeValue("inherited", "false"); versionAtt.SetAttributeValue("sourceName", "acl_id"); versionAtt.SetAttributeValue("name", "dctm:acl_id"); versionAtt.SetAttributeValue("dataType", "STRING"); attributeContainer.AddFirst(versionAtt); if (versionableType) { versionAtt = new XElement(ns + "attribute"); versionAtt.SetAttributeValue("length", "16"); versionAtt.SetAttributeValue("repeating", "false"); versionAtt.SetAttributeValue("inherited", "false"); versionAtt.SetAttributeValue("sourceName", "history_id"); versionAtt.SetAttributeValue("name", "cmis:versionSeriesId"); versionAtt.SetAttributeValue("dataType", "STRING"); attributeContainer.AddFirst(versionAtt); versionAtt = new XElement(ns + "attribute"); versionAtt.SetAttributeValue("length", "16"); versionAtt.SetAttributeValue("repeating", "false"); versionAtt.SetAttributeValue("inherited", "false"); versionAtt.SetAttributeValue("sourceName", "antecedent_id"); versionAtt.SetAttributeValue("name", "cmf:version_antecedent_id"); versionAtt.SetAttributeValue("dataType", "STRING"); attributeContainer.AddFirst(versionAtt); versionAtt = new XElement(ns + "attribute"); versionAtt.SetAttributeValue("length", "0"); versionAtt.SetAttributeValue("repeating", "false"); versionAtt.SetAttributeValue("inherited", "false"); versionAtt.SetAttributeValue("sourceName", "current"); versionAtt.SetAttributeValue("name", "cmis:isLatestVersion"); versionAtt.SetAttributeValue("dataType", "BOOLEAN"); attributeContainer.AddFirst(versionAtt); } } foreach (XElement att in attributeContainer.Elements(ns + "attribute")) { // The attribute is either not inherited or its inheritance is ignored, so add it to the content type's declaration string attName = att.Attribute("name").Value; string attSourceName = att.Attribute("sourceName").Value; string finalName = string.Format("dctm_{0}", attSourceName); // Special case for folder attributes inherited from dm_sysobject bool inherited = XmlConvert.ToBoolean(att.Attribute("inherited").Value) && (typeName != "dm_folder"); bool repeating = XmlConvert.ToBoolean(att.Attribute("repeating").Value); // If this is an inherited attribute, we won't add it because we're not interested in it if (inherited && skipInherited) { continue; } ImportedContentTypeField finalField = null; if (linkNames.Contains(finalName) || (inherited && skipInherited)) { // Existing or inherited link... finalField = new ImportedContentTypeField(existingFields[finalName], attName, finalName, attSourceName, repeating); } else { FieldLinkCreationInformation fieldLink = new FieldLinkCreationInformation(); if (existingFields.ContainsKey(finalName)) { finalField = new ImportedContentTypeField(existingFields[finalName], attName, finalName, attSourceName, repeating); fieldLink.Field = finalField.Field; } else { Log.Info(string.Format("Creating field {0} (first declared by {1})", finalName, typeName)); FieldType attType = Tools.DecodeFieldType(att.Attribute("dataType").Value); if (repeating) { // Default repeating fields to strings, since they'll be concatenated attType = FieldType.Note; } int length = XmlConvert.ToInt32(att.Attribute("length").Value); if (length > 255) { attType = FieldType.Note; } Guid guid = Guid.NewGuid(); string fieldXml = string.Format("<Field DisplayName='{0}' Name='{1}' ID='{2}' Group='{3}' Type='{4}' />", finalName, finalName, guid.ToString(), this.FieldGroup, attType); fieldLink.Field = clientContext.Web.Fields.AddFieldAsXml(fieldXml, false, AddFieldOptions.AddFieldInternalNameHint); clientContext.Load(fieldLink.Field, f => f.Id, f => f.FieldTypeKind, f => f.StaticName, f => f.Group); existingFields[finalName] = fieldLink.Field; finalField = new ImportedContentTypeField(existingFields[finalName], attName, finalName, attSourceName, repeating); } finalType.Type.FieldLinks.Add(fieldLink); linkNames.Add(finalName); updateCount++; } finalType.AddField(finalField); } if (updateCount > 0) { finalType.Type.Update(true); session.ExecuteQuery(); } newTypes.Add(typeName); } // Now, make sure this type exists in the document library List <ContentType> newContentTypes = new List <ContentType>(); foreach (string typeName in newTypes) { if (!documentLibraryTypes.Contains(typeName)) { ContentType ct = documentLibrary.ContentTypes.AddExistingContentType(siteContentTypes[typeName].Type); newContentTypes.Add(ct); clientContext.Load(ct); clientContext.Load(ct, c => c.Parent); } } if (newContentTypes.Count > 0) { session.ExecuteQuery(); foreach (ContentType ct in newContentTypes) { ImportedContentType newCt = new ImportedContentType(this, ct); contentTypesById[ct.Id.StringValue] = newCt; libraryContentTypes[ct.Name] = newCt; } } this.SiteContentTypes = siteContentTypes; this.LibraryContentTypes = libraryContentTypes; this.ContentTypesById = contentTypesById; } }