All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.almworks.jira.structure.api.StructurePluginHelper Maven / Gradle / Ivy

There is a newer version: 17.25.3
Show newest version
package com.almworks.jira.structure.api;

import com.almworks.integers.*;
import com.almworks.jira.structure.api.auth.StructureAuth;
import com.almworks.jira.structure.api.cache.StructureCacheHelper;
import com.almworks.jira.structure.api.error.StructureError;
import com.almworks.jira.structure.api.permissions.CoreAppPermissions;
import com.almworks.jira.structure.api.permissions.StructureAppPermission;
import com.almworks.jira.structure.api.settings.StructureConfiguration;
import com.almworks.jira.structure.api.structure.Structure;
import com.almworks.jira.structure.api.util.CallableE;
import com.atlassian.annotations.Internal;
import com.atlassian.crowd.embedded.api.Group;
import com.atlassian.jira.bc.issue.search.SearchService;
import com.atlassian.jira.bc.issue.worklog.TimeTrackingConfiguration;
import com.atlassian.jira.issue.*;
import com.atlassian.jira.issue.search.SearchException;
import com.atlassian.jira.issue.search.SearchRequestManager;
import com.atlassian.jira.jql.operand.JqlOperandResolver;
import com.atlassian.jira.jql.parser.JqlParseException;
import com.atlassian.jira.jql.parser.JqlQueryParser;
import com.atlassian.jira.jql.util.JqlStringSupport;
import com.atlassian.jira.permission.GlobalPermissionKey;
import com.atlassian.jira.project.Project;
import com.atlassian.jira.project.ProjectManager;
import com.atlassian.jira.security.*;
import com.atlassian.jira.security.plugin.ProjectPermissionKey;
import com.atlassian.jira.security.roles.ProjectRole;
import com.atlassian.jira.security.roles.ProjectRoleManager;
import com.atlassian.jira.user.ApplicationUser;
import com.atlassian.jira.user.preferences.UserPreferencesManager;
import com.atlassian.jira.user.util.UserManager;
import com.atlassian.jira.util.I18nHelper;
import com.atlassian.jira.util.MessageSet;
import com.atlassian.plugin.PluginAccessor;
import com.atlassian.plugin.event.PluginEventManager;
import com.atlassian.query.Query;
import org.jetbrains.annotations.*;

import java.text.Collator;
import java.util.*;

