mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-02-27 01:43:22 +00:00
Bring user and ability related files from spree_core
This commit is contained in:
73
app/models/spree/ability.rb
Normal file
73
app/models/spree/ability.rb
Normal file
@@ -0,0 +1,73 @@
|
||||
# Implementation class for Cancan gem. Instead of overriding this class, consider adding new permissions
|
||||
# using the special +register_ability+ method which allows extensions to add their own abilities.
|
||||
#
|
||||
# See http://github.com/ryanb/cancan for more details on cancan.
|
||||
require 'cancan'
|
||||
|
||||
module Spree
|
||||
class Ability
|
||||
include CanCan::Ability
|
||||
|
||||
class_attribute :abilities
|
||||
self.abilities = Set.new
|
||||
|
||||
# Allows us to go beyond the standard cancan initialize method which makes it difficult for engines to
|
||||
# modify the default +Ability+ of an application. The +ability+ argument must be a class that includes
|
||||
# the +CanCan::Ability+ module. The registered ability should behave properly as a stand-alone class
|
||||
# and therefore should be easy to test in isolation.
|
||||
def self.register_ability(ability)
|
||||
self.abilities.add(ability)
|
||||
end
|
||||
|
||||
def self.remove_ability(ability)
|
||||
self.abilities.delete(ability)
|
||||
end
|
||||
|
||||
def initialize(user)
|
||||
self.clear_aliased_actions
|
||||
|
||||
# override cancan default aliasing (we don't want to differentiate between read and index)
|
||||
alias_action :delete, to: :destroy
|
||||
alias_action :edit, to: :update
|
||||
alias_action :new, to: :create
|
||||
alias_action :new_action, to: :create
|
||||
alias_action :show, to: :read
|
||||
|
||||
user ||= Spree.user_class.new
|
||||
|
||||
if user.respond_to?(:has_spree_role?) && user.has_spree_role?('admin')
|
||||
can :manage, :all
|
||||
else
|
||||
can [:index, :read], Country
|
||||
can [:index, :read], OptionType
|
||||
can [:index, :read], OptionValue
|
||||
can :create, Order
|
||||
can :read, Order do |order, token|
|
||||
order.user == user || order.token && token == order.token
|
||||
end
|
||||
can :update, Order do |order, token|
|
||||
order.user == user || order.token && token == order.token
|
||||
end
|
||||
can [:index, :read], Product
|
||||
can [:index, :read], ProductProperty
|
||||
can [:index, :read], Property
|
||||
can :create, Spree.user_class
|
||||
can [:read, :update, :destroy], Spree.user_class, id: user.id
|
||||
can [:index, :read], State
|
||||
can [:index, :read], StockItem
|
||||
can [:index, :read], StockLocation
|
||||
can [:index, :read], StockMovement
|
||||
can [:index, :read], Taxon
|
||||
can [:index, :read], Taxonomy
|
||||
can [:index, :read], Variant
|
||||
can [:index, :read], Zone
|
||||
end
|
||||
|
||||
# Include any abilities registered by extensions, etc.
|
||||
Ability.abilities.each do |clazz|
|
||||
ability = clazz.send(:new, user)
|
||||
@rules = rules + ability.send(:rules)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
265
spec/models/spree/ability_spec.rb
Normal file
265
spec/models/spree/ability_spec.rb
Normal file
@@ -0,0 +1,265 @@
|
||||
require 'spec_helper'
|
||||
require 'cancan/matchers'
|
||||
require 'spree/testing_support/ability_helpers'
|
||||
require 'spree/testing_support/bar_ability'
|
||||
|
||||
# Fake ability for testing registration of additional abilities
|
||||
class FooAbility
|
||||
include CanCan::Ability
|
||||
|
||||
def initialize(user)
|
||||
# allow anyone to perform index on Order
|
||||
can :index, Spree::Order
|
||||
# allow anyone to update an Order with id of 1
|
||||
can :update, Spree::Order do |order|
|
||||
order.id == 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe Spree::Ability do
|
||||
let(:user) { create(:user) }
|
||||
let(:ability) { Spree::Ability.new(user) }
|
||||
let(:token) { nil }
|
||||
|
||||
before do
|
||||
user.spree_roles.clear
|
||||
end
|
||||
|
||||
TOKEN = 'token123'
|
||||
|
||||
after(:each) {
|
||||
Spree::Ability.abilities = Set.new
|
||||
user.spree_roles = []
|
||||
}
|
||||
|
||||
context 'register_ability' do
|
||||
it 'should add the ability to the list of abilties' do
|
||||
Spree::Ability.register_ability(FooAbility)
|
||||
Spree::Ability.new(user).abilities.should_not be_empty
|
||||
end
|
||||
|
||||
it 'should apply the registered abilities permissions' do
|
||||
Spree::Ability.register_ability(FooAbility)
|
||||
Spree::Ability.new(user).can?(:update, mock_model(Spree::Order, :id => 1)).should be_true
|
||||
end
|
||||
end
|
||||
|
||||
context 'for general resource' do
|
||||
let(:resource) { Object.new }
|
||||
|
||||
context 'with admin user' do
|
||||
before(:each) { user.stub(:has_spree_role?).and_return(true) }
|
||||
it_should_behave_like 'access granted'
|
||||
it_should_behave_like 'index allowed'
|
||||
end
|
||||
|
||||
context 'with customer' do
|
||||
it_should_behave_like 'access denied'
|
||||
it_should_behave_like 'no index allowed'
|
||||
end
|
||||
end
|
||||
|
||||
context 'for admin protected resources' do
|
||||
let(:resource) { Object.new }
|
||||
let(:resource_shipment) { Spree::Shipment.new }
|
||||
let(:resource_product) { Spree::Product.new }
|
||||
let(:resource_user) { Spree.user_class.new }
|
||||
let(:resource_order) { Spree::Order.new }
|
||||
let(:fakedispatch_user) { Spree.user_class.new }
|
||||
let(:fakedispatch_ability) { Spree::Ability.new(fakedispatch_user) }
|
||||
|
||||
context 'with admin user' do
|
||||
it 'should be able to admin' do
|
||||
user.spree_roles << Spree::Role.find_or_create_by(name: 'admin')
|
||||
ability.should be_able_to :admin, resource
|
||||
ability.should be_able_to :index, resource_order
|
||||
ability.should be_able_to :show, resource_product
|
||||
ability.should be_able_to :create, resource_user
|
||||
end
|
||||
end
|
||||
|
||||
context 'with fakedispatch user' do
|
||||
it 'should be able to admin on the order and shipment pages' do
|
||||
user.spree_roles << Spree::Role.find_or_create_by(name: 'bar')
|
||||
|
||||
Spree::Ability.register_ability(BarAbility)
|
||||
|
||||
ability.should_not be_able_to :admin, resource
|
||||
|
||||
ability.should be_able_to :admin, resource_order
|
||||
ability.should be_able_to :index, resource_order
|
||||
ability.should_not be_able_to :update, resource_order
|
||||
# ability.should_not be_able_to :create, resource_order # Fails
|
||||
|
||||
ability.should be_able_to :admin, resource_shipment
|
||||
ability.should be_able_to :index, resource_shipment
|
||||
ability.should be_able_to :create, resource_shipment
|
||||
|
||||
ability.should_not be_able_to :admin, resource_product
|
||||
ability.should_not be_able_to :update, resource_product
|
||||
# ability.should_not be_able_to :show, resource_product # Fails
|
||||
|
||||
ability.should_not be_able_to :admin, resource_user
|
||||
ability.should_not be_able_to :update, resource_user
|
||||
ability.should be_able_to :update, user
|
||||
# ability.should_not be_able_to :create, resource_user # Fails
|
||||
# It can create new users if is has access to the :admin, User!!
|
||||
|
||||
# TODO change the Ability class so only users and customers get the extra premissions?
|
||||
|
||||
Spree::Ability.remove_ability(BarAbility)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with customer' do
|
||||
it 'should not be able to admin' do
|
||||
ability.should_not be_able_to :admin, resource
|
||||
ability.should_not be_able_to :admin, resource_order
|
||||
ability.should_not be_able_to :admin, resource_product
|
||||
ability.should_not be_able_to :admin, resource_user
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'as Guest User' do
|
||||
|
||||
context 'for Country' do
|
||||
let(:resource) { Spree::Country.new }
|
||||
context 'requested by any user' do
|
||||
it_should_behave_like 'read only'
|
||||
end
|
||||
end
|
||||
|
||||
context 'for OptionType' do
|
||||
let(:resource) { Spree::OptionType.new }
|
||||
context 'requested by any user' do
|
||||
it_should_behave_like 'read only'
|
||||
end
|
||||
end
|
||||
|
||||
context 'for OptionValue' do
|
||||
let(:resource) { Spree::OptionType.new }
|
||||
context 'requested by any user' do
|
||||
it_should_behave_like 'read only'
|
||||
end
|
||||
end
|
||||
|
||||
context 'for Order' do
|
||||
let(:resource) { Spree::Order.new }
|
||||
|
||||
context 'requested by same user' do
|
||||
before(:each) { resource.user = user }
|
||||
it_should_behave_like 'access granted'
|
||||
it_should_behave_like 'no index allowed'
|
||||
end
|
||||
|
||||
context 'requested by other user' do
|
||||
before(:each) { resource.user = Spree.user_class.new }
|
||||
it_should_behave_like 'create only'
|
||||
end
|
||||
|
||||
context 'requested with proper token' do
|
||||
let(:token) { 'TOKEN123' }
|
||||
before(:each) { resource.stub :token => 'TOKEN123' }
|
||||
it_should_behave_like 'access granted'
|
||||
it_should_behave_like 'no index allowed'
|
||||
end
|
||||
|
||||
context 'requested with inproper token' do
|
||||
let(:token) { 'FAIL' }
|
||||
before(:each) { resource.stub :token => 'TOKEN123' }
|
||||
it_should_behave_like 'create only'
|
||||
end
|
||||
end
|
||||
|
||||
context 'for Product' do
|
||||
let(:resource) { Spree::Product.new }
|
||||
context 'requested by any user' do
|
||||
it_should_behave_like 'read only'
|
||||
end
|
||||
end
|
||||
|
||||
context 'for ProductProperty' do
|
||||
let(:resource) { Spree::Product.new }
|
||||
context 'requested by any user' do
|
||||
it_should_behave_like 'read only'
|
||||
end
|
||||
end
|
||||
|
||||
context 'for Property' do
|
||||
let(:resource) { Spree::Product.new }
|
||||
context 'requested by any user' do
|
||||
it_should_behave_like 'read only'
|
||||
end
|
||||
end
|
||||
|
||||
context 'for State' do
|
||||
let(:resource) { Spree::State.new }
|
||||
context 'requested by any user' do
|
||||
it_should_behave_like 'read only'
|
||||
end
|
||||
end
|
||||
|
||||
context 'for StockItem' do
|
||||
let(:resource) { Spree::StockItem.new }
|
||||
context 'requested by any user' do
|
||||
it_should_behave_like 'read only'
|
||||
end
|
||||
end
|
||||
|
||||
context 'for StockLocation' do
|
||||
let(:resource) { Spree::StockLocation.new }
|
||||
context 'requested by any user' do
|
||||
it_should_behave_like 'read only'
|
||||
end
|
||||
end
|
||||
|
||||
context 'for StockMovement' do
|
||||
let(:resource) { Spree::StockMovement.new }
|
||||
context 'requested by any user' do
|
||||
it_should_behave_like 'read only'
|
||||
end
|
||||
end
|
||||
|
||||
context 'for Taxons' do
|
||||
let(:resource) { Spree::Taxon.new }
|
||||
context 'requested by any user' do
|
||||
it_should_behave_like 'read only'
|
||||
end
|
||||
end
|
||||
|
||||
context 'for Taxonomy' do
|
||||
let(:resource) { Spree::Taxonomy.new }
|
||||
context 'requested by any user' do
|
||||
it_should_behave_like 'read only'
|
||||
end
|
||||
end
|
||||
|
||||
context 'for User' do
|
||||
context 'requested by same user' do
|
||||
let(:resource) { user }
|
||||
it_should_behave_like 'access granted'
|
||||
it_should_behave_like 'no index allowed'
|
||||
end
|
||||
context 'requested by other user' do
|
||||
let(:resource) { Spree.user_class.new }
|
||||
it_should_behave_like 'create only'
|
||||
end
|
||||
end
|
||||
|
||||
context 'for Variant' do
|
||||
let(:resource) { Spree::Variant.new }
|
||||
context 'requested by any user' do
|
||||
it_should_behave_like 'read only'
|
||||
end
|
||||
end
|
||||
|
||||
context 'for Zone' do
|
||||
let(:resource) { Spree::Zone.new }
|
||||
context 'requested by any user' do
|
||||
it_should_behave_like 'read only'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user