From 72890e516e6888c8a0253d4c1c51e2b6cc33717f Mon Sep 17 00:00:00 2001
From: kosiakkatrina <54268893+kosiakkatrina@users.noreply.github.com>
Date: Tue, 13 Aug 2024 12:01:37 +0100
Subject: [PATCH] CLDC-3564 Update filter search (#2535)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* Add search controller
* Update on confirm
* lint
* Update search endpoint
* remove assigned to filter options
* Explicitly define host in the url
* Update search controller
* Allow searching organisations
* Allow filtering by user without js
* Allow filtering by org without js
* Add filter_type to method calls
* Update filter helpers
* Hide text search input when js is enabled
* Some feature test updates
* fix model test
* Delete a random file 👀
* lint
* Update more tests
* Update inner text for filter
* Keep csv filters the same
* Clear free text filters for csv dowloads
* User path helper
* Update scheme filters and log scopes
* Update which users we can filter by
---
app/controllers/organisations_controller.rb | 15 +-
app/controllers/users_controller.rb | 11 +
app/frontend/controllers/index.js | 3 +
app/frontend/controllers/search_controller.js | 46 +++
app/frontend/modules/search.js | 49 +++
app/helpers/filters_helper.rb | 82 ++++-
app/models/lettings_log.rb | 4 +
app/models/log.rb | 3 +
app/models/organisation.rb | 1 +
app/models/user.rb | 5 +-
app/services/filter_manager.rb | 11 +
app/views/filters/_radio_filter.html.erb | 1 +
.../filters/_text_select_filter.html.erb | 20 ++
app/views/filters/assigned_to.html.erb | 3 +-
app/views/filters/managed_by.html.erb | 3 +-
app/views/filters/owned_by.html.erb | 3 +-
app/views/logs/_log_filters.html.erb | 15 +-
app/views/schemes/_scheme_filters.html.erb | 2 +-
config/routes.rb | 8 +
spec/features/lettings_log_spec.rb | 4 +-
spec/features/organisation_spec.rb | 6 +-
spec/features/user_spec.rb | 7 +-
spec/helpers/filters_helper_spec.rb | 298 ++++++++++++++++--
spec/models/user_spec.rb | 6 +-
.../requests/organisations_controller_spec.rb | 45 +++
spec/requests/users_controller_spec.rb | 61 ++++
26 files changed, 643 insertions(+), 69 deletions(-)
create mode 100644 app/frontend/controllers/search_controller.js
create mode 100644 app/views/filters/_text_select_filter.html.erb
diff --git a/app/controllers/organisations_controller.rb b/app/controllers/organisations_controller.rb
index dfe50fa22..9d3e63b33 100644
--- a/app/controllers/organisations_controller.rb
+++ b/app/controllers/organisations_controller.rb
@@ -4,8 +4,8 @@ class OrganisationsController < ApplicationController
include DuplicateLogsHelper
before_action :authenticate_user!
- before_action :find_resource, except: %i[index new create]
- before_action :authenticate_scope!, except: [:index]
+ before_action :find_resource, except: %i[index new create search]
+ before_action :authenticate_scope!, except: %i[index search]
before_action :session_filters, if: -> { current_user.support? || current_user.organisation.has_managing_agents? }, only: %i[lettings_logs sales_logs email_lettings_csv download_lettings_csv email_sales_csv download_sales_csv]
before_action :session_filters, only: %i[users schemes email_schemes_csv download_schemes_csv]
before_action -> { filter_manager.serialize_filters_to_session }, if: -> { current_user.support? || current_user.organisation.has_managing_agents? }, only: %i[lettings_logs sales_logs email_lettings_csv download_lettings_csv email_sales_csv download_sales_csv]
@@ -280,6 +280,17 @@ class OrganisationsController < ApplicationController
render "schemes/changes"
end
+ def search
+ org_options = current_user.support? ? Organisation.all : Organisation.affiliated_organisations(current_user.organisation)
+ organisations = org_options.search_by(params["query"]).limit(20)
+
+ org_data = organisations.each_with_object({}) do |org, hash|
+ hash[org.id] = { value: org.name }
+ end
+
+ render json: org_data.to_json
+ end
+
private
def filter_type
diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb
index 3fe3b1813..2f7bb2bd6 100644
--- a/app/controllers/users_controller.rb
+++ b/app/controllers/users_controller.rb
@@ -32,6 +32,17 @@ class UsersController < ApplicationController
end
end
+ def search
+ user_options = current_user.support? ? User.all : User.own_and_managing_org_users(current_user.organisation)
+ users = user_options.search_by(params["query"]).limit(20)
+
+ user_data = users.each_with_object({}) do |user, hash|
+ hash[user.id] = { value: user.name, hint: user.email }
+ end
+
+ render json: user_data.to_json
+ end
+
def resend_invite
@user.send_confirmation_instructions
flash[:notice] = "Invitation sent to #{@user.email}"
diff --git a/app/frontend/controllers/index.js b/app/frontend/controllers/index.js
index ece539d15..ef29b99ca 100644
--- a/app/frontend/controllers/index.js
+++ b/app/frontend/controllers/index.js
@@ -13,6 +13,8 @@ import GovukfrontendController from './govukfrontend_controller.js'
import NumericQuestionController from './numeric_question_controller.js'
+import SearchController from './search_controller.js'
+
import FilterLayoutController from './filter_layout_controller.js'
application.register('accessible-autocomplete', AccessibleAutocompleteController)
application.register('conditional-filter', ConditionalFilterController)
@@ -20,3 +22,4 @@ application.register('conditional-question', ConditionalQuestionController)
application.register('govukfrontend', GovukfrontendController)
application.register('numeric-question', NumericQuestionController)
application.register('filter-layout', FilterLayoutController)
+application.register('search', SearchController)
diff --git a/app/frontend/controllers/search_controller.js b/app/frontend/controllers/search_controller.js
new file mode 100644
index 000000000..565b9d0d1
--- /dev/null
+++ b/app/frontend/controllers/search_controller.js
@@ -0,0 +1,46 @@
+import { Controller } from '@hotwired/stimulus'
+import accessibleAutocomplete from 'accessible-autocomplete'
+import 'accessible-autocomplete/dist/accessible-autocomplete.min.css'
+import { searchSuggestion, fetchAndPopulateSearchResults, confirmSelectedOption, searchableName } from '../modules/search'
+
+const options = []
+const populateOptions = (results, selectEl) => {
+ selectEl.innerHTML = ''
+
+ Object.keys(results).forEach((key) => {
+ const option = document.createElement('option')
+ option.value = key
+ option.innerHTML = results[key].value
+ if (results[key].hint) { option.setAttribute('data-hint', results[key].hint) }
+ option.setAttribute('text', searchableName(results[key]))
+ selectEl.appendChild(option)
+ options.push(option)
+ })
+}
+
+export default class extends Controller {
+ connect () {
+ const selectEl = this.element
+ const matches = /^(\w+)\[(\w+)\]$/.exec(selectEl.name)
+ const rawFieldName = matches ? `${matches[1]}[${matches[2]}_raw]` : ''
+ const searchUrl = JSON.parse(this.element.dataset.info).search_url
+
+ document.querySelectorAll('.non-js-text-search-input-field').forEach((el) => {
+ el.style.display = 'none'
+ })
+
+ accessibleAutocomplete.enhanceSelectElement({
+ defaultValue: '',
+ selectElement: selectEl,
+ minLength: 1,
+ source: (query, populateResults) => {
+ fetchAndPopulateSearchResults(query, populateResults, searchUrl, populateOptions, selectEl)
+ },
+ autoselect: true,
+ placeholder: 'Start typing to search',
+ templates: { suggestion: (value) => searchSuggestion(value, options) },
+ name: rawFieldName,
+ onConfirm: (val) => confirmSelectedOption(selectEl, val)
+ })
+ }
+}
diff --git a/app/frontend/modules/search.js b/app/frontend/modules/search.js
index 71944746e..efdf7b9d0 100644
--- a/app/frontend/modules/search.js
+++ b/app/frontend/modules/search.js
@@ -117,6 +117,22 @@ export const suggestion = (value, options) => {
}
}
+export const searchSuggestion = (value, options) => {
+ try {
+ const option = options.find((o) => o.getAttribute('text') === value)
+ if (option) {
+ const result = enhanceOption(option)
+ const html = result.append ? `${result.text} ${result.append}` : `${result.text}`
+ return result.hint ? `${html}
${result.hint}
` : html
+ } else {
+ return 'No results found'
+ }
+ } catch (error) {
+ console.error('Error fetching user option:', error)
+ return value
+ }
+}
+
export const enhanceOption = (option) => {
return {
text: option.text,
@@ -128,6 +144,39 @@ export const enhanceOption = (option) => {
}
}
+export const fetchAndPopulateSearchResults = async (query, populateResults, relativeUrlRoute, populateOptions, selectEl) => {
+ if (/\S/.test(query)) {
+ const results = await fetchUserOptions(query, relativeUrlRoute)
+ populateOptions(results, selectEl)
+ populateResults(Object.values(results).map((o) => searchableName(o)))
+ }
+}
+
+export const fetchUserOptions = async (query, searchUrl) => {
+ try {
+ const response = await fetch(`${searchUrl}?query=${encodeURIComponent(query)}`)
+ const results = await response.json()
+ return results
+ } catch (error) {
+ console.error('Error fetching user options:', error)
+ return []
+ }
+}
+
export const getSearchableName = (option) => {
return option.getAttribute('data-hint') ? option.text + ' ' + option.getAttribute('data-hint') : option.text
}
+
+export const searchableName = (option) => {
+ return option.hint ? option.value + ' ' + option.hint : option.value
+}
+
+export const confirmSelectedOption = (selectEl, val) => {
+ const arrayOfOptions = Array.from(selectEl.options).filter(function (option, index, arr) { return option.value !== '' })
+
+ const selectedOption = [].filter.call(
+ arrayOfOptions,
+ (option) => option.getAttribute('text') === val
+ )[0]
+ if (selectedOption) selectedOption.selected = true
+}
diff --git a/app/helpers/filters_helper.rb b/app/helpers/filters_helper.rb
index 38c15b82b..5f8488bc9 100644
--- a/app/helpers/filters_helper.rb
+++ b/app/helpers/filters_helper.rb
@@ -11,8 +11,8 @@ module FiltersHelper
return true if !selected_filters.key?("owning_organisation") && filter == "owning_organisation_select" && value == :all
return true if !selected_filters.key?("managing_organisation") && filter == "managing_organisation_select" && value == :all
- return true if selected_filters["owning_organisation"].present? && filter == "owning_organisation_select" && value == :specific_org
- return true if selected_filters["managing_organisation"].present? && filter == "managing_organisation_select" && value == :specific_org
+ return true if (selected_filters["owning_organisation"].present? || selected_filters["owning_organisation_text_search"].present?) && filter == "owning_organisation_select" && value == :specific_org
+ return true if (selected_filters["managing_organisation"].present? || selected_filters["managing_organisation_text_search"].present?) && filter == "managing_organisation_select" && value == :specific_org
return false if selected_filters[filter].blank?
@@ -84,16 +84,54 @@ module FiltersHelper
JSON.parse(session[session_name_for(filter_type)])[filter] || ""
end
- def owning_organisation_filter_options(user)
+ def all_owning_organisation_filter_options(user)
organisation_options = user.support? ? Organisation.all : ([user.organisation] + user.organisation.stock_owners + user.organisation.absorbed_organisations).uniq
[OpenStruct.new(id: "", name: "Select an option")] + organisation_options.map { |org| OpenStruct.new(id: org.id, name: org.name) }
end
- def assigned_to_filter_options(user)
+ def owning_organisation_filter_options(user, filter_type)
+ if applied_filters(filter_type)["owning_organisation"].present?
+ organisation_id = applied_filters(filter_type)["owning_organisation"]
+
+ org = if user.support?
+ Organisation.where(id: organisation_id)&.first
+ else
+ Organisation.affiliated_organisations(user.organisation).where(id: organisation_id)&.first
+ end
+ return [OpenStruct.new(id: org.id, name: org.name)] if org.present?
+ end
+
+ [OpenStruct.new(id: "", name: "Select an option")]
+ end
+
+ def assigned_to_csv_filter_options(user)
user_options = user.support? ? User.all : (user.organisation.users + user.organisation.managing_agents.flat_map(&:users) + user.organisation.stock_owners.flat_map(&:users)).uniq
[OpenStruct.new(id: "", name: "Select an option", hint: "")] + user_options.map { |user_option| OpenStruct.new(id: user_option.id, name: user_option.name, hint: user_option.email) }
end
+ def assigned_to_filter_options(filter_type)
+ if applied_filters(filter_type)["assigned_to"] == "specific_user" && applied_filters(filter_type)["user"].present?
+ user_id = applied_filters(filter_type)["user"]
+ selected_user = if current_user.support?
+ User.where(id: user_id)&.first
+ else
+ User.own_and_managing_org_users(current_user.organisation).where(id: user_id)&.first
+ end
+
+ return [OpenStruct.new(id: selected_user.id, name: selected_user.name, hint: selected_user.email)] if selected_user.present?
+ end
+ [OpenStruct.new(id: "", name: "Select an option", hint: "")]
+ end
+
+ def filter_search_url(category)
+ case category
+ when :user
+ search_users_path
+ when :owning_organisation, :managing_organisation
+ search_organisations_path
+ end
+ end
+
def collection_year_options
years = {
current_collection_start_year.to_s => year_combo(current_collection_start_year),
@@ -125,11 +163,26 @@ module FiltersHelper
end
end
- def managing_organisation_filter_options(user)
+ def managing_organisation_csv_filter_options(user)
organisation_options = user.support? ? Organisation.all : ([user.organisation] + user.organisation.managing_agents + user.organisation.absorbed_organisations).uniq
[OpenStruct.new(id: "", name: "Select an option")] + organisation_options.map { |org| OpenStruct.new(id: org.id, name: org.name) }
end
+ def managing_organisation_filter_options(user, filter_type)
+ if applied_filters(filter_type)["managing_organisation"].present?
+ organisation_id = applied_filters(filter_type)["managing_organisation"]
+
+ org = if user.support?
+ Organisation.where(id: organisation_id)&.first
+ else
+ Organisation.affiliated_organisations(user.organisation).where(id: organisation_id)&.first
+ end
+ return [OpenStruct.new(id: org.id, name: org.name)] if org.present?
+ end
+
+ [OpenStruct.new(id: "", name: "Select an option")]
+ end
+
def show_scheme_managing_org_filter?(user)
org = user.organisation
@@ -176,8 +229,8 @@ module FiltersHelper
{ id: "status", label: "Status", value: formatted_status_filter(session_filters) },
filter_type == "lettings_logs" ? { id: "needstype", label: "Needs type", value: formatted_needstype_filter(session_filters) } : nil,
{ id: "assigned_to", label: "Assigned to", value: formatted_assigned_to_filter(session_filters) },
- { id: "owned_by", label: "Owned by", value: formatted_owned_by_filter(session_filters) },
- { id: "managed_by", label: "Managed by", value: formatted_managed_by_filter(session_filters) },
+ { id: "owned_by", label: "Owned by", value: formatted_owned_by_filter(session_filters, filter_type) },
+ { id: "managed_by", label: "Managed by", value: formatted_managed_by_filter(session_filters, filter_type) },
].compact
end
@@ -221,7 +274,7 @@ private
filters.each.sum do |category, category_filters|
if %w[years status needstypes bulk_upload_id].include?(category)
category_filters.count(&:present?)
- elsif %w[user owning_organisation managing_organisation].include?(category)
+ elsif %w[user owning_organisation managing_organisation user_text_search owning_organisation_text_search managing_organisation_text_search].include?(category)
1
else
0
@@ -256,26 +309,27 @@ private
return "All" if session_filters["assigned_to"].include?("all")
return "You" if session_filters["assigned_to"].include?("you")
- selected_user_option = assigned_to_filter_options(current_user).find { |x| x.id == session_filters["user"].to_i }
+ User.own_and_managing_org_users(current_user.organisation).find(session_filters["user"].to_i).name
+ selected_user_option = User.own_and_managing_org_users(current_user.organisation).find(session_filters["user"].to_i)
return unless selected_user_option
- "#{selected_user_option.name} (#{selected_user_option.hint})"
+ "#{selected_user_option.name} (#{selected_user_option.email})"
end
- def formatted_owned_by_filter(session_filters)
+ def formatted_owned_by_filter(session_filters, filter_type)
return "All" if params["id"].blank? && (session_filters["owning_organisation"].blank? || session_filters["owning_organisation"]&.include?("all"))
session_org_id = session_filters["owning_organisation"] || params["id"]
- selected_owning_organisation_option = owning_organisation_filter_options(current_user).find { |org| org.id == session_org_id.to_i }
+ selected_owning_organisation_option = owning_organisation_filter_options(current_user, filter_type).find { |org| org.id == session_org_id.to_i }
return unless selected_owning_organisation_option
selected_owning_organisation_option&.name
end
- def formatted_managed_by_filter(session_filters)
+ def formatted_managed_by_filter(session_filters, filter_type)
return "All" if session_filters["managing_organisation"].blank? || session_filters["managing_organisation"].include?("all")
- selected_managing_organisation_option = managing_organisation_filter_options(current_user).find { |org| org.id == session_filters["managing_organisation"].to_i }
+ selected_managing_organisation_option = managing_organisation_filter_options(current_user, filter_type).find { |org| org.id == session_filters["managing_organisation"].to_i }
return unless selected_managing_organisation_option
selected_managing_organisation_option&.name
diff --git a/app/models/lettings_log.rb b/app/models/lettings_log.rb
index e7a72350d..10ab612cd 100644
--- a/app/models/lettings_log.rb
+++ b/app/models/lettings_log.rb
@@ -132,6 +132,10 @@ class LettingsLog < Log
illness_type_10: false)
}
+ scope :filter_by_user_text_search, ->(param, user) { where(assigned_to: user.support? ? User.search_by(param) : User.own_and_managing_org_users(user.organisation).search_by(param)) }
+ scope :filter_by_owning_organisation_text_search, ->(param, _user) { where(owning_organisation: Organisation.search_by(param)) }
+ scope :filter_by_managing_organisation_text_search, ->(param, _user) { where(managing_organisation: Organisation.search_by(param)) }
+
AUTOGENERATED_FIELDS = %w[id status created_at updated_at discarded_at].freeze
OPTIONAL_FIELDS = %w[tenancycode propcode chcharge].freeze
RENT_TYPE_MAPPING_LABELS = { 1 => "Social Rent", 2 => "Affordable Rent", 3 => "Intermediate Rent" }.freeze
diff --git a/app/models/log.rb b/app/models/log.rb
index c095a8276..3a6c1e982 100644
--- a/app/models/log.rb
+++ b/app/models/log.rb
@@ -53,6 +53,9 @@ class Log < ApplicationRecord
scope :filter_by_organisation, ->(org, _user = nil) { where(owning_organisation: org).or(where(managing_organisation: org)) }
scope :filter_by_owning_organisation, ->(owning_organisation, _user = nil) { where(owning_organisation:) }
scope :filter_by_managing_organisation, ->(managing_organisation, _user = nil) { where(managing_organisation:) }
+ scope :filter_by_user_text_search, ->(param, user) { where(assigned_to: user.support? ? User.search_by(param) : User.own_and_managing_org_users(user.organisation).search_by(param)) }
+ scope :filter_by_owning_organisation_text_search, ->(param, _user) { where(owning_organisation: Organisation.search_by(param)) }
+ scope :filter_by_managing_organisation_text_search, ->(param, _user) { where(managing_organisation: Organisation.search_by(param)) }
attr_accessor :skip_update_status, :skip_update_uprn_confirmed, :select_best_address_match, :skip_dpo_validation
diff --git a/app/models/organisation.rb b/app/models/organisation.rb
index 8f77df166..65b35c24e 100644
--- a/app/models/organisation.rb
+++ b/app/models/organisation.rb
@@ -18,6 +18,7 @@ class Organisation < ApplicationRecord
belongs_to :absorbing_organisation, class_name: "Organisation", optional: true
has_many :absorbed_organisations, class_name: "Organisation", foreign_key: "absorbing_organisation_id"
scope :visible, -> { where(discarded_at: nil) }
+ scope :affiliated_organisations, ->(organisation) { where(id: (organisation.child_organisations + [organisation] + organisation.parent_organisations + organisation.absorbed_organisations).map(&:id)) }
def affiliated_stock_owners
ids = []
diff --git a/app/models/user.rb b/app/models/user.rb
index d25faaa53..c79ceb0d9 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -77,6 +77,7 @@ class User < ApplicationRecord
scope :deactivated, -> { where(active: false) }
scope :active_status, -> { where(active: true).where.not(last_sign_in_at: nil) }
scope :visible, -> { where(discarded_at: nil) }
+ scope :own_and_managing_org_users, ->(organisation) { where(organisation: organisation.child_organisations + [organisation]) }
def lettings_logs
if support?
@@ -209,9 +210,9 @@ class User < ApplicationRecord
def logs_filters(specific_org: false)
if (support? && !specific_org) || organisation.has_managing_agents? || organisation.has_stock_owners?
- %w[years status needstypes assigned_to user managing_organisation owning_organisation bulk_upload_id]
+ %w[years status needstypes assigned_to user managing_organisation owning_organisation bulk_upload_id user_text_search owning_organisation_text_search managing_organisation_text_search]
else
- %w[years status needstypes assigned_to user bulk_upload_id]
+ %w[years status needstypes assigned_to user bulk_upload_id user_text_search]
end
end
diff --git a/app/services/filter_manager.rb b/app/services/filter_manager.rb
index 8d661b3fa..9f68a097c 100644
--- a/app/services/filter_manager.rb
+++ b/app/services/filter_manager.rb
@@ -24,6 +24,9 @@ class FilterManager
next if category == "owning_organisation" && all_orgs
next if category == "managing_organisation" && all_orgs
next if category == "assigned_to"
+ next if category == "user_text_search" && filters["assigned_to"] != "specific_user"
+ next if category == "owning_organisation_text_search" && all_orgs
+ next if category == "managing_organisation_text_search" && all_orgs
logs = logs.public_send("filter_by_#{category}", values, user)
end
@@ -94,11 +97,19 @@ class FilterManager
new_filters[filter] = params[filter] if params[filter].present?
end
+ if params["action"] == "download_csv"
+ new_filters["assigned_to"] = "all" if new_filters["assigned_to"] == "specific_user" && new_filters["user_text_search"].present?
+ new_filters["owning_organisation_select"] = "all" if new_filters["owning_organisation_select"] == "specific_organisation" && new_filters["owning_organisation_text_search"].present?
+ new_filters["managing_organisation_select"] = "all" if new_filters["managing_organisation_select"] == "specific_organisation" && new_filters["managing_organisation_text_search"].present?
+ end
new_filters = new_filters.except("owning_organisation") if params["owning_organisation_select"] == "all"
new_filters = new_filters.except("managing_organisation") if params["managing_organisation_select"] == "all"
new_filters = new_filters.except("user") if params["assigned_to"] == "all"
new_filters["user"] = current_user.id.to_s if params["assigned_to"] == "you"
+ new_filters = new_filters.except("user_text_search") if params["assigned_to"] == "all" || params["assigned_to"] == "you"
+ new_filters = new_filters.except("owning_organisation_text_search") if params["owning_organisation_select"] == "all"
+ new_filters = new_filters.except("managing_organisation_text_search") if params["managing_organisation_select"] == "all"
end
if (filter_type.include?("schemes") || filter_type.include?("users") || filter_type.include?("scheme_locations")) && params["status"].present?
diff --git a/app/views/filters/_radio_filter.html.erb b/app/views/filters/_radio_filter.html.erb
index 6eb902dba..e4d23573c 100644
--- a/app/views/filters/_radio_filter.html.erb
+++ b/app/views/filters/_radio_filter.html.erb
@@ -10,6 +10,7 @@
collection: option[:conditional_filter][:options],
category: option[:conditional_filter][:category],
label: option[:conditional_filter][:label],
+ caption_text: option[:conditional_filter][:caption_text],
secondary: true,
hint_text: option[:conditional_filter][:hint_text],
} %>
diff --git a/app/views/filters/_text_select_filter.html.erb b/app/views/filters/_text_select_filter.html.erb
new file mode 100644
index 000000000..ecc997bba
--- /dev/null
+++ b/app/views/filters/_text_select_filter.html.erb
@@ -0,0 +1,20 @@
+
+<%= f.govuk_text_field "#{category}_text_search".to_sym,
+ label: { text: label, hidden: secondary },
+ "data-controller": "search conditional-filter",
+ caption: { text: caption_text },
+ "data-info": { search_url: filter_search_url(category.to_sym) }.to_json,
+ value: selected_option("#{category}_text_search", @filter_type) %>
+
+<%= f.govuk_select(category.to_sym,
+ label: { text: label, hidden: secondary },
+ "data-controller": "search conditional-filter",
+ "hidden": true,
+ "data-info": { search_url: filter_search_url(category.to_sym) }.to_json) do %>
+ <% collection.each do |answer| %>
+
+ <% end %>
+ <% end %>
diff --git a/app/views/filters/assigned_to.html.erb b/app/views/filters/assigned_to.html.erb
index 9f0582fbb..778d63c8a 100644
--- a/app/views/filters/assigned_to.html.erb
+++ b/app/views/filters/assigned_to.html.erb
@@ -11,7 +11,8 @@
type: "select",
label: "User",
category: "user",
- options: assigned_to_filter_options(current_user),
+ caption_text: "User's name or email",
+ options: assigned_to_csv_filter_options(current_user),
},
},
},
diff --git a/app/views/filters/managed_by.html.erb b/app/views/filters/managed_by.html.erb
index e3d849c9b..5d4b684f3 100644
--- a/app/views/filters/managed_by.html.erb
+++ b/app/views/filters/managed_by.html.erb
@@ -9,7 +9,8 @@
type: "select",
label: "Managed by",
category: "managing_organisation",
- options: managing_organisation_filter_options(current_user),
+ options: managing_organisation_csv_filter_options(current_user),
+ caption_text: "Organisation name",
},
},
},
diff --git a/app/views/filters/owned_by.html.erb b/app/views/filters/owned_by.html.erb
index 7acfd459c..271b68de9 100644
--- a/app/views/filters/owned_by.html.erb
+++ b/app/views/filters/owned_by.html.erb
@@ -9,7 +9,8 @@
type: "select",
label: "Owning Organisation",
category: "owning_organisation",
- options: owning_organisation_filter_options(current_user),
+ options: all_owning_organisation_filter_options(current_user),
+ caption_text: "Organisation name",
},
},
},
diff --git a/app/views/logs/_log_filters.html.erb b/app/views/logs/_log_filters.html.erb
index aaef70377..3beab4b6b 100644
--- a/app/views/logs/_log_filters.html.erb
+++ b/app/views/logs/_log_filters.html.erb
@@ -66,10 +66,11 @@
"specific_user": {
label: "Specific user",
conditional_filter: {
- type: "select",
+ type: "text_select",
label: "User",
category: "user",
- options: assigned_to_filter_options(current_user),
+ options: assigned_to_filter_options(@filter_type),
+ caption_text: "User's name or email",
},
},
},
@@ -86,10 +87,11 @@
"specific_org": {
label: "Specific owning organisation",
conditional_filter: {
- type: "select",
+ type: "text_select",
label: "Owning Organisation",
category: "owning_organisation",
- options: owning_organisation_filter_options(current_user),
+ options: owning_organisation_filter_options(current_user, @filter_type),
+ caption_text: "Organisation name",
},
},
},
@@ -107,10 +109,11 @@
"specific_org": {
label: "Specific managing organisation",
conditional_filter: {
- type: "select",
+ type: "text_select",
label: user_or_org_lettings_path? ? "Managed by" : "Reported by",
category: "managing_organisation",
- options: managing_organisation_filter_options(current_user),
+ options: managing_organisation_filter_options(current_user, @filter_type),
+ caption_text: "Organisation name",
},
},
},
diff --git a/app/views/schemes/_scheme_filters.html.erb b/app/views/schemes/_scheme_filters.html.erb
index ca0538463..51687a096 100644
--- a/app/views/schemes/_scheme_filters.html.erb
+++ b/app/views/schemes/_scheme_filters.html.erb
@@ -35,7 +35,7 @@
type: "select",
label: "Owning Organisation",
category: "owning_organisation",
- options: owning_organisation_filter_options(current_user),
+ options: all_owning_organisation_filter_options(current_user),
},
},
},
diff --git a/config/routes.rb b/config/routes.rb
index e0d9631e9..faea457fe 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -125,6 +125,10 @@ Rails.application.routes.draw do
get "edit-dpo", to: "users#dpo"
get "edit-key-contact", to: "users#key_contact"
+ collection do
+ get :search
+ end
+
member do
get "deactivate", to: "users#deactivate"
get "reactivate", to: "users#reactivate"
@@ -191,6 +195,10 @@ Rails.application.routes.draw do
get "delete-confirmation", to: "organisations#delete_confirmation"
delete "delete", to: "organisations#delete"
end
+
+ collection do
+ get :search
+ end
end
resources :merge_requests, path: "/merge-request" do
diff --git a/spec/features/lettings_log_spec.rb b/spec/features/lettings_log_spec.rb
index 2b977fdd7..ac9a1e4a8 100644
--- a/spec/features/lettings_log_spec.rb
+++ b/spec/features/lettings_log_spec.rb
@@ -89,9 +89,9 @@ RSpec.describe "Lettings Log Features" do
check("In progress")
choose("You")
choose("Specific owning organisation")
- select(stock_owner_1.name, from: "owning_organisation")
+ fill_in("owning-organisation-text-search-field", with: "stock")
choose("Specific managing organisation")
- select(managing_agent_1.name, from: "managing_organisation")
+ fill_in("managing-organisation-text-search-field", with: "managing")
click_button("Apply filters")
end
diff --git a/spec/features/organisation_spec.rb b/spec/features/organisation_spec.rb
index 65f787c2a..1867285eb 100644
--- a/spec/features/organisation_spec.rb
+++ b/spec/features/organisation_spec.rb
@@ -199,14 +199,14 @@ RSpec.describe "User Features" do
it "can filter lettings logs by year" do
check("years-2022-field")
click_button("Apply filters")
- expect(page).to have_current_path("/organisations/#{org_id}/lettings-logs?years[]=&years[]=2022&status[]=&needstypes[]=&assigned_to=all&user=&owning_organisation_select=all&owning_organisation=&managing_organisation_select=all&managing_organisation=")
+ expect(page).to have_current_path("/organisations/#{org_id}/lettings-logs?years[]=&years[]=2022&status[]=&needstypes[]=&assigned_to=all&user_text_search=&user=&owning_organisation_select=all&owning_organisation_text_search=&owning_organisation=&managing_organisation_select=all&managing_organisation_text_search=&managing_organisation=")
expect(page).not_to have_link first_log.id.to_s, href: "/lettings-logs/#{first_log.id}"
end
it "can filter lettings logs by needstype" do
check("needstypes-1-field")
click_button("Apply filters")
- expect(page).to have_current_path("/organisations/#{org_id}/lettings-logs?years[]=&status[]=&needstypes[]=&needstypes[]=1&assigned_to=all&user=&owning_organisation_select=all&owning_organisation=&managing_organisation_select=all&managing_organisation=")
+ expect(page).to have_current_path("/organisations/#{org_id}/lettings-logs?years[]=&status[]=&needstypes[]=&needstypes[]=1&assigned_to=all&user_text_search=&user=&owning_organisation_select=all&owning_organisation_text_search=&owning_organisation=&managing_organisation_select=all&managing_organisation_text_search=&managing_organisation=")
other_general_needs_logs.each do |general_needs_log|
expect(page).to have_link general_needs_log.id.to_s, href: "/lettings-logs/#{general_needs_log.id}"
end
@@ -245,7 +245,7 @@ RSpec.describe "User Features" do
end
check("years-2022-field")
click_button("Apply filters")
- expect(page).to have_current_path("/organisations/#{org_id}/sales-logs?years[]=&years[]=2022&status[]=&assigned_to=all&user=&owning_organisation_select=all&owning_organisation=&managing_organisation_select=all&managing_organisation=")
+ expect(page).to have_current_path("/organisations/#{org_id}/sales-logs?years[]=&years[]=2022&status[]=&assigned_to=all&user_text_search=&user=&owning_organisation_select=all&owning_organisation_text_search=&owning_organisation=&managing_organisation_select=all&managing_organisation_text_search=&managing_organisation=")
expect(page).not_to have_link first_log.id.to_s, href: "/sales-logs/#{first_log.id}"
end
end
diff --git a/spec/features/user_spec.rb b/spec/features/user_spec.rb
index 169465cb1..c30abe1e9 100644
--- a/spec/features/user_spec.rb
+++ b/spec/features/user_spec.rb
@@ -796,12 +796,13 @@ RSpec.describe "User Features" do
visit("/lettings-logs")
choose("owning-organisation-select-specific-org-field", allow_label_click: true)
expect(page).to have_field("owning-organisation-field", with: "")
- find("#owning-organisation-field").click.native.send_keys("F", "i", "l", "t", :down, :enter)
+ find("#owning-organisation-field").click.native.send_keys("F", "i", "l", "t")
+ select(parent_organisation.name, from: "owning-organisation-field-select", visible: false)
click_button("Apply filters")
- expect(page).to have_current_path("/lettings-logs?%5Byears%5D%5B%5D=&%5Bstatus%5D%5B%5D=&%5Bneedstypes%5D%5B%5D=&assigned_to=all&owning_organisation_select=specific_org&owning_organisation=#{parent_organisation.id}&managing_organisation_select=all")
+ expect(page).to have_current_path("/lettings-logs?%5Byears%5D%5B%5D=&%5Bstatus%5D%5B%5D=&%5Bneedstypes%5D%5B%5D=&assigned_to=all&user_text_search=&owning_organisation_select=specific_org&owning_organisation_text_search=&owning_organisation=#{parent_organisation.id}&managing_organisation_select=all&managing_organisation_text_search=")
choose("owning-organisation-select-all-field", allow_label_click: true)
click_button("Apply filters")
- expect(page).to have_current_path("/lettings-logs?%5Byears%5D%5B%5D=&%5Bstatus%5D%5B%5D=&%5Bneedstypes%5D%5B%5D=&assigned_to=all&owning_organisation_select=all&managing_organisation_select=all")
+ expect(page).to have_current_path("/lettings-logs?%5Byears%5D%5B%5D=&%5Bstatus%5D%5B%5D=&%5Bneedstypes%5D%5B%5D=&assigned_to=all&user_text_search=&owning_organisation_select=all&owning_organisation_text_search=&managing_organisation_select=all&managing_organisation_text_search=")
end
end
end
diff --git a/spec/helpers/filters_helper_spec.rb b/spec/helpers/filters_helper_spec.rb
index f04157521..c57f92311 100644
--- a/spec/helpers/filters_helper_spec.rb
+++ b/spec/helpers/filters_helper_spec.rb
@@ -175,27 +175,146 @@ RSpec.describe FiltersHelper do
context "with a support user" do
let(:user) { FactoryBot.create(:user, :support, organisation: child_organisation) }
- it "returns a list of all organisations" do
- expect(owning_organisation_filter_options(user)).to match_array([
- OpenStruct.new(id: "", name: "Select an option"),
- OpenStruct.new(id: child_organisation.id, name: "Child organisation"),
- OpenStruct.new(id: absorbed_organisation.id, name: "Absorbed organisation"),
- OpenStruct.new(id: parent_organisation.id, name: "Parent organisation"),
- OpenStruct.new(id: 99, name: "Other organisation"),
- ])
+ context "when no organisation is selected in the filters" do
+ it "returns an empty list" do
+ expect(owning_organisation_filter_options(user.reload, "lettings_logs")).to eq([
+ OpenStruct.new(id: "", name: "Select an option"),
+ ])
+ end
+ end
+
+ context "when a specific child organisation is selected in the filters" do
+ before do
+ session[:lettings_logs_filters] = { "owning_organisation": child_organisation.id }.to_json
+ end
+
+ it "returns the selected organisation in the list" do
+ expect(owning_organisation_filter_options(user.reload, "lettings_logs")).to eq([
+ OpenStruct.new(id: child_organisation.id, name: "Child organisation"),
+ ])
+ end
+ end
+
+ context "when a specific parent organisation is selected in the filters" do
+ before do
+ session[:lettings_logs_filters] = { "owning_organisation": parent_organisation.id }.to_json
+ end
+
+ it "returns the selected organisation in the list" do
+ expect(owning_organisation_filter_options(user.reload, "lettings_logs")).to eq([
+ OpenStruct.new(id: parent_organisation.id, name: "Parent organisation"),
+ ])
+ end
+ end
+
+ context "when a specific absorbed organisation is selected in the filters" do
+ before do
+ session[:lettings_logs_filters] = { "owning_organisation": absorbed_organisation.id }.to_json
+ end
+
+ it "returns the selected organisation in the list" do
+ expect(owning_organisation_filter_options(user.reload, "lettings_logs")).to eq([
+ OpenStruct.new(id: absorbed_organisation.id, name: "Absorbed organisation"),
+ ])
+ end
+ end
+
+ context "when a specific non related organisation is selected in the filters" do
+ let(:unrelated_organisation) { create(:organisation, name: "Unrelated organisation") }
+
+ before do
+ session[:lettings_logs_filters] = { "owning_organisation": unrelated_organisation.id }.to_json
+ end
+
+ it "returns the selected organisation in the list" do
+ expect(owning_organisation_filter_options(user.reload, "lettings_logs")).to eq([
+ OpenStruct.new(id: unrelated_organisation.id, name: "Unrelated organisation"),
+ ])
+ end
+ end
+
+ context "when a non existing organisation is selected in the filters" do
+ before do
+ session[:lettings_logs_filters] = { "owning_organisation": 143_542_542 }.to_json
+ end
+
+ it "returns an empty list" do
+ expect(owning_organisation_filter_options(user.reload, "lettings_logs")).to eq([
+ OpenStruct.new(id: "", name: "Select an option"),
+ ])
+ end
end
end
context "with a data coordinator user" do
let(:user) { FactoryBot.create(:user, :data_coordinator, organisation: child_organisation) }
- it "returns a list of parent orgs and your own organisation" do
- expect(owning_organisation_filter_options(user.reload)).to eq([
- OpenStruct.new(id: "", name: "Select an option"),
- OpenStruct.new(id: child_organisation.id, name: "Child organisation"),
- OpenStruct.new(id: parent_organisation.id, name: "Parent organisation"),
- OpenStruct.new(id: absorbed_organisation.id, name: "Absorbed organisation"),
- ])
+ context "when no organisation is selected in the filters" do
+ it "returns an empty list" do
+ expect(owning_organisation_filter_options(user.reload, "lettings_logs")).to eq([
+ OpenStruct.new(id: "", name: "Select an option"),
+ ])
+ end
+ end
+
+ context "when a specific child organisation is selected in the filters" do
+ before do
+ session[:lettings_logs_filters] = { "owning_organisation": child_organisation.id }.to_json
+ end
+
+ it "returns the selected organisation in the list" do
+ expect(owning_organisation_filter_options(user.reload, "lettings_logs")).to eq([
+ OpenStruct.new(id: child_organisation.id, name: "Child organisation"),
+ ])
+ end
+ end
+
+ context "when a specific parent organisation is selected in the filters" do
+ before do
+ session[:lettings_logs_filters] = { "owning_organisation": parent_organisation.id }.to_json
+ end
+
+ it "returns the selected organisation in the list" do
+ expect(owning_organisation_filter_options(user.reload, "lettings_logs")).to eq([
+ OpenStruct.new(id: parent_organisation.id, name: "Parent organisation"),
+ ])
+ end
+ end
+
+ context "when a specific absorbed organisation is selected in the filters" do
+ before do
+ session[:lettings_logs_filters] = { "owning_organisation": absorbed_organisation.id }.to_json
+ end
+
+ it "returns the selected organisation in the list" do
+ expect(owning_organisation_filter_options(user.reload, "lettings_logs")).to eq([
+ OpenStruct.new(id: absorbed_organisation.id, name: "Absorbed organisation"),
+ ])
+ end
+ end
+
+ context "when a specific non related organisation is selected in the filters" do
+ before do
+ session[:lettings_logs_filters] = { "owning_organisation": create(:organisation).id }.to_json
+ end
+
+ it "returns an empty list" do
+ expect(owning_organisation_filter_options(user.reload, "lettings_logs")).to eq([
+ OpenStruct.new(id: "", name: "Select an option"),
+ ])
+ end
+ end
+
+ context "when a non existing organisation is selected in the filters" do
+ before do
+ session[:lettings_logs_filters] = { "owning_organisation": 143_542_542 }.to_json
+ end
+
+ it "returns an empty list" do
+ expect(owning_organisation_filter_options(user.reload, "lettings_logs")).to eq([
+ OpenStruct.new(id: "", name: "Select an option"),
+ ])
+ end
end
end
end
@@ -214,27 +333,146 @@ RSpec.describe FiltersHelper do
context "with a support user" do
let(:user) { FactoryBot.create(:user, :support, organisation: parent_organisation) }
- it "returns a list of all organisations" do
- expect(managing_organisation_filter_options(user)).to eq([
- OpenStruct.new(id: "", name: "Select an option"),
- OpenStruct.new(id: parent_organisation.id, name: "Parent organisation"),
- OpenStruct.new(id: absorbed_organisation.id, name: "Absorbed organisation"),
- OpenStruct.new(id: child_organisation.id, name: "Child organisation"),
- OpenStruct.new(id: 99, name: "Other organisation"),
- ])
+ context "when no organisation is selected in the filters" do
+ it "returns an empty list" do
+ expect(managing_organisation_filter_options(user.reload, "lettings_logs")).to eq([
+ OpenStruct.new(id: "", name: "Select an option"),
+ ])
+ end
+ end
+
+ context "when a specific child organisation is selected in the filters" do
+ before do
+ session[:lettings_logs_filters] = { "managing_organisation": child_organisation.id }.to_json
+ end
+
+ it "returns the selected organisation in the list" do
+ expect(managing_organisation_filter_options(user.reload, "lettings_logs")).to eq([
+ OpenStruct.new(id: child_organisation.id, name: "Child organisation"),
+ ])
+ end
+ end
+
+ context "when a specific parent organisation is selected in the filters" do
+ before do
+ session[:lettings_logs_filters] = { "managing_organisation": parent_organisation.id }.to_json
+ end
+
+ it "returns the selected organisation in the list" do
+ expect(managing_organisation_filter_options(user.reload, "lettings_logs")).to eq([
+ OpenStruct.new(id: parent_organisation.id, name: "Parent organisation"),
+ ])
+ end
+ end
+
+ context "when a specific absorbed organisation is selected in the filters" do
+ before do
+ session[:lettings_logs_filters] = { "managing_organisation": absorbed_organisation.id }.to_json
+ end
+
+ it "returns the selected organisation in the list" do
+ expect(managing_organisation_filter_options(user.reload, "lettings_logs")).to eq([
+ OpenStruct.new(id: absorbed_organisation.id, name: "Absorbed organisation"),
+ ])
+ end
+ end
+
+ context "when a specific non related organisation is selected in the filters" do
+ let(:unrelated_organisation) { create(:organisation, name: "Unrelated organisation") }
+
+ before do
+ session[:lettings_logs_filters] = { "managing_organisation": unrelated_organisation.id }.to_json
+ end
+
+ it "returns the selected organisation in the list" do
+ expect(managing_organisation_filter_options(user.reload, "lettings_logs")).to eq([
+ OpenStruct.new(id: unrelated_organisation.id, name: "Unrelated organisation"),
+ ])
+ end
+ end
+
+ context "when a non existing organisation is selected in the filters" do
+ before do
+ session[:lettings_logs_filters] = { "managing_organisation": 143_542_542 }.to_json
+ end
+
+ it "returns an empty list" do
+ expect(managing_organisation_filter_options(user.reload, "lettings_logs")).to eq([
+ OpenStruct.new(id: "", name: "Select an option"),
+ ])
+ end
end
end
context "with a data coordinator user" do
let(:user) { FactoryBot.create(:user, :data_coordinator, organisation: parent_organisation) }
- it "returns a list of child orgs and your own organisation" do
- expect(managing_organisation_filter_options(user.reload)).to eq([
- OpenStruct.new(id: "", name: "Select an option"),
- OpenStruct.new(id: parent_organisation.id, name: "Parent organisation"),
- OpenStruct.new(id: child_organisation.id, name: "Child organisation"),
- OpenStruct.new(id: absorbed_organisation.id, name: "Absorbed organisation"),
- ])
+ context "when no organisation is selected in the filters" do
+ it "returns an empty list" do
+ expect(managing_organisation_filter_options(user.reload, "lettings_logs")).to eq([
+ OpenStruct.new(id: "", name: "Select an option"),
+ ])
+ end
+ end
+
+ context "when a specific child organisation is selected in the filters" do
+ before do
+ session[:lettings_logs_filters] = { "managing_organisation": child_organisation.id }.to_json
+ end
+
+ it "returns the selected organisation in the list" do
+ expect(managing_organisation_filter_options(user.reload, "lettings_logs")).to eq([
+ OpenStruct.new(id: child_organisation.id, name: "Child organisation"),
+ ])
+ end
+ end
+
+ context "when a specific parent organisation is selected in the filters" do
+ before do
+ session[:lettings_logs_filters] = { "managing_organisation": parent_organisation.id }.to_json
+ end
+
+ it "returns the selected organisation in the list" do
+ expect(managing_organisation_filter_options(user.reload, "lettings_logs")).to eq([
+ OpenStruct.new(id: parent_organisation.id, name: "Parent organisation"),
+ ])
+ end
+ end
+
+ context "when a specific absorbed organisation is selected in the filters" do
+ before do
+ session[:lettings_logs_filters] = { "managing_organisation": absorbed_organisation.id }.to_json
+ end
+
+ it "returns the selected organisation in the list" do
+ expect(managing_organisation_filter_options(user.reload, "lettings_logs")).to eq([
+ OpenStruct.new(id: absorbed_organisation.id, name: "Absorbed organisation"),
+ ])
+ end
+ end
+
+ context "when a specific non related organisation is selected in the filters" do
+ before do
+ session[:lettings_logs_filters] = { "managing_organisation": create(:organisation).id }.to_json
+ end
+
+ it "returns an empty list" do
+ expect(managing_organisation_filter_options(user.reload, "lettings_logs")).to eq([
+ OpenStruct.new(id: "", name: "Select an option"),
+ ])
+ end
+ end
+
+ context "when a non existing organisation is selected in the filters" do
+ before do
+ session[:lettings_logs_filters] = { "managing_organisation": 143_542_542 }.to_json
+ end
+
+ it "returns an empty list" do
+ expect(managing_organisation_filter_options(user.reload, "lettings_logs")).to eq([
+ OpenStruct.new(id: "", name: "Select an option"),
+ ])
+ end
end
end
end
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index edb998ac3..6a04e9a0b 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -164,7 +164,7 @@ RSpec.describe User, type: :model do
end
it "can filter lettings logs by user, year and status" do
- expect(user.logs_filters).to match_array(%w[years status needstypes assigned_to user bulk_upload_id])
+ expect(user.logs_filters).to match_array(%w[years status needstypes assigned_to user bulk_upload_id user_text_search])
end
end
@@ -174,7 +174,7 @@ RSpec.describe User, type: :model do
end
it "can filter lettings logs by user, year, status, managing_organisation and owning_organisation" do
- expect(user.logs_filters).to match_array(%w[years status needstypes assigned_to user managing_organisation owning_organisation bulk_upload_id])
+ expect(user.logs_filters).to match_array(%w[years status needstypes assigned_to user managing_organisation owning_organisation bulk_upload_id managing_organisation_text_search owning_organisation_text_search user_text_search])
end
end
end
@@ -215,7 +215,7 @@ RSpec.describe User, type: :model do
end
it "can filter lettings logs by user, year, status, managing_organisation and owning_organisation" do
- expect(user.logs_filters).to match_array(%w[years status needstypes assigned_to user owning_organisation managing_organisation bulk_upload_id])
+ expect(user.logs_filters).to match_array(%w[years status needstypes assigned_to user owning_organisation managing_organisation bulk_upload_id managing_organisation_text_search owning_organisation_text_search user_text_search])
end
end
diff --git a/spec/requests/organisations_controller_spec.rb b/spec/requests/organisations_controller_spec.rb
index 13879a38c..d3e8a8155 100644
--- a/spec/requests/organisations_controller_spec.rb
+++ b/spec/requests/organisations_controller_spec.rb
@@ -75,6 +75,13 @@ RSpec.describe OrganisationsController, type: :request do
end
end
end
+
+ describe "#search" do
+ it "redirects to the sign in page" do
+ get "/organisations/search"
+ expect(response).to redirect_to("/account/sign-in")
+ end
+ end
end
context "when user is signed in" do
@@ -807,6 +814,25 @@ RSpec.describe OrganisationsController, type: :request do
end
end
end
+
+ describe "#search" do
+ let(:parent_organisation) { create(:organisation, name: "parent test organisation") }
+ let(:child_organisation) { create(:organisation, name: "child test organisation") }
+
+ before do
+ user.organisation.update!(name: "test organisation")
+ create(:organisation_relationship, parent_organisation: user.organisation, child_organisation:)
+ create(:organisation_relationship, child_organisation: user.organisation, parent_organisation:)
+ create(:organisation, name: "other organisation test organisation")
+ end
+
+ it "only searches within the current user's organisation, managing agents and stock owners" do
+ get "/organisations/search", headers:, params: { query: "test organisation" }
+ result = JSON.parse(response.body)
+ expect(result.count).to eq(3)
+ expect(result.keys).to match_array([user.organisation.id.to_s, parent_organisation.id.to_s, child_organisation.id.to_s])
+ end
+ end
end
context "with a data provider user" do
@@ -2077,6 +2103,25 @@ RSpec.describe OrganisationsController, type: :request do
end
end
end
+
+ describe "#search" do
+ let(:parent_organisation) { create(:organisation, name: "parent test organisation") }
+ let(:child_organisation) { create(:organisation, name: "child test organisation") }
+ let!(:other_organisation) { create(:organisation, name: "other organisation test organisation") }
+
+ before do
+ user.organisation.update!(name: "test organisation")
+ create(:organisation_relationship, parent_organisation: user.organisation, child_organisation:)
+ create(:organisation_relationship, child_organisation: user.organisation, parent_organisation:)
+ end
+
+ it "searches within all the organisations" do
+ get "/organisations/search", headers:, params: { query: "test organisation" }
+ result = JSON.parse(response.body)
+ expect(result.count).to eq(4)
+ expect(result.keys).to match_array([user.organisation.id.to_s, parent_organisation.id.to_s, child_organisation.id.to_s, other_organisation.id.to_s])
+ end
+ end
end
end
diff --git a/spec/requests/users_controller_spec.rb b/spec/requests/users_controller_spec.rb
index bb0a1cca3..8e87f7f28 100644
--- a/spec/requests/users_controller_spec.rb
+++ b/spec/requests/users_controller_spec.rb
@@ -117,6 +117,13 @@ RSpec.describe UsersController, type: :request do
expect(response).to redirect_to("/account/sign-in")
end
end
+
+ describe "#search" do
+ it "redirects to the sign in page" do
+ get "/users/search"
+ expect(response).to redirect_to("/account/sign-in")
+ end
+ end
end
context "when user is signed in as a data provider" do
@@ -404,6 +411,25 @@ RSpec.describe UsersController, type: :request do
expect(response).to have_http_status(:unauthorized)
end
end
+
+ describe "#search" do
+ let(:parent_relationship) { create(:organisation_relationship, parent_organisation: user.organisation) }
+ let(:child_relationship) { create(:organisation_relationship, child_organisation: user.organisation) }
+ let!(:org_user) { create(:user, organisation: user.organisation, name: "test_name") }
+ let!(:managing_user) { create(:user, organisation: parent_relationship.child_organisation, name: "managing_agent_test_name") }
+
+ before do
+ create(:user, organisation: child_relationship.parent_organisation, name: "stock_owner_test_name")
+ create(:user, name: "other_organisation_test_name")
+ end
+
+ it "only searches within the current user's organisation and managing agents" do
+ get "/users/search", headers:, params: { query: "test_name" }
+ result = JSON.parse(response.body)
+ expect(result.count).to eq(2)
+ expect(result.keys).to match_array([org_user.id.to_s, managing_user.id.to_s])
+ end
+ end
end
context "when user is signed in as a data coordinator" do
@@ -1174,6 +1200,25 @@ RSpec.describe UsersController, type: :request do
expect(response).to have_http_status(:unauthorized)
end
end
+
+ describe "#search" do
+ let(:parent_relationship) { create(:organisation_relationship, parent_organisation: user.organisation) }
+ let(:child_relationship) { create(:organisation_relationship, child_organisation: user.organisation) }
+ let!(:org_user) { create(:user, organisation: user.organisation, email: "test_name@example.com") }
+ let!(:managing_user) { create(:user, organisation: parent_relationship.child_organisation, email: "managing_agent_test_name@example.com") }
+
+ before do
+ create(:user, email: "other_organisation_test_name@example.com")
+ create(:user, organisation: child_relationship.parent_organisation, email: "stock_owner_test_name@example.com")
+ end
+
+ it "only searches within the current user's organisation and managing agents" do
+ get "/users/search", headers:, params: { query: "test_name" }
+ result = JSON.parse(response.body)
+ expect(result.count).to eq(2)
+ expect(result.keys).to match_array([org_user.id.to_s, managing_user.id.to_s])
+ end
+ end
end
context "when user is signed in as a support user" do
@@ -2111,6 +2156,22 @@ RSpec.describe UsersController, type: :request do
expect(page).not_to have_link("User to be deleted")
end
end
+
+ describe "#search" do
+ let(:parent_relationship) { create(:organisation_relationship, parent_organisation: user.organisation) }
+ let(:child_relationship) { create(:organisation_relationship, child_organisation: user.organisation) }
+ let!(:org_user) { create(:user, organisation: user.organisation, name: "test_name") }
+ let!(:managing_user) { create(:user, organisation: child_relationship.parent_organisation, name: "stock_owner_test_name") }
+ let!(:owner_user) { create(:user, organisation: parent_relationship.child_organisation, name: "managing_agent_test_name") }
+ let!(:other_user) { create(:user, name: "other_organisation_test_name") }
+
+ it "searches all users" do
+ get "/users/search", headers:, params: { query: "test_name" }
+ result = JSON.parse(response.body)
+ expect(result.count).to eq(4)
+ expect(result.keys).to match_array([org_user.id.to_s, managing_user.id.to_s, owner_user.id.to_s, other_user.id.to_s])
+ end
+ end
end
describe "title link" do