class Osm::Member

Constants

CID_ADDRESS_1
CID_ADDRESS_2
CID_ADDRESS_3
CID_ADDRESS_4
CID_EMAIL_1
CID_EMAIL_2
CID_FIRST_NAME

Constants for column id

CID_GENDER
CID_LAST_NAME
CID_PHONE_1
CID_PHONE_2
CID_POSTCODE
CID_RECIEVE_EMAIL_1
CID_RECIEVE_EMAIL_2
CID_RECIEVE_PHONE_1
CID_RECIEVE_PHONE_2
CID_SURGERY
CORE_FIELD_IDS
GID_CUSTOM
GID_DOCTOR_CONTACT
GID_EMERGENCY_CONTACT
GID_FLOATING
GID_MEMBER_CONTACT
GID_PRIMARY_CONTACT

Constants for group id

GID_SECONDARY_CONTACT

Public Class Methods

get_for_section(api, section, term=nil, options={}) click to toggle source

Get members for a section @param [Osm::Api] api The api to use to make the request @param [Osm::Section, Fixnum, to_i] section The section (or its ID) to get the members for @param [Osm::Term, Fixnum, to_i, nil] term The term (or its ID) to get the members for, passing nil causes the current term to be used @!macro options_get @return [Array<Osm::Member>]

