mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-01-24 20:36:49 +00:00
Remove Spree module declaration from these files as they were moved out of the spree namespace
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user