aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Brandhof <simon.brandhof@gmail.com>2013-05-14 18:42:51 +0200
committerSimon Brandhof <simon.brandhof@gmail.com>2013-05-14 19:02:41 +0200
commitf5f73537f6b8bf961cd189c93ed2b256dd66c7a2 (patch)
tree5f57109b0d01c7f03162eff95801ece4acd914be
parent971be0c76e753adb739b09f79a42b8502fcf43fa (diff)
downloadsonarqube-f5f73537f6b8bf961cd189c93ed2b256dd66c7a2.tar.gz
sonarqube-f5f73537f6b8bf961cd189c93ed2b256dd66c7a2.zip
SONAR-4323 add search by free text and support of Select2
-rw-r--r--sonar-core/src/main/resources/org/sonar/core/user/UserMapper.xml3
-rw-r--r--sonar-core/src/test/java/org/sonar/core/user/UserDaoTest.java20
-rw-r--r--sonar-core/src/test/resources/org/sonar/core/user/UserDaoTest/selectUsersByText.xml24
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/issue/RubyIssueService.java2
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/user/RubyUserService.java1
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/user/UserQuery.java22
-rw-r--r--sonar-plugin-api/src/test/java/org/sonar/api/user/UserQueryTest.java9
-rw-r--r--sonar-server/src/main/java/org/sonar/server/user/DefaultRubyUserService.java1
-rw-r--r--sonar-server/src/main/webapp/WEB-INF/app/controllers/api/users_controller.rb14
-rw-r--r--sonar-ws-client/src/main/java/org/sonar/wsclient/user/UserQuery.java10
-rw-r--r--sonar-ws-client/src/test/java/org/sonar/wsclient/user/UserQueryTest.java6
11 files changed, 109 insertions, 3 deletions
diff --git a/sonar-core/src/main/resources/org/sonar/core/user/UserMapper.xml b/sonar-core/src/main/resources/org/sonar/core/user/UserMapper.xml
index 5bc41686c67..adfeea60245 100644
--- a/sonar-core/src/main/resources/org/sonar/core/user/UserMapper.xml
+++ b/sonar-core/src/main/resources/org/sonar/core/user/UserMapper.xml
@@ -42,6 +42,9 @@
<if test="includeDeactivated==false">
and u.active=${_true}
</if>
+ <if test="searchText != null">
+ and (u.login like #{searchTextSql} or u.name like #{searchTextSql})
+ </if>
</where>
order by u.name
</select>
diff --git a/sonar-core/src/test/java/org/sonar/core/user/UserDaoTest.java b/sonar-core/src/test/java/org/sonar/core/user/UserDaoTest.java
index b6665245efe..a91acd2bd66 100644
--- a/sonar-core/src/test/java/org/sonar/core/user/UserDaoTest.java
+++ b/sonar-core/src/test/java/org/sonar/core/user/UserDaoTest.java
@@ -102,6 +102,26 @@ public class UserDaoTest extends AbstractDaoTestCase {
}
@Test
+ public void selectUsersByQuery_search_by_login_text() throws Exception {
+ setupData("selectUsersByText");
+
+ UserQuery query = UserQuery.builder().searchText("sbr").build();
+ List<UserDto> users = dao.selectUsers(query);
+ assertThat(users).hasSize(1);
+ assertThat(users.get(0).getLogin()).isEqualTo("sbrandhof");
+ }
+
+ @Test
+ public void selectUsersByQuery_search_by_name_text() throws Exception {
+ setupData("selectUsersByText");
+
+ UserQuery query = UserQuery.builder().searchText("Simon").build();
+ List<UserDto> users = dao.selectUsers(query);
+ assertThat(users).hasSize(1);
+ assertThat(users.get(0).getLogin()).isEqualTo("sbrandhof");
+ }
+
+ @Test
public void selectGroupByName() {
setupData("selectGroupByName");
diff --git a/sonar-core/src/test/resources/org/sonar/core/user/UserDaoTest/selectUsersByText.xml b/sonar-core/src/test/resources/org/sonar/core/user/UserDaoTest/selectUsersByText.xml
new file mode 100644
index 00000000000..4eb95dae80f
--- /dev/null
+++ b/sonar-core/src/test/resources/org/sonar/core/user/UserDaoTest/selectUsersByText.xml
@@ -0,0 +1,24 @@
+<!--
+ ~ 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.
+ -->
+<dataset>
+ <users id="101" login="marius" name="Marius" email="marius@lesbronzes.fr" created_at="2011-05-18" updated_at="2012-07-21" active="[true]"/>
+ <users id="102" login="sbrandhof" name="Simon Brandhof" email="marius@lesbronzes.fr" created_at="2011-05-18" updated_at="2012-07-21" active="[true]"/>
+
+</dataset>
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/issue/RubyIssueService.java b/sonar-plugin-api/src/main/java/org/sonar/api/issue/RubyIssueService.java
index 6f5d6f6a573..61d7ec2bfa2 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/issue/RubyIssueService.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/issue/RubyIssueService.java
@@ -33,6 +33,8 @@ import java.util.Map;
*/
public interface RubyIssueService extends ServerComponent {
+ IssueQueryResult find(String issueKey);
+
/**
* Search for issues.
* <p/>
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 a1e7180a453..cb46f2fa95c 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
@@ -38,6 +38,7 @@ public interface RubyUserService extends ServerComponent {
* <p/>
* Optional parameters are:
* <ul>
+ * <li><code>q</code> to match all the logins or names containing this search query</li>
* <li><code>logins</code>, as an array of strings (['simon', 'julien']) or a comma-separated list of logins ('simon,julien')</li>
* <li><code>includeDeactivated</code> as a boolean. By Default deactivated users are excluded from query.</li>
* </ul>
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/user/UserQuery.java b/sonar-plugin-api/src/main/java/org/sonar/api/user/UserQuery.java
index d4c84c728b4..027be9f5e60 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/user/UserQuery.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/user/UserQuery.java
@@ -19,6 +19,8 @@
*/
package org.sonar.api.user;
+import org.apache.commons.lang.StringUtils;
+
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
import java.util.Arrays;
@@ -33,10 +35,16 @@ public class UserQuery {
private final Collection<String> logins;
private final boolean includeDeactivated;
+ private final String searchText;
+
+ // for internal use in MyBatis
+ final String searchTextSql;
private UserQuery(Builder builder) {
this.logins = builder.logins;
this.includeDeactivated = builder.includeDeactivated;
+ this.searchText = builder.searchText;
+ this.searchTextSql = (searchText !=null ? "%" + searchText + "%" : null);
}
@CheckForNull
@@ -48,6 +56,14 @@ public class UserQuery {
return includeDeactivated;
}
+ /**
+ * Search for logins or names containing a given string
+ */
+ @CheckForNull
+ public String searchText() {
+ return searchText;
+ }
+
public static Builder builder() {
return new Builder();
}
@@ -55,6 +71,7 @@ public class UserQuery {
public static class Builder {
private boolean includeDeactivated = false;
private Collection<String> logins;
+ private String searchText;
private Builder() {
}
@@ -75,6 +92,11 @@ public class UserQuery {
return this;
}
+ public Builder searchText(@Nullable String s) {
+ this.searchText = StringUtils.defaultIfBlank(s, null);
+ return this;
+ }
+
public UserQuery build() {
if (logins != null && logins.size() >= 1000) {
throw new IllegalArgumentException("Max number of logins is 1000. Got " + logins.size());
diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/user/UserQueryTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/user/UserQueryTest.java
index e6dbc92a126..3cbc5822f1c 100644
--- a/sonar-plugin-api/src/test/java/org/sonar/api/user/UserQueryTest.java
+++ b/sonar-plugin-api/src/test/java/org/sonar/api/user/UserQueryTest.java
@@ -33,6 +33,8 @@ public class UserQueryTest {
public void test_all_actives() throws Exception {
assertThat(UserQuery.ALL_ACTIVES.includeDeactivated()).isFalse();
assertThat(UserQuery.ALL_ACTIVES.logins()).isNull();
+ assertThat(UserQuery.ALL_ACTIVES.searchText()).isNull();
+ assertThat(UserQuery.ALL_ACTIVES.searchTextSql).isNull();
}
@Test
@@ -65,4 +67,11 @@ public class UserQueryTest {
assertThat(e).hasMessage("Max number of logins is 1000. Got 1010");
}
}
+
+ @Test
+ public void test_searchText() throws Exception {
+ UserQuery query = UserQuery.builder().searchText("sim").build();
+ assertThat(query.searchText()).isEqualTo("sim");
+ assertThat(query.searchTextSql).isEqualTo("%sim%");
+ }
}
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 db042c5a8d5..d561d7230a5 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
@@ -52,6 +52,7 @@ public class DefaultRubyUserService implements RubyUserService {
builder.includeDeactivated();
}
builder.logins(RubyUtils.toStrings(params.get("logins")));
+ builder.searchText((String)params.get("q"));
return builder.build();
}
}
diff --git a/sonar-server/src/main/webapp/WEB-INF/app/controllers/api/users_controller.rb b/sonar-server/src/main/webapp/WEB-INF/app/controllers/api/users_controller.rb
index 4adc531cb4f..76f73e5b9d3 100644
--- a/sonar-server/src/main/webapp/WEB-INF/app/controllers/api/users_controller.rb
+++ b/sonar-server/src/main/webapp/WEB-INF/app/controllers/api/users_controller.rb
@@ -29,9 +29,17 @@ class Api::UsersController < Api::ApiController
#
def search
users = Api.users.find(params)
- hash = {
- :users => users.map { |user| User.to_hash(user) }
- }
+
+ select2_format=(params[:f]=='s2')
+ if select2_format
+ hash = {
+ :more => false,
+ :results => users.map { |user| {:id => user.login, :text => "#{user.name} (#{user.login})"} }
+ }
+ else
+ hash = {:users => users.map { |user| User.to_hash(user) }}
+ end
+
respond_to do |format|
format.json { render :json => jsonp(hash) }
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
index 49de3a8e506..07f802fb8a9 100644
--- 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
@@ -21,6 +21,7 @@ package org.sonar.wsclient.user;
import org.sonar.wsclient.internal.EncodingUtils;
+import javax.annotation.Nullable;
import java.util.HashMap;
import java.util.Map;
@@ -49,6 +50,15 @@ public class UserQuery {
return this;
}
+ public UserQuery searchText(@Nullable String s) {
+ if (s != null) {
+ params.put("q", s);
+ } else {
+ params.remove("q");
+ }
+ return this;
+ }
+
Map<String, Object> urlParams() {
return params;
}
diff --git a/sonar-ws-client/src/test/java/org/sonar/wsclient/user/UserQueryTest.java b/sonar-ws-client/src/test/java/org/sonar/wsclient/user/UserQueryTest.java
index 752f85c1da4..fbb9b4d26a1 100644
--- a/sonar-ws-client/src/test/java/org/sonar/wsclient/user/UserQueryTest.java
+++ b/sonar-ws-client/src/test/java/org/sonar/wsclient/user/UserQueryTest.java
@@ -48,4 +48,10 @@ public class UserQueryTest {
UserQuery query = UserQuery.create().logins("simon").logins("loic");
assertThat(query.urlParams().get("logins")).isEqualTo("loic");
}
+
+ @Test
+ public void should_search_by_text() throws Exception {
+ UserQuery query = UserQuery.create().searchText("sim");
+ assertThat(query.urlParams().get("q")).isEqualTo("sim");
+ }
}