From 0c2b1eee41d69fd8e10f49cf16a3c665752dc4af Mon Sep 17 00:00:00 2001 From: Frank Ma Date: Thu, 27 Nov 2025 16:47:39 +0000 Subject: [PATCH 1/5] CLDC-4029: Add new filters --- app/helpers/filters_helper.rb | 18 +++++++++++++++- app/models/user.rb | 23 ++++++++++++++++++++ app/services/filter_manager.rb | 8 +++++++ app/views/users/_user_filters.html.erb | 30 ++++++++++++++++++++------ 4 files changed, 72 insertions(+), 7 deletions(-) diff --git a/app/helpers/filters_helper.rb b/app/helpers/filters_helper.rb index 57a3cabc3..3f82ab5d0 100644 --- a/app/helpers/filters_helper.rb +++ b/app/helpers/filters_helper.rb @@ -52,6 +52,22 @@ module FiltersHelper }.freeze end + def user_role_type_filters(include_support = false) + roles = { + "1" => "Data provider", + "2" => "Coordinator", + } + roles["99"] = "Support" if include_support + roles.freeze + end + + def user_additional_responsibilities_filters + { + "data_protection_officer" => "Data protection officer", + "key_contact" => "Key contact", + }.freeze + end + def scheme_status_filters { "incomplete" => "Incomplete", @@ -306,7 +322,7 @@ private def filters_count(filters) filters.each.sum do |category, category_filters| - if %w[years status needstypes bulk_upload_id].include?(category) + if %w[years status needstypes bulk_upload_id role additional_responsibilities].include?(category) category_filters.count(&:present?) elsif %w[user owning_organisation managing_organisation user_text_search owning_organisation_text_search managing_organisation_text_search uploading_organisation].include?(category) 1 diff --git a/app/models/user.rb b/app/models/user.rb index 23dbc196b..93fb0b54c 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -81,6 +81,29 @@ class User < ApplicationRecord filtered_records } + scope :filter_by_role, ->(role, _user = nil) { where(role:) } + scope :filter_by_additional_responsibilities, lambda { |additional_responsibilities, _user| + filtered_records = all + scopes = [] + + additional_responsibilities.each do |responsibility| + case responsibility + when "key_contact" + scopes << send("is_key_contact") + when "data_protection_officer" + scopes << send("is_data_protection_officer") + end + end + + if scopes.any? + filtered_records = filtered_records.merge(scopes.reduce(&:or)) + end + + filtered_records + } + + scope :is_key_contact, -> { where(is_key_contact: true) } + scope :is_data_protection_officer, -> { where(is_dpo: true) } scope :not_signed_in, -> { where(last_sign_in_at: nil, active: true) } scope :deactivated, -> { where(active: false) } scope :activated, -> { where(active: true) } diff --git a/app/services/filter_manager.rb b/app/services/filter_manager.rb index 7757ad39e..a611238bf 100644 --- a/app/services/filter_manager.rb +++ b/app/services/filter_manager.rb @@ -130,6 +130,14 @@ class FilterManager new_filters["status"] = params["status"] end + if filter_type.include?("users") && params["role"].present? + new_filters["role"] = params["role"] + end + + if filter_type.include?("users") && params["additional_responsibilities"].present? + new_filters["additional_responsibilities"] = params["additional_responsibilities"] + end + if filter_type.include?("schemes") current_user.scheme_filters(specific_org:).each do |filter| new_filters[filter] = params[filter] if params[filter].present? diff --git a/app/views/users/_user_filters.html.erb b/app/views/users/_user_filters.html.erb index aa9185c8d..03e686bf4 100644 --- a/app/views/users/_user_filters.html.erb +++ b/app/views/users/_user_filters.html.erb @@ -17,12 +17,30 @@ <%= render partial: "filters/checkbox_filter", locals: { - f:, - options: user_status_filters, - label: "Status", - category: "status", - size: "s", - } %> + f:, + options: user_status_filters, + label: "Status", + category: "status", + size: "s", + } %> + + <%= render partial: "filters/checkbox_filter", + locals: { + f:, + options: user_role_type_filters(current_user.support?), + label: "Role type", + category: "role", + size: "s", + } %> + + <%= render partial: "filters/checkbox_filter", + locals: { + f:, + options: user_additional_responsibilities_filters, + label: "Additional responsibilities", + category: "additional_responsibilities", + size: "s", + } %> <% if request.params["search"].present? %> <%= f.hidden_field :search, value: request.params["search"] %> From 4c13b8bc0a6dcaf120d6e6425012fe335deac2ef Mon Sep 17 00:00:00 2001 From: Frank Ma Date: Thu, 27 Nov 2025 16:47:58 +0000 Subject: [PATCH 2/5] CLDC-4029: Add tests --- spec/services/filter_manager_spec.rb | 47 ++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/spec/services/filter_manager_spec.rb b/spec/services/filter_manager_spec.rb index 78923d7be..006ef0697 100644 --- a/spec/services/filter_manager_spec.rb +++ b/spec/services/filter_manager_spec.rb @@ -94,4 +94,51 @@ describe FilterManager do expect(described_class.filter_schemes(Scheme.all, nil, {}, nil, nil)).to eq(alphabetical_order_schemes) end end + + describe "filter_users" do + let(:data_provider_user) { FactoryBot.create(:user, role: "data_provider") } + let(:data_coordinator_user) { FactoryBot.create(:user, role: "data_coordinator") } + let(:support_user) { FactoryBot.create(:user, role: "support") } + let(:key_contact_user) { FactoryBot.create(:user, is_key_contact: true) } + let(:dpo_user) { FactoryBot.create(:user, is_dpo: true) } + let(:key_contact_dpo_user) { FactoryBot.create(:user, is_key_contact: true, is_dpo: true) } + + context "when filtering by role" do + it "returns users with the role" do + filter = { "role" => %w[data_provider] } + result = described_class.filter_users(User.all, nil, filter, nil) + expect(result).to include(data_provider_user) + expect(result).not_to include(data_coordinator_user) + expect(result).not_to include(support_user) + end + + it "returns users with multiple roles selected" do + filter = { "role" => %w[data_provider data_coordinator] } + result = described_class.filter_users(User.all, nil, filter, nil) + expect(result).to include(data_provider_user) + expect(result).to include(data_coordinator_user) + expect(result).not_to include(support_user) + end + end + + context "when filtering by additional responsibilities" do + it "returns users with the additional responsibilities" do + filter = { "additional_responsibilities" => %w[data_protection_officer] } + result = described_class.filter_users(User.all, nil, filter, nil) + expect(result).to include(dpo_user) + expect(result).to include(key_contact_dpo_user) + expect(result).not_to include(key_contact_user) + expect(result).not_to include(support_user) + end + + it "returns users with multiple additional responsibilities selected" do + filter = { "additional_responsibilities" => %w[data_protection_officer key_contact] } + result = described_class.filter_users(User.all, nil, filter, nil) + expect(result).to include(dpo_user) + expect(result).to include(key_contact_dpo_user) + expect(result).to include(key_contact_user) + expect(result).not_to include(support_user) + end + end + end end From 09bda6d4b5d9ffbddfe3d7487899f3489edc5125 Mon Sep 17 00:00:00 2001 From: Frank Ma Date: Thu, 27 Nov 2025 17:30:29 +0000 Subject: [PATCH 3/5] CLDC-4029: Address linter issues --- app/helpers/filters_helper.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/helpers/filters_helper.rb b/app/helpers/filters_helper.rb index 3f82ab5d0..7b85e0f6b 100644 --- a/app/helpers/filters_helper.rb +++ b/app/helpers/filters_helper.rb @@ -52,7 +52,7 @@ module FiltersHelper }.freeze end - def user_role_type_filters(include_support = false) + def user_role_type_filters(include_support: false) roles = { "1" => "Data provider", "2" => "Coordinator", From 64f21d8840ad8567c4c168cff0ad071a3809528e Mon Sep 17 00:00:00 2001 From: Samuel Young Date: Thu, 4 Dec 2025 15:22:58 +0000 Subject: [PATCH 4/5] CLDC-4029: Pass argument by keyword when required --- app/views/users/_user_filters.html.erb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/users/_user_filters.html.erb b/app/views/users/_user_filters.html.erb index 03e686bf4..876c8925f 100644 --- a/app/views/users/_user_filters.html.erb +++ b/app/views/users/_user_filters.html.erb @@ -27,7 +27,7 @@ <%= render partial: "filters/checkbox_filter", locals: { f:, - options: user_role_type_filters(current_user.support?), + options: user_role_type_filters(include_support: current_user.support?), label: "Role type", category: "role", size: "s", From 69846a049403ff0b7089eefe05a6922e74bc31d8 Mon Sep 17 00:00:00 2001 From: Samuel Young Date: Thu, 11 Dec 2025 17:52:34 +0000 Subject: [PATCH 5/5] CLDC-4029: Reference scopes directly --- app/models/user.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/models/user.rb b/app/models/user.rb index e4b6b41d4..ea8289e53 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -89,9 +89,9 @@ class User < ApplicationRecord additional_responsibilities.each do |responsibility| case responsibility when "key_contact" - scopes << send("is_key_contact") + scopes << is_key_contact when "data_protection_officer" - scopes << send("is_data_protection_officer") + scopes << is_data_protection_officer end end