PageRenderTime 36ms CodeModel.GetById 8ms RepoModel.GetById 0ms app.codeStats 0ms

/jira-project/jira-components/jira-plugins/jira-view-issue-plugin/src/main/java/com/atlassian/jira/plugin/viewissue/ActivityBlockViewIssueContextProvider.java

https://bitbucket.org/ahmed_bilal_360factors/jira7-core
Java | 265 lines | 195 code | 49 blank | 21 comment | 28 complexity | 975f8077bb687e5036d5814f875b30c7 MD5 | raw file
Possible License(s): Apache-2.0
  1. package com.atlassian.jira.plugin.viewissue;
  2. import com.atlassian.event.api.EventPublisher;
  3. import com.atlassian.jira.config.properties.APKeys;
  4. import com.atlassian.jira.config.properties.ApplicationProperties;
  5. import com.atlassian.jira.issue.Issue;
  6. import com.atlassian.jira.plugin.issuetabpanel.GetActionsRequest;
  7. import com.atlassian.jira.plugin.issuetabpanel.IssueAction;
  8. import com.atlassian.jira.plugin.issuetabpanel.IssueTabPanelInvoker;
  9. import com.atlassian.jira.plugin.issuetabpanel.IssueTabPanelModuleDescriptor;
  10. import com.atlassian.jira.plugin.issuetabpanel.ShowPanelRequest;
  11. import com.atlassian.jira.plugin.util.ModuleDescriptorComparator;
  12. import com.atlassian.jira.plugin.viewissue.events.IssueTabRenderedEvent;
  13. import com.atlassian.jira.plugin.webfragment.CacheableContextProvider;
  14. import com.atlassian.jira.security.JiraAuthenticationContext;
  15. import com.atlassian.jira.user.ApplicationUser;
  16. import com.atlassian.jira.util.collect.MapBuilder;
  17. import com.atlassian.jira.util.velocity.VelocityRequestContext;
  18. import com.atlassian.jira.util.velocity.VelocityRequestContextFactory;
  19. import com.atlassian.jira.util.velocity.VelocityRequestSession;
  20. import com.atlassian.jira.web.SessionKeys;
  21. import com.atlassian.plugin.ModuleDescriptor;
  22. import com.atlassian.plugin.PluginAccessor;
  23. import com.atlassian.plugin.PluginParseException;
  24. import com.google.common.collect.ImmutableSet;
  25. import com.google.common.collect.Lists;
  26. import com.google.common.hash.Hashing;
  27. import org.apache.commons.lang.StringUtils;
  28. import org.apache.log4j.Logger;
  29. import java.nio.charset.Charset;
  30. import java.util.ArrayList;
  31. import java.util.Collections;
  32. import java.util.List;
  33. import java.util.Map;
  34. import java.util.Set;
  35. import java.util.stream.Collectors;
  36. /**
  37. * Context Provider for the Activity block section on View Issue page.
  38. * Expensive one so it cached per request/per user/per issue
  39. *
  40. * @since v4.4
  41. */
  42. public class ActivityBlockViewIssueContextProvider implements CacheableContextProvider {
  43. private static final String ORDER_DESC = "desc";
  44. protected final Logger log = Logger.getLogger(ActivityBlockViewIssueContextProvider.class);
  45. private final PluginAccessor pluginAccessor;
  46. private final JiraAuthenticationContext authenticationContext;
  47. private final VelocityRequestContextFactory requestContextFactory;
  48. private final ApplicationProperties applicationProperties;
  49. private final IssueTabPanelInvoker issueTabPanelInvoker;
  50. private final EventPublisher eventPublisher;
  51. private final Set<String> WHITELISTED_KEYS = ImmutableSet.of(
  52. "com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel",
  53. "com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel",
  54. "com.atlassian.jira.plugin.system.issuetabpanels:worklog-tabpanel",
  55. "com.atlassian.jira.plugin.system.issuetabpanels:changehistory-tabpanel",
  56. "com.atlassian.streams.streams-jira-plugin:activity-stream-issue-tab"
  57. );
  58. public ActivityBlockViewIssueContextProvider(PluginAccessor pluginAccessor, JiraAuthenticationContext authenticationContext,
  59. VelocityRequestContextFactory requestContextFactory, ApplicationProperties applicationProperties,
  60. IssueTabPanelInvoker issueTabPanelInvoker, EventPublisher eventPublisher) {
  61. this.pluginAccessor = pluginAccessor;
  62. this.authenticationContext = authenticationContext;
  63. this.requestContextFactory = requestContextFactory;
  64. this.applicationProperties = applicationProperties;
  65. this.issueTabPanelInvoker = issueTabPanelInvoker;
  66. this.eventPublisher = eventPublisher;
  67. }
  68. @Override
  69. public void init(Map<String, String> params) throws PluginParseException {
  70. }
  71. @Override
  72. public Map<String, Object> getContextMap(Map<String, Object> context) {
  73. boolean isAsynchronous = (Boolean) consumeParam(context, "isAsynchronousRequest");
  74. final Issue issue = (Issue) context.get("issue");
  75. final ApplicationUser user = authenticationContext.getUser();
  76. final MapBuilder<String, Object> paramsBuilder = MapBuilder.newBuilder(context);
  77. final ArrayList<IssueTabPanelModuleDescriptor> tabPanelDescriptors = getTabPanels(issue, user);
  78. String currentPageKey = getCurrentTabPanel(tabPanelDescriptors);
  79. IssueTabPanelModuleDescriptor currentTabPanelModuleDescriptor = getTabPanelModuleDescriptor(currentPageKey, tabPanelDescriptors);
  80. final String actionSortOrder = getActionSortOrder();
  81. final VelocityRequestContext requestContext = requestContextFactory.getJiraVelocityRequestContext();
  82. boolean showAllFlag = (requestContext.getRequestParameter("showAll") != null);
  83. String focusId = requestContext.getRequestParameter("focusedCommentId");
  84. GetActionsRequest getActionsRequest = new GetActionsRequest(issue, user, isAsynchronous, showAllFlag, focusId);
  85. List<IssueAction> issueActions = issueTabPanelInvoker.invokeGetActions(getActionsRequest, currentTabPanelModuleDescriptor);
  86. final List<IssueAction> actions = Lists.newArrayList(issueActions);
  87. sort(actions, actionSortOrder);
  88. paramsBuilder.add("tabPanels", tabPanelDescriptors);
  89. paramsBuilder.add("hasPanels", !tabPanelDescriptors.isEmpty());
  90. paramsBuilder.add("currentPageKey", currentPageKey);
  91. paramsBuilder.add("currentTab", currentTabPanelModuleDescriptor);
  92. paramsBuilder.add("isSortable", currentTabPanelModuleDescriptor.isSortable() && actions != null && actions.size() > 1);
  93. paramsBuilder.add("actions", actions);
  94. paramsBuilder.add("hasActions", actions != null && !actions.isEmpty());
  95. paramsBuilder.add("actionError", actions == null);
  96. paramsBuilder.add("actionsSortOrder", actionSortOrder);
  97. sendTabRenderedEvent(currentPageKey, tabPanelDescriptors, issue);
  98. return paramsBuilder.toMap();
  99. }
  100. @Override
  101. public String getUniqueContextKey(Map<String, Object> context) {
  102. final Issue issue = (Issue) context.get("issue");
  103. final ApplicationUser user = authenticationContext.getUser();
  104. return issue.getId() + "/" + (user == null ? "" : user.getName());
  105. }
  106. private void sort(List<IssueAction> actions, String actionSortOrder) {
  107. if (ORDER_DESC.equals(actionSortOrder)) {
  108. Collections.reverse(actions);
  109. }
  110. }
  111. private String getActionSortOrder() {
  112. final String defaultOrder = applicationProperties.getDefaultBackedString(APKeys.JIRA_ISSUE_ACTIONS_ORDER);
  113. final VelocityRequestContext requestContext = requestContextFactory.getJiraVelocityRequestContext();
  114. String actionOrder = requestContext.getRequestParameter("actionOrder");
  115. final VelocityRequestSession session = requestContext.getSession();
  116. if (StringUtils.isNotBlank(actionOrder)) {
  117. if (!actionOrder.equals(defaultOrder)) {
  118. session.setAttribute(SessionKeys.VIEWISSUE_ACTION_ORDER, actionOrder);
  119. return actionOrder;
  120. }
  121. session.removeAttribute(SessionKeys.VIEWISSUE_ACTION_ORDER);
  122. return defaultOrder;
  123. }
  124. actionOrder = (String) session.getAttribute(SessionKeys.VIEWISSUE_ACTION_ORDER);
  125. if (StringUtils.isNotBlank(actionOrder)) {
  126. return actionOrder;
  127. }
  128. return defaultOrder;
  129. }
  130. private String getCurrentTabPanel(List<IssueTabPanelModuleDescriptor> tabPanels) {
  131. final VelocityRequestContext requestContext = requestContextFactory.getJiraVelocityRequestContext();
  132. String page = requestContext.getRequestParameter("page");
  133. final VelocityRequestSession session = requestContext.getSession();
  134. if (StringUtils.isNotBlank(page) && isTabPanelVisisble(page, tabPanels)) {
  135. session.setAttribute(SessionKeys.VIEWISSUE_PAGE, page);
  136. return page;
  137. }
  138. page = (String) session.getAttribute(SessionKeys.VIEWISSUE_PAGE);
  139. if (StringUtils.isNotBlank(page) && isTabPanelVisisble(page, tabPanels)) {
  140. return page;
  141. }
  142. return getDefaultPage(tabPanels);
  143. }
  144. private boolean isTabPanelVisisble(String tabPanelKey, List<IssueTabPanelModuleDescriptor> tabPanels) {
  145. return getTabPanelModuleDescriptor(tabPanelKey, tabPanels) != null;
  146. }
  147. private IssueTabPanelModuleDescriptor getTabPanelModuleDescriptor(String key, List<IssueTabPanelModuleDescriptor> tabPanels) {
  148. for (IssueTabPanelModuleDescriptor tabPanel : tabPanels) {
  149. if (tabPanel.getCompleteKey().equals(key)) {
  150. return tabPanel;
  151. }
  152. }
  153. return null;
  154. }
  155. private ArrayList<IssueTabPanelModuleDescriptor> getTabPanels(Issue issue, ApplicationUser user) {
  156. final List<IssueTabPanelModuleDescriptor> allTabPanels = pluginAccessor.getEnabledModuleDescriptorsByClass(IssueTabPanelModuleDescriptor.class);
  157. final ArrayList<IssueTabPanelModuleDescriptor> filteredTabPanels = Lists.newArrayListWithCapacity(allTabPanels.size());
  158. for (IssueTabPanelModuleDescriptor descriptor : allTabPanels) {
  159. if (issueTabPanelInvoker.invokeShowPanel(new ShowPanelRequest(issue, user), descriptor)) {
  160. filteredTabPanels.add(descriptor);
  161. }
  162. }
  163. Collections.sort(filteredTabPanels, ModuleDescriptorComparator.COMPARATOR);
  164. return filteredTabPanels;
  165. }
  166. private void sendTabRenderedEvent(final String currentPageKey, final List<IssueTabPanelModuleDescriptor> moduleDescriptors,
  167. final Issue issue) {
  168. if (currentPageKey == null) {
  169. return;
  170. }
  171. final int tabIndex = moduleDescriptors.stream()
  172. .map(ModuleDescriptor::getCompleteKey)
  173. .collect(Collectors.toList())
  174. .indexOf(currentPageKey);
  175. // whitelist tab name
  176. String whitelistedTabKey = currentPageKey;
  177. if (!WHITELISTED_KEYS.contains(currentPageKey)) {
  178. whitelistedTabKey = Hashing.md5()
  179. .newHasher().putString(currentPageKey, Charset.defaultCharset()).hash()
  180. .toString();
  181. }
  182. final IssueTabRenderedEvent event = new IssueTabRenderedEvent(whitelistedTabKey, tabIndex, issue.getId());
  183. eventPublisher.publish(event);
  184. }
  185. /**
  186. * @param issueTabPanels a List<IssueTabPanelModuleDescriptor>
  187. * @return the default page (as specified by the {@link IssueTabPanelModuleDescriptor})
  188. * @see com.atlassian.jira.plugin.issuetabpanel.IssueTabPanelModuleDescriptor#isDefault()
  189. */
  190. private String getDefaultPage(List<IssueTabPanelModuleDescriptor> issueTabPanels) {
  191. for (final IssueTabPanelModuleDescriptor descriptor : issueTabPanels) {
  192. if (descriptor.isDefault()) {
  193. return descriptor.getCompleteKey();
  194. }
  195. }
  196. // if no defaults are found, then just return the first one (if there are any)
  197. if (!issueTabPanels.isEmpty()) {
  198. return issueTabPanels.get(0).getCompleteKey();
  199. } else {
  200. return null;
  201. }
  202. }
  203. /**
  204. * Helper method used to consumer context parameters that we don't want to propagate into the issue tab panel
  205. * velocity context.
  206. *
  207. * @param context the context map
  208. * @param paramName the name of the parameter
  209. * @return <code>context</code> minus the entry with key=<code>paramName</code>
  210. */
  211. private Object consumeParam(Map<String, Object> context, String paramName) {
  212. Object result = context.get(paramName);
  213. context.remove(paramName);
  214. return result;
  215. }
  216. }