# File lib/osm/member.rb, line 139
def self.get_for_section(api, section, term=nil, options={})
  require_ability_to(api, :read, :member, section, options)
  if term.nil?
    section = Osm::Section.get(api, section) if section.is_a?(Fixnum)
    term = section.waiting? ? -1 : Osm::Term.get_current_term_for_section(api, section)
  end
  cache_key = ['members', section.to_i, term.to_i]

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

  result = Array.new

  api_response = api.perform_query('ext/members/contact/grid/?action=getMembers', {
    'section_id' => section.to_i,
    'term_id' => term.to_i,
  })

  data = api_response['data'].is_a?(Hash) ? api_response['data'].values : []
  structure = (api_response['meta'] || {})['structure'] || []
  structure = Hash[ structure.map{ |i| [i['group_id'].to_i, i ] } ] # Make a hash of identifier to group data hash

  custom_labels = {}
  key_key = 'column_id'   # the key in the data from OSM to use as the key in additional_information and labels hashes
  structure.each do |gid, group|
    columns = group['columns'] || []
    custom_labels[gid.to_i] = Hash[ columns.map.select{ |a| gid.eql?(GID_CUSTOM) || !CORE_FIELD_IDS.include?(a['column_id'].to_i) }.map{ |c| [c[key_key], c['label']] } ]
  end

  data.each do |item|
    item_data = Hash[ item['custom_data'].map{ |k,v| [k.to_i, v] } ]
    member_contact = item_data[GID_MEMBER_CONTACT].nil? ? nil : Hash[ item_data[GID_MEMBER_CONTACT].map{ |k,v| [k.to_i, v] }.select{ |k,v| CORE_FIELD_IDS.include?(k) } ]
    member_custom = item_data[GID_MEMBER_CONTACT].nil? ? DirtyHashy.new : DirtyHashy[ item_data[GID_MEMBER_CONTACT].select{ |k,v| !CORE_FIELD_IDS.include?(k.to_i) }.map{ |k,v| [k.to_i, v] } ]
    primary_contact = item_data[GID_PRIMARY_CONTACT].nil? ? nil : Hash[ item_data[GID_PRIMARY_CONTACT].map{ |k,v| [k.to_i, v] }.select{ |k,v| CORE_FIELD_IDS.include?(k) } ]
    primary_custom = item_data[GID_PRIMARY_CONTACT].nil? ? DirtyHashy.new : DirtyHashy[ item_data[GID_PRIMARY_CONTACT].select{ |k,v| !CORE_FIELD_IDS.include?(k.to_i) }.map{ |k,v| [k.to_i, v] } ]
    secondary_contact = item_data[GID_SECONDARY_CONTACT].nil? ? nil : Hash[ item_data[GID_SECONDARY_CONTACT].map{ |k,v| [k.to_i, v] }.select{ |k,v| CORE_FIELD_IDS.include?(k) } ]
    secondary_custom = item_data[GID_SECONDARY_CONTACT].nil? ? DirtyHashy.new : DirtyHashy[ item_data[GID_SECONDARY_CONTACT].select{ |k,v| !CORE_FIELD_IDS.include?(k.to_i) }.map{ |k,v| [k.to_i, v] } ]
    emergency_contact = item_data[GID_EMERGENCY_CONTACT].nil? ? nil : Hash[ item_data[GID_EMERGENCY_CONTACT].map{ |k,v| [k.to_i, v] }.select{ |k,v| CORE_FIELD_IDS.include?(k) } ]
    emergency_custom = item_data[GID_EMERGENCY_CONTACT].nil? ? DirtyHashy.new : DirtyHashy[ item_data[GID_EMERGENCY_CONTACT].select{ |k,v| !CORE_FIELD_IDS.include?(k.to_i) }.map{ |k,v| [k.to_i, v] } ]
    doctor_contact = item_data[GID_DOCTOR_CONTACT].nil? ? nil : Hash[ item_data[GID_DOCTOR_CONTACT].map{ |k,v| [k.to_i, v] }.select{ |k,v| CORE_FIELD_IDS.include?(k) } ]
    doctor_custom = item_data[GID_DOCTOR_CONTACT].nil? ? DirtyHashy.new : DirtyHashy[ item_data[GID_DOCTOR_CONTACT].select{ |k,v| !CORE_FIELD_IDS.include?(k.to_i) }.map{ |k,v| [k.to_i, v] } ]
    floating_data = item_data[GID_FLOATING].nil? ? {} : Hash[ item_data[GID_FLOATING].map{ |k,v| [k.to_i, v] }.select{ |k,v| CORE_FIELD_IDS.include?(k) } ]
    custom_data = item_data[GID_CUSTOM].nil? ? DirtyHashy.new : DirtyHashy[ item_data[GID_CUSTOM].map{ |k,v| [k.to_i, v] } ]

    result.push Osm::Member.new(
      :id => Osm::to_i_or_nil(item['member_id']),
      :section_id => Osm::to_i_or_nil(item['section_id']),
      :first_name => item['first_name'],
      :last_name => item['last_name'],
      :grouping_id => Osm::to_i_or_nil(item['patrol_id']),
      :grouping_label => item['patrol'],
      :grouping_leader => item['patrol_role_level'],
      :grouping_leader_label => item['patrol_role_level_label'],
      :age => item['age'],
      :date_of_birth => Osm::parse_date(item['date_of_birth'], :ignore_epoch => true),
      :started_section => Osm::parse_date(item['joined']),
      :finished_section => Osm::parse_date(item['end_date']),
      :joined_movement => Osm::parse_date(item['started']),
      :gender => {'male'=>:male, 'female'=>:female, 'other'=>:other, 'unspecified'=>:unspecified}[(floating_data[CID_GENDER] || '').downcase],
      :contact => member_contact.nil? ? nil : MemberContact.new(
        first_name: item['first_name'],
        last_name: item['last_name'],
        address_1: member_contact[CID_ADDRESS_1],
        address_2: member_contact[CID_ADDRESS_2],
        address_3: member_contact[CID_ADDRESS_3],
        address_4: member_contact[CID_ADDRESS_4],
        postcode: member_contact[CID_POSTCODE],
        phone_1: member_contact[CID_PHONE_1],
        phone_2: member_contact[CID_PHONE_2],
        email_1: member_contact[CID_EMAIL_1],
        email_2: member_contact[CID_EMAIL_2],
        receive_phone_1: member_contact[CID_RECIEVE_PHONE_1].eql?('yes'),
        receive_phone_2: member_contact[CID_RECIEVE_PHONE_2].eql?('yes'),
        receive_email_1: member_contact[CID_RECIEVE_EMAIL_1].eql?('yes'),
        receive_email_2: member_contact[CID_RECIEVE_EMAIL_2].eql?('yes'),
        additional_information: member_custom,
        additional_information_labels: custom_labels[GID_MEMBER_CONTACT],
      ),
      :primary_contact => primary_contact.nil? ? nil : PrimaryContact.new(
        first_name: primary_contact[CID_FIRST_NAME],
        last_name: primary_contact[CID_LAST_NAME],
        address_1: primary_contact[CID_ADDRESS_1],
        address_2: primary_contact[CID_ADDRESS_2],
        address_3: primary_contact[CID_ADDRESS_3],
        address_4: primary_contact[CID_ADDRESS_4],
        postcode: primary_contact[CID_POSTCODE],
        phone_1: primary_contact[CID_PHONE_1],
        phone_2: primary_contact[CID_PHONE_2],
        email_1: primary_contact[CID_EMAIL_1],
        email_2: primary_contact[CID_EMAIL_2],
        receive_phone_1: primary_contact[CID_RECIEVE_PHONE_1].eql?('yes'),
        receive_phone_2: primary_contact[CID_RECIEVE_PHONE_2].eql?('yes'),
        receive_email_1: primary_contact[CID_RECIEVE_EMAIL_1].eql?('yes'),
        receive_email_2: primary_contact[CID_RECIEVE_EMAIL_2].eql?('yes'),
        additional_information: primary_custom,
        additional_information_labels: custom_labels[GID_PRIMARY_CONTACT],
      ),
      :secondary_contact => secondary_contact.nil? ? nil : SecondaryContact.new(
        first_name: secondary_contact[CID_FIRST_NAME],
        last_name: secondary_contact[CID_LAST_NAME],
        address_1: secondary_contact[CID_ADDRESS_1],
        address_2: secondary_contact[CID_ADDRESS_2],
        address_3: secondary_contact[CID_ADDRESS_3],
        address_4: secondary_contact[CID_ADDRESS_4],
        postcode: secondary_contact[CID_POSTCODE],
        phone_1: secondary_contact[CID_PHONE_1],
        phone_2: secondary_contact[CID_PHONE_2],
        email_1: secondary_contact[CID_EMAIL_1],
        email_2: secondary_contact[CID_EMAIL_2],
        receive_phone_1: secondary_contact[CID_RECIEVE_PHONE_1].eql?('yes'),
        receive_phone_2: secondary_contact[CID_RECIEVE_PHONE_2].eql?('yes'),
        receive_email_1: secondary_contact[CID_RECIEVE_EMAIL_1].eql?('yes'),
        receive_email_2: secondary_contact[CID_RECIEVE_EMAIL_2].eql?('yes'),
        additional_information: secondary_custom,
        additional_information_labels: custom_labels[GID_SECONDARY_CONTACT],
      ),
      :emergency_contact => emergency_contact.nil? ? nil : EmergencyContact.new(
        first_name: emergency_contact[CID_FIRST_NAME],
        last_name: emergency_contact[CID_LAST_NAME],
        address_1: emergency_contact[CID_ADDRESS_1],
        address_2: emergency_contact[CID_ADDRESS_2],
        address_3: emergency_contact[CID_ADDRESS_3],
        address_4: emergency_contact[CID_ADDRESS_4],
        postcode: emergency_contact[CID_POSTCODE],
        phone_1: emergency_contact[CID_PHONE_1],
        phone_2: emergency_contact[CID_PHONE_2],
        email_1: emergency_contact[CID_EMAIL_1],
        email_2: emergency_contact[CID_EMAIL_2],
        additional_information: emergency_custom,
        additional_information_labels: custom_labels[GID_EMERGENCY_CONTACT],
      ),
      :doctor => doctor_contact.nil? ? nil : DoctorContact.new(
        first_name: doctor_contact[CID_FIRST_NAME],
        last_name: doctor_contact[CID_LAST_NAME],
        surgery: doctor_contact[CID_SURGERY],
        address_1: doctor_contact[CID_ADDRESS_1],
        address_2: doctor_contact[CID_ADDRESS_2],
        address_3: doctor_contact[CID_ADDRESS_3],
        address_4: doctor_contact[CID_ADDRESS_4],
        postcode: doctor_contact[CID_POSTCODE],
        phone_1: doctor_contact[CID_PHONE_1],
        phone_2: doctor_contact[CID_PHONE_2],
        additional_information: doctor_custom,
        additional_information_labels: custom_labels[GID_DOCTOR_CONTACT],
      ),
      additional_information: custom_data,
      additional_information_labels: custom_labels[GID_CUSTOM],
    )
  end

  cache_write(api, cache_key, result)
  return result
end

Public Instance Methods

<=>(another) click to toggle source

Compare member based on section_id, grouping_id, grouping_leader (descending), last_name then first_name

# File lib/osm/member.rb, line 559
def <=>(another)
  result = self.section_id <=> another.try(:section_id)
  result = self.grouping_id <=> another.try(:grouping_id) if result == 0
  result = -(self.grouping_leader <=> another.try(:grouping_leader)) if result == 0
  result = self.last_name <=> another.try(:last_name) if result == 0
  result = self.first_name <=> another.try(:first_name) if result == 0
  return result
end
age_months() click to toggle source

Get the months element of this scout's age @return [Fixnum] the number of months since this scout's last birthday

# File lib/osm/member.rb, line 419
def age_months
  return age[-2..-1].to_i
end
age_years() click to toggle source

Get the years element of this scout's age @return [Fixnum] the number of years this scout has been alive

# File lib/osm/member.rb, line 413
def age_years
  return age[0..1].to_i
end
create(api) click to toggle source

Create the user in OSM @param [Osm::Api] api The api to use to make the request @return [Boolan, nil] whether the member was successfully added or not (nil is returned if the user was created but not with all the data) @raise [Osm::ObjectIsInvalid] If the Member is invalid @raise [Osm::Error] If the member already exists in OSM

# File lib/osm/member.rb, line 305
def create(api)
  raise Osm::Error, 'the member already exists in OSM' unless id.nil?
  raise Osm::ObjectIsInvalid, 'member is invalid' unless valid?
  require_ability_to(api, :write, :member, section_id)

  data = api.perform_query("users.php?action=newMember", {
    'firstname' => first_name,
    'lastname' => last_name,
    'dob' => date_of_birth.strftime(Osm::OSM_DATE_FORMAT),
    'started' => joined_movement.strftime(Osm::OSM_DATE_FORMAT),
    'startedsection' => started_section.strftime(Osm::OSM_DATE_FORMAT),
    'sectionid' => section_id,
  })

  if (data.is_a?(Hash) && (data['result'] == 'ok') && (data['scoutid'].to_i > 0))
    self.id = data['scoutid'].to_i
    # The cached members for the section will be out of date - remove them
    Osm::Term.get_for_section(api, section_id).each do |term|
      cache_delete(api, ['members', section_id, term.id])
    end
    # Now it's created we need to give OSM the rest of the data
    updated = update(api, true)
    return updated ? true : nil
  else
    return false
  end
end
current?(date=Date.today) click to toggle source

Check if this is a current member of the section they were retrieved for @param date [Date] The date to check membership status for @return true, false

# File lib/osm/member.rb, line 457
def current?(date=Date.today)
  return nil if started_section.nil? and finished_section.nil?
  if finished_section.nil?
    started_section <= date
  elsif started_section.nil?
    finished_section >= date
  else
    (started_section <= date) && (finished_section >= date)
  end
end
female?() click to toggle source

Check if the member is male @return [Boolean]

# File lib/osm/member.rb, line 450
def female?
  gender == :female
end
get_photo(api, black_and_white=!current?, options={}) click to toggle source

Get the member's photo @param [Osm::Api] api The api to use to make the request @param [Boolean] black_and_white Whether you want the photo in blank and white (defaults to false unless the member is not active) @!macro options_get @raise [Osm:Error] if the member doesn't exist in OSM @return the photo of the member

# File lib/osm/member.rb, line 521
def get_photo(api, black_and_white=!current?, options={})
  raise Osm::ObjectIsInvalid, 'member is invalid' unless valid?
  require_ability_to(api, :read, :member, section_id)
  raise Osm::Error, 'the member does not already exist in OSM' if id.nil?

  cache_key = ['member_photo', self.id, black_and_white]

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

  url = "ext/members/contact/images/member.php?sectionid=#{section_id}&scoutid=#{self.id}&bw=#{black_and_white}"
  image = api.perform_query(url)

  cache_write(api, cache_key, image) unless image.nil?
  return image
end
leader?() click to toggle source

Check if the member is in the leaders grouping @return [Boolean]

# File lib/osm/member.rb, line 432
def leader?
  grouping_id.eql?(-2)
