Commits

James Hatherly committed ea2d7ab

Cleaned up do-as-user a lot (removed some redundant code\n Parameterized user group

  • Participants
  • Parent commits 572cea5

Comments (0)

Files changed (3)

File atlassian-kinect-wallboard-extensions/src/main/java/com/atlassian/jirawallboard/resttransitionproxy/ImpersonatableIssueUtilsBean.java

-package com.atlassian.jirawallboard.resttransitionproxy;
-
-import com.atlassian.crowd.embedded.api.User;
-import com.atlassian.jira.issue.IssueManager;
-import com.atlassian.jira.issue.IssueUtilsBean;
-import com.atlassian.jira.security.JiraAuthenticationContext;
-import com.atlassian.jira.workflow.WorkflowManager;
-import com.opensymphony.workflow.Workflow;
-
-/**
- * Extends IssueUtilsBean, takes in 1 extra param - a user to do the IssueUtilsBean methods in the context of.
- *
- * @since v4.4
- */
-public class ImpersonatableIssueUtilsBean extends IssueUtilsBean
-{
-    private final User user;
-    private final WorkflowManager workflowManager;
-
-    public ImpersonatableIssueUtilsBean(IssueManager issueManager, WorkflowManager workflowManager, JiraAuthenticationContext authenticationContext, User user)
-    {
-        super(issueManager, workflowManager, authenticationContext);
-        this.user = user;
-        this.workflowManager = workflowManager;
-    }
-
-    public Workflow getWorkflow()
-    {
-        return workflowManager.makeWorkflow(user != null ? user.getName() : null);
-    }
-}

File atlassian-kinect-wallboard-extensions/src/main/java/com/atlassian/jirawallboard/resttransitionproxy/TransitionAsUserResource.java

 import com.atlassian.jira.issue.IssueInputParametersImpl;
 import com.atlassian.jira.issue.IssueManager;
 import com.atlassian.jira.issue.MutableIssue;
-import com.atlassian.jira.issue.customfields.OperationContext;
-import com.atlassian.jira.issue.customfields.OperationContextImpl;
-import com.atlassian.jira.issue.fields.CommentSystemField;
 import com.atlassian.jira.issue.fields.CustomField;
 import com.atlassian.jira.issue.fields.FieldManager;
 import com.atlassian.jira.issue.fields.OrderableField;
-import com.atlassian.jira.issue.fields.layout.field.FieldLayoutItem;
 import com.atlassian.jira.issue.fields.screen.FieldScreenRenderLayoutItem;
 import com.atlassian.jira.issue.fields.screen.FieldScreenRenderLayoutItemImpl;
 import com.atlassian.jira.issue.fields.screen.FieldScreenRenderTab;
 import com.atlassian.jira.issue.fields.screen.FieldScreenRenderer;
 import com.atlassian.jira.issue.fields.screen.FieldScreenRendererFactory;
-import com.atlassian.jira.issue.operation.IssueOperations;
-import com.atlassian.jira.issue.search.constants.SystemSearchConstants;
 import com.atlassian.jira.jql.resolver.ResolverManager;
 import com.atlassian.jira.project.Project;
 import com.atlassian.jira.security.JiraAuthenticationContext;
 import com.atlassian.jira.security.roles.ProjectRole;
 import com.atlassian.jira.security.roles.ProjectRoleManager;
 import com.atlassian.jira.user.util.UserUtil;
-import com.atlassian.jira.util.I18nHelper;
-import com.atlassian.jira.util.SimpleErrorCollection;
 import com.atlassian.jira.util.json.JSONArray;
 import com.atlassian.jira.util.json.JSONException;
 import com.atlassian.jira.util.json.JSONObject;
-import com.atlassian.jira.web.bean.I18nBean;
 import com.atlassian.jira.workflow.JiraWorkflow;
 import com.atlassian.jira.workflow.WorkflowFunctionUtils;
 import com.atlassian.jira.workflow.WorkflowManager;
     private final ProjectRoleManager projectRoleManager;
     private final WorkflowManager workflowManager;
     private final FieldScreenRendererFactory fieldScreenRendererFactory;
-    private final FieldManager fieldManager;
 
     private static final Logger LOG = Logger.getLogger(TransitionAsUserResource.class);
 
 
     public TransitionAsUserResource(final UserUtil userUtil, final JiraAuthenticationContext authContext, final IssueManager issueManager,
             final ResolverManager resolverManager, final IssueService issueService, final ProjectRoleManager projectRoleManager,
-            final PermissionManager permissionManager, final WorkflowManager workflowManager, final FieldScreenRendererFactory fieldScreenRendererFactory,
-            final FieldManager fieldManager)
+            final PermissionManager permissionManager, final WorkflowManager workflowManager, final FieldScreenRendererFactory fieldScreenRendererFactory)
     {
         this.userUtil = userUtil;
         this.authContext = authContext;
         this.permissionManager = permissionManager;
         this.workflowManager = workflowManager;
         this.fieldScreenRendererFactory = fieldScreenRendererFactory;
-        this.fieldManager = fieldManager;
     }
 
     @POST
             return Response.status(Response.Status.FORBIDDEN).cacheControl(never()).entity(ErrorCollection.of("no user parameter passed in")).build();
         }
 
