class Osm::Badge::Data

Constants

SORT_BY

Public Instance Methods

earnt() click to toggle source

Get what stage which has most recently been earnt (using earnt? will tell you if it's still due (not yet awarded)) @return [Fixnum] the stage which has most recently been due

# File lib/osm/badge.rb, line 654
def earnt
  unless badge.has_levels?
    return earnt? ? 1 : 0
  end

  levels_column = badge.level_requirement
  unless badge.show_level_letters # It's a hikes, nights type badge
    badge.levels.reverse_each do |level|
      return level if requirements[levels_column].to_i >= level
    end
  else # It's an activity type badge
    modules = modules_gained
    letters = ('a'..'z').to_a
    (awarded..badge.levels.last).reverse_each do |level|
      return level if modules.include?(letters[level - 1])
    end
  end
  return 0
end
earnt?() click to toggle source

Check if this badge has been earnt @return [Boolean] whether the badge has been earnt (ignores other badge's and their requirements which might be needed)

# File lib/osm/badge.rb, line 614
def earnt?
  if badge.has_levels?
    return earnt > awarded
  else
    return false if (due.eql?(1) && awarded.eql?(1))
    return true if (due.eql?(1) && awarded.eql?(0))

    if badge.min_modules_required > 0
      return false unless modules_gained.size >= badge.min_modules_required
    end
    if badge.min_requirements_required > 0
      return false unless total_gained >= badge.min_requirements_required
    end
    if badge.requires_modules
      # [['a'], ['b', 'c']] = a and (b or c)
      requires = badge.requires_modules.clone
      modules = modules_gained
      requires.map!{ |a| a.map{ |b| modules.include?(b) } } # Replace letters with true/false
      requires.map!{ |a| a.include?(true) } # Replace each combination with true/false
      return false if requires.include?(false) # Only earnt if all combinations are met
    end
    badge.other_requirements_required.each do |c|
      # {:id => ###, :min => #}
      if requirements.has_key?(c[:id]) # Only check it if the data is in the requirements Hash
        return false unless requirement_met?(c[:id])
        return false if requirements[c[:id]].to_i < c[:min]
      end
    end
    badge.badges_required.each do |b|
      # {:id => ###, :version => #}
      #TODO
    end
    return true
  end
end
gained_in_modules() click to toggle source

Get the number of requirements gained in each module @return [Hash]

# File lib/osm/badge.rb, line 597
def gained_in_modules
  count = {}
  badge.modules.each do |mod|
    count[mod.id] ||= 0
    count[mod.letter] ||= 0
  end
  badge.requirements.each do |requirement|
    next unless requirement_met?(requirement.id)
    count[requirement.mod.id] += 1
    count[requirement.mod.letter] += 1
  end
  count
end
inspect() click to toggle source
# File lib/osm/badge.rb, line 848
def inspect
  Osm.inspect_instance(self, {:replace_with => {'badge' => :name}})
end
mark_awarded(api, date=Date.today, level=due) click to toggle source

Mark the badge as awarded in OSM @param [Osm::Api] api The api to use to make the request @param [Date] date The date to mark the badge as awarded @param [Fixnum] level The level of the badge to award (1 for non-staged badges), setting the level to 0 unawards the badge @return [Boolean] whether the data was updated in OSM

# File lib/osm/badge.rb, line 728
def mark_awarded(api, date=Date.today, level=due)
  raise ArgumentError, 'date is not a Date' unless date.is_a?(Date)
  raise ArgumentError, 'level can not be negative' if level < 0
  section = Osm::Section.get(api, section_id)
  require_ability_to(api, :write, :badge, section)

  date_formatted = date.strftime(Osm::OSM_DATE_FORMAT)
  entries = [{
    'badge_id' => badge.id.to_s,
    'badge_version' => badge.version.to_s,
    'scout_id' => member_id.to_s,
    'level' => level.to_s
  }]

  result = api.perform_query("ext/badges/records/?action=awardBadge", {
    'date' => date_formatted,
    'sectionid' => section_id,
    'entries' => entries.to_json
  })
  updated = result.is_a?(Hash) &&
            (result['scoutid'].to_i == member_id) &&
            (result['awarded'].to_i == level) &&
            (result['awardeddate'] == date_formatted)

  if updated
    awarded = level
    awarded_date = date
  end
  return updated
end
mark_due(api, level=earnt) click to toggle source

Mark the badge as due in OSM @param [Osm::Api] api The api to use to make the request @param [Fixnum] level The level of the badge to award (1 for non-staged badges), setting the level to 0 unawards the badge @return [Boolean] whether the data was updated in OSM

# File lib/osm/badge.rb, line 771
def mark_due(api, level=earnt)
  raise ArgumentError, 'level can not be negative' if level < 0
  section = Osm::Section.get(api, section_id)
  require_ability_to(api, :write, :badge, section)

  result = api.perform_query("ext/badges/records/?action=overrideCompletion", {
    'section_id' => section.id,
    'badge_id' => badge.id,
    'badge_version' => badge.version,
    'scoutid' => member_id,
    'level' => level
  })
  updated = result.is_a?(Hash) &&
            (result['scoutid'].to_i == member_id) &&
            (result['completed'].to_i == level)
  return updated
end
mark_not_awarded(api) click to toggle source

Mark the badge as not awarded in OSM @param [Osm::Api] api The api to use to make the request @return [Boolean] whether the data was updated in OSM

# File lib/osm/badge.rb, line 762
def mark_not_awarded(api)
  mark_awarded(api, Date.today, 0)
end
mark_not_due(api) click to toggle source

Mark the badge as not due in OSM @param [Osm::Api] api The api to use to make the request @return [Boolean] whether the data was updated in OSM

# File lib/osm/badge.rb, line 792
def mark_not_due(api)
  mark_due(api, 0)
end
modules_gained() click to toggle source

Get the letters of modules gained @return [Array<Stirng>]

# File lib/osm/badge.rb, line 585
def modules_gained
  g_i_m = gained_in_modules
  gained = []
  badge.modules.each do |mod|
    next if g_i_m[mod.id] < mod.min_required
    gained.push mod.letter
  end
  gained
end
requirement_met?(requirement_id) click to toggle source

Work out if the requirmeent has been met @param [Fixnum, to_i] requirement_id The id of the requirement to evaluate (e.g. “12”, “xSomething”, “Yes” or “”) @return [Boolean] whether the requirmeent has been met

# File lib/osm/badge.rb, line 855
def requirement_met?(requirement_id)
  data = requirements[requirement_id.to_i].to_s
  return false if data == '0'
  !(data.blank? || data[0].downcase.eql?('x'))
end
started() click to toggle source

Get which stage has been started @return [Fixnum] which stage of the badge has been started by the member (lowest)

# File lib/osm/badge.rb, line 691
def started
  unless badge.has_levels?
    return started? ? 1 : 0
  end
  unless badge.show_level_letters
    # Nights, Hikes or Water
    done = requirements[badge.level_requirement].to_i
    levels = badge.levels                    # e.g. [0,1,2,3,4,5,10]
    return 0 if levels.include?(done)        # Has achieved a level (and not started next )
    return 0 if done >= levels[-1]           # No more levels to do
    (1..(levels.size-1)).to_a.reverse_each do |i|  # indexes from last to 2nd
      this_level = levels[i]
      previous_level = levels[i-1]
      return this_level if (done < this_level && done > previous_level) # this_level has been started (and not finished)
    end
    return 0 # No reason we should ever get here
  else
    # 'Normal' staged
    letters = ('a'..'z').to_a
    top_level = badge.levels[-1]
    return 0 if due == top_level || awarded == top_level # No more levels to do
    ((due + 1)..top_level).reverse_each do |level|
      badge.requirements.each do |requirement|
        next unless requirement.mod.letter.eql?(letters[level - 1]) # Not interested in other levels
        return level if requirement_met?(requirement.id)
      end
    end
    return 0 # No levels started
  end
end
started?() click to toggle source

Check if this badge has been started @return [Boolean] whether the badge has been started by the member (always false if the badge has been completed)

# File lib/osm/badge.rb, line 677
def started?
  if badge.has_levels?
    return (started > due)
  end
  return false if due?
  requirements.each do |key, value|
    return true if requirement_met?(key)
  end
  return false
end
total_gained() click to toggle source

Get the total number of gained requirements @return [Fixnum] the total number of requirements considered gained

# File lib/osm/badge.rb, line 574
def total_gained
  count = 0
  badge.requirements.each do |requirement|
    next unless requirement_met?(requirement.id)
    count += 1
  end
  return count
end
update(api) click to toggle source

Update data in OSM @param [Osm::Api] api The api to use to make the request @return [Boolean] whether the data was updated in OSM @raise [Osm::ObjectIsInvalid] If the Data is invalid

# File lib/osm/badge.rb, line 800
def update(api)
  raise Osm::ObjectIsInvalid, 'data is invalid' unless valid?
  section = Osm::Section.get(api, section_id)
  require_ability_to(api, :write, :badge, section)

  # Update requirements that changed
  requirements_updated = true
  editable_requirements = badge.requirements.select{ |r| r.editable }.map{ |r| r.id }
  requirements.changes.each do |requirement, (was,now)|
    if editable_requirements.include?(requirement)
      result = api.perform_query("ext/badges/records/?action=updateSingleRecord", {
        'scoutid' => member_id,
        'section_id' => section_id,
        'badge_id' => badge.id,
        'badge_version' => badge.version,
        'field' => requirement,
        'value' => now
      })
      requirements_updated = false unless result.is_a?(Hash) &&
                             (result['scoutid'].to_i == member_id) &&
                             (result[requirement.to_s].to_s == now.to_s)
    end
  end

  if requirements_updated
    requirements.clean_up!
  end

  # Update due if it changed
  due_updated = true
  if changed_attributes.include?('due')
    due_updated = mark_due(api, due)
  end

  # Update awarded if it changed
  awarded_updated = true
  if changed_attributes.include?('awarded') || changed_attributes.include?('awarded_date')
    awarded_updated = mark_awarded(api, awarded_date, awarded)
  end

  # reset changed attributes if everything was updated ok
  if due_updated && awarded_updated
    reset_changed_attributes
  end

  return requirements_updated && due_updated && awarded_updated
end