Skip to content

Commit

Permalink
Merge 317b895 into 7c144ad
Browse files Browse the repository at this point in the history
  • Loading branch information
dkniffin committed Dec 3, 2020
2 parents 7c144ad + 317b895 commit 4e55089
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 30 deletions.
9 changes: 5 additions & 4 deletions lib/rolify/adapters/active_record/role_adapter.rb
Expand Up @@ -104,15 +104,16 @@ def build_conditions(relation, args)
end

def build_query(role, resource = nil)
return [ "#{role_table}.name = ?", [ role ] ] if resource == :any
query = "((#{role_table}.name = ?) AND (#{role_table}.resource_type IS NULL) AND (#{role_table}.resource_id IS NULL))"
role = [role].flatten
return [ "#{role_table}.name IN (?)", [ role ] ] if resource == :any
query = "((#{role_table}.name IN (?)) AND (#{role_table}.resource_type IS NULL) AND (#{role_table}.resource_id IS NULL))"
values = [ role ]
if resource
query.insert(0, "(")
query += " OR ((#{role_table}.name = ?) AND (#{role_table}.resource_type = ?) AND (#{role_table}.resource_id IS NULL))"
query += " OR ((#{role_table}.name IN (?)) AND (#{role_table}.resource_type = ?) AND (#{role_table}.resource_id IS NULL))"
values << role << (resource.is_a?(Class) ? resource.to_s : resource.class.name)
if !resource.is_a? Class
query += " OR ((#{role_table}.name = ?) AND (#{role_table}.resource_type = ?) AND (#{role_table}.resource_id = ?))"
query += " OR ((#{role_table}.name IN (?)) AND (#{role_table}.resource_type = ?) AND (#{role_table}.resource_id = ?))"
values << role << resource.class.name << resource.id
end
query += ")"
Expand Down
65 changes: 41 additions & 24 deletions lib/rolify/finders.rb
Expand Up @@ -14,36 +14,53 @@ def without_role(role_name, resource = nil)
end

def with_all_roles(*args)
users = []
parse_args(args, users) do |users_to_add|
users = users_to_add if users.empty?
users &= users_to_add
return [] if users.empty?
end
users
intersect_ars(parse_args(args, :split)).uniq
end

def with_any_role(*args)
users = []
parse_args(args, users) do |users_to_add|
users += users_to_add
end
users.uniq
union_ars(parse_args(args, :join)).uniq
end
end

private

def parse_args(args, users, &block)
args.each do |arg|
if arg.is_a? Hash
users_to_add = self.with_role(arg[:name], arg[:resource])
elsif arg.is_a?(String) || arg.is_a?(Symbol)
users_to_add = self.with_role(arg)
else
raise ArgumentError, "Invalid argument type: only hash or string or symbol allowed"

def parse_args(args, mode, &block)
normalize_args(args, mode).map do |arg|
self.with_role(arg[:name], arg[:resource]).tap do |users_to_add|
block.call(users_to_add) if block
end
block.call(users_to_add)
end
end
end

# In: [:a, "b", { name: :c, resource: :d }]
# Out: [{ name: [:a, "b"] }, { name: :c, resource: :d }]
def normalize_args(args, mode)
groups = args.group_by(&:class)
unless groups.keys.all? { |type| [Hash, Symbol, String].include?(type) }
raise ArgumentError, "Invalid argument type: only hash or string or symbol allowed"
end

normalized = [groups[Hash]]
sym_str_args = [groups[Symbol], groups[String]].flatten.compact
case mode
when :join
normalized += [{ name: sym_str_args }] unless sym_str_args.empty?
when :split
normalized += sym_str_args.map { |arg| { name: arg } }
end

normalized.flatten.compact
end


def intersect_ars(ars)
query = ars.map(&:to_sql).join(" INTERSECT ")
from("(#{query}) AS #{table_name}")
end

# http://stackoverflow.com/a/16868735/1202488
def union_ars(ars)
query = ars.map(&:to_sql).join(" UNION ")
from("(#{query}) AS #{table_name}")
end
end
14 changes: 12 additions & 2 deletions spec/rolify/shared_examples/shared_examples_for_finders.rb
Expand Up @@ -115,7 +115,7 @@
end
end
end


describe ".with_all_roles" do
it { should respond_to(:with_all_roles) }
Expand All @@ -129,6 +129,11 @@
it { subject.with_all_roles({ :name => "visitor".send(param_method), :resource => Forum.last }, { :name => "moderator".send(param_method), :resource => Group }).should eq([ root ]) }
it { subject.with_all_roles({ :name => "visitor".send(param_method), :resource => Group.first }, { :name => "moderator".send(param_method), :resource => Forum }).should eq([ modo ]) }
it { subject.with_all_roles({ :name => "visitor".send(param_method), :resource => :any }, { :name => "moderator".send(param_method), :resource => :any }).should =~ [ root, modo ] }

it 'should return an AR relation' do
subject.with_all_roles("admin".send(param_method), :staff).should be_a(ActiveRecord::Relation)
subject.with_all_roles({ :name => "visitor".send(param_method), :resource => :any }, { :name => "moderator".send(param_method), :resource => :any }).should be_a(ActiveRecord::Relation)
end
end

describe ".with_any_role" do
Expand All @@ -144,6 +149,11 @@
it { subject.with_any_role({ :name => "visitor".send(param_method), :resource => Forum.last }, { :name => "moderator".send(param_method), :resource => Group }).should =~ [ root, visitor ] }
it { subject.with_any_role({ :name => "visitor".send(param_method), :resource => Group.first }, { :name => "moderator".send(param_method), :resource => Forum }).should eq([ modo ]) }
it { subject.with_any_role({ :name => "visitor".send(param_method), :resource => :any }, { :name => "moderator".send(param_method), :resource => :any }).should =~ [ root, modo, visitor ] }

it 'should return an AR relation' do
subject.with_any_role("admin".send(param_method), :staff, { :name => "moderator".send(param_method), :resource => Group }).should be_a(ActiveRecord::Relation)
subject.with_any_role({ :name => "visitor".send(param_method), :resource => :any }, { :name => "moderator".send(param_method), :resource => :any }).should be_a(ActiveRecord::Relation)
end
end
end
end
end

0 comments on commit 4e55089

Please sign in to comment.