PageRenderTime 52ms CodeModel.GetById 30ms RepoModel.GetById 1ms app.codeStats 0ms

/Atlassian.Jira/CustomFieldValueCollection.cs

https://bitbucket.org/farmas/atlassian.net-sdk
C# | 246 lines | 155 code | 33 blank | 58 comment | 29 complexity | 242ce8a4f032dbfef07b26427c3af6e2 MD5 | raw file
Possible License(s): BSD-3-Clause
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Collections.ObjectModel;
  4. using System.Linq;
  5. using System.Threading;
  6. using System.Threading.Tasks;
  7. using Atlassian.Jira.Remote;
  8. using Newtonsoft.Json;
  9. namespace Atlassian.Jira
  10. {
  11. /// <summary>
  12. /// Collection of custom fields
  13. /// </summary>
  14. public class CustomFieldValueCollection : ReadOnlyCollection<CustomFieldValue>, IRemoteIssueFieldProvider
  15. {
  16. private readonly Issue _issue;
  17. internal CustomFieldValueCollection(Issue issue)
  18. : this(issue, new List<CustomFieldValue>())
  19. {
  20. }
  21. internal CustomFieldValueCollection(Issue issue, IList<CustomFieldValue> list)
  22. : base(list)
  23. {
  24. _issue = issue;
  25. }
  26. /// <summary>
  27. /// When Id's are unknown, searches for custom fields by the issue project only.
  28. /// </summary>
  29. public bool SearchByProjectOnly { get; set; }
  30. /// <summary>
  31. /// Add a custom field by name
  32. /// </summary>
  33. /// <param name="fieldName">The name of the custom field as defined in JIRA</param>
  34. /// <param name="fieldValue">The value of the field</param>
  35. public CustomFieldValueCollection Add(string fieldName, string fieldValue)
  36. {
  37. return this.Add(fieldName, new string[] { fieldValue });
  38. }
  39. /// <summary>
  40. /// Add a custom field by name with an array of values
  41. /// </summary>
  42. /// <param name="fieldName">The name of the custom field as defined in JIRA</param>
  43. /// <param name="fieldValues">The values of the field</param>
  44. public CustomFieldValueCollection AddArray(string fieldName, params string[] fieldValues)
  45. {
  46. return this.Add(fieldName, fieldValues, new MultiStringCustomFieldValueSerializer());
  47. }
  48. /// <summary>
  49. /// Add a cascading select field.
  50. /// </summary>
  51. /// <param name="cascadingSelectField">Cascading select field to add.</param>
  52. public CustomFieldValueCollection AddCascadingSelectField(CascadingSelectCustomField cascadingSelectField)
  53. {
  54. return AddCascadingSelectField(cascadingSelectField.Name, cascadingSelectField.ParentOption, cascadingSelectField.ChildOption);
  55. }
  56. /// <summary>
  57. /// Add a cascading select field.
  58. /// </summary>
  59. /// <param name="fieldName">The name of the custom field as defined in JIRA.</param>
  60. /// <param name="parentOption">The value of the parent option.</param>
  61. /// <param name="childOption">The value of the child option.</param>
  62. public CustomFieldValueCollection AddCascadingSelectField(string fieldName, string parentOption, string childOption = null)
  63. {
  64. var options = new List<string>() { parentOption };
  65. if (!string.IsNullOrEmpty(childOption))
  66. {
  67. options.Add(childOption);
  68. }
  69. return AddArray(fieldName, options.ToArray());
  70. }
  71. /// <summary>
  72. /// Add a custom field by name
  73. /// </summary>
  74. /// <param name="fieldName">The name of the custom field as defined in JIRA</param>
  75. /// <param name="fieldValues">The values of the field</param>
  76. public CustomFieldValueCollection Add(string fieldName, string[] fieldValues, ICustomFieldValueSerializer serializer = null)
  77. {
  78. var fieldId = GetCustomFieldId(fieldName);
  79. this.Items.Add(new CustomFieldValue(fieldId, fieldName, _issue) { Values = fieldValues, Serializer = serializer });
  80. return this;
  81. }
  82. /// <summary>
  83. /// Add a custom field by id with an array of values.
  84. /// </summary>
  85. /// <param name="fieldId">The id of the custom field as defined in JIRA.</param>
  86. /// <param name="fieldValues">The values of the field.</param>
  87. public CustomFieldValueCollection AddById(string fieldId, params string[] fieldValues)
  88. {
  89. this.Items.Add(new CustomFieldValue(fieldId, _issue) { Values = fieldValues });
  90. return this;
  91. }
  92. /// <summary>
  93. /// Gets a cascading select custom field by name.
  94. /// </summary>
  95. /// <param name="fieldName">Name of the custom field as defined in JIRA.</param>
  96. /// <returns>CascadingSelectCustomField instance if the field has been set on the issue, null otherwise</returns>
  97. public CascadingSelectCustomField GetCascadingSelectField(string fieldName)
  98. {
  99. CascadingSelectCustomField result = null;
  100. var fieldValue = this[fieldName];
  101. if (fieldValue != null && fieldValue.Values != null)
  102. {
  103. var parentOption = fieldValue.Values.Length > 0 ? fieldValue.Values[0] : null;
  104. var childOption = fieldValue.Values.Length > 1 ? fieldValue.Values[1] : null;
  105. result = new CascadingSelectCustomField(fieldName, parentOption, childOption);
  106. }
  107. return result;
  108. }
  109. /// <summary>
  110. /// Deserializes the custom field value to the specified type.
  111. /// </summary>
  112. /// <typeparam name="T">The type of the object to deserialize to.</typeparam>
  113. /// <param name="fieldName">Name of the custom field as defined in JIRA.</param>
  114. public T GetAs<T>(string fieldName)
  115. {
  116. var result = default(T);
  117. var fieldValue = this[fieldName];
  118. if (fieldValue != null && fieldValue.RawValue != null)
  119. {
  120. result = JsonConvert.DeserializeObject<T>(fieldValue.RawValue.ToString(), _issue.Jira.RestClient.Settings.JsonSerializerSettings);
  121. }
  122. return result;
  123. }
  124. /// <summary>
  125. /// Gets a custom field by name
  126. /// </summary>
  127. /// <param name="fieldName">Name of the custom field as defined in JIRA</param>
  128. /// <returns>CustomField instance if the field has been set on the issue, null otherwise</returns>
  129. public CustomFieldValue this[string fieldName]
  130. {
  131. get
  132. {
  133. var fieldId = GetCustomFieldId(fieldName);
  134. return this.Items.FirstOrDefault(f => f.Id == fieldId);
  135. }
  136. }
  137. private string GetCustomFieldId(string fieldName)
  138. {
  139. var customFields = _issue.Jira.Fields.GetCustomFieldsAsync().Result.Where(f => f.Name.Equals(fieldName, StringComparison.OrdinalIgnoreCase));
  140. var searchByProject = (customFields.Count() > 1) || SearchByProjectOnly;
  141. if (searchByProject)
  142. {
  143. // There are multiple custom fields with the same name, need to find it by the project.
  144. var options = new CustomFieldFetchOptions();
  145. options.ProjectKeys.Add(_issue.Project);
  146. if (!String.IsNullOrEmpty(_issue.Type?.Id))
  147. {
  148. options.IssueTypeIds.Add(_issue.Type.Id);
  149. }
  150. else if (!String.IsNullOrEmpty(_issue.Type?.Name))
  151. {
  152. options.IssueTypeNames.Add(_issue.Type.Name);
  153. }
  154. customFields = _issue.Jira.Fields.GetCustomFieldsAsync(options).Result.Where(f => f.Name.Equals(fieldName, StringComparison.OrdinalIgnoreCase));
  155. }
  156. if (customFields.Count() == 0)
  157. {
  158. var errorMessage = $"Could not find custom field with name '{fieldName}' on the JIRA server.";
  159. if (searchByProject)
  160. {
  161. errorMessage += $" The field was only searched for in the project with key '{_issue.Project}'." +
  162. $" Make sure the custom field is available in the issue create screen for that project.";
  163. }
  164. throw new InvalidOperationException(errorMessage);
  165. }
  166. else
  167. {
  168. return customFields.Single().Id;
  169. }
  170. }
  171. Task<RemoteFieldValue[]> IRemoteIssueFieldProvider.GetRemoteFieldValuesAsync(CancellationToken token)
  172. {
  173. var fieldValues = this.Items
  174. .Where(field => IsCustomFieldNewOrUpdated(field))
  175. .Select(field => new RemoteFieldValue()
  176. {
  177. id = field.Id,
  178. values = field.Values
  179. });
  180. return Task.FromResult(fieldValues.ToArray());
  181. }
  182. private bool IsCustomFieldNewOrUpdated(CustomFieldValue customField)
  183. {
  184. if (this._issue.OriginalRemoteIssue.customFieldValues == null)
  185. {
  186. // Original remote issue had no custom fields, this means that a new one has been added by user.
  187. return true;
  188. }
  189. var originalField = this._issue.OriginalRemoteIssue.customFieldValues.FirstOrDefault(field => field.customfieldId == customField.Id);
  190. if (originalField == null)
  191. {
  192. // A custom field with this id does not exist on the original remote issue, this means that it was
  193. // added by the user
  194. return true;
  195. }
  196. else if (originalField.values == null)
  197. {
  198. // The remote custom field was not initialized, include it on the payload.
  199. return true;
  200. }
  201. else if (customField.Values == null)
  202. {
  203. // Original field had values, but the new field has been set to null.
  204. // User means to clear the value, include it on the payload.
  205. return true;
  206. }
  207. else
  208. {
  209. return !originalField.values.SequenceEqual(customField.Values);
  210. }
  211. }
  212. }
  213. }