Searchable GDPR Delete Requests Table (#17633)
* Adds search functionality to GDPR delete requests table * Adds e2e tests for searching GDPR delete requests * WIP: Address PR review feedback and add a RSpec test * Updates spec name to include _query * Updates Adnub::GDPRDeleteRequests#index * Adjusts expectations within gdpr_delete_requests_query_spec.rb * Adjusts GDPR Delete Requests Query search default * Updates gdpr_delete_requests_query_spec.rb
This commit is contained in:
parent
127fe37e19
commit
b155749db0
5 changed files with 108 additions and 4 deletions
|
|
@ -3,7 +3,7 @@ module Admin
|
|||
layout "admin"
|
||||
|
||||
def index
|
||||
@gdpr_delete_requests = ::GDPRDeleteRequest.order(created_at: :desc).page(params[:page]).per(50)
|
||||
@gdpr_delete_requests = Admin::GDPRDeleteRequestsQuery.call(search: params[:search]).page(params[:page]).per(50)
|
||||
end
|
||||
|
||||
def destroy
|
||||
|
|
|
|||
16
app/queries/admin/gdpr_delete_requests_query.rb
Normal file
16
app/queries/admin/gdpr_delete_requests_query.rb
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
module Admin
|
||||
module GDPRDeleteRequestsQuery
|
||||
QUERY_CLAUSE = "#{GDPRDeleteRequest.table_name}.email ILIKE :search OR " \
|
||||
"#{GDPRDeleteRequest.table_name}.username ILIKE :search".freeze
|
||||
|
||||
def self.call(relation: ::GDPRDeleteRequest.all, search: {})
|
||||
relation = search_relation(relation, search) if search.presence
|
||||
|
||||
relation.order(created_at: :desc)
|
||||
end
|
||||
|
||||
def self.search_relation(relation, search)
|
||||
relation.where(QUERY_CLAUSE, search: "%#{search}%")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -2,10 +2,15 @@
|
|||
<div id="gdpr-delete-requests-content" class="crayons-card overflow-admin-main-layout-padding p-4 m:p-0">
|
||||
<header class="flex flex-col l:flex-row justify-content-between l:items-center p-0 m:p-7 pb-4">
|
||||
<h1 class="crayons-title ml-3 l:ml-0">Members<span class="screen-reader-only"> (GDPR Delete Requests)</span></h1>
|
||||
<%= form_with url: admin_gdpr_delete_requests_path, method: :get, local: true, class: "grow-1 mb-3 m:mb-0" do |f| %>
|
||||
<div class="hidden m:flex flex-col m:flex-row justify-content-between p-3 xl:px-0">
|
||||
<div class="flex grow-1 justify-content-end">
|
||||
<%= paginate @gdpr_delete_requests, theme: "admin", scope: @gdpr_delete_requests, label: "Paginate GDPR delete requests", context: "top" %>
|
||||
</div>
|
||||
<%= render "admin/users/controls/search_field", f: f, placeholder: "Search members...", aria_label: "Search members by email or username", context: "large" %>
|
||||
</div>
|
||||
<% end %>
|
||||
</header>
|
||||
<div class="flex justify-end px-2 m:px-7">
|
||||
<%= paginate @gdpr_delete_requests, theme: "admin", scope: @gdpr_delete_requests, label: "Paginate GDPR delete requests", context: "top" %>
|
||||
</div>
|
||||
<div id="table-description" class="my-4 max-w-75 color-base-60 px-2 m:px-7">
|
||||
These accounts have been deleted from the community. Ensure that any data held in external databases or mailing lists is deleted before marking as "Deleted."
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -62,4 +62,35 @@ describe('GDPR Delete Requests', () => {
|
|||
}).should('not.exist');
|
||||
cy.get('@confirmButton').should('exist').should('have.focus');
|
||||
});
|
||||
|
||||
it('Searches for a user', () => {
|
||||
// The user should be visible on the page
|
||||
cy.findByRole('table')
|
||||
.findByText('gdpr-delete-user@forem.local')
|
||||
.should('exist');
|
||||
|
||||
// Search for a term that should match the entry
|
||||
searchForMember('delete');
|
||||
|
||||
cy.url().should('contain', 'search=delete');
|
||||
cy.findByRole('table')
|
||||
.findByText('gdpr-delete-user@forem.local')
|
||||
.should('exist');
|
||||
|
||||
// Search for a term that shouldn't match the entry
|
||||
searchForMember('something');
|
||||
cy.url().should('contain', 'search=something');
|
||||
cy.findByRole('table')
|
||||
.findByText('gdpr-delete-user@forem.local')
|
||||
.should('not.exist');
|
||||
});
|
||||
|
||||
const searchForMember = (searchTerm) => {
|
||||
cy.findByRole('textbox', {
|
||||
name: 'Search members by email or username',
|
||||
})
|
||||
.clear()
|
||||
.type(searchTerm);
|
||||
cy.findByRole('button', { name: 'Search' }).click();
|
||||
};
|
||||
});
|
||||
|
|
|
|||
52
spec/queries/admin/gdpr_delete_requests_query_spec.rb
Normal file
52
spec/queries/admin/gdpr_delete_requests_query_spec.rb
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
require "rails_helper"
|
||||
|
||||
RSpec.describe Admin::GDPRDeleteRequestsQuery, type: :query do
|
||||
subject { described_class.call(search: search) }
|
||||
|
||||
let!(:gdpr_delete_request_1) { create(:gdpr_delete_request, username: "delete_1", email: "delete_1@test.com") }
|
||||
let!(:gdpr_delete_request_2) { create(:gdpr_delete_request, username: "delete_2", email: "delete_2@test.com") }
|
||||
let!(:gdpr_delete_request_3) { create(:gdpr_delete_request, username: "delete_3", email: "delete_3@test.com") }
|
||||
let!(:gdpr_delete_request_11) { create(:gdpr_delete_request, username: "delete_11", email: "delete_11@test.com") }
|
||||
|
||||
describe ".call" do
|
||||
context "when no arguments are given" do
|
||||
it "returns all users" do
|
||||
# rubocop:disable Layout/LineLength
|
||||
expect(described_class.call).to match_array([gdpr_delete_request_1, gdpr_delete_request_2, gdpr_delete_request_3, gdpr_delete_request_11])
|
||||
# rubocop:enable Layout/LineLength
|
||||
end
|
||||
end
|
||||
|
||||
context "when searching for a user by username" do
|
||||
let(:search) { "delete_2" }
|
||||
|
||||
it { is_expected.to match_array([gdpr_delete_request_2]) }
|
||||
end
|
||||
|
||||
context "when searching for a user by email" do
|
||||
let(:search) { "delete_1@test.com" }
|
||||
|
||||
it { is_expected.to match_array([gdpr_delete_request_1]) }
|
||||
end
|
||||
|
||||
context "when searching for ambiguous terms that matches multiple users" do
|
||||
let(:search) { "delete_1" }
|
||||
|
||||
it { is_expected.to match_array([gdpr_delete_request_1, gdpr_delete_request_11]) }
|
||||
end
|
||||
|
||||
context "when searching for ambiguous terms that matches both emails and usernames" do
|
||||
let(:search) { "delete" }
|
||||
|
||||
# rubocop:disable Layout/LineLength
|
||||
it { is_expected.to match_array([gdpr_delete_request_1, gdpr_delete_request_2, gdpr_delete_request_3, gdpr_delete_request_11]) }
|
||||
# rubocop:enable Layout/LineLength
|
||||
end
|
||||
|
||||
context "when passed a non-existent email or username" do
|
||||
let(:search) { "non_existent_email" }
|
||||
|
||||
it { is_expected.to match_array([]) }
|
||||
end
|
||||
end
|
||||
end
|
||||
Loading…
Add table
Reference in a new issue