Browse Source

Allow searching organisations

pull/2535/head
Kat 2 years ago committed by kosiakkatrina
parent
commit
cae1656831
  1. 15
      app/controllers/organisations_controller.rb
  2. 8
      app/frontend/controllers/search_controller.js
  3. 16
      app/frontend/modules/search.js
  4. 38
      app/helpers/filters_helper.rb
  5. 1
      app/models/organisation.rb
  6. 2
      app/views/filters/_select_filter.html.erb
  7. 2
      app/views/filters/managed_by.html.erb
  8. 2
      app/views/filters/owned_by.html.erb
  9. 6
      app/views/logs/_log_filters.html.erb
  10. 4
      config/routes.rb
  11. 45
      spec/requests/organisations_controller_spec.rb

15
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

8
app/frontend/controllers/search_controller.js

@ -11,8 +11,8 @@ const populateOptions = (results, selectEl) => {
const option = document.createElement('option')
option.value = key
option.innerHTML = searchableName(results[key])
option.setAttribute('data-hint', results[key].hint)
option.textContent = searchableName(results[key])
if (results[key].hint) { option.setAttribute('data-hint', results[key].hint) }
option.setAttribute('text', searchableName(results[key]))
selectEl.appendChild(option)
options.push(option)
})
@ -23,14 +23,14 @@ export default class extends Controller {
const selectEl = this.element
const matches = /^(\w+)\[(\w+)\]$/.exec(selectEl.name)
const rawFieldName = matches ? `${matches[1]}[${matches[2]}_raw]` : ''
const relativeUrlRoute = JSON.parse(this.element.dataset.info).relative_url_route
const searchUrl = JSON.parse(this.element.dataset.info).search_url
accessibleAutocomplete.enhanceSelectElement({
defaultValue: '',
selectElement: selectEl,
minLength: 1,
source: (query, populateResults) => {
fetchAndPopulateSearchResults(query, populateResults, relativeUrlRoute, populateOptions, selectEl)
fetchAndPopulateSearchResults(query, populateResults, searchUrl, populateOptions, selectEl)
},
autoselect: true,
placeholder: 'Start typing to search',

16
app/frontend/modules/search.js

@ -119,8 +119,9 @@ export const suggestion = (value, options) => {
export const searchSuggestion = (value, options) => {
try {
const result = enhanceOption(options.find((o) => o.innerHTML === value))
if (result) {
const option = options.find((o) => o.innerHTML === value)
if (option) {
const result = enhanceOption(option)
const html = result.append ? `<span class="autocomplete__option__append">${result.text}</span> <span>${result.append}</span>` : `<span>${result.text}</span>`
return result.hint ? `${html}<div class="autocomplete__option__hint">${result.hint}</div>` : html
} else {
@ -151,14 +152,9 @@ export const fetchAndPopulateSearchResults = async (query, populateResults, rela
}
}
export const fetchUserOptions = async (query, relativeUrlRoute) => {
export const fetchUserOptions = async (query, searchUrl) => {
try {
let response
if (relativeUrlRoute) {
response = await fetch(`${relativeUrlRoute}/users/search?query=${encodeURIComponent(query)}`)
} else {
response = await fetch(`/users/search?query=${encodeURIComponent(query)}`)
}
const response = await fetch(`${searchUrl}?query=${encodeURIComponent(query)}`)
const results = await response.json()
return results
} catch (error) {
@ -172,7 +168,7 @@ export const getSearchableName = (option) => {
}
export const searchableName = (option) => {
return option.value + ' ' + option.hint
return option.hint ? option.value + ' ' + option.hint : option.value
}
export const confirmSelectedOption = (selectEl, val) => {

38
app/helpers/filters_helper.rb

@ -84,13 +84,31 @@ module FiltersHelper
JSON.parse(session[session_name_for(filter_type)])[filter] || ""
end
def 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) }
def owning_organisation_filter_options(_user, filter_type)
if applied_filters(filter_type)["owning_organisation"].present?
org = Organisation.find(applied_filters(filter_type)["owning_organisation"]) # make sure this doesn't expose anything weird
[OpenStruct.new(id: org.id, name: org.name)]
else
[OpenStruct.new(id: "", name: "Select an option")]
end
end
def assigned_to_filter_options
[OpenStruct.new(id: "", name: "Select an option", hint: "")]
def assigned_to_filter_options(filter_type)
if applied_filters(filter_type)["assigned_to"] == "specific_user"
user = User.find(applied_filters(filter_type)["user"]) # make sure this doesn't expose anything weird
[OpenStruct.new(id: user.id, name: user.name, hint: user.email)]
else
[OpenStruct.new(id: "", name: "Select an option", hint: "")]
end
end
def filter_search_url(category)
case category
when :user
ENV["RAILS_RELATIVE_URL_ROOT"].present? ? "#{ENV['RAILS_RELATIVE_URL_ROOT']}/users/search" : "/users/search"
when :owning_organisation, :managing_organisation
ENV["RAILS_RELATIVE_URL_ROOT"].present? ? "#{ENV['RAILS_RELATIVE_URL_ROOT']}/organisations/search" : "/organisations/search"
end
end
def collection_year_options
@ -124,9 +142,13 @@ module FiltersHelper
end
end
def managing_organisation_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) }
def managing_organisation_filter_options(_user, filter_type)
if applied_filters(filter_type)["managing_organisation"].present?
org = Organisation.find(applied_filters(filter_type)["managing_organisation"]) # make sure this doesn't expose anything weird
[OpenStruct.new(id: org.id, name: org.name)]
else
[OpenStruct.new(id: "", name: "Select an option")]
end
end
def show_scheme_managing_org_filter?(user)

1
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).map(&:id)) }
def affiliated_stock_owners
ids = []

2
app/views/filters/_select_filter.html.erb

@ -1,7 +1,7 @@
<%= f.govuk_select(category.to_sym,
label: { text: label, hidden: secondary },
"data-controller": "search conditional-filter",
"data-info": {relative_url_route: ENV["RAILS_RELATIVE_URL_ROOT"]}.to_json) do %>
"data-info": { search_url: filter_search_url(category.to_sym) }.to_json) do %>
<% collection.each do |answer| %>
<option value="<%= answer.id %>"
data-hint="<%= answer.hint %>"

2
app/views/filters/managed_by.html.erb

@ -9,7 +9,7 @@
type: "select",
label: "Managed by",
category: "managing_organisation",
options: managing_organisation_filter_options(current_user),
options: managing_organisation_filter_options(current_user, @filter_type),
},
},
},

2
app/views/filters/owned_by.html.erb

@ -9,7 +9,7 @@
type: "select",
label: "Owning Organisation",
category: "owning_organisation",
options: owning_organisation_filter_options(current_user),
options: owning_organisation_filter_options(current_user, @filter_type),
},
},
},

6
app/views/logs/_log_filters.html.erb

@ -69,7 +69,7 @@
type: "select",
label: "User",
category: "user",
options: assigned_to_filter_options,
options: assigned_to_filter_options(@filter_type),
},
},
},
@ -89,7 +89,7 @@
type: "select",
label: "Owning Organisation",
category: "owning_organisation",
options: owning_organisation_filter_options(current_user),
options: owning_organisation_filter_options(current_user, @filter_type),
},
},
},
@ -110,7 +110,7 @@
type: "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),
},
},
},

4
config/routes.rb

@ -195,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

45
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

Loading…
Cancel
Save