From 6cd9d71fc8f7c093b2a3da4e0f625fdf82541cb2 Mon Sep 17 00:00:00 2001 From: Simon Brandhof Date: Mon, 13 May 2013 17:16:09 +0200 Subject: [PATCH] SONAR-4323 add Java client to WS /api/users/search --- .../org/sonar/api/user/RubyUserService.java | 4 ++ .../server/user/DefaultRubyUserService.java | 7 ++- .../webapp/WEB-INF/app/models/action_plan.rb | 15 ++--- .../java/org/sonar/wsclient/SonarClient.java | 6 ++ .../org/sonar/wsclient/issue/IssueQuery.java | 2 + .../wsclient/user/DefaultUserClient.java | 62 +++++++++++++++++++ .../org/sonar/wsclient/user/UserClient.java | 31 ++++++++++ .../org/sonar/wsclient/user/UserQuery.java | 59 ++++++++++++++++++ .../org/sonar/wsclient/SonarClientTest.java | 4 +- .../wsclient/user/DefaultUserClientTest.java | 51 +++++++++++++++ 10 files changed, 232 insertions(+), 9 deletions(-) create mode 100644 sonar-ws-client/src/main/java/org/sonar/wsclient/user/DefaultUserClient.java create mode 100644 sonar-ws-client/src/main/java/org/sonar/wsclient/user/UserClient.java create mode 100644 sonar-ws-client/src/main/java/org/sonar/wsclient/user/UserQuery.java create mode 100644 sonar-ws-client/src/test/java/org/sonar/wsclient/user/DefaultUserClientTest.java diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/user/RubyUserService.java b/sonar-plugin-api/src/main/java/org/sonar/api/user/RubyUserService.java index 5247f6b1efa..a1e7180a453 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/user/RubyUserService.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/user/RubyUserService.java @@ -21,6 +21,7 @@ package org.sonar.api.user; import org.sonar.api.ServerComponent; +import javax.annotation.CheckForNull; import java.util.List; import java.util.Map; @@ -29,6 +30,9 @@ import java.util.Map; */ public interface RubyUserService extends ServerComponent { + @CheckForNull + User findByLogin(String login); + /** * Search for users *

diff --git a/sonar-server/src/main/java/org/sonar/server/user/DefaultRubyUserService.java b/sonar-server/src/main/java/org/sonar/server/user/DefaultRubyUserService.java index 96905d535d6..db042c5a8d5 100644 --- a/sonar-server/src/main/java/org/sonar/server/user/DefaultRubyUserService.java +++ b/sonar-server/src/main/java/org/sonar/server/user/DefaultRubyUserService.java @@ -35,6 +35,11 @@ public class DefaultRubyUserService implements RubyUserService { this.finder = finder; } + @Override + public User findByLogin(String login) { + return finder.findByLogin(login); + } + @Override public List find(Map params) { UserQuery query = parseQuery(params); @@ -43,7 +48,7 @@ public class DefaultRubyUserService implements RubyUserService { private UserQuery parseQuery(Map params) { UserQuery.Builder builder = UserQuery.builder(); - if (RubyUtils.toBoolean(params.get("includeDeactivated"))==Boolean.TRUE) { + if (RubyUtils.toBoolean(params.get("includeDeactivated")) == Boolean.TRUE) { builder.includeDeactivated(); } builder.logins(RubyUtils.toStrings(params.get("logins"))); diff --git a/sonar-server/src/main/webapp/WEB-INF/app/models/action_plan.rb b/sonar-server/src/main/webapp/WEB-INF/app/models/action_plan.rb index 5f64e06db3e..52dc7075234 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/models/action_plan.rb +++ b/sonar-server/src/main/webapp/WEB-INF/app/models/action_plan.rb @@ -77,13 +77,14 @@ class ActionPlan < ActiveRecord::Base deadline ? status==STATUS_OPEN && deadline.past? : false end - def self.to_hash(action_plan) - hash = {:key => action_plan.key(), :name => action_plan.name(), :status => action_plan.status()} - hash[:desc] = action_plan.description() if action_plan.description() && !action_plan.description().blank? - hash[:userLogin] = action_plan.userLogin() if action_plan.userLogin() - hash[:deadLine] = Api::Utils.format_datetime(action_plan.deadLine()) if action_plan.deadLine() - hash[:creationDate] = Api::Utils.format_datetime(action_plan.creationDate()) if action_plan.creationDate() - hash[:updateDate] = Api::Utils.format_datetime(action_plan.updateDate()) if action_plan.updateDate() + # since 3.6 + def self.to_hash(java_action_plan) + hash = {:key => java_action_plan.key(), :name => java_action_plan.name(), :status => java_action_plan.status()} + hash[:desc] = java_action_plan.description() if java_action_plan.description() && !java_action_plan.description().blank? + hash[:userLogin] = java_action_plan.userLogin() if java_action_plan.userLogin() + hash[:deadLine] = Api::Utils.format_datetime(java_action_plan.deadLine()) if java_action_plan.deadLine() + hash[:createdAt] = Api::Utils.format_datetime(java_action_plan.createdAt()) if java_action_plan.createdAt() + hash[:updatedAt] = Api::Utils.format_datetime(java_action_plan.updatedAt()) if java_action_plan.updatedAt() hash end diff --git a/sonar-ws-client/src/main/java/org/sonar/wsclient/SonarClient.java b/sonar-ws-client/src/main/java/org/sonar/wsclient/SonarClient.java index e84e75c7780..b8ee9cdd5f1 100644 --- a/sonar-ws-client/src/main/java/org/sonar/wsclient/SonarClient.java +++ b/sonar-ws-client/src/main/java/org/sonar/wsclient/SonarClient.java @@ -22,6 +22,8 @@ package org.sonar.wsclient; import org.sonar.wsclient.internal.HttpRequestFactory; import org.sonar.wsclient.issue.DefaultIssueClient; import org.sonar.wsclient.issue.IssueClient; +import org.sonar.wsclient.user.DefaultUserClient; +import org.sonar.wsclient.user.UserClient; /** * @since 3.6 @@ -38,6 +40,10 @@ public class SonarClient { return new DefaultIssueClient(requestFactory); } + public UserClient userClient() { + return new DefaultUserClient(requestFactory); + } + public static Builder builder() { return new Builder(); } diff --git a/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/IssueQuery.java b/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/IssueQuery.java index 3a1036f18cd..3fe7ed6a18c 100644 --- a/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/IssueQuery.java +++ b/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/IssueQuery.java @@ -127,6 +127,8 @@ public class IssueQuery { private IssueQuery addParam(String key, String[] values) { if (values != null) { params.put(key, EncodingUtils.toQueryParam(values)); + } else { + params.remove(key); } return this; } diff --git a/sonar-ws-client/src/main/java/org/sonar/wsclient/user/DefaultUserClient.java b/sonar-ws-client/src/main/java/org/sonar/wsclient/user/DefaultUserClient.java new file mode 100644 index 00000000000..fd842df823c --- /dev/null +++ b/sonar-ws-client/src/main/java/org/sonar/wsclient/user/DefaultUserClient.java @@ -0,0 +1,62 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2013 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.wsclient.user; + +import com.github.kevinsawicki.http.HttpRequest; +import org.json.simple.JSONValue; +import org.sonar.wsclient.internal.HttpRequestFactory; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * Do not instantiate this class, but use {@link org.sonar.wsclient.SonarClient#userClient()}. + */ +public class DefaultUserClient implements UserClient { + + private final HttpRequestFactory requestFactory; + + /** + * For internal use. Use {@link org.sonar.wsclient.SonarClient} to get an instance. + */ + public DefaultUserClient(HttpRequestFactory requestFactory) { + this.requestFactory = requestFactory; + } + + @Override + public List find(UserQuery query) { + HttpRequest request = requestFactory.get(UserQuery.BASE_URL, query.urlParams()); + if (!request.ok()) { + throw new IllegalStateException("Fail to search for users. Bad HTTP response status: " + request.code()); + } + List result = new ArrayList(); + String json = request.body("UTF-8"); + Map jsonRoot = (Map) JSONValue.parse(json); + List jsonUsers = (List) jsonRoot.get("users"); + if (jsonUsers != null) { + for (Map jsonUser : jsonUsers) { + result.add(new User(jsonUser)); + } + } + return result; + } + +} diff --git a/sonar-ws-client/src/main/java/org/sonar/wsclient/user/UserClient.java b/sonar-ws-client/src/main/java/org/sonar/wsclient/user/UserClient.java new file mode 100644 index 00000000000..d3893f89ef0 --- /dev/null +++ b/sonar-ws-client/src/main/java/org/sonar/wsclient/user/UserClient.java @@ -0,0 +1,31 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2013 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.wsclient.user; + +import java.util.List; + +/** + * @since 3.6 + */ +public interface UserClient { + + List find(UserQuery query); + +} diff --git a/sonar-ws-client/src/main/java/org/sonar/wsclient/user/UserQuery.java b/sonar-ws-client/src/main/java/org/sonar/wsclient/user/UserQuery.java new file mode 100644 index 00000000000..b148e1ad57c --- /dev/null +++ b/sonar-ws-client/src/main/java/org/sonar/wsclient/user/UserQuery.java @@ -0,0 +1,59 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2013 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.wsclient.user; + +import org.sonar.wsclient.internal.EncodingUtils; + +import java.util.HashMap; +import java.util.Map; + +/** + * @since 3.6 + */ +public class UserQuery { + static final String BASE_URL = "/api/users/search"; + + private final Map params = new HashMap(); + + private UserQuery() { + } + + public static UserQuery create() { + return new UserQuery(); + } + + public UserQuery includeDeactivated() { + params.put("includeDeactivated", "true"); + return this; + } + + public UserQuery logins(String... s) { + if (s != null) { + params.put("logins", EncodingUtils.toQueryParam(s)); + } else { + params.remove("logins"); + } + return this; + } + + Map urlParams() { + return params; + } +} diff --git a/sonar-ws-client/src/test/java/org/sonar/wsclient/SonarClientTest.java b/sonar-ws-client/src/test/java/org/sonar/wsclient/SonarClientTest.java index eb50d795426..03ae927b15d 100644 --- a/sonar-ws-client/src/test/java/org/sonar/wsclient/SonarClientTest.java +++ b/sonar-ws-client/src/test/java/org/sonar/wsclient/SonarClientTest.java @@ -21,15 +21,17 @@ package org.sonar.wsclient; import org.junit.Test; import org.sonar.wsclient.issue.DefaultIssueClient; +import org.sonar.wsclient.user.DefaultUserClient; import static org.fest.assertions.Assertions.assertThat; import static org.fest.assertions.Fail.fail; public class SonarClientTest { @Test - public void should_build_client() { + public void should_build_clients() { SonarClient client = SonarClient.builder().url("http://localhost:9000").build(); assertThat(client.issueClient()).isNotNull().isInstanceOf(DefaultIssueClient.class); + assertThat(client.userClient()).isNotNull().isInstanceOf(DefaultUserClient.class); } @Test diff --git a/sonar-ws-client/src/test/java/org/sonar/wsclient/user/DefaultUserClientTest.java b/sonar-ws-client/src/test/java/org/sonar/wsclient/user/DefaultUserClientTest.java new file mode 100644 index 00000000000..795edf4adab --- /dev/null +++ b/sonar-ws-client/src/test/java/org/sonar/wsclient/user/DefaultUserClientTest.java @@ -0,0 +1,51 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2013 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.wsclient.user; + +import org.junit.Rule; +import org.junit.Test; +import org.sonar.wsclient.MockHttpServerInterceptor; +import org.sonar.wsclient.internal.HttpRequestFactory; + +import java.util.List; + +import static org.fest.assertions.Assertions.assertThat; + +public class DefaultUserClientTest { + @Rule + public MockHttpServerInterceptor httpServer = new MockHttpServerInterceptor(); + + @Test + public void should_find_issues() { + HttpRequestFactory requestFactory = new HttpRequestFactory(httpServer.url(), null, null); + httpServer.doReturnBody("{\"users\": [{\"login\": \"simon\", \"name\": \"Simon\", \"active\": true}]}"); + + UserClient client = new DefaultUserClient(requestFactory); + UserQuery query = UserQuery.create().logins("simon", "loic"); + List users = client.find(query); + + assertThat(httpServer.requestedPath()).isEqualTo("/api/users/search?logins=simon,loic"); + assertThat(users).hasSize(1); + User simon = users.get(0); + assertThat(simon.login()).isEqualTo("simon"); + assertThat(simon.name()).isEqualTo("Simon"); + assertThat(simon.active()).isTrue(); + } +} -- 2.39.5