mirror of
https://github.com/varvet/pundit.git
synced 2022-11-09 12:30:11 -05:00

Exceptions raised by #authorize now provide the query (e.g. 'create?') and record (e.g. an instance of 'Post') that caused the exception to be raised, as well as the relevant policy (e.g. an instance of 'PostPolicy'). NotAuthorizedError is modified to continue to inherit from StandardError, but now also has attr_accessor values for :query, :record, and :policy.
278 lines
8.3 KiB
Ruby
278 lines
8.3 KiB
Ruby
require "pundit"
|
|
require "pry"
|
|
require "active_support/core_ext"
|
|
require "active_model/naming"
|
|
|
|
class PostPolicy < Struct.new(:user, :post)
|
|
def update?
|
|
post.user == user
|
|
end
|
|
def destroy?
|
|
false
|
|
end
|
|
def show?
|
|
true
|
|
end
|
|
end
|
|
class PostPolicy::Scope < Struct.new(:user, :scope)
|
|
def resolve
|
|
scope.published
|
|
end
|
|
end
|
|
class Post < Struct.new(:user)
|
|
def self.published
|
|
:published
|
|
end
|
|
end
|
|
|
|
class CommentPolicy < Struct.new(:user, :comment); end
|
|
class CommentPolicy::Scope < Struct.new(:user, :scope)
|
|
def resolve
|
|
scope
|
|
end
|
|
end
|
|
class Comment; extend ActiveModel::Naming; end
|
|
|
|
class Article; end
|
|
|
|
class BlogPolicy < Struct.new(:user, :blog); end
|
|
class Blog; end
|
|
class ArtificialBlog < Blog
|
|
def self.policy_class
|
|
BlogPolicy
|
|
end
|
|
end
|
|
class ArticleTag
|
|
def self.policy_class
|
|
Struct.new(:user, :tag) do
|
|
def show?
|
|
true
|
|
end
|
|
def destroy?
|
|
false
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
describe Pundit do
|
|
let(:user) { double }
|
|
let(:post) { Post.new(user) }
|
|
let(:comment) { Comment.new }
|
|
let(:article) { Article.new }
|
|
let(:controller) { double(:current_user => user, :params => { :action => "update" }).tap { |c| c.extend(Pundit) } }
|
|
let(:artificial_blog) { ArtificialBlog.new }
|
|
let(:article_tag) { ArticleTag.new }
|
|
|
|
describe ".policy_scope" do
|
|
it "returns an instantiated policy scope given a plain model class" do
|
|
expect(Pundit.policy_scope(user, Post)).to eq :published
|
|
end
|
|
|
|
it "returns an instantiated policy scope given an active model class" do
|
|
expect(Pundit.policy_scope(user, Comment)).to eq Comment
|
|
end
|
|
|
|
it "returns nil if the given policy scope can't be found" do
|
|
expect(Pundit.policy_scope(user, Article)).to be_nil
|
|
end
|
|
end
|
|
|
|
describe ".policy_scope!" do
|
|
it "returns an instantiated policy scope given a plain model class" do
|
|
expect(Pundit.policy_scope!(user, Post)).to eq :published
|
|
end
|
|
|
|
it "returns an instantiated policy scope given an active model class" do
|
|
expect(Pundit.policy_scope!(user, Comment)).to eq Comment
|
|
end
|
|
|
|
it "throws an exception if the given policy scope can't be found" do
|
|
expect { Pundit.policy_scope!(user, Article) }.to raise_error(Pundit::NotDefinedError)
|
|
end
|
|
|
|
it "throws an exception if the given policy scope can't be found" do
|
|
expect { Pundit.policy_scope!(user, ArticleTag) }.to raise_error(Pundit::NotDefinedError)
|
|
end
|
|
end
|
|
|
|
describe ".policy" do
|
|
it "returns an instantiated policy given a plain model instance" do
|
|
policy = Pundit.policy(user, post)
|
|
expect(policy.user).to eq user
|
|
expect(policy.post).to eq post
|
|
end
|
|
|
|
it "returns an instantiated policy given an active model instance" do
|
|
policy = Pundit.policy(user, comment)
|
|
expect(policy.user).to eq user
|
|
expect(policy.comment).to eq comment
|
|
end
|
|
|
|
it "returns an instantiated policy given a plain model class" do
|
|
policy = Pundit.policy(user, Post)
|
|
expect(policy.user).to eq user
|
|
expect(policy.post).to eq Post
|
|
end
|
|
|
|
it "returns an instantiated policy given an active model class" do
|
|
policy = Pundit.policy(user, Comment)
|
|
expect(policy.user).to eq user
|
|
expect(policy.comment).to eq Comment
|
|
end
|
|
|
|
it "returns nil if the given policy can't be found" do
|
|
expect(Pundit.policy(user, article)).to be_nil
|
|
expect(Pundit.policy(user, Article)).to be_nil
|
|
end
|
|
|
|
describe "with .policy_class set on the model" do
|
|
it "returns an instantiated policy given a plain model instance" do
|
|
policy = Pundit.policy(user, artificial_blog)
|
|
expect(policy.user).to eq user
|
|
expect(policy.blog).to eq artificial_blog
|
|
end
|
|
|
|
it "returns an instantiated policy given a plain model class" do
|
|
policy = Pundit.policy(user, ArtificialBlog)
|
|
expect(policy.user).to eq user
|
|
expect(policy.blog).to eq ArtificialBlog
|
|
end
|
|
|
|
it "returns an instantiated policy given a plain model instance providing an anonymous class" do
|
|
policy = Pundit.policy(user, article_tag)
|
|
expect(policy.user).to eq user
|
|
expect(policy.tag).to eq article_tag
|
|
end
|
|
|
|
it "returns an instantiated policy given a plain model class providing an anonymous class" do
|
|
policy = Pundit.policy(user, ArticleTag)
|
|
expect(policy.user).to eq user
|
|
expect(policy.tag).to eq ArticleTag
|
|
end
|
|
end
|
|
end
|
|
|
|
describe ".policy!" do
|
|
it "returns an instantiated policy given a plain model instance" do
|
|
policy = Pundit.policy!(user, post)
|
|
expect(policy.user).to eq user
|
|
expect(policy.post).to eq post
|
|
end
|
|
|
|
it "returns an instantiated policy given an active model instance" do
|
|
policy = Pundit.policy!(user, comment)
|
|
expect(policy.user).to eq user
|
|
expect(policy.comment).to eq comment
|
|
end
|
|
|
|
it "returns an instantiated policy given a plain model class" do
|
|
policy = Pundit.policy!(user, Post)
|
|
expect(policy.user).to eq user
|
|
expect(policy.post).to eq Post
|
|
end
|
|
|
|
it "returns an instantiated policy given an active model class" do
|
|
policy = Pundit.policy!(user, Comment)
|
|
expect(policy.user).to eq user
|
|
expect(policy.comment).to eq Comment
|
|
end
|
|
|
|
it "throws an exception if the given policy can't be found" do
|
|
expect { Pundit.policy!(user, article) }.to raise_error(Pundit::NotDefinedError)
|
|
expect { Pundit.policy!(user, Article) }.to raise_error(Pundit::NotDefinedError)
|
|
end
|
|
end
|
|
|
|
describe "#verify_authorized" do
|
|
it "does nothing when authorized" do
|
|
controller.authorize(post)
|
|
controller.verify_authorized
|
|
end
|
|
|
|
it "raises an exception when not authorized" do
|
|
expect { controller.verify_authorized }.to raise_error(Pundit::NotAuthorizedError)
|
|
end
|
|
end
|
|
|
|
describe "#verify_policy_scoped" do
|
|
it "does nothing when policy_scope is used" do
|
|
controller.policy_scope(Post)
|
|
controller.verify_policy_scoped
|
|
end
|
|
|
|
it "raises an exception when policy_scope is not used" do
|
|
expect { controller.verify_policy_scoped }.to raise_error(Pundit::NotAuthorizedError)
|
|
end
|
|
end
|
|
|
|
describe "#authorize" do
|
|
it "infers the policy name and authorized based on it" do
|
|
expect(controller.authorize(post)).to be_truthy
|
|
end
|
|
|
|
it "can be given a different permission to check" do
|
|
expect(controller.authorize(post, :show?)).to be_truthy
|
|
expect { controller.authorize(post, :destroy?) }.to raise_error(Pundit::NotAuthorizedError)
|
|
end
|
|
|
|
it "works with anonymous class policies" do
|
|
expect(controller.authorize(article_tag, :show?)).to be_truthy
|
|
expect { controller.authorize(article_tag, :destroy?) }.to raise_error(Pundit::NotAuthorizedError)
|
|
end
|
|
|
|
it "raises an error when the permission check fails" do
|
|
expect { controller.authorize(Post.new) }.to raise_error(Pundit::NotAuthorizedError)
|
|
end
|
|
|
|
it "raises an error with a query and action" do
|
|
expect { controller.authorize(post, :destroy?) }.to raise_error do |error|
|
|
expect(error.query).to eq :destroy?
|
|
expect(error.record).to eq post
|
|
expect(error.policy).to eq controller.policy(post)
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "#pundit_user" do
|
|
it 'returns the same thing as current_user' do
|
|
expect(controller.pundit_user).to eq controller.current_user
|
|
end
|
|
end
|
|
|
|
describe ".policy" do
|
|
it "returns an instantiated policy" do
|
|
policy = controller.policy(post)
|
|
expect(policy.user).to eq user
|
|
expect(policy.post).to eq post
|
|
end
|
|
|
|
it "throws an exception if the given policy can't be found" do
|
|
expect { controller.policy(article) }.to raise_error(Pundit::NotDefinedError)
|
|
end
|
|
|
|
it "allows policy to be injected" do
|
|
new_policy = OpenStruct.new
|
|
controller.policy = new_policy
|
|
|
|
expect(controller.policy(post)).to eq new_policy
|
|
end
|
|
end
|
|
|
|
describe ".policy_scope" do
|
|
it "returns an instantiated policy scope" do
|
|
expect(controller.policy_scope(Post)).to eq :published
|
|
end
|
|
|
|
it "throws an exception if the given policy can't be found" do
|
|
expect { controller.policy_scope(Article) }.to raise_error(Pundit::NotDefinedError)
|
|
end
|
|
|
|
it "allows policy_scope to be injected" do
|
|
new_scope = OpenStruct.new
|
|
controller.policy_scope = new_scope
|
|
|
|
expect(controller.policy_scope(post)).to eq new_scope
|
|
end
|
|
end
|
|
end
|