Class: Osm::Badge

Inherits:
Model
  • Object
show all
Defined in:
lib/osm/badge.rb

Direct Known Subclasses

ActivityBadge, ChallengeBadge, CoreBadge, StagedBadge

Defined Under Namespace

Classes: Data, Requirement, RequirementModule

Constant Summary

Constants inherited from Model

Model::SORT_BY

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Model

#<, #<=, #>, #>=, #between?, #changed_attributes, configure, #reset_changed_attributes, #to_i

Constructor Details

#initializeObject

Initialize a new Badge

Parameters:

  • attributes (Hash)

    The hash of attributes (see attributes for descriptions, use Symbol of attribute name as the key)



# File 'lib/osm/badge.rb', line 91

Instance Attribute Details

#add_columns_to_moduleFixnum?

Returns the module to add columns to for nights away type badges.

Returns:

  • (Fixnum, nil)

    the module to add columns to for nights away type badges



48
# File 'lib/osm/badge.rb', line 48

attribute :name, :type => String

#badges_requiredArray<Hash>

Returns the other badges required to complete this badge, The ID of the badge, version: The version of the badge.

Returns:

  • (Array<Hash>)

    the other badges required to complete this badge, The ID of the badge, version: The version of the badge



48
# File 'lib/osm/badge.rb', line 48

attribute :name, :type => String

#group_nameString

Returns what group (if any) this badge belongs to (eg Core, Partnership), used only for display sorting.

Returns:

  • (String)

    what group (if any) this badge belongs to (eg Core, Partnership), used only for display sorting



48
# File 'lib/osm/badge.rb', line 48

attribute :name, :type => String

#idFixnum

Returns the badge’s id in OSM.

Returns:

  • (Fixnum)

    the badge’s id in OSM



48
# File 'lib/osm/badge.rb', line 48

attribute :name, :type => String

#identifierString

Returns the identifier used by OSM for this badge & version.

Returns:

  • (String)

    the identifier used by OSM for this badge & version



48
# File 'lib/osm/badge.rb', line 48

attribute :name, :type => String

#latestBoolean

Returns whether this is the latest version of the badge.

Returns:

  • (Boolean)

    whether this is the latest version of the badge



48
# File 'lib/osm/badge.rb', line 48

attribute :name, :type => String

#level_requirementFixnum?

Returns the column which stores the currently earnt level of nights away type badges.

Returns:

  • (Fixnum, nil)

    the column which stores the currently earnt level of nights away type badges



48
# File 'lib/osm/badge.rb', line 48

attribute :name, :type => String

#levelsArray<Fixnum>?

Returns the levels available, nil if it’s a single level badge.

Returns:

  • (Array<Fixnum>, nil)

    the levels available, nil if it’s a single level badge



48
# File 'lib/osm/badge.rb', line 48

attribute :name, :type => String

#min_modules_requiredFixnum

Returns the minimum number of modules which must be completed to earn the badge.

Returns:

  • (Fixnum)

    the minimum number of modules which must be completed to earn the badge



48
# File 'lib/osm/badge.rb', line 48

attribute :name, :type => String

#min_requirements_requiredFixnum

Returns the minimum number of requirements which must be completed to earn the badge.

Returns:

  • (Fixnum)

    the minimum number of requirements which must be completed to earn the badge



48
# File 'lib/osm/badge.rb', line 48

attribute :name, :type => String

#modulesArray<Hash>

Returns Details of the modules which make up the badge.

Returns:

  • (Array<Hash>)

    Details of the modules which make up the badge



48
# File 'lib/osm/badge.rb', line 48

attribute :name, :type => String

#nameString

Returns the name of the badge.

Returns:

  • (String)

    the name of the badge



48
# File 'lib/osm/badge.rb', line 48

attribute :name, :type => String

#other_requirements_requiredArray<Hash>

Returns the requirements (from other badges) required to complete this badge, field ID, min: the minimum numerical value of the field’s data.

Returns:

  • (Array<Hash>)

    the requirements (from other badges) required to complete this badge, field ID, min: the minimum numerical value of the field’s data



48
# File 'lib/osm/badge.rb', line 48

attribute :name, :type => String

#requirement_notesString

Returns a description of the badge.

