]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-4323 add search by free text and support of Select2
authorSimon Brandhof <simon.brandhof@gmail.com>
Tue, 14 May 2013 16:42:51 +0000 (18:42 +0200)
committerSimon Brandhof <simon.brandhof@gmail.com>
Tue, 14 May 2013 17:02:41 +0000 (19:02 +0200)
sonar-core/src/main/resources/org/sonar/core/user/UserMapper.xml
sonar-core/src/test/java/org/sonar/core/user/UserDaoTest.java
sonar-core/src/test/resources/org/sonar/core/user/UserDaoTest/selectUsersByText.xml [new file with mode: 0644]
sonar-plugin-api/src/main/java/org/sonar/api/issue/RubyIssueService.java
sonar-plugin-api/src/main/java/org/sonar/api/user/RubyUserService.java
sonar-plugin-api/src/main/java/org/sonar/api/user/UserQuery.java
sonar-plugin-api/src/test/java/org/sonar/api/user/UserQueryTest.java
sonar-server/src/main/java/org/sonar/server/user/DefaultRubyUserService.java
sonar-server/src/main/webapp/WEB-INF/app/controllers/api/users_controller.rb
sonar-ws-client/src/main/java/org/sonar/wsclient/user/UserQuery.java
sonar-ws-client/src/test/java/org/sonar/wsclient/user/UserQueryTest.java

index 5bc41686c6782cf7401ac3ddc884bd300030d635..adfeea60245a24de5c281eaf073ab83ff11edf1d 100644 (file)
@@ -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>
index b6665245efe3ffbfafa8e1307b5345449386df3a..a91acd2bd66d80fa95ed91cdd8189ff05ce6f293 100644 (file)
@@ -101,6 +101,26 @@ public class UserDaoTest extends AbstractDaoTestCase {
     assertThat(users.get(0).getName()).isEqualTo("Marius");
   }
 
+  @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 (file)
index 0000000..4eb95da
--- /dev/null
@@ -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>
index 6f5d6f6a573d2f8b6835f6ea64681b4e1f1ec5f6..61d7ec2bfa2c0629e42eb8b7cf44e3db4ec023a2 100644 (file)
@@ -33,6 +33,8 @@ import java.util.Map;
  */
 public interface RubyIssueService extends ServerComponent {
 
+  IssueQueryResult find(String issueKey);
+
   /**
    * Search for issues.
    * <p/>
index a1e7180a4531b22dbf9b19d73905e0bf753b2953..cb46f2fa95c42f04a7233a3f870eae0a26f31c33 100644 (file)
@@ -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>
index d4c84c728b44ce43e2979b936c46ee8cfa125093..027be9f5e60c40e3c11347fc55d2fd3466e2afcb 100644 (file)
@@ -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());
index e6dbc92a126abe9cdd143a86cf6de8058322c534..3cbc5822f1c09661534597d964041704f93c7d6b 100644 (file)
@@ -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%");
+  }
 }
index db042c5a8d5ea30fbff63c6eb4a385835a115456..d561d7230a583a462f571ced3807c42af8abab45 100644 (file)
@@ -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();
   }
 }
index 4adc531cb4f3f118f447c3734d62d67d6cf1f60f..76f73e5b9d3dd91643aade9e82eb83a1865ce86e 100644 (file)
@@ -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) }
index 49de3a8e5067e1ff9a01ce5b97f953c1487c69fb..07f802fb8a9c43ec0477b00f47b2009d975dc1d4 100644 (file)
@@ -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;
   }
index 752f85c1da4794f7802df6ed0c76b5c3767e27f0..fbb9b4d26a13e10cda0e2033af23abca8dca29c8 100644 (file)
@@ -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");
+  }
 }