PageRenderTime 25ms CodeModel.GetById 14ms RepoModel.GetById 1ms app.codeStats 0ms

/jira-project/jira-components/jira-core/src/main/java/com/atlassian/jira/web/action/admin/customfields/CustomFieldContextConfigHelperImpl.java

https://bitbucket.org/ahmed_bilal_360factors/jira7-core
Java | 239 lines | 162 code | 28 blank | 49 comment | 37 complexity | d479bb021df8ab3a0b23956dee70c99b MD5 | raw file
Possible License(s): Apache-2.0
  1. package com.atlassian.jira.web.action.admin.customfields;
  2. import com.atlassian.jira.entity.WithFunctions;
  3. import com.atlassian.jira.issue.IssueConstants;
  4. import com.atlassian.jira.issue.context.JiraContextNode;
  5. import com.atlassian.jira.issue.fields.CustomField;
  6. import com.atlassian.jira.issue.fields.config.FieldConfigScheme;
  7. import com.atlassian.jira.issue.fields.config.manager.FieldConfigSchemeManager;
  8. import com.atlassian.jira.issue.issuetype.IssueType;
  9. import com.atlassian.jira.issue.search.SearchException;
  10. import com.atlassian.jira.issue.search.SearchProvider;
  11. import com.atlassian.jira.jql.builder.JqlClauseBuilder;
  12. import com.atlassian.jira.jql.builder.JqlQueryBuilder;
  13. import com.atlassian.jira.project.Project;
  14. import com.atlassian.jira.user.ApplicationUser;
  15. import com.atlassian.jira.util.InjectableComponent;
  16. import com.atlassian.query.Query;
  17. import com.google.common.base.Predicates;
  18. import com.google.common.collect.Iterables;
  19. import com.google.common.collect.Lists;
  20. import com.google.common.collect.Sets;
  21. import org.slf4j.Logger;
  22. import org.slf4j.LoggerFactory;
  23. import java.util.ArrayList;
  24. import java.util.Collection;
  25. import java.util.Collections;
  26. import java.util.List;
  27. import java.util.Set;
  28. import static com.atlassian.jira.util.dbc.Assertions.notNull;
  29. import static com.google.common.collect.ImmutableList.copyOf;
  30. /**
  31. * @since v4.0
  32. */
  33. @InjectableComponent
  34. public class CustomFieldContextConfigHelperImpl implements CustomFieldContextConfigHelper {
  35. private static final Logger log = LoggerFactory.getLogger(CustomFieldContextConfigHelperImpl.class);
  36. private final SearchProvider searchProvider;
  37. private final FieldConfigSchemeManager fieldConfigSchemeManager;
  38. public CustomFieldContextConfigHelperImpl(final SearchProvider searchProvider, final FieldConfigSchemeManager fieldConfigSchemeManager) {
  39. this.searchProvider = notNull("searchProvider", searchProvider);
  40. this.fieldConfigSchemeManager = notNull("fieldConfigSchemeManager", fieldConfigSchemeManager);
  41. }
  42. public boolean doesAddingContextToCustomFieldAffectIssues(final ApplicationUser user, final CustomField customField, final List<JiraContextNode> projectContexts, final List<IssueType> issueTypes, final boolean isNewCustomField) {
  43. if (!isNewCustomField && doesCustomFieldHaveGlobalScheme(customField)) {
  44. return false;
  45. } else {
  46. return doesContextHaveIssues(user, projectContexts, issueTypes);
  47. }
  48. }
  49. public boolean doesChangingContextAffectIssues(final ApplicationUser user, final CustomField customField, final FieldConfigScheme oldFieldConfigScheme, final boolean isNewSchemeGlobal, final List<JiraContextNode> projectContexts, final List<IssueType> issueTypes) {
  50. boolean isOldSchemeGlobal = oldFieldConfigScheme.isGlobal();
  51. // if we are not changing or changing to a global context
  52. if (!isOldSchemeGlobal && !isNewSchemeGlobal) {
  53. // if there is another scheme that is global, then no issues affected
  54. if (doesCustomFieldHaveGlobalScheme(customField)) {
  55. return false;
  56. } else {
  57. // otherwise, check for issues in the pre edit and post edit schemes
  58. if (doesContextHaveIssues(user, projectContexts, issueTypes)) {
  59. return true;
  60. } else {
  61. return doesFieldConfigSchemeHaveIssues(user, oldFieldConfigScheme);
  62. }
  63. }
  64. } else {
  65. // check for issues in the global context
  66. return doesGlobalContextHaveIssues(user);
  67. }
  68. }
  69. public boolean doesRemovingSchemeFromCustomFieldAffectIssues(final ApplicationUser user, final CustomField customField, final FieldConfigScheme fieldConfigScheme) {
  70. // if removing a global scheme
  71. if (fieldConfigScheme.isGlobal()) {
  72. // Check if there exists any issues which do not fall under the scope of other context configurations for the specified custom field.
  73. // For example, if a custom field had a context defined for [Global], [project MKY] and [project HSP, issue type Bug],
  74. // we need to check for any issues which are not in MKY, and are not Bugs in HSP.
  75. final List<FieldConfigScheme> nonGlobalSchemes = getNonGlobalSchemesForCustomField(customField);
  76. if (nonGlobalSchemes.isEmpty()) {
  77. // no other contexts - just check for issues in global context
  78. return doesGlobalContextHaveIssues(user);
  79. } else {
  80. // build up query to find issues not in other contexts
  81. final JqlClauseBuilder clauseBuilder = JqlQueryBuilder.newClauseBuilder().defaultAnd();
  82. for (FieldConfigScheme scheme : nonGlobalSchemes) {
  83. List<Project> projects = scheme.getAssociatedProjectObjects();
  84. projects = projects == null ? Collections.<Project>emptyList() : Collections.unmodifiableList(projects);
  85. Collection<IssueType> issueTypes = scheme.getAssociatedIssueTypes();
  86. List<Long> projectIds = Lists.newArrayList(Iterables.filter(WithFunctions.getIds(projects), Predicates.<Long>notNull()));
  87. List<Long> issueTypeIds = filterAndTransformIssueTypes(issueTypes == null ? Collections.<IssueType>emptySet() : Sets.newHashSet(issueTypes));
  88. clauseBuilder.not().addClause(buildClause(projectIds, issueTypeIds).buildClause());
  89. }
  90. return doesQueryHaveIssues(user, clauseBuilder.buildQuery());
  91. }
  92. } else {
  93. // since we are removing a non-global context, if we still have a global context then no issues are affected
  94. if (doesCustomFieldHaveGlobalScheme(customField)) {
  95. return false;
  96. } else {
  97. // otherwise find out if any issues are in the context of the scheme we are removing
  98. return doesFieldConfigSchemeHaveIssues(user, fieldConfigScheme);
  99. }
  100. }
  101. }
  102. /**
  103. * Determines if there are any issues present under the specified project and issue type context.
  104. *
  105. * @param user the current user
  106. * @param projectContexts project contexts; must not be null
  107. * @param issueTypes issue type GVs; may be null
  108. * @return if there was at least one issue present under the context
  109. */
  110. boolean doesContextHaveIssues(final ApplicationUser user, final List<JiraContextNode> projectContexts, final List<IssueType> issueTypes) {
  111. final List<Long> projectIds = Lists.newArrayList();
  112. for (JiraContextNode context : projectContexts) {
  113. if (context != null && context.getProjectId() != null) {
  114. projectIds.add(context.getProjectId());
  115. }
  116. }
  117. List<Long> issueTypeIds = new ArrayList<>();
  118. if (issueTypes != null) {
  119. issueTypeIds = filterAndTransformIssueTypes(issueTypes);
  120. }
  121. return _doesContextHaveIssues(user, projectIds, issueTypeIds);
  122. }
  123. /**
  124. * Determines if there are any issues present under the specified project and issue type context.
  125. *
  126. * @param user the current user
  127. * @param projects projects in context contexts; must not be null
  128. * @param issueTypes issue type GVs in context; may be null
  129. * @return if there was at least one issue present under the context
  130. */
  131. boolean doesContextHaveIssues(final ApplicationUser user, final List<Project> projects, final Set<IssueType> issueTypes) {
  132. List<Project> projectIds = projects == null ? Collections.<Project>emptyList() : projects;
  133. List<Long> issueTypeIds = new ArrayList<>();
  134. if (issueTypes != null) {
  135. issueTypeIds = filterAndTransformIssueTypes(issueTypes);
  136. }
  137. return _doesContextHaveIssues(user, copyOf(WithFunctions.getIds(projectIds)), issueTypeIds);
  138. }
  139. /**
  140. * Determines if there are any issues present under the global context.
  141. *
  142. * @param user the current user
  143. * @return if there was at least one issue present under the global context
  144. */
  145. boolean doesGlobalContextHaveIssues(final ApplicationUser user) {
  146. return _doesContextHaveIssues(user, Collections.<Long>emptyList(), Collections.<Long>emptyList());
  147. }
  148. boolean _doesContextHaveIssues(final ApplicationUser user, final List<Long> projectIds, final List<Long> issueTypeIds) {
  149. final JqlClauseBuilder clauseBuilder = buildClause(projectIds, issueTypeIds);
  150. return doesQueryHaveIssues(user, clauseBuilder.buildQuery());
  151. }
  152. /**
  153. * Determines if there are any issues present under the context of the field config scheme.
  154. *
  155. * @param user the current user
  156. * @param fieldConfigScheme the field config scheme
  157. * @return if there was at least one issue present under the context
  158. */
  159. boolean doesFieldConfigSchemeHaveIssues(final ApplicationUser user, final FieldConfigScheme fieldConfigScheme) {
  160. List<Project> projects = fieldConfigScheme.getAssociatedProjectObjects();
  161. projects = projects == null ? Collections.<Project>emptyList() : Collections.unmodifiableList(projects);
  162. Collection<IssueType> issueTypes = fieldConfigScheme.getAssociatedIssueTypes();
  163. return doesContextHaveIssues(user, projects, issueTypes == null ? Collections.<IssueType>emptySet() : Sets.newHashSet(issueTypes));
  164. }
  165. private boolean doesCustomFieldHaveGlobalScheme(final CustomField customField) {
  166. final List<FieldConfigScheme> schemes = fieldConfigSchemeManager.getConfigSchemesForField(customField);
  167. for (FieldConfigScheme scheme : schemes) {
  168. if (scheme.isGlobal()) {
  169. return true;
  170. }
  171. }
  172. return false;
  173. }
  174. private List<FieldConfigScheme> getNonGlobalSchemesForCustomField(final CustomField customField) {
  175. final List<FieldConfigScheme> schemes = fieldConfigSchemeManager.getConfigSchemesForField(customField);
  176. final List<FieldConfigScheme> result = new ArrayList<FieldConfigScheme>();
  177. for (FieldConfigScheme scheme : schemes) {
  178. if (!scheme.isGlobal()) {
  179. result.add(scheme);
  180. }
  181. }
  182. return result;
  183. }
  184. private JqlClauseBuilder buildClause(final List<Long> projectIds, final List<Long> issueTypeIds) {
  185. final JqlClauseBuilder clauseBuilder = JqlQueryBuilder.newClauseBuilder().defaultAnd();
  186. if (!projectIds.isEmpty()) {
  187. clauseBuilder.project().inNumbers(projectIds);
  188. }
  189. if (!issueTypeIds.isEmpty()) {
  190. clauseBuilder.issueType().inNumbers(issueTypeIds);
  191. }
  192. return clauseBuilder;
  193. }
  194. /**
  195. * @param issueTypes issue types represented by generic values; may contain nulls, but must not be null
  196. * @return a list of the ids of the generic values; the nulls in the input list are ignored.
  197. */
  198. private List<Long> filterAndTransformIssueTypes(final Collection<IssueType> issueTypes) {
  199. return Lists.newArrayList(Iterables.transform(Iterables.filter(issueTypes, Predicates.<IssueType>notNull()), IssueConstants.getIdAsLong()));
  200. }
  201. private boolean doesQueryHaveIssues(final ApplicationUser user, final Query query) {
  202. try {
  203. final long issueCount = searchProvider.searchCountOverrideSecurity(query, user);
  204. return (issueCount > 0);
  205. } catch (SearchException e) {
  206. log.warn(e.getMessage(), e);
  207. // can't determine whether or not there are issues - but let's just pretend there are
  208. return true;
  209. }
  210. }
  211. }