mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-04-02 06:51:40 +00:00
Add ajax search controller
This commit is contained in:
@@ -1,23 +1,21 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module Products
|
||||
module AjaxSearch
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
def search_producers
|
||||
module Admin
|
||||
class AjaxSearchController < Spree::Admin::BaseController
|
||||
def producers
|
||||
query = OpenFoodNetwork::Permissions.new(spree_current_user)
|
||||
.managed_product_enterprises.is_primary_producer.by_name
|
||||
|
||||
render json: build_search_response(query)
|
||||
end
|
||||
|
||||
def search_categories
|
||||
def categories
|
||||
query = Spree::Taxon.all
|
||||
|
||||
render json: build_search_response(query)
|
||||
end
|
||||
|
||||
def search_tax_categories
|
||||
def tax_categories
|
||||
query = Spree::TaxCategory.all
|
||||
|
||||
render json: build_search_response(query)
|
||||
@@ -4,7 +4,6 @@
|
||||
module Admin
|
||||
class ProductsV3Controller < Spree::Admin::BaseController
|
||||
helper ProductsHelper
|
||||
include ::Products::AjaxSearch
|
||||
|
||||
before_action :init_filters_params
|
||||
before_action :init_pagination_params
|
||||
|
||||
@@ -228,12 +228,11 @@ module Spree
|
||||
:destroy,
|
||||
:destroy_variant,
|
||||
:clone,
|
||||
:create_linked_variant,
|
||||
:search_producers,
|
||||
:search_categories,
|
||||
:search_tax_categories
|
||||
:create_linked_variant
|
||||
], :products_v3
|
||||
|
||||
can [:admin, :producers, :categories, :tax_categories], :ajax_search
|
||||
|
||||
can [:create], Spree::Variant
|
||||
can [:admin, :index, :read, :edit,
|
||||
:update, :search, :delete, :destroy], Spree::Variant do |variant|
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
aria_label: t('.producers.label'),
|
||||
options: selected_option(producer_id, Enterprise),
|
||||
selected_option: producer_id,
|
||||
remote_url: admin_products_search_producers_url,
|
||||
remote_url: admin_ajax_search_producers_url,
|
||||
include_blank: t('.all_producers'),
|
||||
placeholder_value: t('.search_for_producers')))
|
||||
.categories
|
||||
@@ -22,7 +22,7 @@
|
||||
aria_label: t('.categories.label'),
|
||||
options: selected_option(category_id, Spree::Taxon),
|
||||
selected_option: category_id,
|
||||
remote_url: admin_products_search_categories_url,
|
||||
remote_url: admin_ajax_search_categories_url,
|
||||
include_blank: t('.all_categories'),
|
||||
placeholder_value: t('.search_for_categories')))
|
||||
-if variant_tag_enabled?(spree_current_user)
|
||||
|
||||
@@ -61,7 +61,7 @@
|
||||
aria_label: t('.producer_field_name'),
|
||||
options: variant.supplier_id ? [[variant.supplier.name, variant.supplier_id]] : [],
|
||||
selected_option: variant.supplier_id,
|
||||
remote_url: admin_products_search_producers_url,
|
||||
remote_url: admin_ajax_search_producers_url,
|
||||
placeholder_value: t('admin.products_v3.filters.select_producer')))
|
||||
= error_message_on variant, :supplier
|
||||
%td.col-category.field.naked_inputs
|
||||
@@ -70,7 +70,7 @@
|
||||
options: variant.primary_taxon_id ? [[variant.primary_taxon.name, variant.primary_taxon_id]] : [],
|
||||
selected_option: variant.primary_taxon_id,
|
||||
aria_label: t('.category_field_name'),
|
||||
remote_url: admin_products_search_categories_url,
|
||||
remote_url: admin_ajax_search_categories_url,
|
||||
placeholder_value: t('admin.products_v3.filters.select_category')))
|
||||
= error_message_on variant, :primary_taxon
|
||||
%td.col-tax_category.field.naked_inputs
|
||||
@@ -80,7 +80,7 @@
|
||||
selected_option: variant.tax_category_id,
|
||||
aria_label: t('.tax_category_field_name'),
|
||||
include_blank: t('.none_tax_category'),
|
||||
remote_url: admin_products_search_tax_categories_url,
|
||||
remote_url: admin_ajax_search_tax_categories_url,
|
||||
placeholder_value: t('.search_for_tax_categories')))
|
||||
= error_message_on variant, :tax_category
|
||||
- if variant_tag_enabled?(spree_current_user)
|
||||
|
||||
@@ -27,7 +27,7 @@ FileUtils.chdir APP_ROOT do
|
||||
system("bundle check 2> /dev/null") || system!(BUNDLE_ENV, "bundle install")
|
||||
|
||||
# Install JavaScript dependencies
|
||||
system!("script/nodenv-install.sh")
|
||||
system("script/nodenv-install.sh")
|
||||
system!("bin/yarn")
|
||||
|
||||
# puts "\n== Copying sample files =="
|
||||
|
||||
@@ -83,9 +83,13 @@ Openfoodnetwork::Application.routes.draw do
|
||||
delete 'products_v3/destroy_variant/:id', to: 'products_v3#destroy_variant', as: 'destroy_variant'
|
||||
post 'clone/:id', to: 'products_v3#clone', as: 'clone_product'
|
||||
post 'products/create_linked_variant', to: 'products_v3#create_linked_variant', as: 'create_linked_variant'
|
||||
get 'products_v3/search_producers', to: 'products_v3#search_producers', as: 'products_search_producers'
|
||||
get 'products_v3/search_categories', to: 'products_v3#search_categories', as: 'products_search_categories'
|
||||
get 'products_v3/search_tax_categories', to: 'products_v3#search_tax_categories', as: 'products_search_tax_categories'
|
||||
|
||||
scope :ajax_search, as: :ajax_search, controller: :ajax_search do
|
||||
get :producers
|
||||
get :categories
|
||||
get :tax_categories
|
||||
end
|
||||
|
||||
resources :product_preview, only: [:show]
|
||||
|
||||
resources :variant_overrides do
|
||||
|
||||
285
spec/requests/admin/ajax_search_controller_spec.rb
Normal file
285
spec/requests/admin/ajax_search_controller_spec.rb
Normal file
@@ -0,0 +1,285 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
RSpec.describe "Admin::AjaxSearch" do
|
||||
include AuthenticationHelper
|
||||
|
||||
let(:admin_user) { create(:admin_user) }
|
||||
let(:regular_user) { create(:user) }
|
||||
|
||||
describe "GET /admin/ajax_search/producers" do
|
||||
context "when user is not logged in" do
|
||||
it "redirects to login" do
|
||||
get admin_ajax_search_producers_path
|
||||
|
||||
expect(response).to redirect_to %r|#/login$|
|
||||
end
|
||||
end
|
||||
|
||||
context "when user is logged in without permissions" do
|
||||
before { login_as regular_user }
|
||||
|
||||
it "redirects to unauthorized" do
|
||||
get admin_ajax_search_producers_path
|
||||
|
||||
expect(response).to redirect_to('/unauthorized')
|
||||
end
|
||||
end
|
||||
|
||||
context "when user is an admin" do
|
||||
before { login_as admin_user }
|
||||
|
||||
let!(:producer1) { create(:supplier_enterprise, name: "Apple Farm") }
|
||||
let!(:producer2) { create(:supplier_enterprise, name: "Berry Farm") }
|
||||
let!(:producer3) { create(:supplier_enterprise, name: "Cherry Orchard") }
|
||||
let!(:distributor) { create(:distributor_enterprise, name: "Distributor") }
|
||||
|
||||
it "returns producers sorted alphabetically by name" do
|
||||
get admin_ajax_search_producers_path
|
||||
|
||||
expect(response).to have_http_status(:ok)
|
||||
json_response = response.parsed_body
|
||||
|
||||
expect(json_response["results"].pluck("label")).to eq(['Apple Farm', 'Berry Farm',
|
||||
'Cherry Orchard'])
|
||||
expect(json_response["pagination"]["more"]).to be false
|
||||
end
|
||||
|
||||
it "filters producers by search query" do
|
||||
get admin_ajax_search_producers_path, params: { q: "berry" }
|
||||
|
||||
json_response = response.parsed_body
|
||||
expect(json_response["results"].pluck("label")).to eq(['Berry Farm'])
|
||||
expect(json_response["results"].pluck("value")).to eq([producer2.id])
|
||||
end
|
||||
|
||||
it "filters are case insensitive" do
|
||||
get admin_ajax_search_producers_path, params: { q: "BERRY" }
|
||||
|
||||
json_response = response.parsed_body
|
||||
expect(json_response["results"].pluck("label")).to eq(['Berry Farm'])
|
||||
end
|
||||
|
||||
it "filters with partial matches" do
|
||||
get admin_ajax_search_producers_path, params: { q: "Farm" }
|
||||
|
||||
json_response = response.parsed_body
|
||||
expect(json_response["results"].pluck("label")).to eq(['Apple Farm', 'Berry Farm'])
|
||||
end
|
||||
|
||||
it "excludes non-producer enterprises" do
|
||||
get admin_ajax_search_producers_path
|
||||
|
||||
json_response = response.parsed_body
|
||||
expect(json_response["results"].pluck("label")).not_to include('Distributor')
|
||||
end
|
||||
|
||||
context "with more than 30 producers" do
|
||||
before do
|
||||
create_list(:supplier_enterprise, 35) do |enterprise, i|
|
||||
enterprise.update!(name: "Producer #{(i + 1).to_s.rjust(2, '0')}")
|
||||
end
|
||||
end
|
||||
|
||||
it "returns first page with 30 results and more flag as true" do
|
||||
get admin_ajax_search_producers_path, params: { page: 1 }
|
||||
|
||||
json_response = response.parsed_body
|
||||
expect(json_response["results"].length).to eq(30)
|
||||
expect(json_response["pagination"]["more"]).to be true
|
||||
end
|
||||
|
||||
it "returns remaining results on second page with more flag as false" do
|
||||
get admin_ajax_search_producers_path, params: { page: 2 }
|
||||
|
||||
json_response = response.parsed_body
|
||||
expect(json_response["results"].length).to eq(8)
|
||||
expect(json_response["pagination"]["more"]).to be false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "when user has enterprise permissions" do
|
||||
let!(:my_producer) { create(:supplier_enterprise, name: "My Producer") }
|
||||
let!(:other_producer) { create(:supplier_enterprise, name: "Other Producer") }
|
||||
let(:user_with_producer) { create(:user, enterprises: [my_producer]) }
|
||||
|
||||
before { login_as user_with_producer }
|
||||
|
||||
it "returns only managed producers" do
|
||||
get admin_ajax_search_producers_path
|
||||
|
||||
json_response = response.parsed_body
|
||||
expect(json_response["results"].pluck("label")).to eq(['My Producer'])
|
||||
expect(json_response["results"].pluck("label")).not_to include('Other Producer')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "GET /admin/ajax_search/categories" do
|
||||
context "when user is not logged in" do
|
||||
it "redirects to login" do
|
||||
get admin_ajax_search_categories_path
|
||||
|
||||
expect(response).to redirect_to %r|#/login$|
|
||||
end
|
||||
end
|
||||
|
||||
context "when user is logged in without permissions" do
|
||||
before { login_as regular_user }
|
||||
|
||||
it "redirects to unauthorized" do
|
||||
get admin_ajax_search_categories_path
|
||||
|
||||
expect(response).to redirect_to('/unauthorized')
|
||||
end
|
||||
end
|
||||
|
||||
context "when user is an admin" do
|
||||
before { login_as admin_user }
|
||||
|
||||
let!(:category1) { create(:taxon, name: "Vegetables") }
|
||||
let!(:category2) { create(:taxon, name: "Fruits") }
|
||||
let!(:category3) { create(:taxon, name: "Dairy") }
|
||||
|
||||
it "returns categories sorted alphabetically by name" do
|
||||
get admin_ajax_search_categories_path
|
||||
|
||||
expect(response).to have_http_status(:ok)
|
||||
json_response = response.parsed_body
|
||||
|
||||
expect(json_response["results"].pluck("label")).to eq(['Dairy', 'Fruits', 'Vegetables'])
|
||||
expect(json_response["pagination"]["more"]).to be false
|
||||
end
|
||||
|
||||
it "filters categories by search query" do
|
||||
get admin_ajax_search_categories_path, params: { q: "fruit" }
|
||||
|
||||
json_response = response.parsed_body
|
||||
expect(json_response["results"].pluck("label")).to eq(['Fruits'])
|
||||
expect(json_response["results"].pluck("value")).to eq([category2.id])
|
||||
end
|
||||
|
||||
it "filters are case insensitive" do
|
||||
get admin_ajax_search_categories_path, params: { q: "VEGETABLES" }
|
||||
|
||||
json_response = response.parsed_body
|
||||
expect(json_response["results"].pluck("label")).to eq(['Vegetables'])
|
||||
end
|
||||
|
||||
it "filters with partial matches" do
|
||||
get admin_ajax_search_categories_path, params: { q: "ege" }
|
||||
|
||||
json_response = response.parsed_body
|
||||
expect(json_response["results"].pluck("label")).to eq(['Vegetables'])
|
||||
end
|
||||
|
||||
context "with more than 30 categories" do
|
||||
before do
|
||||
create_list(:taxon, 35) do |taxon, i|
|
||||
taxon.update!(name: "Category #{(i + 1).to_s.rjust(2, '0')}")
|
||||
end
|
||||
end
|
||||
|
||||
it "returns first page with 30 results and more flag as true" do
|
||||
get admin_ajax_search_categories_path, params: { page: 1 }
|
||||
|
||||
json_response = response.parsed_body
|
||||
expect(json_response["results"].length).to eq(30)
|
||||
expect(json_response["pagination"]["more"]).to be true
|
||||
end
|
||||
|
||||
it "returns remaining results on second page with more flag as false" do
|
||||
get admin_ajax_search_categories_path, params: { page: 2 }
|
||||
|
||||
json_response = response.parsed_body
|
||||
expect(json_response["results"].length).to eq(8)
|
||||
expect(json_response["pagination"]["more"]).to be false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "GET /admin/ajax_search/tax_categories" do
|
||||
context "when user is not logged in" do
|
||||
it "redirects to login" do
|
||||
get admin_ajax_search_tax_categories_path
|
||||
|
||||
expect(response).to redirect_to %r|#/login$|
|
||||
end
|
||||
end
|
||||
|
||||
context "when user is logged in without permissions" do
|
||||
before { login_as regular_user }
|
||||
|
||||
it "redirects to unauthorized" do
|
||||
get admin_ajax_search_tax_categories_path
|
||||
|
||||
expect(response).to redirect_to('/unauthorized')
|
||||
end
|
||||
end
|
||||
|
||||
context "when user is an admin" do
|
||||
before { login_as admin_user }
|
||||
|
||||
let!(:tax_cat1) { create(:tax_category, name: "GST") }
|
||||
let!(:tax_cat2) { create(:tax_category, name: "VAT") }
|
||||
let!(:tax_cat3) { create(:tax_category, name: "No Tax") }
|
||||
|
||||
it "returns tax categories sorted alphabetically by name" do
|
||||
get admin_ajax_search_tax_categories_path
|
||||
|
||||
expect(response).to have_http_status(:ok)
|
||||
json_response = response.parsed_body
|
||||
|
||||
expect(json_response["results"].pluck("label")).to eq(['GST', 'No Tax', 'VAT'])
|
||||
expect(json_response["pagination"]["more"]).to be false
|
||||
end
|
||||
|
||||
it "filters tax categories by search query" do
|
||||
get admin_ajax_search_tax_categories_path, params: { q: "vat" }
|
||||
|
||||
json_response = response.parsed_body
|
||||
expect(json_response["results"].pluck("label")).to eq(['VAT'])
|
||||
expect(json_response["results"].pluck("value")).to eq([tax_cat2.id])
|
||||
end
|
||||
|
||||
it "filters are case insensitive" do
|
||||
get admin_ajax_search_tax_categories_path, params: { q: "GST" }
|
||||
|
||||
json_response = response.parsed_body
|
||||
expect(json_response["results"].pluck("label")).to eq(['GST'])
|
||||
end
|
||||
|
||||
it "filters with partial matches" do
|
||||
get admin_ajax_search_tax_categories_path, params: { q: "tax" }
|
||||
|
||||
json_response = response.parsed_body
|
||||
expect(json_response["results"].pluck("label")).to eq(['No Tax'])
|
||||
end
|
||||
|
||||
context "with more than 30 tax categories" do
|
||||
before do
|
||||
create_list(:tax_category, 35) do |tax_cat, i|
|
||||
tax_cat.update!(name: "Tax Category #{(i + 1).to_s.rjust(2, '0')}")
|
||||
end
|
||||
end
|
||||
|
||||
it "returns first page with 30 results and more flag as true" do
|
||||
get admin_ajax_search_tax_categories_path, params: { page: 1 }
|
||||
|
||||
json_response = response.parsed_body
|
||||
expect(json_response["results"].length).to eq(30)
|
||||
expect(json_response["pagination"]["more"]).to be true
|
||||
end
|
||||
|
||||
it "returns remaining results on second page with more flag as false" do
|
||||
get admin_ajax_search_tax_categories_path, params: { page: 2 }
|
||||
|
||||
json_response = response.parsed_body
|
||||
expect(json_response["results"].length).to eq(8)
|
||||
expect(json_response["pagination"]["more"]).to be false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user