From c3e3ac9088c896048f09721acf9194a60a8a886a Mon Sep 17 00:00:00 2001 From: Simon Brandhof Date: Sun, 2 Aug 2015 23:26:59 +0200 Subject: [PATCH] WS api/issues/assign in Java+Protobuf --- .../issue/InternalRubyIssueService.java | 10 -- .../sonar/server/issue/ws/AssignAction.java | 80 +++++++++++++ .../org/sonar/server/issue/ws/IssuesWs.java | 18 --- .../issue/ws/OperationResponseWriter.java | 49 ++++++++ .../platformlevel/PlatformLevel4.java | 3 + .../server/issue/ws/AssignActionTest.java | 110 ++++++++++++++++++ .../java/org/sonar/server/ws/WsUtilsTest.java | 19 +++ .../app/controllers/api/issues_controller.rb | 18 --- 8 files changed, 261 insertions(+), 46 deletions(-) create mode 100644 server/sonar-server/src/main/java/org/sonar/server/issue/ws/AssignAction.java create mode 100644 server/sonar-server/src/main/java/org/sonar/server/issue/ws/OperationResponseWriter.java create mode 100644 server/sonar-server/src/test/java/org/sonar/server/issue/ws/AssignActionTest.java diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/InternalRubyIssueService.java b/server/sonar-server/src/main/java/org/sonar/server/issue/InternalRubyIssueService.java index 2690882d762..ecb4e0a02a3 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/issue/InternalRubyIssueService.java +++ b/server/sonar-server/src/main/java/org/sonar/server/issue/InternalRubyIssueService.java @@ -192,16 +192,6 @@ public class InternalRubyIssueService { return result; } - public Result assign(String issueKey, @Nullable String assignee) { - Result result = Result.of(); - try { - result.set(issueService.assign(issueKey, StringUtils.defaultIfBlank(assignee, null))); - } catch (Exception e) { - result.addError(e.getMessage()); - } - return result; - } - public Result setSeverity(String issueKey, String severity) { Result result = Result.of(); try { diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/ws/AssignAction.java b/server/sonar-server/src/main/java/org/sonar/server/issue/ws/AssignAction.java new file mode 100644 index 00000000000..cdcf0243d35 --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/issue/ws/AssignAction.java @@ -0,0 +1,80 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2014 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * SonarQube is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.server.issue.ws; + +import org.apache.commons.lang.BooleanUtils; +import org.sonar.api.server.ws.Request; +import org.sonar.api.server.ws.Response; +import org.sonar.api.server.ws.WebService; +import org.sonar.server.issue.IssueService; +import org.sonar.server.user.UserSession; + +public class AssignAction implements IssuesWsAction { + + public static final String ASSIGN_ACTION = "assign"; + + private final UserSession userSession; + private final IssueService issueService; + private final OperationResponseWriter responseWriter; + + public AssignAction(UserSession userSession, IssueService issueService, OperationResponseWriter responseWriter) { + this.userSession = userSession; + this.issueService = issueService; + this.responseWriter = responseWriter; + } + + @Override + public void define(WebService.NewController controller) { + WebService.NewAction action = controller.createAction(ASSIGN_ACTION) + .setDescription("Assign/Unassign an issue. Requires authentication and Browse permission on project") + .setSince("3.6") + .setHandler(this) + .setPost(true); + // TODO add example of response + + action.createParam("issue") + .setDescription("Key of the issue") + .setRequired(true) + .setExampleValue("5bccd6e8-f525-43a2-8d76-fcb13dde79ef"); + action.createParam("assignee") + // TODO document absent value for unassign, or _me for assigning to me + .setDescription("Login of the assignee") + .setExampleValue("admin"); + action.createParam("me") + .setDescription("(deprecated) Assign the issue to the logged-in user. Replaced by the parameter assignee=_me") + .setBooleanPossibleValues(); + } + + @Override + public void handle(Request request, Response response) throws Exception { + + String assignee = request.param("assignee"); + if ("_me".equals(assignee) || BooleanUtils.isTrue(request.paramAsBoolean("me"))) { + // Permission is currently checked by IssueService. We still + // check that user is authenticated in order to get his login. + userSession.checkLoggedIn(); + assignee = userSession.getLogin(); + } + String key = request.mandatoryParam("issue"); + issueService.assign(key, assignee); + + responseWriter.write(key, request, response); + } +} diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/ws/IssuesWs.java b/server/sonar-server/src/main/java/org/sonar/server/issue/ws/IssuesWs.java index 9089029b21a..3232d0725da 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/issue/ws/IssuesWs.java +++ b/server/sonar-server/src/main/java/org/sonar/server/issue/ws/IssuesWs.java @@ -62,7 +62,6 @@ public class IssuesWs implements WebService { private static void defineRailsActions(NewController controller) { defineChangelogAction(controller); - defineAssignAction(controller); defineAddCommentAction(controller); defineDeleteCommentAction(controller); defineEditCommentAction(controller); @@ -89,23 +88,6 @@ public class IssuesWs implements WebService { RailsHandler.addFormatParam(action); } - private static void defineAssignAction(NewController controller) { - WebService.NewAction action = controller.createAction(ASSIGN_ACTION) - .setDescription("Assign/Unassign an issue. Requires authentication and Browse permission on project") - .setSince("3.6") - .setHandler(RailsHandler.INSTANCE) - .setPost(true); - - action.createParam("issue") - .setDescription("Key of the issue") - .setRequired(true) - .setExampleValue("5bccd6e8-f525-43a2-8d76-fcb13dde79ef"); - action.createParam("assignee") - .setDescription("Login of the assignee") - .setExampleValue("admin"); - RailsHandler.addFormatParam(action); - } - private static void defineAddCommentAction(NewController controller) { WebService.NewAction action = controller.createAction(ADD_COMMENT_ACTION) .setDescription("Add a comment. Requires authentication and Browse permission on project") diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/ws/OperationResponseWriter.java b/server/sonar-server/src/main/java/org/sonar/server/issue/ws/OperationResponseWriter.java new file mode 100644 index 00000000000..13d3bbe0a77 --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/issue/ws/OperationResponseWriter.java @@ -0,0 +1,49 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2014 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * SonarQube is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.server.issue.ws; + +import org.sonar.api.server.ws.Request; +import org.sonar.api.server.ws.Response; +import org.sonar.server.ws.WsUtils; +import org.sonarqube.ws.Issues; + +import static java.util.Collections.singletonList; +import static org.sonar.server.issue.ws.SearchAdditionalField.ALL_ADDITIONAL_FIELDS; + +public class OperationResponseWriter { + + private final SearchResponseLoader loader; + private final SearchResponseFormat format; + + public OperationResponseWriter(SearchResponseLoader loader, SearchResponseFormat format) { + this.loader = loader; + this.format = format; + } + + public void write(String issueKey, Request request, Response response) throws Exception { + SearchResponseLoader.Collector collector = new SearchResponseLoader.Collector( + ALL_ADDITIONAL_FIELDS, singletonList(issueKey)); + SearchResponseData data = loader.load(collector, null); + + Issues.Search responseBody = this.format.format(ALL_ADDITIONAL_FIELDS, data, null, null); + + WsUtils.writeProtobuf(responseBody, request, response); + } +} diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java b/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java index b4e68e63bb3..2ac4baecc07 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java +++ b/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java @@ -158,6 +158,7 @@ import org.sonar.server.issue.ws.IssueActionsWriter; import org.sonar.server.issue.ws.IssueComponentHelper; import org.sonar.server.issue.ws.IssueJsonWriter; import org.sonar.server.issue.ws.IssuesWs; +import org.sonar.server.issue.ws.OperationResponseWriter; import org.sonar.server.issue.ws.SearchResponseFormat; import org.sonar.server.issue.ws.SearchResponseLoader; import org.sonar.server.issue.ws.SetTagsAction; @@ -608,6 +609,8 @@ public class PlatformLevel4 extends PlatformLevel { WsResponseCommonFormat.class, SearchResponseLoader.class, SearchResponseFormat.class, + OperationResponseWriter.class, + org.sonar.server.issue.ws.AssignAction.class, org.sonar.server.issue.ws.ShowAction.class, org.sonar.server.issue.ws.SearchAction.class, org.sonar.server.issue.ws.Search2Action.class, diff --git a/server/sonar-server/src/test/java/org/sonar/server/issue/ws/AssignActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/issue/ws/AssignActionTest.java new file mode 100644 index 00000000000..d61c898ef56 --- /dev/null +++ b/server/sonar-server/src/test/java/org/sonar/server/issue/ws/AssignActionTest.java @@ -0,0 +1,110 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2014 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * SonarQube is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.server.issue.ws; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.sonar.api.server.ws.Request; +import org.sonar.api.server.ws.Response; +import org.sonar.server.exceptions.UnauthorizedException; +import org.sonar.server.issue.IssueService; +import org.sonar.server.tester.UserSessionRule; +import org.sonar.server.ws.WsActionTester; + +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +public class AssignActionTest { + + @Rule + public ExpectedException expectedException = ExpectedException.none(); + + @Rule + public UserSessionRule userSession = UserSessionRule.standalone(); + + IssueService issueService = mock(IssueService.class); + OperationResponseWriter responseWriter = mock(OperationResponseWriter.class); + AssignAction underTest = new AssignAction(userSession, issueService, responseWriter); + WsActionTester tester = new WsActionTester(underTest); + + @Test + public void assign_to_me() throws Exception { + userSession.login("perceval"); + + tester.newRequest() + .setParam("issue", "ABC") + .setParam("assignee", "_me") + .execute(); + + verify(issueService).assign("ABC", "perceval"); + verify(responseWriter).write(eq("ABC"), any(Request.class), any(Response.class)); + } + + @Test + public void assign_to_me_with_deprecated_param() throws Exception { + userSession.login("perceval"); + + tester.newRequest() + .setParam("issue", "ABC") + .setParam("me", "true") + .execute(); + + verify(issueService).assign("ABC", "perceval"); + verify(responseWriter).write(eq("ABC"), any(Request.class), any(Response.class)); + } + + @Test + public void assign_to_someone() throws Exception { + userSession.login("perceval"); + + tester.newRequest() + .setParam("issue", "ABC") + .setParam("assignee", "arthur") + .execute(); + + verify(issueService).assign("ABC", "arthur"); + verify(responseWriter).write(eq("ABC"), any(Request.class), any(Response.class)); + } + + @Test + public void must_be_authenticated_to_assign_to_me() throws Exception { + expectedException.expect(UnauthorizedException.class); + + tester.newRequest() + .setParam("issue", "ABC") + .setParam("assignee", "_me") + .execute(); + } + + @Test + public void unassign() throws Exception { + userSession.login("perceval"); + + tester.newRequest() + .setParam("issue", "ABC") + .execute(); + + verify(issueService).assign("ABC", null); + verify(responseWriter).write(eq("ABC"), any(Request.class), any(Response.class)); + } +} diff --git a/server/sonar-server/src/test/java/org/sonar/server/ws/WsUtilsTest.java b/server/sonar-server/src/test/java/org/sonar/server/ws/WsUtilsTest.java index 0edfbecb6fd..a0227286f39 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/ws/WsUtilsTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/ws/WsUtilsTest.java @@ -1,3 +1,22 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2014 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * SonarQube is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ package org.sonar.server.ws; import org.junit.Test; diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/controllers/api/issues_controller.rb b/server/sonar-web/src/main/webapp/WEB-INF/app/controllers/api/issues_controller.rb index 020b2511474..9d06746a051 100644 --- a/server/sonar-web/src/main/webapp/WEB-INF/app/controllers/api/issues_controller.rb +++ b/server/sonar-web/src/main/webapp/WEB-INF/app/controllers/api/issues_controller.rb @@ -145,24 +145,6 @@ class Api::IssuesController < Api::ApiController end end - # - # Assign an existing issue to a user or un-assign. - # - # POST /api/issues/assign?issue=&assignee=&me= - # A nil or blank assignee removes the assignee. - # - # -- Example - # curl -X POST -v -u admin:admin 'http://localhost:9000/api/issues/assign?issue=4a2881e7-825e-4140-a154-01f420c43d11&assignee=emmerik' - # - def assign - verify_post_request - require_parameters :issue - - assignee = (params[:me]=='true' ? current_user.login : params[:assignee]) - result = Internal.issues.assign(params[:issue], assignee) - render_result_issue(result) - end - # # Change the severity of an existing issue -- 2.39.5