-        final Issue issue = getIssueObject(issueKey, user);
+        //Set the authContext's loggedInUser to the impersonated user
+        authContext.setLoggedInUser(user);
+        final Issue issue = getIssueObject(issueKey);
+        authContext.setLoggedInUser(oldUser);
 
         // Now we need to begin parsing the request JSON that they sent in to us.
         final JSONObject json;
             throw new RESTException(Response.Status.BAD_REQUEST, "provided json structure invalid");
         }
 
-        //Set the authContext to the requested user (in case user is ignored somewhere further down the track)
-        this.authContext.setLoggedInUser(user);
+        //Update the user for the transition
+        authContext.setLoggedInUser(user);
+        final IssueService.TransitionValidationResult validationResult = issueService.validateTransition(user, issue.getId(), actionId, issueInputParameters);
 
-        final IssueService.TransitionValidationResult validationResult = this.validateTransition(issueService, user, issue.getId(), actionId, issueInputParameters);
-
-        if (!validationResult.isValid())
-        {
-            final ErrorCollection errorCollection = ErrorCollection.builder().addErrorCollection(validationResult.getErrorCollection()).build();
-            //Reset the authContext
-            this.authContext.setLoggedInUser(oldUser);
-            throw new RESTException(Response.Status.BAD_REQUEST, errorCollection);
+        try {
+            if (!validationResult.isValid())
+            {
+                final ErrorCollection errorCollection = ErrorCollection.builder().addErrorCollection(validationResult.getErrorCollection()).build();
+                throw new RESTException(Response.Status.BAD_REQUEST, errorCollection);
+            }
+            else
+            {
+                issueService.transition(user, validationResult);
+                return Response.noContent().build();
+            }
+        } finally {
+            //and reset the user to the old one
+            authContext.setLoggedInUser(oldUser);
         }
-        else
-        {
-            issueService.transition(user, validationResult);
-            //Reset the authContext
-            this.authContext.setLoggedInUser(oldUser);
-            return Response.noContent().build();
-        }
-    }
-
-    //This method needed to be duplicated from DefaultIssueService
-    public IssueService.TransitionValidationResult validateTransition(IssueService issueService, User user, Long issueId, int actionId, IssueInputParameters issueInputParameters)
-    {
-
-        ImpersonatableIssueUtilsBean issueUtilsBean = new ImpersonatableIssueUtilsBean(issueManager, workflowManager, authContext, user);
-
-        I18nBean i18n = new I18nBean(user);
-
-        if (issueInputParameters == null)
-        {
-            throw new IllegalArgumentException("You must provide a non-null issueInputParameters.");
-        }
-
-        final Map<String, Object> fieldValuesHolder = cloneFieldValuesHolder(issueInputParameters);
-        final SimpleErrorCollection errors = new SimpleErrorCollection();
-        if (issueId == null)
-        {
-            errors.addErrorMessage(i18n.getText("issue.service.transition.issue.is.null"));
-            return new IssueService.TransitionValidationResult(null, errors, fieldValuesHolder, null, actionId);
-        }
-
-        // Try to lookup the issue that we must update
-        final MutableIssue issue = issueManager.getIssueObject(issueId);
-
-        if (issue == null)
-        {
-            errors.addErrorMessage(i18n.getText("issue.service.transition.issue.is.null"));
-            return new IssueService.TransitionValidationResult(null, errors, fieldValuesHolder, null, actionId);
-        }
-
-        final JiraWorkflow workflow = workflowManager.getWorkflow(issue);
-        if (workflow == null)
-        {
-            return null;
-        }
-
-        final WorkflowDescriptor descriptor = workflow.getDescriptor();
-        if (descriptor == null)
-        {
-            return null;
-        }
-        final ActionDescriptor actionDescriptor = descriptor.getAction(actionId);
-
-        // Validate that the action exists
-        if (actionDescriptor == null)
-        {
-            errors.addErrorMessage(i18n.getText("issue.service.transition.issue.no.action", String.valueOf(actionId)));
-            return new IssueService.TransitionValidationResult(null, errors, fieldValuesHolder, null, actionId);
-        }
-
-        // Validate that the action is a valid action
-        if (!issueUtilsBean.isValidAction(issue, actionId))
-        {
-            errors.addErrorMessage(i18n.getText("issue.service.transition.issue.action.invalid", actionDescriptor.getName(), issue.getKey()));
-            return new IssueService.TransitionValidationResult(null, errors, fieldValuesHolder, null, actionId);
-        }
-
-        MutableIssue updatedIssue;
-        // We only want to update the issue if there is an associated screen with the transition
-        if (StringUtils.isNotEmpty(actionDescriptor.getView()))
-        {
-            updatedIssue = validateAndUpdateIssueFromFields(user, issue, issueInputParameters, fieldValuesHolder,
-                    errors, i18n, fieldScreenRendererFactory.getFieldScreenRenderer(user, issue, actionDescriptor), false);
-            if (errors.hasAnyErrors())
-            {
-                return new IssueService.TransitionValidationResult(null, errors, fieldValuesHolder, null, actionId);
-            }
-            // Comment information is handled by the generated change history so no need to put it into the additional
-            // parameters
-        }
-        else
-        {
-            updatedIssue = issue;
-        }
-
-        final Map<String, Object> additionalParams = createAdditionalParameters(user, fieldValuesHolder);
-        return new IssueService.TransitionValidationResult(updatedIssue, errors, fieldValuesHolder, additionalParams, actionId);
-    }
-
-    private void validateAndPopulateParams(User user, MutableIssue issue, IssueInputParameters issueInputParameters, Map<String, Object> fieldValuesHolder, OperationContext operationContext, com.atlassian.jira.util.ErrorCollection errorCollection, I18nHelper i18n, FieldScreenRenderer fieldScreenRenderer)
-        {
-            // If a comment has been provided then we will validate it.
-            if (issueInputParameters.getCommentValue() != null)
-            {
-                // validate comments params if there
-                OrderableField field = (OrderableField) fieldManager.getField(SystemSearchConstants.forComments().getFieldId());
-                field.populateFromParams(fieldValuesHolder, issueInputParameters.getActionParameters());
-                field.validateParams(operationContext, errorCollection, i18n, issue, getFieldScreenRendererLayoutItemForField(user, issue, field));
-            }
-
-            final boolean retainIssueValues = issueInputParameters.retainExistingValuesWhenParameterNotProvided();
-            for (final FieldScreenRenderTab fieldScreenRenderTab : fieldScreenRenderer.getFieldScreenRenderTabs())
-            {
-                for (final FieldScreenRenderLayoutItem fieldScreenRenderLayoutItem : fieldScreenRenderTab.getFieldScreenRenderLayoutItemsForProcessing())
-                {
-                    if (fieldScreenRenderLayoutItem.isShow(issue))
-                    {
-                        final OrderableField orderableField = fieldScreenRenderLayoutItem.getOrderableField();
-                        // If they have not provided the field value then we need to populate the field values holder from
-                        // the issue, otherwise we can populate it from the action parameters
-                        // NOTE: some fields, like the multi-select and checkboxes work such that when the user selects NO values,
-                        // the action parameters has nothing submitted for that field. This mechanism is used to "unset" field
-                        // values for these fields. Therefore we need a special flag on the input parameters that tells us
-                        // how we should treat the "unset" fields.
-                        if (retainIssueValues && !issueInputParameters.isFieldPresent(orderableField.getId()))
-                        {
-                            // We need to populate the field values holder from the issue so that if someone is using
-                            // the service programatically and just trying to update a subset of the fields that are visible
-                            // on the screen we will not over-write or null out the existing values by not having a value
-                            // for them in the field values holder. The calls to validate and update expect the field values
-                            // holder to have stuff for the field when called. Not having stuff usually results in null'ing
-                            // out the fields value.
-                            orderableField.populateFromIssue(fieldValuesHolder, issue);
-                        }
-                        else
-                        {
-                            orderableField.populateFromParams(fieldValuesHolder, issueInputParameters.getActionParameters());
-                        }
-
-                        orderableField.validateParams(operationContext, errorCollection, i18n, issue, fieldScreenRenderLayoutItem);
-                    }
-                }
-            }
-        }
-
-
-    private MutableIssue validateAndUpdateIssueFromFields(User user, MutableIssue issue, IssueInputParameters issueInputParameters,
-            Map<String, Object> fieldValuesHolder, com.atlassian.jira.util.ErrorCollection errorCollection, I18nHelper i18n,
-            final FieldScreenRenderer fieldScreenRenderer, boolean updateComment)
-    {
-        final OperationContext operationContext = new OperationContextImpl(IssueOperations.EDIT_ISSUE_OPERATION, fieldValuesHolder);
-        final com.atlassian.jira.util.ErrorCollection localCollection = new SimpleErrorCollection();
-
-        // Check that the incoming values are valid values
-        validateAndPopulateParams(user, issue, issueInputParameters, fieldValuesHolder, operationContext, localCollection, i18n, fieldScreenRenderer);
-
-        // Update the issue with the passed in values if we have passed all the validation
-        if (!localCollection.hasAnyErrors())
-        {
-            updateIssueFromFields(fieldScreenRenderer, issue, user, fieldValuesHolder, updateComment);
-        }
-        else
-        {
-            issue = null;
-            errorCollection.addErrorCollection(localCollection);
-        }
-
-        return issue;
-    }
-
-    private void updateIssueWithComment(final MutableIssue issue, final User user, final Map<String, Object> fieldValuesHolder)
-    {
-        final OrderableField commentField = (OrderableField) fieldManager.getField(SystemSearchConstants.forComments().getFieldId());
-        final FieldLayoutItem fieldLayoutItem = getFieldScreenRendererLayoutItemForField(user, issue, commentField).getFieldLayoutItem();
-        commentField.updateIssue(fieldLayoutItem, issue, fieldValuesHolder);
-    }
-
-    private FieldScreenRenderLayoutItem getFieldScreenRendererLayoutItemForField(User user, Issue issue, OrderableField field)
-    {
-        final FieldScreenRenderer renderer = fieldScreenRendererFactory.getFieldScreenRenderer(user, issue, IssueOperations.VIEW_ISSUE_OPERATION, false);
-        return renderer.getFieldScreenRenderLayoutItem(field);
-    }
-
-    private void updateIssueFromFields(FieldScreenRenderer fieldScreenRenderer, MutableIssue issue, User user,
-            Map<String, Object> fieldValuesHolder, boolean updateComment)
-    {
-        ///JRA-20604, JRADEV-1246: We should not call this method when doing a transition. When doing a transition,
-        // the comment is updated using CreateIssueComment
-        if (updateComment)
-        {
-            // This hack is here until the comment field becomes placeable on screens by the users
-            updateIssueWithComment(issue, user, fieldValuesHolder);
-        }
-
-        for (final FieldScreenRenderTab fieldScreenRenderTab : fieldScreenRenderer.getFieldScreenRenderTabs())
-        {
-            for (final FieldScreenRenderLayoutItem fieldScreenRenderLayoutItem : fieldScreenRenderTab.getFieldScreenRenderLayoutItemsForProcessing())
-            {
-                if (fieldScreenRenderLayoutItem.isShow(issue))
-                {
-                    fieldScreenRenderLayoutItem.getOrderableField().updateIssue(fieldScreenRenderLayoutItem.getFieldLayoutItem(), issue, fieldValuesHolder);
-                }
-            }
-        }
-    }
-
-    private Map<String, Object> createAdditionalParameters(final User user, final Map<String, Object> fieldValuesHolder)
-    {
-        final Map<String, Object> additionalParams = new HashMap<String, Object>();
-        // put the username into the additional params
-        additionalParams.put("username", (user != null) ? user.getName() : null);
-
-        ///JRA-20604, JRADEV-1246: Need to populate the comment parameters into the additionalParams so they will be available
-        //to the workflow actions. Importantly, this means that the event fired by the workflow will contain a comment if provided
-        //by the user.
-        final CommentSystemField commentSystemField = (CommentSystemField) fieldManager.getOrderableField(IssueFieldConstants.COMMENT);
-        commentSystemField.populateAdditionalInputs(fieldValuesHolder, additionalParams);
-
-        return additionalParams;
-    }
-
-    private Map<String, Object> cloneFieldValuesHolder(IssueInputParameters issueInputParameters)
-    {
-        Map<String, Object> clonedFieldValuesHolder = new HashMap<String, Object>();
-        clonedFieldValuesHolder.putAll(issueInputParameters.getFieldValuesHolder());
-        return clonedFieldValuesHolder;
     }
 
     @GET
     @Path ("/{issueKey}/transitions")
     public Response getTransitions(@PathParam ("issueKey") final String issueKey, @QueryParam ("username") final String username)
     {
-        //Reject if not the designated user.
-        if (!authContext.getLoggedInUser().getName().equals(WALLBOARD_USER))
+        //Get the current user
+        User oldUser = authContext.getLoggedInUser();
+        if (!oldUser.getName().equals(WALLBOARD_USER))
         {
             return Response.status(Response.Status.FORBIDDEN).cacheControl(never()).entity(ErrorCollection.of("Resource can only be accessed by " + WALLBOARD_USER)).build();
         }
 
+        //get the impersonating user
         final User user = userUtil.getUserObject(username);
         if (user == null)
         {
             return Response.status(Response.Status.FORBIDDEN).cacheControl(never()).entity(ErrorCollection.of("no user parameter passed in")).build();
         }
 
-        final Issue issue = getIssueObject(issueKey, user);
+        Map<Integer, ExtendedTransitionsBean> map;
 
-        final List<ActionDescriptor> actions = loadAvailableActions(user, issue);
-        Collections.sort(actions, new Comparator<ActionDescriptor>()
-        {
-            public int compare(ActionDescriptor o1, ActionDescriptor o2)
+        //Impersonate the requested user
+        authContext.setLoggedInUser(user);
+        try {
+            final Issue issue = getIssueObject(issueKey);
+
+            final List<ActionDescriptor> actions = loadAvailableActions(user, issue);
+            Collections.sort(actions, new Comparator<ActionDescriptor>()
             {
-                return getSequenceFromAction(o1).compareTo(getSequenceFromAction(o2));
+                public int compare(ActionDescriptor o1, ActionDescriptor o2)
+                {
+                    return getSequenceFromAction(o1).compareTo(getSequenceFromAction(o2));
+                }
+            });
+
+            map = new HashMap<Integer, ExtendedTransitionsBean>();
+
+            for (ActionDescriptor action : actions)
+            {
+                final FieldScreenRenderer fieldScreenRenderer = fieldScreenRendererFactory.getFieldScreenRenderer(user, issue, action);
+                String status = getStatusFromStep(issue, action.getUnconditionalResult().getStep());
+                final ExtendedTransitionsBean transitions = new ExtendedTransitionsBean(action.getName(), getRequiredFields(fieldScreenRenderer, issue), status);
+                map.put(action.getId(), transitions);
             }
-        });
-
-        Map<Integer, ExtendedTransitionsBean> map = new HashMap<Integer, ExtendedTransitionsBean>();
-
-        for (ActionDescriptor action : actions)
-        {
-            final FieldScreenRenderer fieldScreenRenderer = fieldScreenRendererFactory.getFieldScreenRenderer(user, issue, action);
-            String status = getStatusFromStep(issue, action.getUnconditionalResult().getStep());
-            final ExtendedTransitionsBean transitions = new ExtendedTransitionsBean(action.getName(), getRequiredFields(fieldScreenRenderer, issue), status);
-            map.put(action.getId(), transitions);
+        } finally {
+            //Return to the old user
+            authContext.setLoggedInUser(oldUser);
         }
-
         return Response.ok(map).build();
 
     }
         return map;
     }
 
