point_rules.rb 3.55 KB
module Merit
  class PointRules
    include Merit::PointRulesMethods

    AVAILABLE_RULES = {
      :comment_author => {
        :action => 'comment#create',
        :undo_action => 'comment#destroy',
        :to => :author,
        :value => 1,
        :description => _('Point weight for comment author'),
        :default_weight => 150
      },
      :comment_article_author => {
        :action => 'comment#create',
        :undo_action => 'comment#destroy',
        :to => lambda {|comment| comment.source.author},
        :value => 1,
        :description => _('Point weight for article author of a comment'),
        :default_weight => 50
      },
      :comment_article => {
        :action => 'comment#create',
        :undo_action => 'comment#destroy',
        :to => lambda {|comment| comment.source},
        :value => 1,
        :description => _('Point weight for source article of a comment'),
        :default_weight => 50
      },
      :article_author => {
        :action => 'article#create',
        :undo_action => 'article#destroy',
        :to => :author,
        :value => 1,
        :description => _('Point weight for article author'),
        :default_weight => 500
      },
      :article_community => {
        :action => 'article#create',
        :undo_action => 'article#destroy',
        :to => :profile,
        :value => 1,
        :description => _('Point weight for article community'),
        :default_weight => 600,
        :condition => lambda {|target| target.profile.community? }
      },
      :vote_voteable_author => {
        :action => 'vote#create',
        :undo_action => 'vote#destroy',
        :to => lambda {|vote| vote.voteable.author},
        :profile => lambda {|vote| vote.voteable.profile},
        :value => lambda {|vote| vote.vote},
        :description => _('Point weight for the author of a voted content'),
        :default_weight => 50
      },
      :vote_voteable => {
        :action => 'vote#create',
        :undo_action => 'vote#destroy',
        :to => lambda {|vote| vote.voteable},
        :profile => lambda {|vote| vote.voteable.profile},
        :value => lambda {|vote| vote.vote},
        :description => _('Point weight for a voted content'),
        :default_weight => 50
      },
      :vote_voter => {
        :action => 'vote#create',
        :undo_action => 'vote#destroy',
        :to => lambda {|vote| vote.voter},
        :profile => lambda {|vote| vote.voter},
        :value => lambda {|vote| 1},
        :description => _('Point weight for a voter'),
        :default_weight => 10
      },
    }

    def weight(category)
      settings = Noosfero::Plugin::Settings.new(@environment, GamificationPlugin)
      settings.settings.fetch(:point_rules, {}).fetch(category.to_s, {}).fetch('weight', AVAILABLE_RULES[category][:default_weight]).to_i
    end

    def calculate_score(target, category, value)
      value = value.call(target) if value.respond_to?(:call)
      weight(category) * value
    end

    def condition(setting, target)
      condition = setting[:condition]
      condition.present? ? condition.call(target) : true
    end

    def initialize(environment=nil)
      return if environment.nil?
      @environment = environment

      AVAILABLE_RULES.each do |category, setting|
        [setting[:action], setting[:undo_action]].compact.zip([1, -1]).each do |action, signal|
          score lambda {|target| signal * calculate_score(target, category, setting[:value])}, :on => action, :to => setting[:to], :category => category do |target|
            condition(setting, target)
          end
        end
      end
    end

  end
end