summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSean McGivern <sean@mcgivern.me.uk>2016-11-01 16:14:22 +0000
committerSean McGivern <sean@mcgivern.me.uk>2016-11-01 16:14:22 +0000
commit16d98f425ced770dea7701f883f64e263d962a01 (patch)
treef0f6ea605bf22ae21147a9fa78b7cebf7b422953
parentb58d7ceaf503fcc3725abc6f7b671edd89fbb9c3 (diff)
parentf8530580100f56fe3bef5f3a73d3e543b038f98f (diff)
downloadgitlab-ce-16d98f425ced770dea7701f883f64e263d962a01.tar.gz
Merge branch 'Allow-admin-to-search-for-user-by-secondary-email-address' into 'master'
Allow admin to search for user by secondary email address Closes #23761 See merge request !7115
-rw-r--r--CHANGELOG.md2
-rw-r--r--app/controllers/admin/users_controller.rb2
-rw-r--r--app/models/user.rb18
-rw-r--r--app/views/admin/users/index.html.haml2
-rw-r--r--spec/models/user_spec.rb74
5 files changed, 96 insertions, 2 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 575baec5fef..cef3997c7d4 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -43,6 +43,8 @@ Please view this file on the master branch, on stable branches it's out of date.
- Refactor email, use setter method instead AR callbacks for email attribute (Semyon Pupkov)
- Shortened merge request modal to let clipboard button not overlap
- In all filterable drop downs, put input field in focus only after load is complete (Ido @leibo)
+- Improve search query parameter naming in /admin/users !7115 (YarNayar)
+- Allow to search for user by secondary email address in the admin interface(/admin/users) !7115 (YarNayar)
## 8.13.3
diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb
index f35f4a8c811..bb912ed10cc 100644
--- a/app/controllers/admin/users_controller.rb
+++ b/app/controllers/admin/users_controller.rb
@@ -3,7 +3,7 @@ class Admin::UsersController < Admin::ApplicationController
def index
@users = User.order_name_asc.filter(params[:filter])
- @users = @users.search(params[:name]) if params[:name].present?
+ @users = @users.search_with_secondary_emails(params[:search_query]) if params[:search_query].present?
@users = @users.sort(@sort = params[:sort])
@users = @users.page(params[:page])
end
diff --git a/app/models/user.rb b/app/models/user.rb
index e2a97c3a757..af3c0b7dc02 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -258,6 +258,24 @@ class User < ActiveRecord::Base
)
end
+ # searches user by given pattern
+ # it compares name, email, username fields and user's secondary emails with given pattern
+ # This method uses ILIKE on PostgreSQL and LIKE on MySQL.
+
+ def search_with_secondary_emails(query)
+ table = arel_table
+ email_table = Email.arel_table
+ pattern = "%#{query}%"
+ matched_by_emails_user_ids = email_table.project(email_table[:user_id]).where(email_table[:email].matches(pattern))
+
+ where(
+ table[:name].matches(pattern).
+ or(table[:email].matches(pattern)).
+ or(table[:username].matches(pattern)).
+ or(table[:id].in(matched_by_emails_user_ids))
+ )
+ end
+
def by_login(login)
return nil unless login
diff --git a/app/views/admin/users/index.html.haml b/app/views/admin/users/index.html.haml
index 357123c2c13..d3038ae644f 100644
--- a/app/views/admin/users/index.html.haml
+++ b/app/views/admin/users/index.html.haml
@@ -10,7 +10,7 @@
= hidden_field_tag "filter", h(params[:filter])
.search-holder
.search-field-holder
- = search_field_tag :name, params[:name], placeholder: 'Search by name, email or username', class: 'form-control search-text-input js-search-input', spellcheck: false
+ = search_field_tag :search_query, params[:search_query], placeholder: 'Search by name, email or username', class: 'form-control search-text-input js-search-input', spellcheck: false
= icon("search", class: "search-icon")
.dropdown
- toggle_text = if @sort.present? then sort_options_hash[@sort] else sort_title_name end
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index 10c39b90212..d1ed774a914 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -599,6 +599,80 @@ describe User, models: true do
end
end
+ describe '.search_with_secondary_emails' do
+ def search_with_secondary_emails(query)
+ described_class.search_with_secondary_emails(query)
+ end
+
+ let!(:user) { create(:user) }
+ let!(:email) { create(:email) }
+
+ it 'returns users with a matching name' do
+ expect(search_with_secondary_emails(user.name)).to eq([user])
+ end
+
+ it 'returns users with a partially matching name' do
+ expect(search_with_secondary_emails(user.name[0..2])).to eq([user])
+ end
+
+ it 'returns users with a matching name regardless of the casing' do
+ expect(search_with_secondary_emails(user.name.upcase)).to eq([user])
+ end
+
+ it 'returns users with a matching email' do
+ expect(search_with_secondary_emails(user.email)).to eq([user])
+ end
+
+ it 'returns users with a partially matching email' do
+ expect(search_with_secondary_emails(user.email[0..2])).to eq([user])
+ end
+
+ it 'returns users with a matching email regardless of the casing' do
+ expect(search_with_secondary_emails(user.email.upcase)).to eq([user])
+ end
+
+ it 'returns users with a matching username' do
+ expect(search_with_secondary_emails(user.username)).to eq([user])
+ end
+
+ it 'returns users with a partially matching username' do
+ expect(search_with_secondary_emails(user.username[0..2])).to eq([user])
+ end
+
+ it 'returns users with a matching username regardless of the casing' do
+ expect(search_with_secondary_emails(user.username.upcase)).to eq([user])
+ end
+
+ it 'returns users with a matching whole secondary email' do
+ expect(search_with_secondary_emails(email.email)).to eq([email.user])
+ end
+
+ it 'returns users with a matching part of secondary email' do
+ expect(search_with_secondary_emails(email.email[1..4])).to eq([email.user])
+ end
+
+ it 'return users with a matching part of secondary email regardless of case' do
+ expect(search_with_secondary_emails(email.email[1..4].upcase)).to eq([email.user])
+ expect(search_with_secondary_emails(email.email[1..4].downcase)).to eq([email.user])
+ expect(search_with_secondary_emails(email.email[1..4].capitalize)).to eq([email.user])
+ end
+
+ it 'returns multiple users with matching secondary emails' do
+ email1 = create(:email, email: '1_testemail@example.com')
+ email2 = create(:email, email: '2_testemail@example.com')
+ email3 = create(:email, email: 'other@email.com')
+ email3.user.update_attributes!(email: 'another@mail.com')
+
+ expect(
+ search_with_secondary_emails('testemail@example.com').map(&:id)
+ ).to include(email1.user.id, email2.user.id)
+
+ expect(
+ search_with_secondary_emails('testemail@example.com').map(&:id)
+ ).not_to include(email3.user.id)
+ end
+ end
+
describe 'by_username_or_id' do
let(:user1) { create(:user, username: 'foo') }