Patch #39181 » 0001-API-compatibility-to-legacy-status-and-name-query-pa.patch
| app/controllers/users_controller.rb | ||
|---|---|---|
| 45 | 45 |
use_session = !request.format.csv? |
| 46 | 46 |
retrieve_query(UserQuery, use_session) |
| 47 | 47 | |
| 48 |
# API backwards compatibility: handle legacy status and name filter parameters |
|
| 49 |
unless request.format.html? |
|
| 50 |
if status_id = params[:status].presence |
|
| 51 |
@query.add_filter 'status', '=', [status_id] |
|
| 52 |
end |
|
| 53 |
if name = params[:name].presence |
|
| 54 |
@query.add_filter 'name', '~', [name] |
|
| 55 |
end |
|
| 56 |
if group_id = params[:group_id].presence |
|
| 57 |
@query.add_filter 'is_member_of_group', '=', [group_id] |
|
| 58 |
end |
|
| 59 |
end |
|
| 60 | ||
| 48 | 61 |
if @query.valid? |
| 49 | 62 |
scope = @query.results_scope |
| 50 | 63 | |
| app/models/user_query.rb | ||
|---|---|---|
| 51 | 51 |
type: :list_optional, |
| 52 | 52 |
values: ->{ Redmine::Twofa.available_schemes.map {|s| [I18n.t("twofa__#{s}__name"), s] } }
|
| 53 | 53 |
end |
| 54 |
add_available_filter "name", type: :text, label: :field_name_or_email_or_login |
|
| 54 | 55 |
add_available_filter "login", type: :string |
| 55 | 56 |
add_available_filter "firstname", type: :string |
| 56 | 57 |
add_available_filter "lastname", type: :string |
| ... | ... | |
| 165 | 166 | |
| 166 | 167 |
joins.any? ? joins.join(' ') : nil
|
| 167 | 168 |
end |
| 169 | ||
| 170 |
def sql_for_name_field(field, operator, value) |
|
| 171 |
case operator |
|
| 172 |
when '*' |
|
| 173 |
'1=1' |
|
| 174 |
when '!*' |
|
| 175 |
'1=0' |
|
| 176 |
else |
|
| 177 |
# match = (operator == '~') |
|
| 178 |
match = !operator.start_with?('!')
|
|
| 179 |
matching_operator = operator.sub /^\!/, '' |
|
| 180 |
name_sql = %w(login firstname lastname).map{|field| sql_for_field(:name, operator, value, User.table_name, field)}
|
|
| 181 | ||
| 182 |
emails = EmailAddress.table_name |
|
| 183 |
email_sql = <<-SQL |
|
| 184 |
#{match ? "EXISTS" : "NOT EXISTS"}
|
|
| 185 |
(SELECT 1 FROM #{emails} WHERE
|
|
| 186 |
#{emails}.user_id = #{User.table_name}.id AND
|
|
| 187 |
#{sql_for_field(:name, matching_operator, value, emails, 'address')})
|
|
| 188 |
SQL |
|
| 189 | ||
| 190 |
conditions = name_sql + [email_sql] |
|
| 191 |
op = match ? " OR " : " AND " |
|
| 192 |
"(#{conditions.map{|s| "(#{s})"}.join(op)})"
|
|
| 193 |
end |
|
| 194 | ||
| 195 |
end |
|
| 168 | 196 |
end |
| config/locales/en.yml | ||
|---|---|---|
| 1410 | 1410 |
twofa_text_group_disabled: "This setting is only effective when the global two factor authentication setting is set to 'optional'. Currently, two factor authentication is disabled." |
| 1411 | 1411 |
text_user_destroy_confirmation: "Are you sure you want to delete this user and remove all references to them? This cannot be undone. Often, locking a user instead of deleting them is the better solution. To confirm, please enter their login (%{login}) below."
|
| 1412 | 1412 |
text_project_destroy_enter_identifier: "To confirm, please enter the project's identifier (%{identifier}) below."
|
| 1413 |
field_name_or_email_or_login: Name, email or login |
|
| test/integration/api_test/users_test.rb | ||
|---|---|---|
| 82 | 82 |
end |
| 83 | 83 |
end |
| 84 | 84 | |
| 85 |
test "GET /users.json with legacy filter params" do |
|
| 86 |
get '/users.json', :headers => credentials('admin'), params: { status: 3 }
|
|
| 87 |
assert_response :success |
|
| 88 |
json = ActiveSupport::JSON.decode(response.body) |
|
| 89 |
assert json.key?('users')
|
|
| 90 |
users = User.where(status: 3) |
|
| 91 |
assert_equal users.size, json['users'].size |
|
| 92 | ||
| 93 |
get '/users.json', :headers => credentials('admin'), params: { name: 'jsmith' }
|
|
| 94 |
assert_response :success |
|
| 95 |
json = ActiveSupport::JSON.decode(response.body) |
|
| 96 |
assert json.key?('users')
|
|
| 97 |
assert_equal 1, json['users'].size |
|
| 98 |
assert_equal 2, json['users'][0]['id'] |
|
| 99 | ||
| 100 |
get '/users.json', :headers => credentials('admin'), params: { group_id: '10' }
|
|
| 101 |
assert_response :success |
|
| 102 |
json = ActiveSupport::JSON.decode(response.body) |
|
| 103 |
assert json.key?('users')
|
|
| 104 |
assert_equal 1, json['users'].size |
|
| 105 |
assert_equal 8, json['users'][0]['id'] |
|
| 106 | ||
| 107 |
# there should be an implicit filter for status = 1 |
|
| 108 |
User.where(id: [2, 8]).update_all status: 3 |
|
| 109 | ||
| 110 |
get '/users.json', :headers => credentials('admin'), params: { name: 'jsmith' }
|
|
| 111 |
assert_response :success |
|
| 112 |
json = ActiveSupport::JSON.decode(response.body) |
|
| 113 |
assert json.key?('users')
|
|
| 114 |
assert_equal 0, json['users'].size |
|
| 115 | ||
| 116 |
get '/users.json', :headers => credentials('admin'), params: { group_id: '10' }
|
|
| 117 |
assert_response :success |
|
| 118 |
json = ActiveSupport::JSON.decode(response.body) |
|
| 119 |
assert json.key?('users')
|
|
| 120 |
assert_equal 0, json['users'].size |
|
| 121 |
end |
|
| 122 | ||
| 85 | 123 |
test "GET /users/:id.xml should return the user" do |
| 86 | 124 |
Redmine::Configuration.with 'avatar_server_url' => 'https://gravatar.com' do |
| 87 | 125 |
with_settings :gravatar_enabled => '1', :gravatar_default => 'robohash' do |
| test/unit/user_query_test.rb | ||
|---|---|---|
| 108 | 108 |
end |
| 109 | 109 |
end |
| 110 | 110 | |
| 111 |
def test_name_or_email_or_login_filter |
|
| 112 |
[ |
|
| 113 |
['~', 'jsmith', [2]], |
|
| 114 |
['^', 'jsm', [2]], |
|
| 115 |
['$', 'ith', [2]], |
|
| 116 |
['~', 'john', [2]], |
|
| 117 |
['~', 'smith', [2]], |
|
| 118 |
['~', 'somenet', [1, 2, 3, 4]], |
|
| 119 |
['!~', 'somenet', [7, 8, 9]], |
|
| 120 |
['^', 'dlop', [3]], |
|
| 121 |
['$', 'bar', [7, 8, 9]], |
|
| 122 |
['=', 'bar', []], |
|
| 123 |
['=', 'someone@foo.bar', [7]], |
|
| 124 |
['*', '', [1, 2, 3, 4, 7, 8, 9]], |
|
| 125 |
['!*', '', []], |
|
| 126 |
].each do |op, string, result| |
|
| 127 |
q = UserQuery.new name: '_' |
|
| 128 |
q.add_filter('name', op, [string])
|
|
| 129 |
users = find_users_with_query q |
|
| 130 |
assert_equal result, users.map(&:id).sort, "#{op} #{string} should have found #{result}"
|
|
| 131 |
end |
|
| 132 |
end |
|
| 133 | ||
| 111 | 134 |
def test_group_filter |
| 112 | 135 |
q = UserQuery.new name: '_' |
| 113 | 136 |
q.add_filter('is_member_of_group', '=', ['10', '99'])
|
- « Previous
- 1
- 2
- Next »