/jira-project/jira-components/jira-core/src/main/java/com/atlassian/jira/web/action/admin/customfields/CustomFieldContextConfigHelperImpl.java
Java | 239 lines | 162 code | 28 blank | 49 comment | 37 complexity | d479bb021df8ab3a0b23956dee70c99b MD5 | raw file
Possible License(s): Apache-2.0
- package com.atlassian.jira.web.action.admin.customfields;
- import com.atlassian.jira.entity.WithFunctions;
- import com.atlassian.jira.issue.IssueConstants;
- import com.atlassian.jira.issue.context.JiraContextNode;
- import com.atlassian.jira.issue.fields.CustomField;
- import com.atlassian.jira.issue.fields.config.FieldConfigScheme;
- import com.atlassian.jira.issue.fields.config.manager.FieldConfigSchemeManager;
- import com.atlassian.jira.issue.issuetype.IssueType;
- import com.atlassian.jira.issue.search.SearchException;
- import com.atlassian.jira.issue.search.SearchProvider;
- import com.atlassian.jira.jql.builder.JqlClauseBuilder;
- import com.atlassian.jira.jql.builder.JqlQueryBuilder;
- import com.atlassian.jira.project.Project;
- import com.atlassian.jira.user.ApplicationUser;
- import com.atlassian.jira.util.InjectableComponent;
- import com.atlassian.query.Query;
- import com.google.common.base.Predicates;
- import com.google.common.collect.Iterables;
- import com.google.common.collect.Lists;
- import com.google.common.collect.Sets;
- import org.slf4j.Logger;
- import org.slf4j.LoggerFactory;
- import java.util.ArrayList;
- import java.util.Collection;
- import java.util.Collections;
- import java.util.List;
- import java.util.Set;
- import static com.atlassian.jira.util.dbc.Assertions.notNull;
- import static com.google.common.collect.ImmutableList.copyOf;
- /**
- * @since v4.0
- */
- @InjectableComponent
- public class CustomFieldContextConfigHelperImpl implements CustomFieldContextConfigHelper {
- private static final Logger log = LoggerFactory.getLogger(CustomFieldContextConfigHelperImpl.class);
- private final SearchProvider searchProvider;
- private final FieldConfigSchemeManager fieldConfigSchemeManager;
- public CustomFieldContextConfigHelperImpl(final SearchProvider searchProvider, final FieldConfigSchemeManager fieldConfigSchemeManager) {
- this.searchProvider = notNull("searchProvider", searchProvider);
- this.fieldConfigSchemeManager = notNull("fieldConfigSchemeManager", fieldConfigSchemeManager);
- }
- public boolean doesAddingContextToCustomFieldAffectIssues(final ApplicationUser user, final CustomField customField, final List<JiraContextNode> projectContexts, final List<IssueType> issueTypes, final boolean isNewCustomField) {
- if (!isNewCustomField && doesCustomFieldHaveGlobalScheme(customField)) {
- return false;
- } else {
- return doesContextHaveIssues(user, projectContexts, issueTypes);
- }
- }
- public boolean doesChangingContextAffectIssues(final ApplicationUser user, final CustomField customField, final FieldConfigScheme oldFieldConfigScheme, final boolean isNewSchemeGlobal, final List<JiraContextNode> projectContexts, final List<IssueType> issueTypes) {
- boolean isOldSchemeGlobal = oldFieldConfigScheme.isGlobal();
- // if we are not changing or changing to a global context
- if (!isOldSchemeGlobal && !isNewSchemeGlobal) {
- // if there is another scheme that is global, then no issues affected
- if (doesCustomFieldHaveGlobalScheme(customField)) {
- return false;
- } else {
- // otherwise, check for issues in the pre edit and post edit schemes
- if (doesContextHaveIssues(user, projectContexts, issueTypes)) {
- return true;
- } else {
- return doesFieldConfigSchemeHaveIssues(user, oldFieldConfigScheme);
- }
- }
- } else {
- // check for issues in the global context
- return doesGlobalContextHaveIssues(user);
- }
- }
- public boolean doesRemovingSchemeFromCustomFieldAffectIssues(final ApplicationUser user, final CustomField customField, final FieldConfigScheme fieldConfigScheme) {
- // if removing a global scheme
- if (fieldConfigScheme.isGlobal()) {
- // Check if there exists any issues which do not fall under the scope of other context configurations for the specified custom field.
- // For example, if a custom field had a context defined for [Global], [project MKY] and [project HSP, issue type Bug],
- // we need to check for any issues which are not in MKY, and are not Bugs in HSP.
- final List<FieldConfigScheme> nonGlobalSchemes = getNonGlobalSchemesForCustomField(customField);
- if (nonGlobalSchemes.isEmpty()) {
- // no other contexts - just check for issues in global context
- return doesGlobalContextHaveIssues(user);
- } else {
- // build up query to find issues not in other contexts
- final JqlClauseBuilder clauseBuilder = JqlQueryBuilder.newClauseBuilder().defaultAnd();
- for (FieldConfigScheme scheme : nonGlobalSchemes) {
- List<Project> projects = scheme.getAssociatedProjectObjects();
- projects = projects == null ? Collections.<Project>emptyList() : Collections.unmodifiableList(projects);
- Collection<IssueType> issueTypes = scheme.getAssociatedIssueTypes();
- List<Long> projectIds = Lists.newArrayList(Iterables.filter(WithFunctions.getIds(projects), Predicates.<Long>notNull()));
- List<Long> issueTypeIds = filterAndTransformIssueTypes(issueTypes == null ? Collections.<IssueType>emptySet() : Sets.newHashSet(issueTypes));
- clauseBuilder.not().addClause(buildClause(projectIds, issueTypeIds).buildClause());
- }
- return doesQueryHaveIssues(user, clauseBuilder.buildQuery());
- }
- } else {
- // since we are removing a non-global context, if we still have a global context then no issues are affected
- if (doesCustomFieldHaveGlobalScheme(customField)) {
- return false;
- } else {
- // otherwise find out if any issues are in the context of the scheme we are removing
- return doesFieldConfigSchemeHaveIssues(user, fieldConfigScheme);
- }
- }
- }
- /**
- * Determines if there are any issues present under the specified project and issue type context.
- *
- * @param user the current user
- * @param projectContexts project contexts; must not be null
- * @param issueTypes issue type GVs; may be null
- * @return if there was at least one issue present under the context
- */
- boolean doesContextHaveIssues(final ApplicationUser user, final List<JiraContextNode> projectContexts, final List<IssueType> issueTypes) {
- final List<Long> projectIds = Lists.newArrayList();
- for (JiraContextNode context : projectContexts) {
- if (context != null && context.getProjectId() != null) {
- projectIds.add(context.getProjectId());
- }
- }
- List<Long> issueTypeIds = new ArrayList<>();
- if (issueTypes != null) {
- issueTypeIds = filterAndTransformIssueTypes(issueTypes);
- }
- return _doesContextHaveIssues(user, projectIds, issueTypeIds);
- }
- /**
- * Determines if there are any issues present under the specified project and issue type context.
- *
- * @param user the current user
- * @param projects projects in context contexts; must not be null
- * @param issueTypes issue type GVs in context; may be null
- * @return if there was at least one issue present under the context
- */
- boolean doesContextHaveIssues(final ApplicationUser user, final List<Project> projects, final Set<IssueType> issueTypes) {
- List<Project> projectIds = projects == null ? Collections.<Project>emptyList() : projects;
- List<Long> issueTypeIds = new ArrayList<>();
- if (issueTypes != null) {
- issueTypeIds = filterAndTransformIssueTypes(issueTypes);
- }
- return _doesContextHaveIssues(user, copyOf(WithFunctions.getIds(projectIds)), issueTypeIds);
- }
- /**
- * Determines if there are any issues present under the global context.
- *
- * @param user the current user
- * @return if there was at least one issue present under the global context
- */
- boolean doesGlobalContextHaveIssues(final ApplicationUser user) {
- return _doesContextHaveIssues(user, Collections.<Long>emptyList(), Collections.<Long>emptyList());
- }
- boolean _doesContextHaveIssues(final ApplicationUser user, final List<Long> projectIds, final List<Long> issueTypeIds) {
- final JqlClauseBuilder clauseBuilder = buildClause(projectIds, issueTypeIds);
- return doesQueryHaveIssues(user, clauseBuilder.buildQuery());
- }
- /**
- * Determines if there are any issues present under the context of the field config scheme.
- *
- * @param user the current user
- * @param fieldConfigScheme the field config scheme
- * @return if there was at least one issue present under the context
- */
- boolean doesFieldConfigSchemeHaveIssues(final ApplicationUser user, final FieldConfigScheme fieldConfigScheme) {
- List<Project> projects = fieldConfigScheme.getAssociatedProjectObjects();
- projects = projects == null ? Collections.<Project>emptyList() : Collections.unmodifiableList(projects);
- Collection<IssueType> issueTypes = fieldConfigScheme.getAssociatedIssueTypes();
- return doesContextHaveIssues(user, projects, issueTypes == null ? Collections.<IssueType>emptySet() : Sets.newHashSet(issueTypes));
- }
- private boolean doesCustomFieldHaveGlobalScheme(final CustomField customField) {
- final List<FieldConfigScheme> schemes = fieldConfigSchemeManager.getConfigSchemesForField(customField);
- for (FieldConfigScheme scheme : schemes) {
- if (scheme.isGlobal()) {
- return true;
- }
- }
- return false;
- }
- private List<FieldConfigScheme> getNonGlobalSchemesForCustomField(final CustomField customField) {
- final List<FieldConfigScheme> schemes = fieldConfigSchemeManager.getConfigSchemesForField(customField);
- final List<FieldConfigScheme> result = new ArrayList<FieldConfigScheme>();
- for (FieldConfigScheme scheme : schemes) {
- if (!scheme.isGlobal()) {
- result.add(scheme);
- }
- }
- return result;
- }
- private JqlClauseBuilder buildClause(final List<Long> projectIds, final List<Long> issueTypeIds) {
- final JqlClauseBuilder clauseBuilder = JqlQueryBuilder.newClauseBuilder().defaultAnd();
- if (!projectIds.isEmpty()) {
- clauseBuilder.project().inNumbers(projectIds);
- }
- if (!issueTypeIds.isEmpty()) {
- clauseBuilder.issueType().inNumbers(issueTypeIds);
- }
- return clauseBuilder;
- }
- /**
- * @param issueTypes issue types represented by generic values; may contain nulls, but must not be null
- * @return a list of the ids of the generic values; the nulls in the input list are ignored.
- */
- private List<Long> filterAndTransformIssueTypes(final Collection<IssueType> issueTypes) {
- return Lists.newArrayList(Iterables.transform(Iterables.filter(issueTypes, Predicates.<IssueType>notNull()), IssueConstants.getIdAsLong()));
- }
- private boolean doesQueryHaveIssues(final ApplicationUser user, final Query query) {
- try {
- final long issueCount = searchProvider.searchCountOverrideSecurity(query, user);
- return (issueCount > 0);
- } catch (SearchException e) {
- log.warn(e.getMessage(), e);
- // can't determine whether or not there are issues - but let's just pretend there are
- return true;
- }
- }
- }