diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb index f0979f5b1..627e629c3 100644 --- a/app/controllers/admin/users_controller.rb +++ b/app/controllers/admin/users_controller.rb @@ -51,6 +51,7 @@ module Admin search: params[:search], role: params[:role], roles: params[:roles], + statuses: params[:statuses], joining_start: params[:joining_start], joining_end: params[:joining_end], date_format: params[:date_format], diff --git a/app/helpers/admin/users_helper.rb b/app/helpers/admin/users_helper.rb index 3f31a8354..7de7e4892 100644 --- a/app/helpers/admin/users_helper.rb +++ b/app/helpers/admin/users_helper.rb @@ -58,6 +58,11 @@ module Admin end end + # We de-scoped filtering by "Good standing" due to the complexity of it not mapping directly to a specific role + def filterable_statuses + Constants::Role::BASE_ROLES.reject { |status| status == "Good standing" } + end + # Provides the remaining count when a limit for a resource is imposed on the UI. # # @param [Integer] The total count @@ -89,5 +94,21 @@ module Admin str + " & #{overflow_count(count, imposed_limit: imposed_limit)} others" end end + + # Returns a string hex code representing the indicator color for the given status (also known as BASE_ROLE) + def status_to_indicator_color(status) + case status + when "Suspended" + "#DC2626" + when "Warned" + "#F59E0B" + when "Comment Suspended" + "#DC2626" + when "Trusted" + "#059669" + else + "#A3A3A3" + end + end end end diff --git a/app/lib/constants/role.rb b/app/lib/constants/role.rb index ea08658a8..2edebe207 100644 --- a/app/lib/constants/role.rb +++ b/app/lib/constants/role.rb @@ -1,12 +1,15 @@ module Constants module Role - BASE_ROLES = [ - "Warned", - "Comment Suspended", - "Suspended", - "Good standing", - "Trusted", - ].freeze + BASE_ROLES_LABELS_TO_WHERE_CLAUSE = { + "Warned" => { name: "warned", resource_type: nil }, + "Comment Suspended" => { name: "comment_suspended", resource_type: nil }, + "Suspended" => { name: "suspended", resource_type: nil }, + # This "role" is a weird amalgamation of multiple roles. + "Good standing" => :good_standing, + "Trusted" => { name: "trusted", resource_type: nil } + }.freeze + + BASE_ROLES = BASE_ROLES_LABELS_TO_WHERE_CLAUSE.keys.freeze SPECIAL_ROLES_LABELS_TO_WHERE_CLAUSE = { "Admin" => { name: "admin", resource_type: nil }, @@ -28,5 +31,8 @@ module Constants }.freeze SPECIAL_ROLES = SPECIAL_ROLES_LABELS_TO_WHERE_CLAUSE.keys.freeze + + ALL_ROLES_LABELS_TO_WHERE_CLAUSE = + SPECIAL_ROLES_LABELS_TO_WHERE_CLAUSE.merge(BASE_ROLES_LABELS_TO_WHERE_CLAUSE).freeze end end diff --git a/app/queries/admin/users_query.rb b/app/queries/admin/users_query.rb index b8b9e45b1..a67134ba2 100644 --- a/app/queries/admin/users_query.rb +++ b/app/queries/admin/users_query.rb @@ -9,6 +9,7 @@ module Admin # @param role [String, nil] # @param search [String, nil] # @param roles [Array, nil] + # @param statuses [Array, nil] # @param organizations [Array, nil] # @param joining_start [String, nil] # @param joining_end [String, nil] @@ -18,6 +19,7 @@ module Admin search: nil, roles: [], organizations: [], + statuses: [], joining_start: nil, joining_end: nil, date_format: "DD/MM/YYYY") @@ -25,8 +27,9 @@ module Admin # need to favor one or the other. if role.presence relation = relation.with_role(role, :any) - elsif roles.presence - relation = filter_roles(relation: relation, roles: roles) + elsif roles.presence || statuses.presence + # "statuses" are a subset of roles, so we can handle these filters together + relation = filter_roles(relation: relation, roles: [roles, statuses].compact.reduce([], :|)) end if organizations.presence @@ -76,16 +79,19 @@ module Admin # query per role is inadequate. # # @see https://github.com/RolifyCommunity/rolify/blob/0c883f4173f409766338b9c6dfc64b0fc8ec8a52/lib/rolify/finders.rb#L26-L32 - def self.filter_roles(relation:, roles:, role_map: Constants::Role::SPECIAL_ROLES_LABELS_TO_WHERE_CLAUSE) + def self.filter_roles(relation:, roles:, role_map: Constants::Role::ALL_ROLES_LABELS_TO_WHERE_CLAUSE) conditions = [] values = [] # Assemble the conditions and positional parameter values roles.each do |role| where_clause = role_map.fetch(role) + resource_type = where_clause.fetch(:resource_type, nil) + name = where_clause.fetch(:name) + condition = "(#{Role.table_name}.name = ? AND #{Role.table_name}.resource_id IS NULL" - values << where_clause.fetch(:name) + values << name # We need to use `IS NULL` instead of `= NULL` as those are different meanings. if resource_type.nil? @@ -98,7 +104,8 @@ module Admin conditions << condition end - relation.joins(:roles).where(%((#{conditions.join(') OR (')})), *values) + sub_query = User.select(:id).distinct.joins(:roles).where(%((#{conditions.join(') OR (')})), *values) + relation.where(id: sub_query) end private_class_method :filter_roles end diff --git a/app/views/admin/users/index.html.erb b/app/views/admin/users/index.html.erb index f2f6b4f96..cc82fad18 100644 --- a/app/views/admin/users/index.html.erb +++ b/app/views/admin/users/index.html.erb @@ -23,7 +23,7 @@
<%= render "admin/users/index/user_actions_dropdown", user: user, id: "responsive-#{user.id}" %> @@ -32,7 +32,7 @@
- <%= render "admin/users/index/status_indicator", user: user %> + <%= render "admin/users/index/user_status_indicator", user: user %>