end
male?() click to toggle source

Check if the member is male @return [Boolean]

# File lib/osm/member.rb, line 444
def male?
  gender == :male
end
name(seperator=' ') click to toggle source

Get the full name @param [String] seperator What to split the member's first name and last name with @return [String] this scout's full name seperated by the optional seperator

# File lib/osm/member.rb, line 426
def name(seperator=' ')
  return [first_name, last_name].select{ |i| !i.blank? }.join(seperator)
end
update(api, force=false) click to toggle source

Update the member in OSM @param [Osm::Api] api The api to use to make the request @param [Boolean] force Whether to force updates (ie tell OSM every attribute changed even if we don't think it did) @return [Boolean] whether the member was successfully updated or not @raise [Osm::ObjectIsInvalid] If the Member is invalid

# File lib/osm/member.rb, line 338
def update(api, force=false)
  raise Osm::ObjectIsInvalid, 'member is invalid' unless valid?
  require_ability_to(api, :write, :member, section_id)

  updated = true

  # Do core attributes
  attribute_map = [
    ['first_name', 'firstname', first_name],
    ['last_name', 'lastname', last_name],
    ['grouping_id', 'patrolid', grouping_id],
    ['grouping_leader', 'patrolleader', grouping_leader],
    ['date_of_birth', 'dob', date_of_birth.strftime(Osm::OSM_DATE_FORMAT)],
    ['started_section', 'startedsection', started_section.strftime(Osm::OSM_DATE_FORMAT)],
    ['joined_movement', 'started', joined_movement.strftime(Osm::OSM_DATE_FORMAT)],
  ] # our name => OSM name
  attribute_map.select{ |attr,col,val| force || changed_attributes.include?(attr) }.each do |attr,col,val|
    data = api.perform_query("ext/members/contact/?action=update", {
      'scoutid' => self.id,
      'column' => col,
      'value' => val,
      'sectionid' => section_id,
    })
    updated = updated && data.is_a?(Hash) && data['ok'].eql?(true)
  end # each attr to update

  # Do 'floating' attributes
  if force || changed_attributes.include?('gender')
    new_value = {male: 'Male', female: 'Female', other: 'Other'}[gender] || 'Unspecified'
    data = api.perform_query("ext/customdata/?action=updateColumn&section_id=#{section_id}", {
      'associated_id' => self.id,
      'associated_type' => 'member',
      'value' => new_value,
      'column_id' => CID_GENDER,
      'group_id' => GID_FLOATING,
      'context' => 'members',
    })
    updated = updated && data.is_a?(Hash) && data['data'].is_a?(Hash) && data['data']['value'].eql?(new_value)
  end

  # Do custom attributes
  additional_information.keys.select{ |a| force || additional_information.changes.keys.include?(a) }.each do |attr|
    new_value = additional_information[attr]
    data = api.perform_query("ext/customdata/?action=updateColumn&section_id=#{section_id}", {
      'associated_id' => self.id,
      'associated_type' => 'member',
      'value' => new_value,
      'column_id' => attr,
      'group_id' => GID_CUSTOM,
      'context' => 'members',
    })
    updated = updated && data.is_a?(Hash) && data['data'].is_a?(Hash) && data['data']['value'].to_s.eql?(new_value.to_s)
  end # each attr to update

  # Do contacts
  updated = (contact.nil? || contact.update(api, self, force)) && updated
  updated = (primary_contact.nil? || primary_contact.update(api, self, force)) && updated
  updated = (secondary_contact.nil? || secondary_contact.update(api, self, force)) && updated
  updated = (emergency_contact.nil? ||emergency_contact.update(api, self, force)) && updated
  updated = (doctor.nil? || doctor.update(api, self, force)) && updated

  # Finish off
  if updated
    reset_changed_attributes
    additional_information.clean_up!
    # The cached columns for the members will be out of date - remove them
    Osm::Term.get_for_section(api, section_id).each do |term|
      Osm::Model.cache_delete(api, ['members', section_id, term.id])
    end
  end
  return updated
end
youth?() click to toggle source

Check if the member is in a non-leaders grouping @return [Boolean]

# File lib/osm/member.rb, line 438
def youth?
  grouping_id > 0
end