BigW Consortium Gitlab

base_policy.rb 2.27 KB
Newer Older
1
class BasePolicy
2 3 4 5 6 7 8
  class RuleSet
    attr_reader :can_set, :cannot_set
    def initialize(can_set, cannot_set)
      @can_set = can_set
      @cannot_set = cannot_set
    end

Douwe Maan committed
9
    delegate :size, to: :to_set
10

11 12 13 14
    def self.empty
      new(Set.new, Set.new)
    end

15 16 17 18
    def self.none
      empty.freeze
    end

19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
    def can?(ability)
      @can_set.include?(ability) && !@cannot_set.include?(ability)
    end

    def include?(ability)
      can?(ability)
    end

    def to_set
      @can_set - @cannot_set
    end

    def merge(other)
      @can_set.merge(other.can_set)
      @cannot_set.merge(other.cannot_set)
    end

    def can!(*abilities)
      @can_set.merge(abilities)
    end

    def cannot!(*abilities)
      @cannot_set.merge(abilities)
    end

    def freeze
      @can_set.freeze
      @cannot_set.freeze
      super
    end
  end

51 52 53 54
  def self.abilities(user, subject)
    new(user, subject).abilities
  end

55
  def self.class_for(subject)
56 57
    return GlobalPolicy if subject == :global
    raise ArgumentError, 'no policy for nil' if subject.nil?
58

59
    if subject.class.try(:presenter?)
60 61 62
      subject = subject.subject
    end

63 64 65 66 67 68
    subject.class.ancestors.each do |klass|
      next unless klass.name

      begin
        policy_class = "#{klass.name}Policy".constantize

http://jneen.net/ committed
69
        # NOTE: the < operator here tests whether policy_class
70 71 72 73 74 75 76 77
        # inherits from BasePolicy
        return policy_class if policy_class < BasePolicy
      rescue NameError
        nil
      end
    end

    raise "no policy for #{subject.class.name}"
78 79
  end

80
  attr_reader :user, :subject
81 82 83 84 85 86
  def initialize(user, subject)
    @user = user
    @subject = subject
  end

  def abilities
87
    return RuleSet.none if @user && @user.blocked?
88 89 90 91 92 93
    return anonymous_abilities if @user.nil?
    collect_rules { rules }
  end

  def anonymous_abilities
    collect_rules { anonymous_rules }
94 95
  end

96 97 98 99
  def anonymous_rules
    rules
  end

100 101 102 103
  def rules
    raise NotImplementedError
  end

104
  def delegate!(new_subject)
105
    @rule_set.merge(Ability.allowed(@user, new_subject))
106 107
  end

108
  def can?(rule)
109
    @rule_set.can?(rule)
110 111
  end

112
  def can!(*rules)
113
    @rule_set.can!(*rules)
114 115 116
  end

  def cannot!(*rules)
117
    @rule_set.cannot!(*rules)
118
  end
119 120 121 122

  private

  def collect_rules(&b)
123
    @rule_set = RuleSet.empty
124
    yield
125
    @rule_set
126
  end
127
end