class Decidim::Gamification::BadgeScorer

This class is responsible of updating scores given a model and a badge. Will also trigger any side-effects such as notifications.

Public Class Methods

new(model, badge) click to toggle source

Public: Initializes the class.

model - The model for which to update scores. badge - The `Badge` to update.

# File lib/decidim/gamification/badge_scorer.rb, line 13
def initialize(model, badge)
  raise "Invalid badge for this UserBase type" unless badge.valid_for?(model)

  @model = model
  @badge = badge
end

Public Instance Methods

decrement(amount = 1) click to toggle source

Public: Decrements the score for the model and badge.

amount - Amount to decrement. Defaults to 1.

Returns a `BadgeScore`.

# File lib/decidim/gamification/badge_scorer.rb, line 41
def decrement(amount = 1)
  raise InvalidAmountException unless amount.positive?

  with_level_tracking do
    badge_score = BadgeScore.find_by(
      user: @model,
      badge_name: @badge.name
    )

    next if badge_score.blank?

    badge_score.decrement(:value, amount)
    badge_score.value = 0 if badge_score.value.negative?
    badge_score.save!
  end
end
increment(amount = 1) click to toggle source

Public: Increments the score for the model and badge.

amount - Amount to increment. Defaults to 1.

Returns a `BadgeScore`.

# File lib/decidim/gamification/badge_scorer.rb, line 25
def increment(amount = 1)
  raise InvalidAmountException unless amount.positive?

  with_level_tracking do
    BadgeScore.find_or_create_by(
      user: @model,
      badge_name: @badge.name
    ).increment(:value, amount).save!
  end
end
set(score) click to toggle source

Public: Sets the score for the model and badge.

score - Score to set.

Returns a `BadgeScore`.

# File lib/decidim/gamification/badge_scorer.rb, line 63
def set(score)
  raise NegativeScoreException if score.negative?

  with_level_tracking do
    BadgeScore.find_or_create_by(
      user_id: @model.id,
      badge_name: @badge.name
    ).update!(value: score)
  end
end

Private Instance Methods

badges_enabled?() click to toggle source
# File lib/decidim/gamification/badge_scorer.rb, line 120
def badges_enabled?
  @model.organization.badges_enabled?
end
publish_event(name:, klass:, previous_level:, current_level:) click to toggle source
# File lib/decidim/gamification/badge_scorer.rb, line 106
def publish_event(name:, klass:, previous_level:, current_level:)
  Decidim::EventsManager.publish(
    event: name,
    event_class: klass,
    resource: @model,
    affected_users: recipients,
    extra: {
      badge_name: @badge.name.to_s,
      previous_level: previous_level,
      current_level: current_level
    }
  )
end
recipients() click to toggle source
# File lib/decidim/gamification/badge_scorer.rb, line 124
def recipients
  case @model
  when User
    [@model]
  when UserGroup
    @model.users
  end
end
send_notification(previous_level, current_level) click to toggle source
# File lib/decidim/gamification/badge_scorer.rb, line 89
def send_notification(previous_level, current_level)
  return unless current_level > previous_level
  return unless badges_enabled?

  if previous_level.zero?
    publish_event(name: "decidim.events.gamification.badge_earned",
                  klass: BadgeEarnedEvent,
                  previous_level: previous_level,
                  current_level: current_level)
  else
    publish_event(name: "decidim.events.gamification.level_up",
                  klass: LevelUpEvent,
                  previous_level: previous_level,
                  current_level: current_level)
  end
end
with_level_tracking() { || ... } click to toggle source
# File lib/decidim/gamification/badge_scorer.rb, line 79
def with_level_tracking
  previous_level = BadgeStatus.new(@model, @badge).level

  yield

  current_status = BadgeStatus.new(@model, @badge)
  send_notification(previous_level, current_status.level)
  current_status
end