Merge branch 'feature/user-datetime-search-api-mysql' into 'master'

Add creation time filters to user search API for admins

Closes #29507

See merge request !12682
This commit is contained in:
Douwe Maan 2017-07-07 20:52:17 +00:00
commit 94e2a28684
13 changed files with 87 additions and 16 deletions

View file

@ -0,0 +1,8 @@
module CreatedAtFilter
def by_created_at(items)
items = items.created_before(params[:created_before]) if params[:created_before].present?
items = items.created_after(params[:created_after]) if params[:created_after].present?
items
end
end

View file

@ -19,6 +19,8 @@
# iids: integer[]
#
class IssuableFinder
include CreatedAtFilter
NONE = '0'.freeze
IRRELEVANT_PARAMS_FOR_CACHE_KEY = %i[utf8 sort page].freeze
@ -32,6 +34,7 @@ class IssuableFinder
def execute
items = init_collection
items = by_scope(items)
items = by_created_at(items)
items = by_state(items)
items = by_group(items)
items = by_search(items)
@ -42,7 +45,6 @@ class IssuableFinder
items = by_iids(items)
items = by_milestone(items)
items = by_label(items)
items = by_created_at(items)
# Filtering by project HAS TO be the last because we use the project IDs yielded by the issuable query thus far
items = by_project(items)
@ -411,18 +413,6 @@ class IssuableFinder
params[:non_archived].present? ? items.non_archived : items
end
def by_created_at(items)
if params[:created_after].present?
items = items.where(items.klass.arel_table[:created_at].gteq(params[:created_after]))
end
if params[:created_before].present?
items = items.where(items.klass.arel_table[:created_at].lteq(params[:created_before]))
end
items
end
def current_user_related?
params[:scope] == 'created-by-me' || params[:scope] == 'authored' || params[:scope] == 'assigned-to-me'
end

View file

@ -14,6 +14,8 @@
# external: boolean
#
class UsersFinder
include CreatedAtFilter
attr_accessor :current_user, :params
def initialize(current_user, params = {})
@ -29,6 +31,7 @@ class UsersFinder
users = by_active(users)
users = by_external_identity(users)
users = by_external(users)
users = by_created_at(users)
users
end

View file

@ -0,0 +1,12 @@
module CreatedAtFilterable
extend ActiveSupport::Concern
included do
scope :created_before, ->(date) { where(scoped_table[:created_at].lteq(date)) }
scope :created_after, ->(date) { where(scoped_table[:created_at].gteq(date)) }
def self.scoped_table
arel_table.alias(table_name)
end
end
end

View file

@ -10,6 +10,7 @@ class Issue < ActiveRecord::Base
include FasterCacheKeys
include RelativePositioning
include IgnorableColumn
include CreatedAtFilterable
ignore_column :position
@ -50,8 +51,6 @@ class Issue < ActiveRecord::Base
scope :order_due_date_asc, -> { reorder('issues.due_date IS NULL, issues.due_date ASC') }
scope :order_due_date_desc, -> { reorder('issues.due_date IS NULL, issues.due_date DESC') }
scope :created_after, -> (datetime) { where("created_at >= ?", datetime) }
scope :preload_associations, -> { preload(:labels, project: :namespace) }
after_save :expire_etag_cache

View file

@ -5,6 +5,7 @@ class MergeRequest < ActiveRecord::Base
include Referable
include Sortable
include IgnorableColumn
include CreatedAtFilterable
ignore_column :position

View file

@ -12,6 +12,7 @@ class User < ActiveRecord::Base
include TokenAuthenticatable
include IgnorableColumn
include FeatureGate
include CreatedAtFilterable
DEFAULT_NOTIFICATION_LEVEL = :participating

View file

@ -0,0 +1,4 @@
---
title: Add creation time filters to user search API for admins
merge_request: 12682
author:

View file

@ -26,7 +26,8 @@ module Gitlab
#{config.root}/app/models/members
#{config.root}/app/models/project_services
#{config.root}/app/workers/concerns
#{config.root}/app/services/concerns))
#{config.root}/app/services/concerns
#{config.root}/app/finders/concerns))
config.generators.templates.push("#{config.root}/generator_templates")

View file

@ -146,6 +146,12 @@ GET /users?extern_uid=1234567&provider=github
You can search for users who are external with: `/users?external=true`
You can search users by creation date time range with:
```
GET /users?created_before=2001-01-02T00:00:00.060Z&created_after=1999-01-02T00:00:00.060
```
## Single user
Get a single user.

View file

@ -48,6 +48,8 @@ module API
optional :active, type: Boolean, default: false, desc: 'Filters only active users'
optional :external, type: Boolean, default: false, desc: 'Filters only external users'
optional :blocked, type: Boolean, default: false, desc: 'Filters only blocked users'
optional :created_after, type: DateTime, desc: 'Return users created after the specified time'
optional :created_before, type: DateTime, desc: 'Return users created before the specified time'
all_or_none_of :extern_uid, :provider
use :pagination
@ -55,6 +57,10 @@ module API
get do
authenticated_as_admin! if params[:external].present? || (params[:extern_uid].present? && params[:provider].present?)
unless current_user&.admin?
params.except!(:created_after, :created_before)
end
users = UsersFinder.new(current_user, params).execute
authorized = can?(current_user, :read_users_list)

View file

@ -45,6 +45,17 @@ describe UsersFinder do
expect(users).to contain_exactly(user, user1, user2, omniauth_user)
end
it 'filters by created_at' do
filtered_user_before = create(:user, created_at: 3.days.ago)
filtered_user_after = create(:user, created_at: Time.now + 3.days)
users = described_class.new(user,
created_after: 2.days.ago,
created_before: Time.now + 2.days).execute
expect(users.map(&:username)).not_to include([filtered_user_before.username, filtered_user_after.username])
end
end
context 'with an admin user' do

View file

@ -163,6 +163,35 @@ describe API::Users do
expect(response).to have_http_status(400)
end
it "returns a user created before a specific date" do
user = create(:user, created_at: Date.new(2000, 1, 1))
get api("/users?created_before=2000-01-02T00:00:00.060Z", admin)
expect(response).to have_http_status(200)
expect(json_response.size).to eq(1)
expect(json_response.first['username']).to eq(user.username)
end
it "returns no users created before a specific date" do
create(:user, created_at: Date.new(2001, 1, 1))
get api("/users?created_before=2000-01-02T00:00:00.060Z", admin)
expect(response).to have_http_status(200)
expect(json_response.size).to eq(0)
end
it "returns users created before and after a specific date" do
user = create(:user, created_at: Date.new(2001, 1, 1))
get api("/users?created_before=2001-01-02T00:00:00.060Z&created_after=1999-01-02T00:00:00.060", admin)
expect(response).to have_http_status(200)
expect(json_response.size).to eq(1)
expect(json_response.first['username']).to eq(user.username)
end
end
end