/**
 * 

{@code StructurePluginHelper} is a helper component that provides a lot of helpful methods and which is extensively * used by Structure plugin itself and by Structure extensions.

* *

As a consumer of Structure API, you can also benefit from using these methods, however, since this class is * marked {@code @Internal}, you may need to retest or recompile your code with every new minor or micro release of * the Structure API.

* *

* The methods in this class form several groups: *

* *
    *
  • Quick access to components,
  • *
  • Permission and access checks,
  • *
  • Web resource utilities for building pages that include Structure widget,
  • *
  • Searching and filtering utilities,
  • *
  • I18n tools,
  • *
  • Caching and lifecycle tools,
  • *
  • Miscellaneous helper methods.
  • *
*/ @Internal public interface StructurePluginHelper { // === Permission and access checks === /** * Checks user access to the issue for viewing or editing. Edit check includes verifying that issue editing is not * prohibited by workflow. * * @param issue issue ID * @param checkEdit if true, edit permissions are required. * @param user user to check for * @return specific error or {@code null} if everything is ok */ @Nullable StructureError getIssueError(@Nullable Long issue, boolean checkEdit, @Nullable ApplicationUser user); /** * Convenience method to check issue access for the current user. * * @param issue issue ID * @param checkEdit if true, edit permissions are required. * @return specific error or {@code null} if everything is ok * @see #getIssueError(Long, boolean, ApplicationUser) */ @Nullable default StructureError getIssueError(@Nullable Long issue, boolean checkEdit) { return getIssueError(issue, checkEdit, StructureAuth.getUser()); } /** * Checks user access to the issue for viewing or editing. Edit check includes verifying that issue editing is not * prohibited by workflow. Also can check if the project that the issue belongs to is enabled for Structure. * * @param issue issue * @param checkEdit if true, edit permissions are required * @param checkProjectEnabledForStructure if true, issue's project must be enabled for Structure * @param user user to check for * @return specific error or {@code null} if everything is ok */ @Contract("null, _, _, _ -> !null") @Nullable StructureError getIssueError(@Nullable Issue issue, boolean checkEdit, boolean checkProjectEnabledForStructure, @Nullable ApplicationUser user); /** * Convenience method to check issue access for the current user. * * @param issue issue * @param checkEdit if true, edit permissions are required * @return specific error or {@code null} if everything is ok * @see #getIssueError(Issue, boolean, boolean, ApplicationUser) */ @Contract("null, _ -> !null") @Nullable default StructureError getIssueError(@Nullable Issue issue, boolean checkEdit) { return getIssueError(issue, checkEdit, false, StructureAuth.getUser()); } /** * Convenience method to check issue access for the current user. * * @param issue issue * @param checkEdit if true, edit permissions are required * @param checkProjectEnabledForStructure if true, issue's project must be enabled for Structure * @return specific error or {@code null} if everything is ok * @see #getIssueError(Issue, boolean, boolean, ApplicationUser) */ @Contract("null, _, _ -> !null") @Nullable default StructureError getIssueError(@Nullable Issue issue, boolean checkEdit, boolean checkProjectEnabledForStructure) { return getIssueError(issue, checkEdit, checkProjectEnabledForStructure, StructureAuth.getUser()); } /** * Checks if the project is enabled for Structure and the current user can see it. * * @param project the project * @return true if the project is "structured" and visible to the current user */ boolean isProjectStructuredForCurrentUser(@Nullable Project project); /** * Checks if the given user is allowed to work with Structure add-on. * * @return true if the given user can work with Structure */ default boolean isStructureAvailableToUser(@Nullable ApplicationUser user) { return isAllowed(CoreAppPermissions.USE, user); } /** * Checks if the current user is allowed to work with Structure add-on. * * @return true if the current user can work with Structure */ default boolean isStructureAvailableToCurrentUser() { return isStructureAvailableToUser(StructureAuth.getUser()); } /** * Checks if the given user is allowed to create new structures. */ default boolean isCreateStructureAllowed(@Nullable ApplicationUser user) { return isAllowed(CoreAppPermissions.CREATE_STRUCTURE, user); } /** * Checks if the given user is allowed to create and run synchronizers. */ default boolean isSynchronizationAllowed(@Nullable ApplicationUser user) { return isAllowed(CoreAppPermissions.SYNCHRONIZATION, user); } /** * Checks if the given user is allowed to create and run generators. */ default boolean isAutomationAccessAllowed(@Nullable ApplicationUser user) { return isAllowed(CoreAppPermissions.AUTOMATION, user); } /** * Checks if the given user allowed to perform the action guarded by the given permission. * @see com.almworks.jira.structure.api.permissions.CoreAppPermissions */ boolean isAllowed(@NotNull StructureAppPermission permission, @Nullable ApplicationUser user); /** * Checks if the current user has authenticated in the system. * * @return true if the current user is not anonymous */ default boolean isAuthenticated() { return getUser() != null; } /** * Checks if the given user is a Jira administrator (but not necessarily "System Administrator"!). * * @return true if the given user is an admin. */ boolean isAdmin(@Nullable ApplicationUser user); /** * Checks if the current user is a Jira administrator (but not necessarily "System Administrator"!). * * @return true if the current user is an admin. */ default boolean isAdmin() { return isAdmin(getUser()); } /** * Checks if the given user is a Jira system administrator. * * @param user the user to check * @return {@code true} if the given user is not {@code null} and a Jira system administrator. */ boolean isSystemAdmin(@Nullable ApplicationUser user); /** * Checks if the current user is a Jira system administrator. * * @return {@code true} if the current user is a Jira system administrator. */ default boolean isSystemAdmin() { return isSystemAdmin(getUser()); } /** * Checks if the given user can create new views. */ boolean isViewCreationAllowed(@Nullable ApplicationUser user); /** * Checks if the given user can share views. */ boolean isViewSharingAllowed(@Nullable ApplicationUser user); /** * Checks if the issue can be edited by the given user. Besides permissions, the issue may be non-editable because * of workflow. * * @param issue issue in question * @param user user to make the edit * @return true if the user can now edit the issue */ boolean isIssueEditable(@Nullable Issue issue, @Nullable ApplicationUser user); /** * Checks if the given user has the given global permission. * * @param permission global permission * @param user user in question * @return true if permission is granted */ boolean hasPermission(@NotNull GlobalPermissionKey permission, @Nullable ApplicationUser user); /** * Checks if the given user has the given project-level permission on an issue's project. * * @param permission project permission from {@link com.atlassian.jira.permission.ProjectPermissions} * @param issue an issue * @param user user in question * @return true if permission is granted */ boolean hasPermission(@NotNull ProjectPermissionKey permission, @Nullable Issue issue, @Nullable ApplicationUser user); /** * Checks if the given user has the given project-level permission on a project. * * @param permission project permission from {@link com.atlassian.jira.permission.ProjectPermissions} * @param project a project * @param user user in question * @return true if permission is granted */ boolean hasPermission(@NotNull ProjectPermissionKey permission, @Nullable Project project, @Nullable ApplicationUser user); /** * Retrieves the current user. * * @return current user * @see StructureAuth */ @Nullable ApplicationUser getUser(); /** * Retrieves the security groups that the user is allowed to see. JIRA admin is allowed to see all groups. * All non-admin users are allowed to see the groups they are in. * * @param user user * @return groups that the user is allowed to see */ @NotNull List getAvailableGroups(@Nullable ApplicationUser user); /** * Retrieves the security groups that the current user is allowed to see. JIRA admin is allowed to see all groups. * All non-admin users are allowed to see the groups they are in. * * @return groups that the current user is allowed to see */ @NotNull default List getAvailableGroupsForCurrentUser() { return getAvailableGroups(getUser()); } /** * Retrieves the roles that exist in the system. The returned list is owned by the caller and may be modified. */ @NotNull List getAvailableRoles(); /** * Retrieves the list of projects that are enabled for structure and visible to the current user. * The returned list is owned by the caller and may be modified. */ @NotNull List getStructureProjectsForCurrentUser(); /** * Retrieves the list of projects that are visible to the current user. * The returned list is owned by the caller and may be modified. * The returned projects may not be enabled for structure. */ @NotNull List getProjectsForCurrentUser(); // === Quick access to JIRA components === @NotNull JiraAuthenticationContext getAuthenticationContext(); @NotNull IssueManager getIssueManager(); @NotNull PermissionManager getPermissionManager(); @NotNull PluginAccessor getPluginAccessor(); @NotNull PluginEventManager getEventManager(); @NotNull ProjectManager getProjectManager(); @NotNull ProjectRoleManager getProjectRoleManager(); @NotNull UserManager getUserManager(); @NotNull JqlStringSupport getJqlStringSupport(); @NotNull JqlQueryParser getJqlQueryParser(); @NotNull SearchService getSearchService(); @NotNull JqlOperandResolver getJqlOperandResolver(); @NotNull SearchRequestManager getSearchRequestManager(); @NotNull GlobalPermissionManager getGlobalPermissionManager(); @NotNull TimeTrackingConfiguration getTimeTrackingConfiguration(); @NotNull UserPreferencesManager getUserPreferencesManager(); @NotNull CustomFieldManager getCustomFieldManager(); // === Web resource utilities === /** * Requires all resources needed to render Structure Widget. */ void requireWidgetResource(); /** *

Requires a resource that may be localized. A localized version of the resource will have _locale suffix in its * key - for example, com.almworks.jira.structure:my-resource_de

* *

The locale of current user is used to load the resource. If such resource is missing, nothing happens.

* * @param resourceKey base resource key */ void requireLocalizedResource(@NotNull String resourceKey); /** * Marks resource as needed for loading. Must be called before a page starts being rendered. If resource is missing, * JIRA logs a warning but rendering continues. * * @param resourceKey resource key */ void requireResource(@NotNull String resourceKey); /** * Marks resource as needed for loading, if the resource exists. If the resource is missing, nothing happens. * Must be called before a page starts being rendered. * * @param resourceKey resource key * @see #requireResource(String) */ void requireResourceIfPresent(String resourceKey); /** * Loads resources needed for the issue details layout. */ void requireIssueDetailsResources(); /** * Loads resources associated with a context * * @param context context name */ void requireResourcesForContext(String context); /** * Loads resources needed for "quick edit" code to work (dialog with editing / creating an issue). */ void requireQuickEditResources(); /** * Loads resources needed for standard JIRA keyboard shortcuts. */ void requireIssueShortcuts(); // === Searching and filtering tools === /** * Used to figure out which projects are not visible to the user. The list of project IDs may contain non-existent * IDs - they will also be reported as invisible. * * @param projects list of project IDs * @param user the user * @param overrideSecurity if true, permissions don't matter, only project existence is checked * @param invisibleCollector a collector to get the IDs of invisible projects */ void filterInvisibleProjects(@Nullable LongSizedIterable projects, @Nullable ApplicationUser user, boolean overrideSecurity, @NotNull LongCollector invisibleCollector); /** * Runs JQL search. * * @param query JQL (empty or null string will result in empty result) * @return IDs of matching issues * @throws SearchException if search problem happened * @throws JqlParseException if JQL is invalid */ @NotNull LongArray searchQuery(@Nullable String query) throws SearchException, JqlParseException; /** * Runs search. * * @param query query * @return IDs of matching issues * @throws SearchException if search problem happened */ @NotNull LongArray searchQuery(@Nullable Query query) throws SearchException; /** * Runs JQL search with sorting. * * @param query JQL (empty or null string will result in empty result) * @return IDs of matching issues * @throws SearchException if search problem happened * @throws JqlParseException if JQL is invalid */ @NotNull LongArray searchAndSortQuery(@Nullable String query) throws SearchException, JqlParseException; /** * Runs search with sorting. * * @param query query * @return IDs of matching issues * @throws SearchException if search problem happened */ @NotNull LongArray searchAndSortQuery(@Nullable Query query) throws SearchException; /** * Runs search with sorting and result count limit. * * @param query query * @param limit maximum number of issues in the result * @return IDs of matching issues * @throws SearchException if search problem happened */ @NotNull LongArray searchAndSortQuery(@Nullable Query query, int limit) throws SearchException; /** *

* Passes the issues through JIRA search engine and lets the caller collect either all matching or non-matching * issues. *

*

The implementation sorts issues and splits them up into chunks (of 100+ ids each) and creates * a JQL query for each. * This has proven to be a quick method of checking. However, if the number of issues is likely to be the same order * of magnitude as the full result of the query, it's better to run the full query and compare result with the list. *

*

The issues are checked to be accessible for the current user - so no need to run additional BROWSE permission checks. * You can quickly check which issues among the list are visible to the user by running matchIssues() with * null query. *

*

If it is certain that the issue list is sorted, it's more efficient to call {@link StructurePluginHelper#matchIssuesSorted}.

*

If you need to skip checking for the user access or check access for non-current user, * use {@link com.almworks.jira.structure.api.auth.StructureAuth#sudo)}.

* * @param query query to check against. If null, the issues are only checked to be visible to the user and to the * Structure plugin * @param issues issue IDs * @param collectMatching if true, collector will receive the issues that match query and visible to the user; * if false, collector will receive non-matching issues * @param collector an instance for receiving the results. Chunks are processed in order, for each chunk the * (non-)matching issues are added. No guarantees are made for the order of the results inside the same chunk. * @throws com.atlassian.jira.issue.search.SearchException if a bad thing happens */ void matchIssues(@Nullable LongList issues, @Nullable Query query, boolean collectMatching, @NotNull LongCollector collector) throws SearchException; /** *

Passes the issues, sorted by their IDs, through JIRA search engine to collect matching or non-matching issues.

* *

This is more efficient method than {@link #matchIssues} if you already have IDs sorted.

* * @param issuesSorted issues list * @param query additional query * @param collectMatching if true, collector receives matching issues, if false, collector receives non-matching issues. * @param collector the collector * @throws SearchException if a bad thing happens * @see #matchIssues(LongList, Query, boolean, LongCollector) */ void matchIssuesSorted(@Nullable LongList issuesSorted, @Nullable Query query, boolean collectMatching, LongCollector collector) throws SearchException; /** * A variation of {@link #matchIssuesSorted(LongList, Query, boolean, LongCollector)} that lets you specify * the user and override security checks. * * @param issuesSorted issues list * @param query additional query * @param collectMatching if true, collector receives matching issues, if false, collector receives non-matching issues. * @param user the user that will be used to check access * @param overrideSecurity if true, user access will not be checked * @param collector the collector * @throws SearchException if a bad thing happens * @see #matchIssues(LongList, Query, boolean, LongCollector) * @see StructureAuth#sudo(ApplicationUser, boolean, CallableE) */ void matchIssuesSorted(@Nullable LongList issuesSorted, @Nullable Query query, boolean collectMatching, @Nullable ApplicationUser user, boolean overrideSecurity, LongCollector collector) throws SearchException; /** * Checks if the query is valid and that the user has access to all the things mentioned in the query. * * @param user user * @param query query * @return a collection of error messages */ @NotNull MessageSet validateQuery(ApplicationUser user, Query query); /** * Retrieves a query that limits scope to the projects enabled for Structure. You can use that query to combine with * whatever business logic query you have. * * @return configuration query ("project in ...") or {@code null} if Structure is allowed for all projects * @see StructureConfiguration#getConfigurationScopeQuery() */ @Nullable default Query getConfigurationScopeQuery() { return getConfiguration().getConfigurationScopeQuery(); } // === I18n tools === /** * Retrieves i18n helper for a concrete user. * * @param user the user * @return i18n helper */ @NotNull I18nHelper getI18n(@Nullable ApplicationUser user); /** * Retrieves i18n helper for the current user. */ @NotNull default I18nHelper getI18n() { return getI18n(getUser()); } /** * Returns comparator for sorting structures by name, according to the given user's locale. * * @param user the user to take locale from * @return a comparator that can be used to sort structures */ @NotNull Comparator getStructureComparator(@Nullable ApplicationUser user); /** * Returns a collator for strings in the user's locale. * * @param user the user * @return collator */ @NotNull Collator getCollator(@Nullable ApplicationUser user); /** * Returns the current user's locale. */ @NotNull Locale getLocale(); // === Caching and lifecycle tools === StructureCacheHelper getCacheHelper(); /** * Returns true when Structure cannot be used because it is locked, either for full restore or for system startup. */ boolean isStructureLocked(); // === Miscellaneous tools === /** * Retrieves an instance of Issue. * * @param issueId the ID of the issue * @return the issue, or null if the issue cannot be found or there is an exception getting it */ @Nullable Issue getIssue(long issueId); /** * Retrieves an instance of issue by issue key. * * @param key issue key * @return the issue, or null if the issue cannot be found or there is an exception getting it */ @Nullable Issue getIssue(String key); /** * Retrieves {@code StructureConfiguration} */ @NotNull StructureConfiguration getConfiguration(); /** * Creates a new instance of the given class, injecting all dependencies into the constructor. Those dependencies may * include other Structure's services or system services. * * @param clazz class to be instantiated * @param type parameter * @return created instance */ T instantiate(@NotNull Class clazz); }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy