robertgauld/OSMExtender

View on GitHub
app/models/automation_task_chief_scout_award.rb

Summary

Maintainability
C
1 day
Test Coverage
class AutomationTaskChiefScoutAward < AutomationTask

  ALLOWED_SECTIONS = [:beavers, :cubs, :scouts]

  BADGE_COUNTS = {
    beavers: 4,
    cubs: 6,
    scouts: 6
  }

  BADGE_IDS = {
    beavers: 1529,
    cubs: 1587,
    scouts: 1539
  }

  REQUIREMENT_IDS = {
    beavers: 114257,
    cubs: 114603,
    scouts: 114339
  }

 ACHIEVED_ACTIONS = [
    '{COUNT-OF-BADGES} of {BADGES-NEEDED}',
    '{COUNT-OF-BADGES}',
    '[YES]',
  ]

  UNACHIEVED_ACTIONS = [
    'x{COUNT-OF-BADGES} of {BADGES-NEEDED}',
    'x{COUNT-OF-BADGES}',
    'Progress bar',
    'Nothing',
  ]


  def self.required_permissions
    [ [:write, :badge], [:read, :member] ]
  end

  def self.configuration_labels
    {
      unachieved_action: "When it's not achieved set the badges column to:",
      achieved_action: "When it's achieved set the badges column to:",
    }
  end

  def self.default_configuration
    {
      unachieved_action: 0,
      achieved_action: 0,
    }
  end

  def self.configuration_types
    {
      unachieved_action: :positive_integer,
      achieved_action: :positive_integer,
    }
  end

  def self.human_name
    "Chief Scout's award"
  end

  def human_configuration
    "Set badges column to \"#{ACHIEVED_ACTIONS[configuration[:achieved_action]]}\" or \"#{UNACHIEVED_ACTIONS[configuration[:unachieved_action]]}\"."
  end



  private
  def perform_task(user=self.user)
    ret_val = {log_lines: log_lines=[], errors: errors=[]}

    section = Osm::Section.get(user.osm_api, section_id)
    if section.nil?
      return {success: false, errors: ['Could not retrieve section from OSM.']}
    end

    badge = Osm::ChallengeBadge.get_badges_for_section(user.osm_api, section) || []
    badge = badge.select{ |b| b.id.eql?(BADGE_IDS[section.type]) }.first
    if badge.nil?
      return {success: false, errors: ["Could not retrieve Chief Scout's Award badge from OSM."]}
    end
    member_badge_data = badge.get_data_for_section(user.osm_api, section)
                             .map{ |d| [d.member_id, d] }
                             .to_h

    member_start_dates = Osm::Member.get_for_section(user.osm_api, section)
                                    &.map{ |m| [m.id, m.started_section] }
                                    &.select { |(_id, started_section)| !!started_section }
                                    &.to_h
    if member_start_dates.nil?
      return {success: false, errors: ['Could not retrieve Start dates from OSM.']}
    end

    activity_badges = Osm::ActivityBadge.get_badges_for_section(user.osm_api, section)&.map{ |b| [b.identifier, b] }&.to_h
    if activity_badges.nil?
      return {success: false, errors: ['Could not retrieve Activity badges from OSM.']}
    end
    staged_badges = Osm::StagedBadge.get_badges_for_section(user.osm_api, section)&.map{ |b| [b.identifier, b] }&.to_h
    if staged_badges.nil?
      return {success: false, errors: ['Could not retrieve Staged badges from OSM.']}
    end

    badge_summaries = Osm::Badge.get_summary_for_section(user.osm_api, section)
    badge_summaries.each do |badge_summary|
      count_for_member = 0

      start_date = member_start_dates[badge_summary[:member_id]]
      unless start_date.is_a?(Date) # Can't do the comparrison
        # errors.push "Couldn't get started section date for #{badge_summary[:name]}."
        next badge_summary
      end

      activity_badges.keys.each do |identifier|
        if [:awarded, :due].include?(badge_summary[identifier])
          count_for_member += 1
        end        
      end # each activity badge identifier

      staged_badges.keys.each do |identifier|
        if badge_summary[identifier].eql?(:awarded)
          # Don't want to count staged badge awarded in previous section
          award_date = badge_summary["#{identifier}_date"]
          unless award_date.is_a?(Date)  # Can't do the comparrison
            errors.push "Couldn't get awarded date for #{badge_summary[:name]}'s #{staged_badges[identifier].name} badge."
            next identifier
          end

          if start_date <= award_date    # Awarded after starting section
            count_for_member += 1
          end

        elsif badge_summary[identifier].eql?(:due)
          # Always want to count a due badge
          count_for_member += 1
        end
      end # each staged badge identifier

      log_lines.push "#{badge_summary[:name]} has achieved #{count_for_member} of #{BADGE_COUNTS[section.type]} activity/staged activity badges."

      set_data_to = ''
      if count_for_member >= BADGE_COUNTS[section.type]
        # Member has achieved required number of badges since joining section
        case configuration[:achieved_action]
        when 0
          set_data_to = "#{count_for_member} of #{BADGE_COUNTS[section.type]}"
        when 1
          set_data_to = "#{count_for_member}"
        when 2
          set_data_to = '[YES]'
        end

      else
        # Member has NOT achieved required number of badges since joining section
        case configuration[:unachieved_action]
        when 0
          set_data_to = "x#{count_for_member} of #{BADGE_COUNTS[section.type]}"
        when 1
          set_data_to = "x#{count_for_member}"
        when 2 # Progress bar
          if count_for_member > 0
            set_data_to = "#{'x' * count_for_member}#{'_' * (BADGE_COUNTS[section.type] - count_for_member)}"
          end
        when 3
          set_data_to = ''
        end

      end # if achieved

      # Update data value if it changed
      badge_data = member_badge_data[badge_summary[:member_id]]
      unless (badge_data.requirements[REQUIREMENT_IDS[section.type]] || '').eql?(set_data_to)
        badge_data.requirements[REQUIREMENT_IDS[section.type]] = set_data_to    
        begin
          if badge_data.update(user.osm_api)
            log_lines.push(["Updated data in OSM to \"#{set_data_to}\"."])
          else
            errors.push "Couldn't update #{badge_summary[:name]}'s data to \"#{set_data_to}\"."
          end
        rescue Osm::Error => exception
          errors.push "Couldn't update #{badge_summary[:name]}'s data to \"#{set_data_to}\". OSM said \"#{exception.message}\"."
        end
      end

    end # each badge_summary

    ret_val.merge(success: ret_val[:errors].empty?)
  end

end