public void NewMaObjCreated(EventHandlerEnvironment env) { if (env.ObjVerEx.IsFirstVersion) { string mitarbeiter = $"{env.ObjVerEx.GetPropertyText("PD.Nachname")}, {env.ObjVerEx.GetPropertyText("PD.Vorname")}"; env.ObjVerEx.SetProperty("PD.VollstName", MFDataType.MFDatatypeText, mitarbeiter); int maObjType = env.Vault.ObjectTypeOperations.GetObjectTypeIDByAlias("Obj.MA"); //need ObjTypeID to get ObjectType for OwnerPropertyDef MFPropertyValuesBuilder vmdProperties = new MFPropertyValuesBuilder(env.Vault) .SetClass("CL.VMD") .Add("PD.VMD-Name", MFDataType.MFDatatypeText, $"VMD-{mitarbeiter}") .SetLookup(env.Vault.ObjectTypeOperations.GetObjectType(maObjType).OwnerPropertyDef, env.ObjVer) ; int newVMD = env.Vault.ObjectOperations.CreateNewObjectExQuick( env.Vault.ObjectTypeOperations.GetObjectTypeIDByAlias("Obj.VMD"), vmdProperties.Values ); env.ObjVerEx.SetProperty("PD.VertraulicheMitarbeiterdaten", MFDataType.MFDatatypeUninitialized, newVMD); //env.ObjVerEx.SetProperty("PD.FirstCheckin", MFDataType.MFDatatypeBoolean, false); env.ObjVerEx.SaveProperties(); } //chown when M-Files User is created if (env.ObjVerEx.HasValue("PD.MFUser")) { env.ObjVerEx.SaveProperty(MFBuiltInPropertyDef.MFBuiltInPropertyDefCreatedBy, MFDataType.MFDatatypeUninitialized, env.ObjVerEx.GetProperty("PD.MFUser")); env.ObjVerEx.GetDirectReference("PD.VertraulicheMitarbeiterdaten").SaveProperty(MFBuiltInPropertyDef.MFBuiltInPropertyDefCreatedBy, MFDataType.MFDatatypeUninitialized, env.ObjVerEx.GetProperty("PD.MFUser")); } }
/// <summary> /// Executes the <see cref="ObjectSelector"/> rule against the <see cref="XNode"/>, /// importing matching objects. /// </summary> /// <param name="vault">The vault reference to use for processing the import.</param> /// <param name="node">The node to import data from.</param> /// <param name="objectSelector">The selector to execute.</param> /// <param name="xmlFile">The information about the XML file being imported.</param> /// <param name="parent">A parent object to create a relationship to, if appropriate.</param> /// <param name="xmlNamespaceManager">A namespace manager for using XML prefixes in XPath statements.</param> /// <returns>A list of files which were attached to the object, for deletion.</returns> public List <FileInfo> ImportXmlFile( Vault vault, XNode node, ObjectSelector objectSelector, FileInfo xmlFile = null, ObjVer parent = null, XmlNamespaceManager xmlNamespaceManager = null) { // Sanity. if (vault == null) { throw new ArgumentNullException(nameof(vault)); } if (null == node) { throw new ArgumentNullException(nameof(node)); } if (null == objectSelector) { throw new ArgumentNullException(nameof(objectSelector)); } if (string.IsNullOrWhiteSpace(objectSelector.XPathQuery)) { throw new ArgumentException("The XPath query for the object was empty", nameof(objectSelector)); } if (null == objectSelector.PropertySelectors) { throw new ArgumentException("The object selector contained no property selectors.", nameof(objectSelector)); } if (false == objectSelector.ObjectType.IsResolved) { throw new InvalidOperationException("The object selector object type is not resolved"); } if (false == objectSelector.Class.IsResolved) { throw new InvalidOperationException("The object selector class is not resolved"); } // Create a list of attached files (which can then be deleted later). var attachedFilesToDelete = new List <FileInfo>(); // Create the namespace manager. if (null != xmlNamespaceManager) { // Copy data from the other manager (so we don't accidentally affect other queries). var xmlNamespaceManager2 = new XmlNamespaceManager(new NameTable()); foreach (string prefix in xmlNamespaceManager) { // Don't add default. if (string.IsNullOrWhiteSpace(prefix)) { continue; } if (prefix == "xsi") { continue; } if (prefix == "xmlns") { continue; } // Add. xmlNamespaceManager2.AddNamespace(prefix, xmlNamespaceManager.LookupNamespace(prefix)); } xmlNamespaceManager = xmlNamespaceManager2; } else { xmlNamespaceManager = new XmlNamespaceManager(new NameTable()); } // Populate the namespace manager. if (null != objectSelector.XmlNamespaces) { foreach (var ns in objectSelector.XmlNamespaces) { // If the namespace manager already contains a prefix then remove it. string existingPrefix = xmlNamespaceManager.LookupPrefix(ns.Uri); if (false == string.IsNullOrEmpty(existingPrefix)) { xmlNamespaceManager.RemoveNamespace(existingPrefix, ns.Uri); } xmlNamespaceManager.AddNamespace(ns.Prefix, ns.Uri); } } // Find matching nodes. foreach (var matchingElement in node.XPathSelectElements(objectSelector.XPathQuery, xmlNamespaceManager)) { // Hold all the properties being read. var propertyValuesBuilder = new MFPropertyValuesBuilder(vault); // Add the class property value. propertyValuesBuilder.SetClass(objectSelector.Class.ID); // Retrieve the properties. foreach (var propertySelector in objectSelector.PropertySelectors) { // Sanity. if (string.IsNullOrWhiteSpace(propertySelector.XPathQuery)) { throw new ArgumentException("The object selector contained no property selectors.", nameof(objectSelector)); } if (false == propertySelector.PropertyDef.IsResolved) { throw new InvalidOperationException("The property value selector property definition is not resolved"); } // Retrieve the element for the property value. // var matchingPropertyElement = matchingElement // .XPathSelectElement(propertySelector.XPathQuery, xmlNamespaceManager); //if (null == matchingPropertyElement) // continue; // Find the property definition type. var propertyDefType = vault .PropertyDefOperations .GetPropertyDef(propertySelector.PropertyDef.ID) .DataType; // Check if it's lookup or multilookup var isLookup = ((propertyDefType == MFDataType.MFDatatypeMultiSelectLookup) || (propertyDefType == MFDataType.MFDatatypeLookup)); #region itterate XAttributes from XPath if (propertySelector.XPathQuery.Contains("@")) { List <int> listLookup = new List <int>(); IEnumerable matchingPropertyAttributes = (IEnumerable)matchingElement.XPathEvaluate(propertySelector.XPathQuery); foreach (System.Xml.Linq.XAttribute matchingPropertyAttribute in matchingPropertyAttributes) { string szValue = matchingPropertyAttribute.Value; if (propertyDefType == MFDataType.MFDatatypeBoolean) { propertyValuesBuilder.Add( propertySelector.PropertyDef.ID, propertyDefType, CastToBool(szValue)); } else if (propertyDefType == MFDataType.MFDatatypeDate) { szValue = $"{szValue} 00:00:00"; propertyValuesBuilder.Add( propertySelector.PropertyDef.ID, propertyDefType, szValue); } else if (isLookup) { var iLookupDef = (propertySelector.LookupOrValuelistStrategy == LookupOrValuelistStrategy.SearchLookup ? propertySelector.LookupObjectDef.ID : propertySelector.LookupValueListDef.ID); var iLookupItem = LookupRef(vault, iLookupDef, propertyDefType, propertySelector.SearchByLookupID, szValue, propertySelector.LookupOrValuelistStrategy); if (iLookupItem != -1) { listLookup.Add(iLookupItem); } } else { propertyValuesBuilder.Add( propertySelector.PropertyDef.ID, propertyDefType, szValue); } } // Lookup or MultiSelectLookup and found something if ((isLookup) && (listLookup.Count != 0)) { int[] arrLookupIDs = listLookup.ToArray(); propertyValuesBuilder.Add( propertySelector.PropertyDef.ID, propertyDefType, arrLookupIDs); } } #endregion else #region itterate XElements from XPath { List <int> listLookup = new List <int>(); var matchingPropertyElements = matchingElement.XPathSelectElements(propertySelector.XPathQuery); if (null == matchingPropertyElements) { continue; } // iterate found XElements foreach (var matchingPropertyElement in matchingPropertyElements) { if (null == matchingPropertyElement) { continue; } string szValue = matchingPropertyElement.Value; if (propertyDefType == MFDataType.MFDatatypeBoolean) { propertyValuesBuilder.Add( propertySelector.PropertyDef.ID, propertyDefType, CastToBool(szValue)); } else if (propertyDefType == MFDataType.MFDatatypeDate) { szValue = $"{szValue} 00:00:00"; propertyValuesBuilder.Add( propertySelector.PropertyDef.ID, propertyDefType, szValue); } else if (isLookup) { var iLookupDef = (propertySelector.LookupOrValuelistStrategy == LookupOrValuelistStrategy.SearchLookup ? propertySelector.LookupObjectDef.ID : propertySelector.LookupValueListDef.ID); var iLookupItem = LookupRef(vault, iLookupDef, propertyDefType, propertySelector.SearchByLookupID, szValue, propertySelector.LookupOrValuelistStrategy); if (iLookupItem != -1) { listLookup.Add(iLookupItem); } propertyValuesBuilder.AddLookup( propertySelector.PropertyDef.ID, szValue); } else { propertyValuesBuilder.Add( propertySelector.PropertyDef.ID, propertyDefType, szValue); } } // Lookup or MultiSelectLookup and found something if ((isLookup) && (listLookup.Count != 0)) { int[] arrLookupIDs = listLookup.ToArray(); propertyValuesBuilder.Add( propertySelector.PropertyDef.ID, propertyDefType, arrLookupIDs); } } #endregion // Add the property to the builder. //propertyValuesBuilder.Add( //propertySelector.PropertyDef.ID, //propertyDefType, //matchingPropertyElement.Value); } // Set the static values foreach (var staticPropertyValue in objectSelector.StaticPropertyValues ?? new List <StaticPropertyValue>()) { // Sanity. if (false == staticPropertyValue.PropertyDef.IsResolved) { throw new InvalidOperationException("The property value selector property definition is not resolved"); } // Find the property definition type. var propertyDefType = vault .PropertyDefOperations .GetPropertyDef(staticPropertyValue.PropertyDef.ID) .DataType; // Add the property to the builder. propertyValuesBuilder.Add( staticPropertyValue.PropertyDef.ID, propertyDefType, staticPropertyValue.Value); } // Create a reference to the parent? if (null != parent) { // If the property definition to use was configured then use that. if (true == objectSelector.ParentRelationshipPropertyDef?.IsResolved) { // Check that this property is a list and is for the correct object type. var parentRelationshipPropertyDef = vault .PropertyDefOperations .GetPropertyDef(objectSelector.ParentRelationshipPropertyDef.ID); if (false == parentRelationshipPropertyDef.BasedOnValueList || parentRelationshipPropertyDef.ValueList != parent.Type) { throw new InvalidOperationException( $"The property def {parentRelationshipPropertyDef.Name} ({parentRelationshipPropertyDef.ID}) is not based on value list {parent.Type}."); } // Use the configured property definition. propertyValuesBuilder.Add( parentRelationshipPropertyDef.ID, parentRelationshipPropertyDef.DataType, parent.ID); } else { // Retrieve data about the parent object type. var parentObjectType = vault .ObjectTypeOperations .GetObjectType(parent.Type); // Retrieve data about the child object type. var childObjectType = vault .ObjectTypeOperations .GetObjectType(objectSelector.ObjectType.ID); // Is there an owner for this child type? if (childObjectType.HasOwnerType) { // Use the "owner" property definition. propertyValuesBuilder.Add( parentObjectType.OwnerPropertyDef, MFDataType.MFDatatypeLookup, parent.ID); } else { // Use the default property definition. propertyValuesBuilder.Add( parentObjectType.DefaultPropertyDef, MFDataType.MFDatatypeMultiSelectLookup, parent.ID); } } } // Create a container for any attached files. var sourceObjectFiles = new SourceObjectFiles(); // Should we attach the file to this object? if (objectSelector.AttachFileToThisObject) { // Locate the files to retrieve. sourceObjectFiles = this.FindFilesToAttach(objectSelector, xmlFile, matchingElement, xmlNamespaceManager); // If we were supposed to attach a file but no files were found then throw an exception. if (objectSelector.AttachedFileConfiguration?.FileNotFoundHandlingStrategy == FileNotFoundHandlingStrategy.Fail && 0 == sourceObjectFiles.Count) { throw new InvalidOperationException("Attached file expected but not found."); } if (objectSelector.AttachedFileConfiguration?.AttachedFileHandlingStrategy == AttachedFileHandlingStrategy.AttachToCurrentObject) { // Retrieve information about the object type from the vault. var objectType = vault .ObjectTypeOperations .GetObjectType(objectSelector.ObjectType.ID); // If the object type cannot have files but we are meant to attach a file, then fail. if (false == objectType.CanHaveFiles) { throw new InvalidOperationException( $"The object type {objectType.NameSingular} cannot have files, but the configuration states to attach a file."); } } } // Which source object files should we use for the new object? var sourceObjectFilesForNewObject = objectSelector.AttachedFileConfiguration?.AttachedFileHandlingStrategy == AttachedFileHandlingStrategy.AttachToCurrentObject ? sourceObjectFiles : new SourceObjectFiles(); // Add the object to the vault. var createdObject = vault .ObjectOperations .CreateNewObjectEx( objectSelector.ObjectType.ID, propertyValuesBuilder.Values, sourceObjectFilesForNewObject, SFD: objectSelector.ObjectType.ID == (int)MFBuiltInObjectType.MFBuiltInObjectTypeDocument && sourceObjectFilesForNewObject.Count == 1 ); // The files which need to be deleted. attachedFilesToDelete.AddRange( sourceObjectFiles .Cast <SourceObjectFile>() .Select(sof => new FileInfo(sof.SourceFilePath)) ); // Are there any related objects (e.g. children) to create? foreach (var childObjectSelector in objectSelector.ChildObjectSelectors) { attachedFilesToDelete.AddRange(this.ImportXmlFile(vault, matchingElement, childObjectSelector, xmlFile: xmlFile, parent: createdObject.ObjVer, xmlNamespaceManager: xmlNamespaceManager)); } // Clean up the collections we were using. propertyValuesBuilder = new MFPropertyValuesBuilder(vault); // Handle creating a new object for the file. if ( objectSelector.AttachFileToThisObject && objectSelector.AttachedFileConfiguration?.AttachedFileHandlingStrategy == AttachedFileHandlingStrategy.CreateNewObject) { // Set the static values foreach (var staticPropertyValue in objectSelector.AttachedFileConfiguration?.StaticPropertyValues ?? new List <StaticPropertyValue>()) { // Sanity. if (false == staticPropertyValue.PropertyDef.IsResolved) { throw new InvalidOperationException("The property value selector property definition is not resolved"); } // Find the property definition type. var propertyDefType = vault .PropertyDefOperations .GetPropertyDef(staticPropertyValue.PropertyDef.ID) .DataType; // Add the property to the builder. propertyValuesBuilder.Add( staticPropertyValue.PropertyDef.ID, propertyDefType, staticPropertyValue.Value); } // Add the class property value. propertyValuesBuilder.SetClass(objectSelector.AttachedFileConfiguration.Class.ID); // Add a reference from this new object to the one we created earlier. { // Retrieve data about the parent object type. var parentObjectType = vault .ObjectTypeOperations .GetObjectType(createdObject.ObjVer.Type); // Set the relationship. propertyValuesBuilder.Add( parentObjectType.DefaultPropertyDef, MFDataType.MFDatatypeMultiSelectLookup, createdObject.ObjVer.ID); } // Add the object to the vault. var createdDocumentObject = vault .ObjectOperations .CreateNewObjectEx( objectSelector.AttachedFileConfiguration.ObjectType.ID, propertyValuesBuilder.Values, sourceObjectFiles, SFD: objectSelector.AttachedFileConfiguration.ObjectType.ID == (int)MFBuiltInObjectType.MFBuiltInObjectTypeDocument && sourceObjectFiles.Count == 1 ); } } // Return the files to remove. return(attachedFilesToDelete); }
/// <summary> /// Implementation for <see cref="CreateCopy(ObjVerEx, ObjectCopyOptions" />. /// Interaction with the vault is via the <paramref name="objectCopyCreator"/>. /// </summary> /// <param name="source">The source object to copy.</param> /// <param name="objectCopyOptions">Options about how to copy the object.</param> /// <param name="objectCopyCreator">The instance that will actually create the copy.</param> /// <returns></returns> internal static ObjVerEx CreateCopy ( this ObjVerEx source, ObjectCopyOptions objectCopyOptions = null, IObjectCopyCreator objectCopyCreator = null ) { // Sanity. if (null == source) { throw new ArgumentNullException(nameof(source)); } objectCopyOptions = objectCopyOptions ?? new ObjectCopyOptions(); objectCopyCreator = objectCopyCreator ?? new ObjectCopyCreator(); // Create properties for the new object. // If we should copy the source properties then start there, // otherwise use an empty collection. var propertyValues = new MFPropertyValuesBuilder ( source.Vault, objectCopyOptions.CopySourceProperties ? source.Properties.Clone() : new PropertyValues() ); // Remove system properties if requested. if (objectCopyOptions.RemoveSystemProperties) { propertyValues.RemoveSystemProperties(); } // Create an instruction to set SFD to false (will be applied in next section). // Will be set accordingly later. { var instruction = new PropertyValueInstruction() { InstructionType = PropertyValueInstructionType.RemovePropertyValue }; instruction.PropertyValue.PropertyDef = (int)MFBuiltInPropertyDef.MFBuiltInPropertyDefSingleFileObject; objectCopyOptions.Properties.Add(instruction); } // Modify the properties as appropriate by running the instructions. if (null != objectCopyOptions.Properties) { foreach (var instruction in objectCopyOptions.Properties) { if (null == instruction) { continue; } instruction.ApplyTo(propertyValues.Values); } } // Are there any properties that are deleted? foreach (PropertyValue property in propertyValues.Values.Clone()) { try { var loadedProperty = source.Vault.PropertyDefOperations.GetPropertyDef(property.PropertyDef); } catch { // Property cannot be loaded; it has been deleted. propertyValues.Values.RemoveProperty(property.PropertyDef); } } // Create the object, but do not check it in. var newObject = new ObjVerEx(source.Vault, objectCopyCreator.CreateObject ( source.Vault, objectCopyOptions.TargetObjectType ?? source.ObjVer.Type, propertyValues.Values, sourceObjectFiles: null, // We will add these later. singleFileDocument: false, // Always false here, until we know how many files we're copying. checkIn: false, // Don't check in until the files have been added. accessControlList: objectCopyOptions.CopySourceACL ? source.ACL : null )); // Copy the source files to the new object. var fileCount = 0; if (objectCopyOptions.CopySourceFiles && null != source?.Info?.Files) { // Note: using .Cast() here throws out our Moq tests, so let's not use it... foreach (ObjectFile file in source.Info.Files) { fileCount++; using (var fileStream = file.OpenRead(source.Vault)) { objectCopyCreator.AddFile(newObject, file.Title, file.Extension, fileStream); } } } // Add any additional files. if (null != objectCopyOptions.AdditionalFiles) { foreach (SourceObjectFile sourceFile in objectCopyOptions.AdditionalFiles) { fileCount++; objectCopyCreator.AddFile ( newObject, sourceFile.Title, sourceFile.Extension, sourceFile.SourceFilePath ); } } // If the option is set to false then we'll get whatever the source was // (unless it went from a document to something else, in which case it's always false). if (objectCopyOptions.SetSingleFileDocumentIfAppropriate) { // True if a single file. objectCopyCreator.SetSingleFileDocument ( newObject, newObject.Type == (int)MFBuiltInObjectType.MFBuiltInObjectTypeDocument && fileCount == 1 ); } // Check in? if (objectCopyOptions.CheckInObject) { objectCopyCreator.CheckIn ( newObject, objectCopyOptions.CheckInComments ?? "", objectCopyOptions.CreatedByUserId ?? -1 ); } // Return the shiny new object. return(newObject); }