Returns:

  • (String)

    a description of the badge



48
# File 'lib/osm/badge.rb', line 48

attribute :name, :type => String

#requirementsArray<Osm::Badge::Requirement>

Returns the requirements of the badge.

Returns:



48
# File 'lib/osm/badge.rb', line 48

attribute :name, :type => String

#requires_modulesArray<Array<String>>?

Returns the module letters required to gain the badge, at least one from each inner Array.

Returns:

  • (Array<Array<String>>, nil)

    the module letters required to gain the badge, at least one from each inner Array



48
# File 'lib/osm/badge.rb', line 48

attribute :name, :type => String

#sharingSymbol

Returns the sharing status of this badge (:draft, :private, :optin, :default_locked, :optin_locked).

Returns:

  • (Symbol)

    the sharing status of this badge (:draft, :private, :optin, :default_locked, :optin_locked)



48
# File 'lib/osm/badge.rb', line 48

attribute :name, :type => String

#show_level_lettersBoolean

Returns Whether to show letters not numbers for the levels of a staged badge.

Returns:

  • (Boolean)

    Whether to show letters not numbers for the levels of a staged badge



48
# File 'lib/osm/badge.rb', line 48

attribute :name, :type => String

#user_idFixnum

Returns the OSM user who created this (version of the) badge.

Returns:

  • (Fixnum)

    the OSM user who created this (version of the) badge



48
# File 'lib/osm/badge.rb', line 48

attribute :name, :type => String

#versionFixnum

Returns the version of the badge.

Returns:

  • (Fixnum)

    the version of the badge



48
# File 'lib/osm/badge.rb', line 48

attribute :name, :type => String

Class Method Details

.get_badges_for_section(api, section, section_type = nil, options = {}) ⇒ Array<Osm::Badge>

Get badges