-    private Issue getIssueObject(final String issueKey, final User user) throws RESTException
+    private Issue getIssueObject(final String issueKey) throws RESTException
     {
 
         final MutableIssue issue = issueManager.getIssueObject(issueKey);
         {
             throw new RESTException(ErrorCollection.of("Issue does not exist"));
         }
+        User user = authContext.getLoggedInUser();
         if (!permissionManager.hasPermission(Permissions.BROWSE, issue, user))
         {
             ErrorCollection.Builder errorBuilder = ErrorCollection.Builder.newBuilder().addErrorMessage("User has no permission to see issue");

File atlassian-kinect-wallboard-extensions/src/main/resources/js/wallboard-interaction.js

     AJS.WALLBOARD.funcs = {};
 
     AJS.WALLBOARD.restVersion = "interactiveWallboard/1.0";
-    AJS.WALLBOARD.userGroup = "kinect-users";
     AJS.WALLBOARD.selectedUser = null;
 
     AJS.WALLBOARD.eventsToPropogate = "userPicked stopInteraction userOut handOpen handClose handIn handOut handOff handOn";
 
     AJS.WALLBOARD.initializeInteractiveExtensions = function()
     {
+        var uri = AJS.parseUri(document.location);
+
+        AJS.WALLBOARD.userGroup = uri.queryKey["userGroup"];
+        if(!AJS.WALLBOARD.userGroup || AJS.WALLBOARD.userGroup == ""){
+            AJS.log("No userGroup param passed, no as-user interaction enabled");
+        }
+
+
         gadgets.rpc.register("get_impersonated_user", function() {
             return AJS.WALLBOARD.selectedUser;
         });