Limiting report display to a project or user group

Written on August 14, 2016

We needed to display JIRA report only in a certain project and for users in specific groups. The group part was easy, but getting current project’s key was not.

I found several solutions on the internet, but none of them worked. In the end I used a combination of parsing HTTP request and the UserProjectHistoryManager class.

To hide or show a report, you simply return true or false in report’s showReport() method.

public abstract class MyReport extends AbstractReport {

  @Override
  public boolean showReport() {
    return true;
  }
}

To check whether current user belongs to a group I created a simple method:

protected boolean isCurrentUserInGroup(String groupName) {
  ApplicationUser loggedInUser = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser();
  return ComponentAccessor.getGroupManager().isUserInGroup(loggedInUser, groupName);    
}

Now the project key. I got it using the UserProjectHistoryManager.getProjectHistoryWithoutPermissionChecks() method, but it doesn’t immediately reflect changing the project from the main menu. So I combined it with extracting the key directly from the HTTP request.

I did not find a way to get UserProjectHistoryManager using ComponentAccessor, so I used @Scanned annotation on the class and @ComponentImport in the report’s constructor for it to be injected automatically. There was no need to import UserProjectHistoryManager in atlassian-plugin.xml on JIRA 7, but it seems it might be necessary in older versions.

This is the method for getting current project’s key:

protected String getCurrentProjectKey() {
  HttpServletRequest request = ServletActionContext.getRequest();
  if (request != null)
  {
    // extract project's key from request
    Pattern r = Pattern.compile("/projects/([A-Z]+)");
    Matcher m = r.matcher(request.getRequestURI());
    if (m.find())  // this works on the project reports page
      return m.group(1);
    else {  // this works everywhere else
      ApplicationUser loggedInUser = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser();
      // get current project from user's history (does not work when switching between recent project from the main menu)
      List<UserHistoryItem> historyList = projectHistoryManager.getProjectHistoryWithoutPermissionChecks(loggedInUser);
      if (historyList != null && historyList.size() > 0) {
        Project currentProject = ComponentAccessor.getProjectManager().getProjectObj(Long.parseLong(historyList.get(0).getEntityId()));
        if (currentProject != null)
          return currentProject.getKey();
      }
    }
  }
  
  return null;
}

To show the report only for project “PRJ” and the “managers” group, I called the above methods like this:

@Override
public boolean showReport() {
  return "PRJ".equals(getCurrentProjectKey()) && isCurrentUserInGroup("managers");
}

This is the final class with all methods combined:

package com.example.jira.reports;

import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.servlet.http.HttpServletRequest;

import webwork.action.ServletActionContext;

import com.atlassian.jira.component.ComponentAccessor;
import com.atlassian.jira.plugin.report.impl.AbstractReport;
import com.atlassian.jira.project.Project;
import com.atlassian.jira.user.ApplicationUser;
import com.atlassian.jira.user.UserHistoryItem;
import com.atlassian.jira.user.UserProjectHistoryManager;
import com.atlassian.plugin.spring.scanner.annotation.component.Scanned;
import com.atlassian.plugin.spring.scanner.annotation.imports.ComponentImport;

@Scanned
public abstract class MyReport extends AbstractReport {
  
  private UserProjectHistoryManager projectHistoryManager;
  
  public MyReport(@ComponentImport UserProjectHistoryManager projectHistoryManager) {
    this.projectHistoryManager = projectHistoryManager;
  }

  protected String getCurrentProjectKey() {
    HttpServletRequest request = ServletActionContext.getRequest();
    if (request != null)
    {
      // extract project's key from request
      Pattern r = Pattern.compile("/projects/([A-Z]+)");
      Matcher m = r.matcher(request.getRequestURI());
      if (m.find())  // this works on the project reports page
        return m.group(1);
      else {  // this works everywhere else
        ApplicationUser loggedInUser = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser();
        // get current project from user's history (does not work when switching between recent project from the main menu)
        List<UserHistoryItem> historyList = projectHistoryManager.getProjectHistoryWithoutPermissionChecks(loggedInUser);
        if (historyList != null && historyList.size() > 0) {
          Project currentProject = ComponentAccessor.getProjectManager().getProjectObj(Long.parseLong(historyList.get(0).getEntityId()));
          if (currentProject != null)
            return currentProject.getKey();
        }
      }
    }
    
    return null;
  }
  
  protected boolean isCurrentUserInGroup(String groupName) {
    ApplicationUser loggedInUser = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser();
    return ComponentAccessor.getGroupManager().isUserInGroup(loggedInUser, groupName);    
  }
  
  @Override
  public boolean showReport() {
    // show report only for project "PRJ" and "managers" group
    return "PRJ".equals(getCurrentProjectKey()) && isCurrentUserInGroup("managers");
  }
}

Comments