/// <summary> /// Determines if the column is a lookup /// </summary> /// <param name="List"></param> /// <param name="ColumnName"></param> /// <param name="LookupListName"></param> /// <returns></returns> static bool IsLookup(SPListDefinition List, string ColumnName, out SPFieldDefinitionModel LookupField) { LookupField = null; foreach (var spc in List.FieldDefinitions .Where(sfield => sfield.InternalName.Equals(ColumnName, StringComparison.CurrentCultureIgnoreCase) && sfield.FieldTypeKind == FieldType.Lookup)) { LookupField = spc; return(true); } return(false); }
/// <summary> /// Provisions a site column based on the field definition specified /// </summary> /// <param name="hostWeb">The instantiated site/web to which the column will be retrieved and/or provisioned</param> /// <param name="fieldDefinition">The definition for the field</param> /// <param name="loggerVerbose">Provides a method for verbose logging</param> /// <param name="loggerError">Provides a method for exception logging</param> /// <param name="SiteGroups">(OPTIONAL) collection of group, required if this is a PeoplePicker field</param> /// <param name="provisionerChoices">(OPTIONAL) deserialized choices from JSON</param> /// <returns></returns> public static Field CreateColumn(this Web hostWeb, SPFieldDefinitionModel fieldDefinition, ITraceLogger logger, List <SPGroupDefinitionModel> SiteGroups, List <SiteProvisionerFieldChoiceModel> provisionerChoices = null) { if (fieldDefinition == null) { throw new ArgumentNullException("fieldDef", "Field definition is required."); } if (string.IsNullOrEmpty(fieldDefinition.InternalName)) { throw new ArgumentNullException("InternalName"); } if (fieldDefinition.LoadFromJSON && (provisionerChoices == null || !provisionerChoices.Any(pc => pc.FieldInternalName == fieldDefinition.InternalName))) { throw new ArgumentNullException("provisionerChoices", string.Format("You must specify a collection of field choices for the field {0}", fieldDefinition.Title)); } var fields = hostWeb.Context.LoadQuery(hostWeb.Fields.Include(f => f.Id, f => f.InternalName, f => f.Title, f => f.JSLink, f => f.Indexed, f => f.CanBeDeleted, f => f.Required)); hostWeb.Context.ExecuteQueryRetry(); var returnField = fields.FirstOrDefault(f => f.Id == fieldDefinition.FieldGuid || f.InternalName == fieldDefinition.InternalName || f.Title == fieldDefinition.InternalName); if (returnField == null) { var finfoXml = hostWeb.CreateFieldDefinition(fieldDefinition, SiteGroups, provisionerChoices); logger.LogInformation("Provision Site field {0} with XML:{1}", fieldDefinition.InternalName, finfoXml); try { var createdField = hostWeb.CreateField(finfoXml, executeQuery: false); hostWeb.Context.ExecuteQueryRetry(); } catch (Exception ex) { logger.LogError(ex, "EXCEPTION: field {0} with message {1}", fieldDefinition.InternalName, ex.Message); } finally { returnField = hostWeb.Fields.GetByInternalNameOrTitle(fieldDefinition.InternalName); hostWeb.Context.Load(returnField, fd => fd.Id, fd => fd.Title, fd => fd.Indexed, fd => fd.InternalName, fd => fd.CanBeDeleted, fd => fd.Required); hostWeb.Context.ExecuteQuery(); } } return(returnField); }
/// <summary> /// Provisions a column based on the field defintion to the host list /// </summary> /// <param name="hostList">The instantiated list/library to which the field will be added</param> /// <param name="fieldDef">The definition for the field</param> /// <param name="loggerVerbose">Provides a method for verbose logging</param> /// <param name="loggerError">Provides a method for exception logging</param> /// <param name="SiteGroups">(OPTIONAL) collection of group, required if this is a PeoplePicker field</param> /// <param name="JsonFilePath">(OPTIONAL) file path except if loading choices from JSON</param> /// <returns></returns> /// <exception cref="ArgumentNullException">For field definitions that do not contain all required data</exception> public static Field CreateListColumn(this List hostList, SPFieldDefinitionModel fieldDef, Action <string, string[]> loggerVerbose, Action <string, string[]> loggerError, List <SPGroupDefinitionModel> SiteGroups, string JsonFilePath = null) { if (fieldDef == null) { throw new ArgumentNullException("fieldDef", "Field definition is required."); } if (!hostList.IsPropertyAvailable("Context")) { } var fields = hostList.Fields; hostList.Context.Load(fields, fc => fc.Include(f => f.Id, f => f.InternalName, f => f.Title, f => f.JSLink, f => f.Indexed, f => f.CanBeDeleted, f => f.Required)); hostList.Context.ExecuteQueryRetry(); var returnField = fields.FirstOrDefault(f => f.Id == fieldDef.FieldGuid || f.InternalName == fieldDef.InternalName); if (returnField == null) { try { var baseFieldXml = hostList.CreateFieldDefinition(fieldDef, SiteGroups, JsonFilePath); loggerVerbose("Provision field {0} with XML:{1}", new string[] { fieldDef.InternalName, baseFieldXml }); // Should throw an exception if the field ID or Name exist in the list var baseField = hostList.CreateField(baseFieldXml, fieldDef.AddToDefaultView, executeQuery: false); hostList.Context.ExecuteQueryRetry(); } catch (Exception ex) { var msg = ex.Message; loggerError("EXCEPTION: field {0} with message {1}", new string[] { fieldDef.InternalName, msg }); } finally { returnField = hostList.Fields.GetByInternalNameOrTitle(fieldDef.InternalName); hostList.Context.Load(returnField, fd => fd.Id, fd => fd.Title, fd => fd.Indexed, fd => fd.InternalName, fd => fd.CanBeDeleted, fd => fd.Required); hostList.Context.ExecuteQueryRetry(); } } return(returnField); }
/// <summary> /// Provisions a column based on the field defintion to the host list /// </summary> /// <param name="hostList">The instantiated list/library to which the field will be added</param> /// <param name="fieldDefinition">The definition for the field</param> /// <param name="loggerVerbose">Provides a method for verbose logging</param> /// <param name="loggerError">Provides a method for exception logging</param> /// <param name="SiteGroups">(OPTIONAL) collection of group, required if this is a PeoplePicker field</param> /// <param name="provisionerChoices">(OPTIONAL) deserialized choices from JSON</param> /// <returns></returns> /// <exception cref="ArgumentNullException">For field definitions that do not contain all required data</exception> public static Field CreateListColumn(this List hostList, SPFieldDefinitionModel fieldDefinition, ITraceLogger logger, List <SPGroupDefinitionModel> SiteGroups, List <SiteProvisionerFieldChoiceModel> provisionerChoices = null) { if (fieldDefinition == null) { throw new ArgumentNullException("fieldDef", "Field definition is required."); } if (fieldDefinition.LoadFromJSON && (provisionerChoices == null || !provisionerChoices.Any(pc => pc.FieldInternalName == fieldDefinition.InternalName))) { throw new ArgumentNullException("provisionerChoices", string.Format("You must specify a collection of field choices for the field {0}", fieldDefinition.Title)); } // load fields into memory hostList.Context.Load(hostList.Fields, fc => fc.Include(f => f.Id, f => f.InternalName, fctx => fctx.Title, f => f.Title, f => f.JSLink, f => f.Indexed, f => f.CanBeDeleted, f => f.Required)); hostList.Context.ExecuteQueryRetry(); var returnField = hostList.Fields.FirstOrDefault(f => f.Id == fieldDefinition.FieldGuid || f.InternalName == fieldDefinition.InternalName); if (returnField == null) { try { var baseFieldXml = hostList.CreateFieldDefinition(fieldDefinition, SiteGroups, provisionerChoices); logger.LogInformation("Provision List {0} field {1} with XML:{2}", hostList.Title, fieldDefinition.InternalName, baseFieldXml); // Should throw an exception if the field ID or Name exist in the list var baseField = hostList.CreateField(baseFieldXml, fieldDefinition.AddToDefaultView, executeQuery: false); hostList.Context.ExecuteQueryRetry(); } catch (Exception ex) { var msg = ex.Message; logger.LogError(ex, "EXCEPTION: field {0} with message {1}", fieldDefinition.InternalName, msg); } finally { returnField = hostList.Fields.GetByInternalNameOrTitle(fieldDefinition.InternalName); hostList.Context.Load(returnField, fd => fd.Id, fd => fd.Title, fd => fd.Indexed, fd => fd.InternalName, fd => fd.CanBeDeleted, fd => fd.Required); hostList.Context.ExecuteQueryRetry(); } } return(returnField); }
/// <summary> /// Provisions a site column based on the field definition specified /// </summary> /// <param name="hostWeb">The instantiated site/web to which the column will be retrieved and/or provisioned</param> /// <param name="fieldDef">The definition for the field</param> /// <param name="loggerVerbose">Provides a method for verbose logging</param> /// <param name="loggerError">Provides a method for exception logging</param> /// <param name="SiteGroups">(OPTIONAL) collection of group, required if this is a PeoplePicker field</param> /// <param name="JsonFilePath">(OPTIONAL) file path except if loading choices from JSON</param> /// <returns></returns> public static Field CreateColumn(this Web hostWeb, SPFieldDefinitionModel fieldDef, Action <string, string[]> loggerVerbose, Action <Exception, string, string[]> loggerError, List <SPGroupDefinitionModel> SiteGroups, string JsonFilePath = null) { if (!hostWeb.IsPropertyAvailable("Context")) { } var fields = hostWeb.Fields; hostWeb.Context.Load(fields, fc => fc.Include(f => f.Id, f => f.InternalName, f => f.Title, f => f.JSLink, f => f.Indexed, f => f.CanBeDeleted, f => f.Required)); hostWeb.Context.ExecuteQueryRetry(); var returnField = fields.FirstOrDefault(f => f.Id == fieldDef.FieldGuid || f.InternalName == fieldDef.InternalName); if (returnField == null) { var finfoXml = hostWeb.CreateFieldDefinition(fieldDef, SiteGroups, JsonFilePath); loggerVerbose("Provision field {0} with XML:{1}", new string[] { fieldDef.InternalName, finfoXml }); try { var createdField = hostWeb.CreateField(finfoXml, executeQuery: false); hostWeb.Context.ExecuteQueryRetry(); } catch (Exception ex) { loggerError(ex, "EXCEPTION: field {0} with message {1}", new string[] { fieldDef.InternalName, ex.Message }); } finally { returnField = hostWeb.Fields.GetByInternalNameOrTitle(fieldDef.InternalName); hostWeb.Context.Load(returnField, fd => fd.Id, fd => fd.Title, fd => fd.Indexed, fd => fd.InternalName, fd => fd.CanBeDeleted, fd => fd.Required); hostWeb.Context.ExecuteQuery(); } } return(returnField); }
/// <summary> /// Builds a Field Creation Info object from the Definition model and returns its resulting XML /// </summary> /// <param name="host">The instantiated web/list/library to which the field will be added</param> /// <param name="fieldDefinition">The definition pulled from a SP Site or user construction</param> /// <param name="siteGroups">The collection of site groups that a user/group field make filter</param> /// <param name="JsonFilePath">The file path to a JSON file containing Choice lookups</param> /// <returns></returns> public static string CreateFieldDefinition(this SecurableObject host, SPFieldDefinitionModel fieldDefinition, List <SPGroupDefinitionModel> siteGroups, string JsonFilePath = null) { var idguid = fieldDefinition.FieldGuid; var choiceXml = string.Empty; var defaultChoiceXml = string.Empty; var attributes = new List <KeyValuePair <string, string> >(); if (string.IsNullOrEmpty(fieldDefinition.InternalName)) { throw new ArgumentNullException("InternalName"); } if (string.IsNullOrEmpty(fieldDefinition.DisplayName)) { throw new ArgumentNullException("DisplayName"); } if (!string.IsNullOrEmpty(fieldDefinition.LoadFromJSON) && string.IsNullOrEmpty(JsonFilePath)) { throw new ArgumentNullException("JsonFilePath", "You must specify a file path to the JSON file if loading from JSON"); } if (!string.IsNullOrEmpty(fieldDefinition.PeopleGroupName) && (siteGroups == null || siteGroups.Count() <= 0)) { throw new ArgumentNullException("SiteGroups", string.Format("You must specify a collection of group for the field {0}", fieldDefinition.DisplayName)); } if (string.IsNullOrEmpty(fieldDefinition.LookupListName) && fieldDefinition.fieldType == FieldType.Lookup) { throw new ArgumentNullException("LookupListName", string.Format("you must specify a lookup list title for the field {0}", fieldDefinition.DisplayName)); } if (!string.IsNullOrEmpty(fieldDefinition.Description)) { attributes.Add(new KeyValuePair <string, string>("Description", fieldDefinition.Description)); } if (fieldDefinition.FieldIndexed) { attributes.Add(new KeyValuePair <string, string>("Indexed", fieldDefinition.FieldIndexed.ToString().ToUpper())); } if (fieldDefinition.AppendOnly) { attributes.Add(new KeyValuePair <string, string>("AppendOnly", fieldDefinition.AppendOnly.ToString().ToUpper())); } var choices = new FieldType[] { FieldType.Choice, FieldType.GridChoice, FieldType.MultiChoice, FieldType.OutcomeChoice }; if (choices.Any(a => a == fieldDefinition.fieldType)) { if (!string.IsNullOrEmpty(fieldDefinition.LoadFromJSON)) { var filePath = string.Format("{0}\\{1}", JsonFilePath, fieldDefinition.LoadFromJSON); //#TODO: Check file path var contents = JsonConvert.DeserializeObject <List <SPChoiceModel> >(System.IO.File.ReadAllText(filePath)); fieldDefinition.FieldChoices.Clear(); fieldDefinition.FieldChoices.AddRange(contents); } choiceXml = string.Format("<CHOICES>{0}</CHOICES>", string.Join("", fieldDefinition.FieldChoices.Select(s => string.Format("<CHOICE>{0}</CHOICE>", s.Choice.Trim())).ToArray())); if (!string.IsNullOrEmpty(fieldDefinition.ChoiceDefault)) { defaultChoiceXml = string.Format("<Default>{0}</Default>", fieldDefinition.ChoiceDefault); } if (fieldDefinition.fieldType == FieldType.Choice) { attributes.Add(new KeyValuePair <string, string>("Format", fieldDefinition.ChoiceFormat.ToString("f"))); } } else if (fieldDefinition.fieldType == FieldType.DateTime) { if (fieldDefinition.DateFieldFormat.HasValue) { attributes.Add(new KeyValuePair <string, string>("DisplayFormat", fieldDefinition.DateFieldFormat.Value.ToString("f"))); } } else if (fieldDefinition.fieldType == FieldType.Note) { attributes.Add(new KeyValuePair <string, string>("RichText", fieldDefinition.RichTextField.ToString().ToUpper())); attributes.Add(new KeyValuePair <string, string>("NumLines", fieldDefinition.NumLines.ToString())); if (fieldDefinition.RestrictedMode) { attributes.Add(new KeyValuePair <string, string>("RestrictedMode", fieldDefinition.RestrictedMode.ToString().ToUpper())); } else { attributes.Add(new KeyValuePair <string, string>("RichTextMode", "FullHtml")); attributes.Add(new KeyValuePair <string, string>("IsolateStyles", true.ToString().ToUpper())); } } else if (fieldDefinition.fieldType == FieldType.User) { //AllowMultipleValues if (fieldDefinition.MultiChoice) { attributes.Add(new KeyValuePair <string, string>("Mult", fieldDefinition.MultiChoice.ToString().ToUpper())); } //SelectionMode if (fieldDefinition.PeopleOnly) { attributes.Add(new KeyValuePair <string, string>("UserSelectionMode", FieldUserSelectionMode.PeopleOnly.ToString("d"))); } if (!string.IsNullOrEmpty(fieldDefinition.PeopleLookupField)) { attributes.Add(new KeyValuePair <string, string>("ShowField", fieldDefinition.PeopleLookupField)); //fldUser.LookupField = fieldDef.PeopleLookupField; } if (!string.IsNullOrEmpty(fieldDefinition.PeopleGroupName)) { var group = siteGroups.FirstOrDefault(f => f.Title == fieldDefinition.PeopleGroupName); if (group != null) { attributes.Add(new KeyValuePair <string, string>("UserSelectionScope", group.Id.ToString())); } } } else if (fieldDefinition.fieldType == FieldType.Lookup) { var lParentList = host.GetAssociatedWeb().GetListByTitle(fieldDefinition.LookupListName); var strParentListID = lParentList.Id; attributes.Add(new KeyValuePair <string, string>("EnforceUniqueValues", false.ToString().ToUpper())); attributes.Add(new KeyValuePair <string, string>("List", strParentListID.ToString("B"))); attributes.Add(new KeyValuePair <string, string>("ShowField", fieldDefinition.LookupListFieldName)); } var finfo = fieldDefinition.ToCreationObject(); finfo.AdditionalAttributes = attributes; var finfoXml = FieldAndContentTypeExtensions.FormatFieldXml(finfo); if (!string.IsNullOrEmpty(choiceXml)) { XDocument xd = XDocument.Parse(finfoXml); XElement root = xd.FirstNode as XElement; if (!string.IsNullOrEmpty(defaultChoiceXml)) { root.Add(XElement.Parse(defaultChoiceXml)); } root.Add(XElement.Parse(choiceXml)); finfoXml = xd.ToString(); } return(finfoXml); }
/// <summary> /// Process the request /// </summary> public override void ExecuteCmdlet() { base.ExecuteCmdlet(); // Initialize logging instance with Powershell logger ITraceLogger logger = new DefaultUsageLogger(LogVerbose, LogWarning, LogError); // Skip these specific fields var skiptypes = new FieldType[] { FieldType.Invalid, FieldType.Computed, FieldType.ContentTypeId, FieldType.Invalid, FieldType.WorkflowStatus, FieldType.WorkflowEventType, FieldType.Threading, FieldType.ThreadIndex, FieldType.Recurrence, FieldType.PageSeparator, FieldType.OutcomeChoice, FieldType.CrossProjectLink, FieldType.ModStat, FieldType.Error, FieldType.MaxItems, FieldType.Attachments }; // Definition file to operate on SiteProvisionerModel siteDefinition = null; try { // Retreive JSON Provisioner file and deserialize it var filePath = new System.IO.FileInfo(this.ProvisionerFilePath); var filePathJSON = System.IO.File.ReadAllText(filePath.FullName); siteDefinition = JsonConvert.DeserializeObject <SiteProvisionerModel>(filePathJSON); } catch (Exception ex) { logger.LogError(ex, "Failed to parse {0} Exception {1}", ProvisionerFilePath, ex.Message); return; } // Expectation is that list already exists in target location foreach (var customListDefinition in siteDefinition.Lists.OrderBy(ob => ob.ProvisionOrder)) { var etlList = this.ClientContext.Web.GetListByTitle(customListDefinition.ListName, lctx => lctx.Id, lctx => lctx.RootFolder.ServerRelativeUrl, lctx => lctx.Title); logger.LogInformation("List {0}", etlList.Title); var dataMigratedFieldModel = new SPFieldDefinitionModel(FieldType.Boolean) { InternalName = "DataMigrated", Title = "DataMigrated", AddToDefaultView = false, AutoIndexed = true, DefaultValue = "0", FieldGuid = new Guid("9a353694-a5b4-4be4-a77a-c67bb071fbb5"), FieldIndexed = true, GroupName = "customcolumns" }; var dataMigratedField = etlList.CreateListColumn(dataMigratedFieldModel, logger, null, null); var sourceFieldModel = new SPFieldDefinitionModel(FieldType.Integer) { InternalName = "SourceItemID", Title = "SourceItemID", AddToDefaultView = false, AutoIndexed = true, FieldGuid = new Guid("e57a0936-5e8b-45d6-8c1c-d3e971c5b570"), FieldIndexed = true, GroupName = "customcolumns" }; var sourceField = etlList.CreateListColumn(sourceFieldModel, logger, null, null); // pull the internal names from list definition var customFields = customListDefinition.FieldDefinitions .Where(lf => !skiptypes.Any(st => lf.FieldTypeKind == st)) .Select(s => s.InternalName); logger.LogWarning("Processing list {0} found {1} fields to be processed", etlList.Title, customFields.Count()); // enumerate list items and add them to the list if (customListDefinition.ListItems != null && customListDefinition.ListItems.Any()) { foreach (var item in customListDefinition.ListItems) { var lici = new ListItemCreationInformation(); var newItem = etlList.AddItem(lici); newItem[ConstantsFields.Field_Title] = item.Title; newItem["SourceItemID"] = item.Id; newItem["DataMigrated"] = true; newItem.Update(); logger.LogInformation("Processing list {0} Setting up Item {1}", etlList.Title, item.Id); var customColumns = item.ColumnValues.Where(cv => customFields.Any(cf => cf.Equals(cv.FieldName))); foreach (var spRefCol in customColumns) { var internalFieldName = spRefCol.FieldName; var itemColumnValue = spRefCol.FieldValue; if (IsLookup(customListDefinition, internalFieldName, out SPFieldDefinitionModel strParent)) { newItem[internalFieldName] = GetParentItemID(this.ClientContext, itemColumnValue, strParent, logger); } else if (IsUser(customListDefinition, internalFieldName)) { newItem[internalFieldName] = GetUserID(this.ClientContext, itemColumnValue, logger); } else { newItem[internalFieldName] = itemColumnValue; } newItem.Update(); } etlList.Context.ExecuteQueryRetry(); } } } }
/// <summary> /// Returns the parent item ID /// </summary> /// <param name="cContext"></param> /// <param name="ItemName"></param> /// <param name="ParentListColumn"></param> /// <param name="logger">diagnostics logger</param> /// <returns></returns> static int GetParentItemID(ClientContext cContext, dynamic ItemName, SPFieldDefinitionModel ParentListColumn, ITraceLogger logger) { int nReturn = -1; var parentListName = string.Empty; var parentListColumnName = string.Empty; NativeFieldLookupValue lookupValue = null; try { string itemJsonString = ItemName.ToString(); Newtonsoft.Json.Linq.JObject jobject = Newtonsoft.Json.Linq.JObject.Parse(itemJsonString); lookupValue = jobject.ToObject <NativeFieldLookupValue>(); parentListName = ParentListColumn.LookupListName; parentListColumnName = ParentListColumn.LookupListFieldName; logger.LogInformation("Start GetParentItemID {0} for column {1}", parentListName, parentListColumnName); Web wWeb = cContext.Web; var lParentList = cContext.Web.GetListByTitle(parentListName, lctx => lctx.Id, lctx => lctx.Title); var camlQuery = new CamlQuery() { ViewXml = CAML.ViewQuery( CAML.Where( CAML.Eq( CAML.FieldValue(parentListColumnName, FieldType.Text.ToString("f"), lookupValue.LookupValue)) ), string.Empty, 10 ) }; ListItemCollectionPosition itemPosition = null; while (true) { var collListItem = lParentList.GetItems(camlQuery); cContext.Load(collListItem, lictx => lictx.ListItemCollectionPosition); cContext.ExecuteQueryRetry(); itemPosition = collListItem.ListItemCollectionPosition; foreach (var oListItem in collListItem) { nReturn = oListItem.Id; break; } // we drop out of the forloop above but if we are paging do we want to skip duplicate results if (itemPosition == null) { break; } } logger.LogInformation("Complete GetParentItemID {0} resulted in ID => {1}", parentListName, nReturn); } catch (Exception ex) { logger.LogError(ex, "Failed to query lookup value {0}", ex.Message); } return(nReturn); }
/// <summary> /// Builds a Field Creation Info object from the Definition model and returns its resulting XML /// </summary> /// <param name="host">The instantiated web/list/library to which the field will be added</param> /// <param name="fieldDefinition">The definition pulled from a SP Site or user construction</param> /// <param name="siteGroups">The collection of site groups that a user/group field make filter</param> /// <param name="provisionerChoices">(OPTIONAL) The collection of hoice lookups as defined in the serialized JSON file</param> /// <returns></returns> public static string CreateFieldDefinition(this SecurableObject host, SPFieldDefinitionModel fieldDefinition, List <SPGroupDefinitionModel> siteGroups, List <SiteProvisionerFieldChoiceModel> provisionerChoices = null) { var idguid = fieldDefinition.FieldGuid; var choiceXml = string.Empty; var defaultChoiceXml = string.Empty; var formulaXml = string.Empty; var fieldReferenceXml = string.Empty; var attributes = new List <KeyValuePair <string, string> >(); if (string.IsNullOrEmpty(fieldDefinition.InternalName)) { throw new ArgumentNullException("InternalName"); } if (string.IsNullOrEmpty(fieldDefinition.Title)) { throw new ArgumentNullException("DisplayName"); } if (!string.IsNullOrEmpty(fieldDefinition.PeopleGroupName) && (siteGroups == null || siteGroups.Count() <= 0)) { throw new ArgumentNullException("SiteGroups", string.Format("You must specify a collection of group for the field {0}", fieldDefinition.Title)); } if (string.IsNullOrEmpty(fieldDefinition.LookupListName) && fieldDefinition.FieldTypeKind == FieldType.Lookup) { throw new ArgumentNullException("LookupListName", string.Format("you must specify a lookup list title for the field {0}", fieldDefinition.Title)); } if (fieldDefinition.LoadFromJSON && (provisionerChoices == null || !provisionerChoices.Any(pc => pc.FieldInternalName == fieldDefinition.InternalName))) { throw new ArgumentNullException("provisionerChoices", string.Format("You must specify a collection of field choices for the field {0}", fieldDefinition.Title)); } if (!string.IsNullOrEmpty(fieldDefinition.Description)) { attributes.Add(new KeyValuePair <string, string>("Description", fieldDefinition.Description.UnescapeXml().EscapeXml(true))); } if (fieldDefinition.FieldIndexed) { attributes.Add(new KeyValuePair <string, string>("Indexed", fieldDefinition.FieldIndexed.ToString().ToUpper())); } if (fieldDefinition.AppendOnly) { attributes.Add(new KeyValuePair <string, string>("AppendOnly", fieldDefinition.AppendOnly.ToString().ToUpper())); } var choices = new FieldType[] { FieldType.Choice, FieldType.GridChoice, FieldType.MultiChoice, FieldType.OutcomeChoice }; if (choices.Any(a => a == fieldDefinition.FieldTypeKind)) { if (fieldDefinition.LoadFromJSON && (provisionerChoices != null && provisionerChoices.Any(fc => fc.FieldInternalName == fieldDefinition.InternalName))) { var choicecontents = provisionerChoices.FirstOrDefault(fc => fc.FieldInternalName == fieldDefinition.InternalName); fieldDefinition.FieldChoices.Clear(); fieldDefinition.FieldChoices.AddRange(choicecontents.Choices); } //AllowMultipleValues if (fieldDefinition.MultiChoice) { attributes.Add(new KeyValuePair <string, string>("Mult", fieldDefinition.MultiChoice.ToString().ToUpper())); } choiceXml = string.Format("<CHOICES>{0}</CHOICES>", string.Join("", fieldDefinition.FieldChoices.Select(s => string.Format("<CHOICE>{0}</CHOICE>", s.Choice.Trim())).ToArray())); if (!string.IsNullOrEmpty(fieldDefinition.ChoiceDefault)) { defaultChoiceXml = string.Format("<Default>{0}</Default>", fieldDefinition.ChoiceDefault); } if (fieldDefinition.FieldTypeKind == FieldType.Choice) { attributes.Add(new KeyValuePair <string, string>("Format", fieldDefinition.ChoiceFormat.ToString("f"))); } } else if (fieldDefinition.FieldTypeKind == FieldType.DateTime) { if (fieldDefinition.DateFieldFormat.HasValue) { attributes.Add(new KeyValuePair <string, string>("Format", fieldDefinition.DateFieldFormat.Value.ToString("f"))); } } else if (fieldDefinition.FieldTypeKind == FieldType.Note) { attributes.Add(new KeyValuePair <string, string>("RichText", fieldDefinition.RichTextField.ToString().ToUpper())); attributes.Add(new KeyValuePair <string, string>("RestrictedMode", fieldDefinition.RestrictedMode.ToString().ToUpper())); attributes.Add(new KeyValuePair <string, string>("NumLines", fieldDefinition.NumLines.ToString())); if (!fieldDefinition.RestrictedMode) { attributes.Add(new KeyValuePair <string, string>("RichTextMode", "FullHtml")); attributes.Add(new KeyValuePair <string, string>("IsolateStyles", true.ToString().ToUpper())); } } else if (fieldDefinition.FieldTypeKind == FieldType.User) { //AllowMultipleValues if (fieldDefinition.MultiChoice) { attributes.Add(new KeyValuePair <string, string>("Mult", fieldDefinition.MultiChoice.ToString().ToUpper())); } //SelectionMode if (fieldDefinition.PeopleOnly) { attributes.Add(new KeyValuePair <string, string>("UserSelectionMode", FieldUserSelectionMode.PeopleOnly.ToString("d"))); } if (!string.IsNullOrEmpty(fieldDefinition.PeopleLookupField)) { attributes.Add(new KeyValuePair <string, string>("ShowField", fieldDefinition.PeopleLookupField)); //fldUser.LookupField = fieldDef.PeopleLookupField; } if (!string.IsNullOrEmpty(fieldDefinition.PeopleGroupName)) { var group = siteGroups.FirstOrDefault(f => f.Title == fieldDefinition.PeopleGroupName); if (group != null) { attributes.Add(new KeyValuePair <string, string>("UserSelectionScope", group.Id.ToString())); } } } else if (fieldDefinition.FieldTypeKind == FieldType.Lookup) { var lParentList = host.GetAssociatedWeb().GetListByTitle(fieldDefinition.LookupListName); var strParentListID = lParentList.Id; attributes.Add(new KeyValuePair <string, string>("EnforceUniqueValues", false.ToString().ToUpper())); attributes.Add(new KeyValuePair <string, string>("List", strParentListID.ToString("B"))); attributes.Add(new KeyValuePair <string, string>("ShowField", fieldDefinition.LookupListFieldName)); if (fieldDefinition.MultiChoice) { attributes.Add(new KeyValuePair <string, string>("Mult", fieldDefinition.MultiChoice.ToString().ToUpper())); } } else if (fieldDefinition.FieldTypeKind == FieldType.Calculated) { attributes.Add(new KeyValuePair <string, string>("ResultType", fieldDefinition.OutputType.Value.ToString("f"))); formulaXml = string.Format("<Formula>{0}</Formula>", fieldDefinition.DefaultFormula.UnescapeXml().EscapeXml()); fieldReferenceXml = string.Format("<FieldRefs>{0}</FieldRefs>", string.Join("", fieldDefinition.FieldReferences.Select(s => CAML.FieldRef(s.Trim())).ToArray())); } // construct the XML var finfo = fieldDefinition.ToCreationObject(); finfo.AdditionalAttributes = attributes; var finfoXml = FieldAndContentTypeExtensions.FormatFieldXml(finfo); if (!string.IsNullOrEmpty(choiceXml)) { XDocument xd = XDocument.Parse(finfoXml); XElement root = xd.FirstNode as XElement; if (!string.IsNullOrEmpty(defaultChoiceXml)) { root.Add(XElement.Parse(defaultChoiceXml)); } root.Add(XElement.Parse(choiceXml)); finfoXml = xd.ToString(); } if (!string.IsNullOrEmpty(formulaXml)) { XDocument xd = XDocument.Parse(finfoXml); XElement root = xd.FirstNode as XElement; root.Add(XElement.Parse(formulaXml)); if (!string.IsNullOrEmpty(fieldReferenceXml)) { root.Add(XElement.Parse(fieldReferenceXml)); } finfoXml = xd.ToString(); } return(finfoXml); }
/// <summary> /// Parse the Field into the portable field definition object /// </summary> /// <param name="context">The web context in which the field is provisioned</param> /// <param name="field">The field from which we are pulling a portable definition</param> /// <param name="logger">Injectable logger for writing Trace events</param> /// <param name="siteGroups">A collection of SharePoint groups</param> /// <param name="schemaXml">(OPTIONAL) the schema xml parsed into an XDocument</param> /// <returns></returns> public static SPFieldDefinitionModel RetrieveField(this ClientContext context, Field field, ITraceLogger logger, IEnumerable <Group> siteGroups = null, XElement schemaXml = null) { field.EnsureProperties( lft => lft.Id, lft => lft.AutoIndexed, lft => lft.CanBeDeleted, lft => lft.DefaultFormula, lft => lft.DefaultValue, lft => lft.Group, lft => lft.Description, lft => lft.EnforceUniqueValues, lft => lft.FieldTypeKind, lft => lft.Filterable, lft => lft.FromBaseType, lft => lft.Hidden, lft => lft.Indexed, lft => lft.InternalName, lft => lft.JSLink, lft => lft.NoCrawl, lft => lft.ReadOnlyField, lft => lft.Required, lft => lft.SchemaXml, lft => lft.Scope, lft => lft.Title); var fieldModel = new SPFieldDefinitionModel() { FieldGuid = field.Id, AutoIndexed = field.AutoIndexed, CanBeDeleted = field.CanBeDeleted, DefaultFormula = field.DefaultFormula, DefaultValue = field.DefaultValue, GroupName = field.Group, Description = field.Description, EnforceUniqueValues = field.EnforceUniqueValues, FieldTypeKind = field.FieldTypeKind, FromBaseType = field.FromBaseType, Filterable = field.Filterable, HiddenField = field.Hidden, FieldIndexed = field.Indexed, InternalName = field.InternalName, JSLink = field.JSLink, NoCrawl = field.NoCrawl, ReadOnlyField = field.ReadOnlyField, Required = field.Required, Scope = field.Scope, Title = field.Title, }; // if the schemaXML was not passed in, parse it into a node if (schemaXml == null) { var xdoc = XDocument.Parse(field.SchemaXml, LoadOptions.PreserveWhitespace); schemaXml = xdoc.Element("Field"); } var fieldTypeFromXml = string.Empty; if (schemaXml.Attribute("Type") != null) { fieldTypeFromXml = schemaXml.Attribute("Type").Value; fieldModel.FieldTypeKindText = fieldTypeFromXml; } var choices = new FieldType[] { FieldType.Choice, FieldType.GridChoice, FieldType.OutcomeChoice }; if (field.FieldTypeKind == FieldType.DateTime) { var fieldCast = (FieldDateTime)field; fieldCast.EnsureProperties( fc => fc.DisplayFormat, fc => fc.DateTimeCalendarType, fc => fc.FriendlyDisplayFormat); fieldModel.DateFieldFormat = fieldCast.DisplayFormat; } else if (field.FieldTypeKind == FieldType.Text) { var fieldCast = (FieldText)field; fieldCast.EnsureProperties( fc => fc.MaxLength); fieldModel.MaxLength = fieldCast.MaxLength; } else if (field.FieldTypeKind == FieldType.Note) { var fieldCast = (FieldMultiLineText)field; fieldCast.EnsureProperties( fc => fc.AllowHyperlink, fc => fc.NumberOfLines, fc => fc.AppendOnly, fc => fc.RestrictedMode, fc => fc.RichText); fieldModel.NumLines = fieldCast.NumberOfLines; fieldModel.AppendOnly = fieldCast.AppendOnly; fieldModel.RestrictedMode = fieldCast.RestrictedMode; fieldModel.RichTextField = fieldCast.RichText; } else if (field.FieldTypeKind == FieldType.User) { var fieldCast = (FieldUser)field; fieldCast.EnsureProperties( fc => fc.SelectionMode, fc => fc.SelectionGroup, fc => fc.AllowDisplay, fc => fc.Presence, fc => fc.AllowMultipleValues, fc => fc.IsDependentLookup, fc => fc.IsRelationship, fc => fc.LookupList, fc => fc.LookupField, fc => fc.DependentLookupInternalNames, fc => fc.PrimaryFieldId); fieldModel.PeopleLookupField = fieldCast.LookupField; fieldModel.PeopleOnly = (fieldCast.SelectionMode == FieldUserSelectionMode.PeopleOnly); fieldModel.MultiChoice = fieldCast.AllowMultipleValues; if (fieldCast.SelectionGroup > 0) { var groupId = fieldCast.SelectionGroup; if (siteGroups == null) { siteGroups = context.LoadQuery(context.Web.SiteGroups .Where(w => w.Id == groupId).Include(group => group.Id, group => group.Title)); context.ExecuteQueryRetry(); } if (siteGroups.Any(sg => sg.Id == groupId)) { // we loaded this into context earlier var groupObject = siteGroups.FirstOrDefault(fg => fg.Id == groupId); fieldModel.PeopleGroupName = groupObject.Title; } } } else if (field.FieldTypeKind == FieldType.Lookup) { var fieldCast = (FieldLookup)field; fieldCast.EnsureProperties( fc => fc.LookupList, fc => fc.LookupField, fc => fc.LookupWebId, fc => fc.FromBaseType, fc => fc.AllowMultipleValues, fc => fc.IsDependentLookup, fc => fc.IsRelationship, fc => fc.DependentLookupInternalNames, fc => fc.PrimaryFieldId); if (!string.IsNullOrEmpty(fieldCast.LookupList)) { var lookupGuid = fieldCast.LookupList.TryParseGuid(Guid.Empty); if (lookupGuid != Guid.Empty) { var fieldLookup = context.Web.Lists.GetById(lookupGuid); context.Load(fieldLookup, flp => flp.Title); context.ExecuteQueryRetry(); fieldModel.LookupListName = fieldLookup.Title; fieldModel.LookupListFieldName = fieldCast.LookupField; } } fieldModel.MultiChoice = fieldCast.AllowMultipleValues; } else if (field.FieldTypeKind == FieldType.Calculated) { var fieldCast = (FieldCalculated)field; fieldCast.EnsureProperties( fc => fc.DateFormat, fc => fc.DisplayFormat, fc => fc.Formula, fc => fc.OutputType, fc => fc.ShowAsPercentage); var xfieldReferences = schemaXml.Element("FieldRefs"); if (xfieldReferences != null) { var fieldreferences = new List <string>(); var xFields = xfieldReferences.Elements("FieldRef"); if (xFields != null) { foreach (var xFieldName in xFields.Select(s => s.Attribute("Name"))) { // var xFieldName = xField.Attribute("Name"); fieldreferences.Add(xFieldName.Value); } } fieldModel.FieldReferences = fieldreferences; } fieldModel.OutputType = fieldCast.OutputType; fieldModel.DefaultFormula = fieldCast.Formula; } else if (field.FieldTypeKind == FieldType.URL) { var fieldCast = (FieldUrl)field; fieldCast.EnsureProperties( fc => fc.DisplayFormat); fieldModel.UrlFieldFormat = fieldCast.DisplayFormat; } else if (field.FieldTypeKind == FieldType.MultiChoice) { var fieldCast = (FieldMultiChoice)field; fieldCast.EnsureProperties( fc => fc.Choices, fc => fc.DefaultValue, fc => fc.FillInChoice, fc => fc.Mappings); var choiceOptions = fieldCast.Choices.Select(s => { var optionDefault = default(Nullable <bool>); if (!string.IsNullOrEmpty(field.DefaultValue) && (field.DefaultValue.Equals(s, StringComparison.CurrentCultureIgnoreCase))) { optionDefault = true; } var option = new SPChoiceModel() { Choice = s, DefaultChoice = optionDefault }; return(option); }).ToList(); fieldModel.FieldChoices = choiceOptions; fieldModel.MultiChoice = field.FieldTypeKind == FieldType.MultiChoice; } else if (choices.Any(a => a == field.FieldTypeKind)) { var fieldCast = (FieldChoice)field; fieldCast.EnsureProperties( fc => fc.Choices, fc => fc.DefaultValue, fc => fc.FillInChoice, fc => fc.Mappings, fc => fc.EditFormat); var choiceOptions = fieldCast.Choices.Select(s => { var optionDefault = default(Nullable <bool>); if (!string.IsNullOrEmpty(field.DefaultValue) && (field.DefaultValue.Equals(s, StringComparison.CurrentCultureIgnoreCase))) { optionDefault = true; } var option = new SPChoiceModel() { Choice = s, DefaultChoice = optionDefault }; return(option); }).ToList(); fieldModel.FieldChoices = choiceOptions; fieldModel.ChoiceFormat = fieldCast.EditFormat; fieldModel.MultiChoice = field.FieldTypeKind == FieldType.MultiChoice; } else if (field.FieldTypeKind == FieldType.Invalid && fieldTypeFromXml.IndexOf("TaxonomyFieldType", StringComparison.InvariantCultureIgnoreCase) > -1) { var termsetproperties = schemaXml.Element("Customization").Element("ArrayOfProperty").Elements("Property"); var termsetpropkeyvalue = new List <KeyValuePair <string, string> >(); foreach (var termsetproperty in termsetproperties) { var termsetname = termsetproperty.Element("Name"); var termsetvalue = termsetproperty.Element("Value"); termsetpropkeyvalue.Add(new KeyValuePair <string, string>(termsetname.Value, (termsetvalue != null ? termsetvalue.Value : string.Empty))); } var termSetId = termsetpropkeyvalue.First(f => f.Key == "TermSetId"); var termSetGuid = termSetId.Value.TryParseGuid(Guid.Empty); if (termSetGuid != Guid.Empty) { var taxonomyDetails = context.GetTaxonomyFieldInfo(logger, termSetGuid); taxonomyDetails.Customization = termsetpropkeyvalue; fieldModel.TaxonomyInformation = taxonomyDetails; } } return(fieldModel); }