Parameters:

  • api (Osm::Api)

    The api to use to make the request

  • section (Osm::Section, Fixnum, #to_i)

    The section (or its ID) to get the due badges for

  • section_type (Symbol) (defaults to: nil)

    The type of section to get badges for (if nil uses the type of the section param)

Returns:

Raises:



101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
# File 'lib/osm/badge.rb', line 101

def self.get_badges_for_section(api, section, section_type=nil, options={})
  raise Error, 'This method must be called on one of the subclasses (CoreBadge, ChallengeBadge, StagedBadge or ActivityBadge)' if type.nil?
  require_ability_to(api, :read, :badge, section, options)
  section = Osm::Section.get(api, section, options) unless section.is_a?(Osm::Section)
  section_type ||= section.type
  cache_key = ['badges', section_type, type]

  if !options[:no_cache] && Osm::Model.cache_exist?(api, cache_key)
    return cache_read(api, cache_key)
  end

  term_id = Osm::Term.get_current_term_for_section(api, section, options).to_i
  badges = []
  badge_sharing_map = {
    'draft' => :draft,
    'private' => :private,
    'optin' => :optin,
    'optin-locked' => :optin_locked,
    'default-locked' => :default_locked
  }

  data = api.perform_query("ext/badges/records/?action=getBadgeStructureByType&section=#{section_type}&type_id=#{type_id}&term_id=#{term_id}&section_id=#{section.id}")
  badge_order = data["badgeOrder"].to_s.split(',')
  structures = data["structure"] || {}
  details = data["details"] || {}

  badge_order.each do |b|
    structure = structures[b]
    detail = details[b]
    config = ActiveSupport::JSON.decode(detail['config'] || '{}')

    badge = new(
      :id => detail['badge_id'],
      :version => detail['badge_version'],
      :identifier => detail['badge_identifier'],
      :name => detail['name'],
      :requirement_notes => detail['description'],
      :group_name => detail['group_name'],
      :latest => detail['latest'].to_i.eql?(1),
      :sharing => badge_sharing_map[detail['sharing']],
      :user_id => Osm.to_i_or_nil(detail['userid']),
      :levels => config['levelslist'],
      :min_modules_required => config['numModulesRequired'].to_i,
      :min_requirements_required => config['minRequirementsCompleted'].to_i,
      :add_columns_to_module => Osm.to_i_or_nil(config['addcolumns']),
      :level_requirement => Osm.to_i_or_nil(config['levels_column_id']),
      :requires_modules => config['requires'],
      :other_requirements_required => (config['columnsRequired'] || []).map{ |i| {id: Osm.to_i_or_nil(i['id']), min: i['min'].to_i} },
      :badges_required => (config['badgesRequired'] || []).map{ |i| {id: Osm.to_i_or_nil(i['id']), version: i['version'].to_i} },
      :show_level_letters => !!config['shownumbers'],
    )

    modules = module_completion_data(api, badge, options)
    badge.modules = modules
    modules = Hash[*modules.map{|m| [m.letter, m]}.flatten]

    requirements = []
    ((structure[1] || {})['rows'] || []).each do |r|
      requirements.push Osm::Badge::Requirement.new(
        :badge => badge,
        :name => r['name'],
        :description => r['tooltip'],
        :mod => modules[r['module']],
        :id => Osm::to_i_or_nil(r['field']),
        :editable => r['editable'].to_s.eql?('true'),
      )
    end
    badge.requirements = requirements

    badges.push badge
  end

  cache_write(api, cache_key, badges)
  return badges
end

.get_summary_for_section(api, section, term = nil, options = {}) ⇒ Array<Hash>

Get a summary of badges earnt by members

Parameters:

  • api (Osm::Api)

    The api to use to make the request

  • section (Osm::Section, Fixnum, #to_i)

    The section (or its ID) to get the due badges for

  • term (Osm::Term, Fixnum, #to_i, nil) (defaults to: nil)

    The term (or its ID) to get the due badges for, passing nil causes the current term to be used

Returns:

  • (Array<Hash>)

Raises:



183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
# File 'lib/osm/badge.rb', line 183

def self.get_summary_for_section(api, section, term=nil, options={})
  raise Error, 'This method must NOT be called on one of the subclasses(CoreBadge, ChallengeBadge, StagedBadge or ActivityBadge)' unless type.nil?
  require_ability_to(api, :read, :badge, section, options)
  section = Osm::Section.get(api, section, options) unless section.is_a?(Osm::Section)
  term_id = (term.nil? ? Osm::Term.get_current_term_for_section(api, section, options) : term).to_i
  cache_key = ['badge-summary', section.id, term_id]

  if !options[:no_cache] && Osm::Model.cache_exist?(api, cache_key)
    return cache_read(api, cache_key)
  end

  summary = []
  data = api.perform_query("ext/badges/records/summary/?action=get&mode=verbose&section=#{section.type}&sectionid=#{section.id}&termid=#{term_id}")
  data['items'].each do |item|
    new_item = {
      :first_name => item['firstname'],
      :last_name => item['lastname'],
      :name => "#{item['firstname']} #{item['lastname']}",
      :member_id => Osm.to_i_or_nil(item['scout_id']),
    }

    badge_data = Hash[item.to_a.select{ |k,v| !!k.match(/\d+_\d+/) }]
    badge_data.each do |badge_identifier, status|
      if status.is_a?(String)
        # Possible statuses: 
        # 'Started',
        # 'Due', 'Due Lvl 2'
        # 'Awarded', 'Awarded Lvl 2', '01/02/2003', '02/03/2004 (Lvl 2)'
        if status.eql?('Started')
          new_item[badge_identifier] = :started
        elsif status.eql?('Due')
          new_item[badge_identifier] = :due
        elsif match_data = status.match(/\ADue Lvl (\d+)\Z/)
          new_item[badge_identifier] = :due
          new_item["#{badge_identifier}_level"] = match_data[1].to_i
        elsif status.eql?('Awarded')
          new_item[badge_identifier] = :awarded
        elsif match_data = status.match(/\AAwarded Lvl (\d+)\Z/)
          new_item[badge_identifier] = :awarded
          new_item["#{badge_identifier}_level"] = match_data[1].to_i
        elsif match_data = status.match(Osm::OSM_DATE_REGEX)
          new_item[badge_identifier] = :awarded
          new_item["#{badge_identifier}_date"] = Osm.parse_date(match_data[0])
        elsif match_data = status.match(/\A(#{Osm::OSM_DATE_REGEX_UNANCHORED.to_s}) \(Lvl (\d+)\)\Z/)
          new_item[badge_identifier] = :awarded
          new_item["#{badge_identifier}_date"] = Osm.parse_date(match_data[1])
          new_item["#{badge_identifier}_level"] = match_data[2].to_i
        end
      end
    end

    summary.push new_item
  end

  cache_write(api, cache_key, summary)
  return summary
end

.typeObject



382
383
384
# File 'lib/osm/badge.rb', line 382

def self.type
  nil
end

Instance Method Details

#<=>(another) ⇒ Object

Compare Badge based on name then id then version (desc)



312
313
314
315
316
317
# File 'lib/osm/badge.rb', line 312

def <=>(another)
  result = self.name <=> another.try(:name)
  result = self.id <=> another.try(:id) if result == 0
  result = another.try(:version) <=> self.version if result == 0
  return result
end

#add_columns?Boolean

Returns:

  • (Boolean)


284
285
286
# File 'lib/osm/badge.rb', line 284

def add_columns?
  !add_columns_to_module.nil?
end

#get_data_for_section(api, section, term = nil, options = {}) ⇒ Array<Osm::Badge::Data>

Get a list of badge requirements met by members

Parameters:

  • api (Osm::Api)

    The api to use to make the request

  • section (Osm::Section, Fixnum, #to_i)

    The section (or its ID) to get the due badges for

  • term (Osm::Term, Fixnum, #to_i, nil) (defaults to: nil)

    The term (or its ID) to get the due badges for, passing nil causes the current term to be used

Returns:

Raises:



247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
# File 'lib/osm/badge.rb', line 247

def get_data_for_section(api, section, term=nil, options={})
  raise Error, 'This method must be called on one of the subclasses (CoreBadge, ChallengeBadge, StagedBadge or ActivityBadge)' if type.nil?
  Osm::Model.require_ability_to(api, :read, :badge, section, options)
  section = Osm::Section.get(api, section, options) unless section.is_a?(Osm::Section)
  term_id = (term.nil? ? Osm::Term.get_current_term_for_section(api, section, options) : term).to_i
  cache_key = ['badge_data', section.id, term_id, id, version]

  if !options[:no_cache] && cache_exist?(api, cache_key)
    return cache_read(api, cache_key)
  end

  datas = []
  data = api.perform_query("ext/badges/records/?action=getBadgeRecords&term_id=#{term_id}&section=#{section.type}&badge_id=#{id}&section_id=#{section.id}&badge_version=#{version}")

  data['items'].each do |d|
    datas.push Osm::Badge::Data.new(
      :member_id => d['scoutid'],
      :first_name => d['firstname'],
      :last_name => d['lastname'],
      :due => d['completed'].to_i,
      :awarded => d['awarded'].to_i,
      :awarded_date => Osm.parse_date(d['awardeddate']),
      :requirements => Hash[d.map{ |k,v| [k.to_i, v] }].except(0),
      :section_id => section.id,
      :badge => self,
    )
  end

  cache_write(api, cache_key, datas)
  return datas
end

#has_levels?Boolean

Returns:

  • (Boolean)


280
281
282
# File 'lib/osm/badge.rb', line 280

def has_levels?
  !levels.nil?
end

#module_idsObject



306
307
308
# File 'lib/osm/badge.rb', line 306

def module_ids
  @module_ids ||= modules.map{ |m| m.id }.sort
end

#module_lettersObject



302
303
304
# File 'lib/osm/badge.rb', line 302

def module_letters
  @module_letters ||= modules.map{ |m| m.letter }.sort
end

#module_mapObject



288
289
290
291
292
293
294
# File 'lib/osm/badge.rb', line 288

def module_map
  @module_map ||= Hash[
    *modules.map{ |m| 
      [m.id, m.letter, m.letter, m.id]
    }.flatten
  ].except('z')
end

#needed_per_moduleObject



296
297
298
299
300
# File 'lib/osm/badge.rb', line 296

def needed_per_module
  @needed_per_module ||= Hash[*modules.map{ |m|
    [m.id, m.min_required, m.letter, m.min_required]
  }.flatten].except('z')
end

#typeObject



385
386
387
# File 'lib/osm/badge.rb', line 385

def type
  self.class.type
end