From aa3c1aa0fe4d9fdd4a89acc17e00b73dd6735da6 Mon Sep 17 00:00:00 2001 From: luisramos0 Date: Thu, 1 Aug 2019 14:30:11 +0100 Subject: [PATCH] Remove Spree module declaration from these files as they were moved out of the spree namespace --- app/controllers/api/products_controller.rb | 190 +++++----- app/controllers/api/variants_controller.rb | 130 ++++--- .../api/products_controller_spec.rb | 358 +++++++++--------- .../api/variants_controller_spec.rb | 330 ++++++++-------- 4 files changed, 500 insertions(+), 508 deletions(-) diff --git a/app/controllers/api/products_controller.rb b/app/controllers/api/products_controller.rb index 8a8d4475f5..6efa38806c 100644 --- a/app/controllers/api/products_controller.rb +++ b/app/controllers/api/products_controller.rb @@ -1,126 +1,124 @@ require 'open_food_network/permissions' -module Spree - module Api - class ProductsController < ::Api::BaseController - respond_to :json +module Api + class ProductsController < ::Api::BaseController + respond_to :json - skip_authorization_check only: [:show, :bulk_products, :overridable] + skip_authorization_check only: [:show, :bulk_products, :overridable] - def show - @product = find_product(params[:id]) - render json: @product, serializer: ::Api::Admin::ProductSerializer - end + def show + @product = find_product(params[:id]) + render json: @product, serializer: ::Api::Admin::ProductSerializer + end - def create - authorize! :create, Product - params[:product][:available_on] ||= Time.zone.now - @product = Product.new(params[:product]) - begin - if @product.save - render json: @product, serializer: ::Api::Admin::ProductSerializer, status: 201 - else - invalid_resource!(@product) - end - rescue ActiveRecord::RecordNotUnique - @product.permalink = nil - retry - end - end - - def update - authorize! :update, Product - @product = find_product(params[:id]) - if @product.update_attributes(params[:product]) - render json: @product, serializer: ::Api::Admin::ProductSerializer, status: 200 + def create + authorize! :create, Product + params[:product][:available_on] ||= Time.zone.now + @product = Product.new(params[:product]) + begin + if @product.save + render json: @product, serializer: ::Api::Admin::ProductSerializer, status: 201 else invalid_resource!(@product) end + rescue ActiveRecord::RecordNotUnique + @product.permalink = nil + retry end + end - def destroy - authorize! :delete, Product - @product = find_product(params[:id]) - @product.update_attribute(:deleted_at, Time.zone.now) - @product.variants_including_master.update_all(deleted_at: Time.zone.now) - render json: @product, serializer: ::Api::Admin::ProductSerializer, status: 204 + def update + authorize! :update, Product + @product = find_product(params[:id]) + if @product.update_attributes(params[:product]) + render json: @product, serializer: ::Api::Admin::ProductSerializer, status: 200 + else + invalid_resource!(@product) end + end - # TODO: This should be named 'managed'. Is the action above used? Maybe we should remove it. - def bulk_products - @products = OpenFoodNetwork::Permissions.new(current_api_user).editable_products. - merge(product_scope). - order('created_at DESC'). - ransack(params[:q]).result. - page(params[:page]).per(params[:per_page]) + def destroy + authorize! :delete, Product + @product = find_product(params[:id]) + @product.update_attribute(:deleted_at, Time.zone.now) + @product.variants_including_master.update_all(deleted_at: Time.zone.now) + render json: @product, serializer: ::Api::Admin::ProductSerializer, status: 204 + end - render_paged_products @products - end + # TODO: This should be named 'managed'. Is the action above used? Maybe we should remove it. + def bulk_products + @products = OpenFoodNetwork::Permissions.new(current_api_user).editable_products. + merge(product_scope). + order('created_at DESC'). + ransack(params[:q]).result. + page(params[:page]).per(params[:per_page]) - def overridable - producers = OpenFoodNetwork::Permissions.new(current_api_user). - variant_override_producers.by_name + render_paged_products @products + end - @products = paged_products_for_producers producers + def overridable + producers = OpenFoodNetwork::Permissions.new(current_api_user). + variant_override_producers.by_name - render_paged_products @products - end + @products = paged_products_for_producers producers - def soft_delete - authorize! :delete, Spree::Product - @product = find_product(params[:product_id]) - authorize! :delete, @product - @product.destroy - render json: @product, serializer: ::Api::Admin::ProductSerializer, status: 204 - end + render_paged_products @products + end - # POST /api/products/:product_id/clone - # - def clone - authorize! :create, Spree::Product - original_product = find_product(params[:product_id]) - authorize! :update, original_product + def soft_delete + authorize! :delete, Spree::Product + @product = find_product(params[:product_id]) + authorize! :delete, @product + @product.destroy + render json: @product, serializer: ::Api::Admin::ProductSerializer, status: 204 + end - @product = original_product.duplicate + # POST /api/products/:product_id/clone + # + def clone + authorize! :create, Spree::Product + original_product = find_product(params[:product_id]) + authorize! :update, original_product - render json: @product, serializer: ::Api::Admin::ProductSerializer, status: 201 - end + @product = original_product.duplicate - private + render json: @product, serializer: ::Api::Admin::ProductSerializer, status: 201 + end - # Copied and modified from Spree::Api::BaseController to allow - # enterprise users to access inactive products - def product_scope - # This line modified - if current_api_user.has_spree_role?("admin") || current_api_user.enterprises.present? - scope = Spree::Product - if params[:show_deleted] - scope = scope.with_deleted - end - else - scope = Spree::Product.active + private + + # Copied and modified from Spree::Api::BaseController to allow + # enterprise users to access inactive products + def product_scope + # This line modified + if current_api_user.has_spree_role?("admin") || current_api_user.enterprises.present? + scope = Spree::Product + if params[:show_deleted] + scope = scope.with_deleted end - - scope.includes(:master) + else + scope = Spree::Product.active end - def paged_products_for_producers(producers) - Spree::Product.scoped. - merge(product_scope). - where(supplier_id: producers). - by_producer.by_name. - ransack(params[:q]).result. - page(params[:page]).per(params[:per_page]) - end + scope.includes(:master) + end - def render_paged_products(products) - serializer = ActiveModel::ArraySerializer.new( - products, - each_serializer: ::Api::Admin::ProductSerializer - ) + def paged_products_for_producers(producers) + Spree::Product.scoped. + merge(product_scope). + where(supplier_id: producers). + by_producer.by_name. + ransack(params[:q]).result. + page(params[:page]).per(params[:per_page]) + end - render text: { products: serializer, pages: products.num_pages }.to_json - end + def render_paged_products(products) + serializer = ActiveModel::ArraySerializer.new( + products, + each_serializer: ::Api::Admin::ProductSerializer + ) + + render text: { products: serializer, pages: products.num_pages }.to_json end end end diff --git a/app/controllers/api/variants_controller.rb b/app/controllers/api/variants_controller.rb index 2f1e6ab342..8c5ddafc39 100644 --- a/app/controllers/api/variants_controller.rb +++ b/app/controllers/api/variants_controller.rb @@ -1,81 +1,79 @@ -module Spree - module Api - class VariantsController < ::Api::BaseController - respond_to :json +module Api + class VariantsController < ::Api::BaseController + respond_to :json - skip_authorization_check only: [:index, :show] - before_filter :product + skip_authorization_check only: [:index, :show] + before_filter :product - def index - @variants = scope.includes(:option_values).ransack(params[:q]).result - render json: @variants, each_serializer: ::Api::VariantSerializer + def index + @variants = scope.includes(:option_values).ransack(params[:q]).result + render json: @variants, each_serializer: ::Api::VariantSerializer + end + + def show + @variant = scope.includes(:option_values).find(params[:id]) + render json: @variant, serializer: ::Api::VariantSerializer + end + + def create + authorize! :create, Variant + @variant = scope.new(params[:variant]) + if @variant.save + render json: @variant, serializer: ::Api::VariantSerializer, status: 201 + else + invalid_resource!(@variant) end + end - def show - @variant = scope.includes(:option_values).find(params[:id]) - render json: @variant, serializer: ::Api::VariantSerializer + def update + authorize! :update, Variant + @variant = scope.find(params[:id]) + if @variant.update_attributes(params[:variant]) + render json: @variant, serializer: ::Api::VariantSerializer, status: 200 + else + invalid_resource!(@product) end + end - def create - authorize! :create, Variant - @variant = scope.new(params[:variant]) - if @variant.save - render json: @variant, serializer: ::Api::VariantSerializer, status: 201 + def soft_delete + @variant = scope.find(params[:variant_id]) + authorize! :delete, @variant + + VariantDeleter.new.delete(@variant) + render json: @variant, serializer: ::Api::VariantSerializer, status: 204 + end + + def destroy + authorize! :delete, Variant + @variant = scope.find(params[:id]) + @variant.destroy + render json: @variant, serializer: ::Api::VariantSerializer, status: 204 + end + + private + + def product + @product ||= Spree::Product.find_by_permalink(params[:product_id]) if params[:product_id] + end + + def scope + if @product + unless current_api_user.has_spree_role?("admin") || params[:show_deleted] + variants = @product.variants_including_master else - invalid_resource!(@variant) + variants = @product.variants_including_master.with_deleted end - end - - def update - authorize! :update, Variant - @variant = scope.find(params[:id]) - if @variant.update_attributes(params[:variant]) - render json: @variant, serializer: ::Api::VariantSerializer, status: 200 - else - invalid_resource!(@product) - end - end - - def soft_delete - @variant = scope.find(params[:variant_id]) - authorize! :delete, @variant - - VariantDeleter.new.delete(@variant) - render json: @variant, serializer: ::Api::VariantSerializer, status: 204 - end - - def destroy - authorize! :delete, Variant - @variant = scope.find(params[:id]) - @variant.destroy - render json: @variant, serializer: ::Api::VariantSerializer, status: 204 - end - - private - - def product - @product ||= Spree::Product.find_by_permalink(params[:product_id]) if params[:product_id] - end - - def scope - if @product - unless current_api_user.has_spree_role?("admin") || params[:show_deleted] - variants = @product.variants_including_master - else - variants = @product.variants_including_master.with_deleted + else + variants = Variant.scoped + if current_api_user.has_spree_role?("admin") + unless params[:show_deleted] + variants = Variant.active end else - variants = Variant.scoped - if current_api_user.has_spree_role?("admin") - unless params[:show_deleted] - variants = Variant.active - end - else - variants = variants.active - end + variants = variants.active end - variants end + variants end end end diff --git a/spec/controllers/api/products_controller_spec.rb b/spec/controllers/api/products_controller_spec.rb index 70b8b805bd..32efb09ddc 100644 --- a/spec/controllers/api/products_controller_spec.rb +++ b/spec/controllers/api/products_controller_spec.rb @@ -1,226 +1,224 @@ require 'spec_helper' -module Spree - describe Spree::Api::ProductsController, type: :controller do - render_views +describe Api::ProductsController, type: :controller do + render_views - let(:supplier) { create(:supplier_enterprise) } - let(:supplier2) { create(:supplier_enterprise) } - let!(:product) { create(:product, supplier: supplier) } - let!(:inactive_product) { create(:product, available_on: Time.zone.now.tomorrow, name: "inactive") } - let(:product_other_supplier) { create(:product, supplier: supplier2) } - let(:product_with_image) { create(:product_with_image, supplier: supplier) } - let(:attributes) { ["id", "name", "supplier", "price", "on_hand", "available_on", "permalink_live"] } - let(:all_attributes) { ["id", "name", "price", "available_on", "variants"] } - let(:variants_attributes) { ["id", "options_text", "unit_value", "unit_description", "unit_to_display", "on_demand", "display_as", "display_name", "name_to_display", "sku", "on_hand", "price"] } + let(:supplier) { create(:supplier_enterprise) } + let(:supplier2) { create(:supplier_enterprise) } + let!(:product) { create(:product, supplier: supplier) } + let!(:inactive_product) { create(:product, available_on: Time.zone.now.tomorrow, name: "inactive") } + let(:product_other_supplier) { create(:product, supplier: supplier2) } + let(:product_with_image) { create(:product_with_image, supplier: supplier) } + let(:attributes) { ["id", "name", "supplier", "price", "on_hand", "available_on", "permalink_live"] } + let(:all_attributes) { ["id", "name", "price", "available_on", "variants"] } + let(:variants_attributes) { ["id", "options_text", "unit_value", "unit_description", "unit_to_display", "on_demand", "display_as", "display_name", "name_to_display", "sku", "on_hand", "price"] } - let(:current_api_user) { build(:user) } + let(:current_api_user) { build(:user) } + before do + allow(controller).to receive(:spree_current_user) { current_api_user } + end + + context "as a normal user" do before do - allow(controller).to receive(:spree_current_user) { current_api_user } + allow(current_api_user) + .to receive(:has_spree_role?).with("admin").and_return(false) end - context "as a normal user" do + it "gets a single product" do + product.master.images.create!(attachment: image("thinking-cat.jpg")) + product.variants.create!(unit_value: "1", unit_description: "thing") + product.variants.first.images.create!(attachment: image("thinking-cat.jpg")) + product.set_property("spree", "rocks") + api_get :show, id: product.to_param + + expect(all_attributes.all?{ |attr| json_response.keys.include? attr }).to eq(true) + expect(variants_attributes.all?{ |attr| json_response['variants'].first.keys.include? attr }).to eq(true) + end + + context "finds a product by permalink first then by id" do + let!(:other_product) { create(:product, permalink: "these-are-not-the-droids-you-are-looking-for") } + + before do + product.update_attribute(:permalink, "#{other_product.id}-and-1-ways") + end + + specify do + api_get :show, id: product.to_param + + expect(json_response["permalink_live"]).to match(/and-1-ways/) + product.destroy + + api_get :show, id: other_product.id + expect(json_response["permalink_live"]).to match(/droids/) + end + end + + it "cannot see inactive products" do + api_get :show, id: inactive_product.to_param + + expect(json_response["error"]).to eq("The resource you were looking for could not be found.") + expect(response.status).to eq(404) + end + + it "returns a 404 error when it cannot find a product" do + api_get :show, id: "non-existant" + + expect(json_response["error"]).to eq("The resource you were looking for could not be found.") + expect(response.status).to eq(404) + end + + include_examples "modifying product actions are restricted" + end + + context "as an enterprise user" do + let(:current_api_user) do + user = create(:user) + user.enterprise_roles.create(enterprise: supplier) + user + end + + it "soft deletes my products" do + spree_delete :soft_delete, product_id: product.to_param, format: :json + + expect(response.status).to eq(204) + expect { product.reload }.not_to raise_error + expect(product.deleted_at).not_to be_nil + end + + it "is denied access to soft deleting another enterprises' product" do + spree_delete :soft_delete, product_id: product_other_supplier.to_param, format: :json + + assert_unauthorized! + expect { product_other_supplier.reload }.not_to raise_error + expect(product_other_supplier.deleted_at).to be_nil + end + end + + context "as an administrator" do + before do + allow(current_api_user) + .to receive(:has_spree_role?).with("admin").and_return(true) + end + + it "soft deletes a product" do + spree_delete :soft_delete, product_id: product.to_param, format: :json + + expect(response.status).to eq(204) + expect { product.reload }.not_to raise_error + expect(product.deleted_at).not_to be_nil + end + + it "can create a new product" do + api_post :create, product: { name: "The Other Product", + price: 19.99, + shipping_category_id: create(:shipping_category).id, + supplier_id: supplier.id, + primary_taxon_id: FactoryBot.create(:taxon).id, + variant_unit: "items", + variant_unit_name: "things", + unit_description: "things" } + + expect(all_attributes.all?{ |attr| json_response.keys.include? attr }).to eq(true) + expect(response.status).to eq(201) + end + + it "cannot create a new product with invalid attributes" do + api_post :create, product: {} + + expect(response.status).to eq(422) + expect(json_response["error"]).to eq("Invalid resource. Please fix errors and try again.") + errors = json_response["errors"] + expect(errors.keys).to match_array(["name", "price", "primary_taxon", "shipping_category_id", "supplier", "variant_unit"]) + end + + it "can update a product" do + api_put :update, id: product.to_param, product: { name: "New and Improved Product!" } + + expect(response.status).to eq(200) + end + + it "cannot update a product with an invalid attribute" do + api_put :update, id: product.to_param, product: { name: "" } + + expect(response.status).to eq(422) + expect(json_response["error"]).to eq("Invalid resource. Please fix errors and try again.") + expect(json_response["errors"]["name"]).to eq(["can't be blank"]) + end + + it "can delete a product" do + expect(product.deleted_at).to be_nil + api_delete :destroy, id: product.to_param + + expect(response.status).to eq(204) + expect(product.reload.deleted_at).not_to be_nil + end + end + + describe '#clone' do + context 'as a normal user' do before do allow(current_api_user) .to receive(:has_spree_role?).with("admin").and_return(false) end - it "gets a single product" do - product.master.images.create!(attachment: image("thinking-cat.jpg")) - product.variants.create!(unit_value: "1", unit_description: "thing") - product.variants.first.images.create!(attachment: image("thinking-cat.jpg")) - product.set_property("spree", "rocks") - api_get :show, id: product.to_param + it 'denies access' do + spree_post :clone, product_id: product.id, format: :json - expect(all_attributes.all?{ |attr| json_response.keys.include? attr }).to eq(true) - expect(variants_attributes.all?{ |attr| json_response['variants'].first.keys.include? attr }).to eq(true) + assert_unauthorized! end - - context "finds a product by permalink first then by id" do - let!(:other_product) { create(:product, permalink: "these-are-not-the-droids-you-are-looking-for") } - - before do - product.update_attribute(:permalink, "#{other_product.id}-and-1-ways") - end - - specify do - api_get :show, id: product.to_param - - expect(json_response["permalink_live"]).to match(/and-1-ways/) - product.destroy - - api_get :show, id: other_product.id - expect(json_response["permalink_live"]).to match(/droids/) - end - end - - it "cannot see inactive products" do - api_get :show, id: inactive_product.to_param - - expect(json_response["error"]).to eq("The resource you were looking for could not be found.") - expect(response.status).to eq(404) - end - - it "returns a 404 error when it cannot find a product" do - api_get :show, id: "non-existant" - - expect(json_response["error"]).to eq("The resource you were looking for could not be found.") - expect(response.status).to eq(404) - end - - include_examples "modifying product actions are restricted" end - context "as an enterprise user" do + context 'as an enterprise user' do let(:current_api_user) do user = create(:user) user.enterprise_roles.create(enterprise: supplier) user end - it "soft deletes my products" do - spree_delete :soft_delete, product_id: product.to_param, format: :json + it 'responds with a successful response' do + spree_post :clone, product_id: product.id, format: :json - expect(response.status).to eq(204) - expect { product.reload }.not_to raise_error - expect(product.deleted_at).not_to be_nil + expect(response.status).to eq(201) end - it "is denied access to soft deleting another enterprises' product" do - spree_delete :soft_delete, product_id: product_other_supplier.to_param, format: :json + it 'clones the product' do + spree_post :clone, product_id: product.id, format: :json - assert_unauthorized! - expect { product_other_supplier.reload }.not_to raise_error - expect(product_other_supplier.deleted_at).to be_nil + expect(json_response['name']).to eq("COPY OF #{product.name}") + end + + it 'clones a product with image' do + spree_post :clone, product_id: product_with_image.id, format: :json + + expect(response.status).to eq(201) + expect(json_response['name']).to eq("COPY OF #{product_with_image.name}") end end - context "as an administrator" do + context 'as an administrator' do before do allow(current_api_user) .to receive(:has_spree_role?).with("admin").and_return(true) end - it "soft deletes a product" do - spree_delete :soft_delete, product_id: product.to_param, format: :json + it 'responds with a successful response' do + spree_post :clone, product_id: product.id, format: :json - expect(response.status).to eq(204) - expect { product.reload }.not_to raise_error - expect(product.deleted_at).not_to be_nil - end - - it "can create a new product" do - api_post :create, product: { name: "The Other Product", - price: 19.99, - shipping_category_id: create(:shipping_category).id, - supplier_id: supplier.id, - primary_taxon_id: FactoryBot.create(:taxon).id, - variant_unit: "items", - variant_unit_name: "things", - unit_description: "things" } - - expect(all_attributes.all?{ |attr| json_response.keys.include? attr }).to eq(true) expect(response.status).to eq(201) end - it "cannot create a new product with invalid attributes" do - api_post :create, product: {} + it 'clones the product' do + spree_post :clone, product_id: product.id, format: :json - expect(response.status).to eq(422) - expect(json_response["error"]).to eq("Invalid resource. Please fix errors and try again.") - errors = json_response["errors"] - expect(errors.keys).to match_array(["name", "price", "primary_taxon", "shipping_category_id", "supplier", "variant_unit"]) + expect(json_response['name']).to eq("COPY OF #{product.name}") end - it "can update a product" do - api_put :update, id: product.to_param, product: { name: "New and Improved Product!" } + it 'clones a product with image' do + spree_post :clone, product_id: product_with_image.id, format: :json - expect(response.status).to eq(200) - end - - it "cannot update a product with an invalid attribute" do - api_put :update, id: product.to_param, product: { name: "" } - - expect(response.status).to eq(422) - expect(json_response["error"]).to eq("Invalid resource. Please fix errors and try again.") - expect(json_response["errors"]["name"]).to eq(["can't be blank"]) - end - - it "can delete a product" do - expect(product.deleted_at).to be_nil - api_delete :destroy, id: product.to_param - - expect(response.status).to eq(204) - expect(product.reload.deleted_at).not_to be_nil - end - end - - describe '#clone' do - context 'as a normal user' do - before do - allow(current_api_user) - .to receive(:has_spree_role?).with("admin").and_return(false) - end - - it 'denies access' do - spree_post :clone, product_id: product.id, format: :json - - assert_unauthorized! - end - end - - context 'as an enterprise user' do - let(:current_api_user) do - user = create(:user) - user.enterprise_roles.create(enterprise: supplier) - user - end - - it 'responds with a successful response' do - spree_post :clone, product_id: product.id, format: :json - - expect(response.status).to eq(201) - end - - it 'clones the product' do - spree_post :clone, product_id: product.id, format: :json - - expect(json_response['name']).to eq("COPY OF #{product.name}") - end - - it 'clones a product with image' do - spree_post :clone, product_id: product_with_image.id, format: :json - - expect(response.status).to eq(201) - expect(json_response['name']).to eq("COPY OF #{product_with_image.name}") - end - end - - context 'as an administrator' do - before do - allow(current_api_user) - .to receive(:has_spree_role?).with("admin").and_return(true) - end - - it 'responds with a successful response' do - spree_post :clone, product_id: product.id, format: :json - - expect(response.status).to eq(201) - end - - it 'clones the product' do - spree_post :clone, product_id: product.id, format: :json - - expect(json_response['name']).to eq("COPY OF #{product.name}") - end - - it 'clones a product with image' do - spree_post :clone, product_id: product_with_image.id, format: :json - - expect(response.status).to eq(201) - expect(json_response['name']).to eq("COPY OF #{product_with_image.name}") - end + expect(response.status).to eq(201) + expect(json_response['name']).to eq("COPY OF #{product_with_image.name}") end end end diff --git a/spec/controllers/api/variants_controller_spec.rb b/spec/controllers/api/variants_controller_spec.rb index 2e5fef6cd2..9964d40c1b 100644 --- a/spec/controllers/api/variants_controller_spec.rb +++ b/spec/controllers/api/variants_controller_spec.rb @@ -1,199 +1,197 @@ require 'spec_helper' -module Spree - describe Spree::Api::VariantsController, type: :controller do - render_views +describe Api::VariantsController, type: :controller do + render_views - let(:supplier) { FactoryBot.create(:supplier_enterprise) } - let!(:variant1) { FactoryBot.create(:variant) } - let!(:variant2) { FactoryBot.create(:variant) } - let!(:variant3) { FactoryBot.create(:variant) } - let(:attributes) { [:id, :options_text, :price, :on_hand, :unit_value, :unit_description, :on_demand, :display_as, :display_name] } + let(:supplier) { FactoryBot.create(:supplier_enterprise) } + let!(:variant1) { FactoryBot.create(:variant) } + let!(:variant2) { FactoryBot.create(:variant) } + let!(:variant3) { FactoryBot.create(:variant) } + let(:attributes) { [:id, :options_text, :price, :on_hand, :unit_value, :unit_description, :on_demand, :display_as, :display_name] } - before do - allow(controller).to receive(:spree_current_user) { current_api_user } + before do + allow(controller).to receive(:spree_current_user) { current_api_user } + end + + context "as a normal user" do + sign_in_as_user! + + let!(:product) { create(:product) } + let!(:variant) do + variant = product.master + variant.option_values << create(:option_value) + variant end - context "as a normal user" do - sign_in_as_user! + it "retrieves a list of variants with appropriate attributes" do + spree_get :index, format: :json - let!(:product) { create(:product) } - let!(:variant) do - variant = product.master - variant.option_values << create(:option_value) - variant + keys = json_response.first.keys.map(&:to_sym) + expect(attributes.all?{ |attr| keys.include? attr }).to eq(true) + end + + it "is denied access when trying to delete a variant" do + product = create(:product) + variant = product.master + spree_delete :soft_delete, variant_id: variant.to_param, product_id: product.to_param, format: :json + + assert_unauthorized! + expect { variant.reload }.not_to raise_error + expect(variant.deleted_at).to be_nil + end + + it 'can query the results through a parameter' do + expected_result = create(:variant, sku: 'FOOBAR') + api_get :index, q: { sku_cont: 'FOO' } + + expect(json_response.size).to eq(1) + expect(json_response.first['sku']).to eq expected_result.sku + end + + # Regression test for spree#2141 + context "a deleted variant" do + before do + variant.update_column(:deleted_at, Time.zone.now) end - it "retrieves a list of variants with appropriate attributes" do - spree_get :index, format: :json - - keys = json_response.first.keys.map(&:to_sym) - expect(attributes.all?{ |attr| keys.include? attr }).to eq(true) + it "is not returned in the results" do + api_get :index + expect(json_response.count).to eq(10) # there are 11 variants end - it "is denied access when trying to delete a variant" do - product = create(:product) - variant = product.master - spree_delete :soft_delete, variant_id: variant.to_param, product_id: product.to_param, format: :json - - assert_unauthorized! - expect { variant.reload }.not_to raise_error - expect(variant.deleted_at).to be_nil - end - - it 'can query the results through a parameter' do - expected_result = create(:variant, sku: 'FOOBAR') - api_get :index, q: { sku_cont: 'FOO' } - - expect(json_response.size).to eq(1) - expect(json_response.first['sku']).to eq expected_result.sku - end - - # Regression test for spree#2141 - context "a deleted variant" do - before do - variant.update_column(:deleted_at, Time.zone.now) - end - - it "is not returned in the results" do - api_get :index - expect(json_response.count).to eq(10) # there are 11 variants - end - - it "is not returned even when show_deleted is passed" do - api_get :index, show_deleted: true - expect(json_response.count).to eq(10) # there are 11 variants - end - end - - it "can see a single variant" do - api_get :show, id: variant.to_param - - keys = json_response.keys.map(&:to_sym) - expect((attributes).all?{ |attr| keys.include? attr }).to eq(true) - end - - it "cannot create a new variant if not an admin" do - api_post :create, variant: { sku: "12345" } - - assert_unauthorized! - end - - it "cannot update a variant" do - api_put :update, id: variant.to_param, variant: { sku: "12345" } - - assert_unauthorized! - end - - it "cannot delete a variant" do - api_delete :destroy, id: variant.to_param - - assert_unauthorized! - expect { variant.reload }.not_to raise_error + it "is not returned even when show_deleted is passed" do + api_get :index, show_deleted: true + expect(json_response.count).to eq(10) # there are 11 variants end end - context "as an enterprise user" do - sign_in_as_enterprise_user! [:supplier] - let(:supplier_other) { create(:supplier_enterprise) } - let(:product) { create(:product, supplier: supplier) } - let(:variant) { product.master } - let(:product_other) { create(:product, supplier: supplier_other) } - let(:variant_other) { product_other.master } + it "can see a single variant" do + api_get :show, id: variant.to_param - it "soft deletes a variant" do - spree_delete :soft_delete, variant_id: variant.to_param, product_id: product.to_param, format: :json - - expect(response.status).to eq(204) - expect { variant.reload }.not_to raise_error - expect(variant.deleted_at).to be_present - end - - it "is denied access to soft deleting another enterprises' variant" do - spree_delete :soft_delete, variant_id: variant_other.to_param, product_id: product_other.to_param, format: :json - - assert_unauthorized! - expect { variant.reload }.not_to raise_error - expect(variant.deleted_at).to be_nil - end - - context 'when the variant is not the master' do - before { variant.update_attribute(:is_master, false) } - - it 'refreshes the cache' do - expect(OpenFoodNetwork::ProductsCache).to receive(:variant_destroyed).with(variant) - spree_delete :soft_delete, variant_id: variant.id, product_id: variant.product.permalink, format: :json - end - end + keys = json_response.keys.map(&:to_sym) + expect((attributes).all?{ |attr| keys.include? attr }).to eq(true) end - context "as an administrator" do - sign_in_as_admin! + it "cannot create a new variant if not an admin" do + api_post :create, variant: { sku: "12345" } - let(:product) { create(:product) } - let(:variant) { product.master } - let(:resource_scoping) { { product_id: variant.product.to_param } } + assert_unauthorized! + end - it "soft deletes a variant" do - spree_delete :soft_delete, variant_id: variant.to_param, product_id: product.to_param, format: :json + it "cannot update a variant" do + api_put :update, id: variant.to_param, variant: { sku: "12345" } - expect(response.status).to eq(204) - expect { variant.reload }.not_to raise_error - expect(variant.deleted_at).not_to be_nil - end + assert_unauthorized! + end - it "doesn't delete the only variant of the product" do - product = create(:product) - variant = product.variants.first - spree_delete :soft_delete, variant_id: variant.to_param, product_id: product.to_param, format: :json + it "cannot delete a variant" do + api_delete :destroy, id: variant.to_param - expect(variant.reload).to_not be_deleted - expect(assigns(:variant).errors[:product]).to include "must have at least one variant" - end + assert_unauthorized! + expect { variant.reload }.not_to raise_error + end + end - context 'when the variant is not the master' do - before { variant.update_attribute(:is_master, false) } + context "as an enterprise user" do + sign_in_as_enterprise_user! [:supplier] + let(:supplier_other) { create(:supplier_enterprise) } + let(:product) { create(:product, supplier: supplier) } + let(:variant) { product.master } + let(:product_other) { create(:product, supplier: supplier_other) } + let(:variant_other) { product_other.master } - it 'refreshes the cache' do - expect(OpenFoodNetwork::ProductsCache).to receive(:variant_destroyed).with(variant) - spree_delete :soft_delete, variant_id: variant.id, product_id: variant.product.permalink, format: :json - end - end + it "soft deletes a variant" do + spree_delete :soft_delete, variant_id: variant.to_param, product_id: product.to_param, format: :json - context "deleted variants" do - before do - variant.update_column(:deleted_at, Time.zone.now) - end + expect(response.status).to eq(204) + expect { variant.reload }.not_to raise_error + expect(variant.deleted_at).to be_present + end - it "are visible by admin" do - api_get :index, show_deleted: 1 + it "is denied access to soft deleting another enterprises' variant" do + spree_delete :soft_delete, variant_id: variant_other.to_param, product_id: product_other.to_param, format: :json - expect(json_response.count).to eq(2) - end - end + assert_unauthorized! + expect { variant.reload }.not_to raise_error + expect(variant.deleted_at).to be_nil + end - it "can create a new variant" do - original_number_of_variants = variant.product.variants.count - api_post :create, variant: { sku: "12345", unit_value: "weight", unit_description: "L" } + context 'when the variant is not the master' do + before { variant.update_attribute(:is_master, false) } - expect(attributes.all?{ |attr| json_response.include? attr.to_s }).to eq(true) - expect(response.status).to eq(201) - expect(json_response["sku"]).to eq("12345") - expect(variant.product.variants.count).to eq(original_number_of_variants + 1) - end - - it "can update a variant" do - api_put :update, id: variant.to_param, variant: { sku: "12345" } - - expect(response.status).to eq(200) - end - - it "can delete a variant" do - api_delete :destroy, id: variant.to_param - - expect(response.status).to eq(204) - expect { Spree::Variant.find(variant.id) }.to raise_error(ActiveRecord::RecordNotFound) + it 'refreshes the cache' do + expect(OpenFoodNetwork::ProductsCache).to receive(:variant_destroyed).with(variant) + spree_delete :soft_delete, variant_id: variant.id, product_id: variant.product.permalink, format: :json end end end + + context "as an administrator" do + sign_in_as_admin! + + let(:product) { create(:product) } + let(:variant) { product.master } + let(:resource_scoping) { { product_id: variant.product.to_param } } + + it "soft deletes a variant" do + spree_delete :soft_delete, variant_id: variant.to_param, product_id: product.to_param, format: :json + + expect(response.status).to eq(204) + expect { variant.reload }.not_to raise_error + expect(variant.deleted_at).not_to be_nil + end + + it "doesn't delete the only variant of the product" do + product = create(:product) + variant = product.variants.first + spree_delete :soft_delete, variant_id: variant.to_param, product_id: product.to_param, format: :json + + expect(variant.reload).to_not be_deleted + expect(assigns(:variant).errors[:product]).to include "must have at least one variant" + end + + context 'when the variant is not the master' do + before { variant.update_attribute(:is_master, false) } + + it 'refreshes the cache' do + expect(OpenFoodNetwork::ProductsCache).to receive(:variant_destroyed).with(variant) + spree_delete :soft_delete, variant_id: variant.id, product_id: variant.product.permalink, format: :json + end + end + + context "deleted variants" do + before do + variant.update_column(:deleted_at, Time.zone.now) + end + + it "are visible by admin" do + api_get :index, show_deleted: 1 + + expect(json_response.count).to eq(2) + end + end + + it "can create a new variant" do + original_number_of_variants = variant.product.variants.count + api_post :create, variant: { sku: "12345", unit_value: "weight", unit_description: "L" } + + expect(attributes.all?{ |attr| json_response.include? attr.to_s }).to eq(true) + expect(response.status).to eq(201) + expect(json_response["sku"]).to eq("12345") + expect(variant.product.variants.count).to eq(original_number_of_variants + 1) + end + + it "can update a variant" do + api_put :update, id: variant.to_param, variant: { sku: "12345" } + + expect(response.status).to eq(200) + end + + it "can delete a variant" do + api_delete :destroy, id: variant.to_param + + expect(response.status).to eq(204) + expect { Spree::Variant.find(variant.id) }.to raise_error(ActiveRecord::RecordNotFound) + end + end end