class Persons

Attributes

print_card_responsible[RW]
print_card_student[RW]
resps[RW]

Public Class Methods

admin_users() click to toggle source
# File Entities/Person.rb, line 87
def self.admin_users
  ConfigBase.persons_add_del_users == %w(true) &&
      !get_config(false, :Entities, :Persons, :user_simulation)
end
center() click to toggle source
# File Entities/Person.rb, line 523
def Persons.center
  Persons.find_by_permissions(:center)
end
centers() click to toggle source
# File Entities/Person.rb, line 527
def Persons.centers
  Persons.search_by_permissions(:center)
end
check_login(login, password) click to toggle source
# File Entities/Person.rb, line 574
def Persons.check_login(login, password)
  return nil unless p = Persons.match_by_login_name(login)
  p.check_pass(password) ? p : nil
end
create_empty() click to toggle source
# File Entities/Person.rb, line 257
def self.create_empty
  Entities.Persons.create([])
end
master_center() click to toggle source
# File Entities/Person.rb, line 531
def Persons.master_center
  Persons.centers.find { |c| c.has_permission?(:center_director) }
end
master_center_login_name() click to toggle source
# File Entities/Person.rb, line 535
def Persons.master_center_login_name
  (c = Persons.master_center) ? c.login_name : 'master'
end
responsibles_raw() click to toggle source
# File Entities/Person.rb, line 413
def self.responsibles_raw
  return Persons.data.select { |k, v|
    v._permissions &&
        Permission.can_view(v._permissions.reject { |perm| perm.to_s == 'admin' },
                            'FlagResponsible')
  }.collect { |k, v| Persons.find_by_person_id(k) }
end
responsibles_sort(resps) click to toggle source
# File Entities/Person.rb, line 421
def self.responsibles_sort(resps)
  resps.collect { |p|
    [p.person_id, p.full_name]
  }.sort { |a, b| a.last <=> b.last }
end
search_in(str, field = nil, center: nil, max: 20) click to toggle source
# File Entities/Person.rb, line 539
def Persons.search_in(str, field = nil, center: nil, max: 20)
  # Don't search if there are few caracters and lots of Persons
  dputs(3) { "search_in - _#{str}_ - #{Persons.data.length}" }
  if (!str || str.length < 3) && (Persons.data.length > max)
    return field ? View.reply(:empty, field) : []
  end

  result = Persons.data.select { |k, v|
    #dp v
    str.split(/ /).collect { |s|
      ret = false
      %i( login_name family_name first_name
      permissions person_id email phone groups ).each { |i|
        #dp "#{i} - #{v[i]} - #{v[i].to_s =~ /#{str}/}"
        ret ||= !!(v[i].to_s =~ /#{s}/i)
      }
      ret
    }.compact.inject(:&)
  }.sort { |a, b|
    if a[1]._login_name.to_s == str
      -1
    elsif b[1]._login_name.to_s == str
      1
    else
      "#{a[1]._first_name} #{a[1]._family_name}" <=>
          "#{b[1]._first_name} #{b[1]._family_name}"
    end
  }.first(max).collect { |k, v| Persons.get_data_instance(k) }

  dputs(3) { "Result is: #{result.collect { |r| r.login_name }}" }
  not result and result = []

  result
end
update_fetchmailrc() click to toggle source
# File Entities/Person.rb, line 482
  def self.update_fetchmailrc
    begin
      File.open('/etc/fetchmailrc', 'w') { |f|
        f.write <<-start
        set daemon 600

        start
        Persons.search_by_permissions(:email).each { |p|
          if p.acc_proto.class == Array &&
              p.acc_port.class == Array &&
              p.acc_supp.class == Array &&
              p.email && p.acc_pass
            proto, port, supp =
                p.acc_proto.join, p.acc_port.join, p.acc_supp.join
            if proto.length * port.length * p.email.length * p.acc_pass.length > 0
              dputs(2) { "Adding #{p.login_name} to fetchmailrc" }
              f.write <<-person
                poll #{p.acc_remote} uidl with proto #{p.acc_proto.join}
                auth password port #{p.acc_port.join}
                user '#{p.email}' there with password '#{p.acc_pass}'
                    is #{p.login_name} here
                mimedecode #{p.acc_supp.join}
                option limit 1000000 batchlimit 10 fetchlimit 10 fetchsizelimit 20

              person
            end
          end
        }

        f.chmod 0700
      }
      FileUtils.chown 'fetchmail', 'nobody', '/etc/fetchmailrc'
    rescue Errno::EACCES => e
      dputs(0) { "Can't write fetchmailrc here..." }
      self.permissions = permissions - %w(email)
    rescue ArgumentError
      dputs(0) { "Didn't find fetchmail-user" }
      self.permissions = permissions - %w(email)
    end
  end

Public Instance Methods

accents_replace(login) click to toggle source
# File Entities/Person.rb, line 185
def accents_replace(login)
  login = login.downcase.gsub(/ /, '_')
  accents = Hash[*%w( a àáâä e éèêë i ìíîï o òóôöœ u ùúûü c ç ss ß )]
  dputs(2) { "Login was #{login}" }
  accents.each { |k, v|
    login.gsub!(/[#{v}]/, k)
  }
  login.gsub!(/[^a-z0-9_-]/, '_')
  dputs(2) { "Login is #{login}" }
  login
end
add_internet_credit(session, data) click to toggle source

Adds cash to a persons account. The hash “data” should contain the following fields:

  • credit_add : how much CFA to add

  • person_id : the id of the person to receive the credit

# File Entities/Person.rb, line 280
def add_internet_credit(session, data)
  dputs(5) { "data is #{data.inspect}" }
  client = match_by_login_name(data['login_name'].to_s)
  if data._credit_add and client
    actor = session.owner
    dputs(3) { "Adding cash to #{client.full_name} from #{actor.full_name}" }
    if client.login_name.to_s.length > 0
      actor.add_internet_credit(client, data._credit_add)
    else
      dputs(0) { "Bizarre client: #{client.inspect} - #{session.inspect} - #{data.inspect}" }
    end
    return client
  end
  return nil
end
create(d) click to toggle source
Calls superclass method
# File Entities/Person.rb, line 216
def create(d)
  # Sanitize first and family-name
  if d.has_key? :complete_name
    d[:first_name] = d[:complete_name]
  end
  if d.has_key? :first_name
    if not d.has_key? :family_name or d[:family_name].length == 0
      d[:first_name], d[:family_name] = create_first_family(d[:first_name])
    end
    d[:first_name].capitalize_all!
    d[:family_name].capitalize_all!
  elsif d.has_key? :login_name
    d[:first_name] = d[:login_name]
  else
    dputs(0) { "Error: Trying to create Person with missing names: #{d.inspect}" }
    return nil
  end
  if !d[:login_name] or d[:login_name].length == 0
    d[:login_name] = create_login_name(d[:first_name], d[:family_name])
  end

  if d.has_key? :login_name_prefix
    d[:login_name] = d[:login_name_prefix] + d[:login_name]
  end
  d[:login_name] = find_empty_login_name(d[:login_name])
  d[:person_id] = nil
  log_msg :person, "Creating Person #{d.inspect}"

  person = super(d, true)

  person.password_plain = d.has_key?(:password) ? d[:password] : rand(10000).to_s.rjust(4, '0')
  person.password = person.password_plain

  if (cmd = ConfigBase.persons_addeduser_cmd).to_s.length > 0
    dputs(2) { "Going to call #{cmd} #{person.login_name} #{person.password_plain}" }
    System.run_bool("#{cmd} #{person.login_name} #{person.password_plain}")
  end

  return person
end
create_add_course(student, owner, course, check_double = false) click to toggle source
# File Entities/Person.rb, line 458
def create_add_course(student, owner, course, check_double = false)
  prefix = ConfigBase.has_function?(:course_server) ?
      "#{owner.login_name}_" : ''
  login_name = Persons.create_login_name(student)
  if not (person = Persons.match_by_login_name(prefix + student))
    if check_double and
        Persons.search_by_login_name("^#{prefix}#{login_name}[0-9]*$").length > 0
      return nil
    else
      person = Persons.create({:first_name => student,
                               :login_name_prefix => prefix,
                               :permissions => %w( student ), :town => @town, :country => @country})
    end
  end
  #person.email = "#{person.login_name}@ndjair.net"
  person and course.students_add person
  person
end
create_first_family(fullname) click to toggle source
# File Entities/Person.rb, line 171
def create_first_family(fullname)
  # Trying to be intelligent about splitting up of names
  if fullname.split(' ').length > 1
    names = fullname.split(' ')
    s = names.length < 4 ? 0 : 1
    first = names[0..s].join(' ')
    family = names[(s+1)..-1].join(' ')
    dputs(2) { "Creating user #{names.inspect} as #{first} - #{family}" }
    [first, family]
  else
    [fullname, '']
  end
end
create_login_name(first, family = '') click to toggle source

Creates a login-name out of “first” and “family” name - should work nicely in Africa, perhaps a bit bizarre in Western-countries (like “tlinus” instead of “ltorvalds”) if “family” is empty, it tries to generate some sensible values for “first” and “family” by itself

# File Entities/Person.rb, line 202
def create_login_name(first, family = '')
  if family.length == 0
    first, family = create_first_family(first)
  end
  if family.length > 0
    dputs(2) { 'Family name + First name' }
    login = family.chars.first + first.split.first
  else
    login = first.split.first
  end

  accents_replace(login)
end
create_person(full_name, creator = nil, login_prop = nil) click to toggle source
# File Entities/Person.rb, line 261
def create_person(full_name, creator = nil, login_prop = nil)
  new_data = {:login_name => login_prop,
              :complete_name => full_name}
  perms = ['internet']
  if creator and creator.permissions.index('center')
    new_data.merge!({:login_name_prefix => "#{creator.login_name}_"})
    perms.push('teacher')
  end
  Persons.create(new_data.merge(:permissions => perms))
end
data_create(data) click to toggle source
# File Entities/Person.rb, line 360
def data_create(data)
  dputs(2) { "Creating new data #{data.inspect}" }
  if has_storage? :LDAP
    user = data[:login_name]
    if Kernel.system("ldapadduser #{user} plugdev")
      if (cmd = ConfigBase.persons_adduser_cmd).to_s.length > 0
        dputs(2) { "Going to call #{cmd} #{user.inspect}" }
        System.run_bool("#{cmd} #{user}")
      end
    else
      dputs(0) { "Error: Couldn't create #{user}" }
    end
  end
end
delete_all(local_only = false) click to toggle source
Calls superclass method
# File Entities/Person.rb, line 477
def delete_all(local_only = false)
  super(local_only)
  @resps = []
end
fetch_account(r, a) click to toggle source
# File Entities/Person.rb, line 141
def fetch_account(r, a)
  Accounts.get_by_path_or_create("#{r}::#{a}")
end
find_empty_login_name(login) click to toggle source

Searches for an empty name starting with “login”, adding 2, 3, 4, …

# File Entities/Person.rb, line 160
def find_empty_login_name(login)
  suffix = ''
  login = accents_replace(login)
  while match_by_login_name(login + suffix.to_s)
    dputs(2) { "Found #{login + suffix.to_s} to already exist" }
    suffix = suffix.to_i + 1
    suffix = 2 if suffix == 1
  end
  login + suffix.to_s
end
find_full_name(name) click to toggle source
# File Entities/Person.rb, line 375
def find_full_name(name)
  dputs(2) { "Searching for #{name}" }
  @data.each_key { |k|
    if @data[k]
      fn = "#{data[k][:first_name]} #{data[k][:family_name]}"
      dputs(2) { "Searching in #{fn}" }
      if fn =~ /#{name}/i
        dputs(2) { 'Found it' }
        return get_data_instance(k)
      end
    end
  }
  return nil
end
find_name_or_create(name) click to toggle source
# File Entities/Person.rb, line 390
def find_name_or_create(name)
  first, last = name.split(' ', 2)
  find_full_name(name) or
      create(:first_name => first, :family_name => last)
end
get_login_with_permission(perm) click to toggle source
# File Entities/Person.rb, line 296
def get_login_with_permission(perm)
  #persons = Entities.Persons.search_by_permissions(perm)
  persons = Persons.data.select { |k, v|
    v._permissions && v._permissions.index(perm) }.
      collect { |k, v| Persons.get_data_instance(k) }
  if persons
    # The "select" at the end removes empty entries
    persons.collect { |p|
      p.login_name
    }.select { |s| s }
  else
    []
  end
end
icc_get(tr) click to toggle source
# File Entities/Person.rb, line 579
def icc_get(tr)
  c = tr._center
  return "Error: Didn't find center #{c.inspect}}" unless center = Persons.match_by_login_name(c._login_name)
  return "Error: Passwords do not match for #{c.inspect}" unless center.password_plain == c._password_plain
  login_name = "#{c._login_name}_#{tr._name.first}"
  log_msg :Persons, "ICC-get for #{login_name.inspect}"
  if p = Persons.match_by_login_name(login_name)
    p = p.to_hash
    p._login_name = tr._name.first
    p
  else
    "Error: Didn't find #{login_name}"
  end
end
list_assistants() click to toggle source
# File Entities/Person.rb, line 315
def list_assistants
  get_login_with_permission('assistant').sort
end
list_students() click to toggle source
# File Entities/Person.rb, line 319
def list_students
  get_login_with_permission('student').sort
end
list_teachers() click to toggle source
# File Entities/Person.rb, line 311
def list_teachers
  get_login_with_permission('teacher').sort
end
listp_account_due() click to toggle source
# File Entities/Person.rb, line 323
def listp_account_due
  search_by_account_due('.+').select { |p|
    # CashboxCredit-permission is the least for everybody who handles money.
    p.login_name != 'admin' && p.has_permission?(:CashboxCredit)
  }.collect { |p|
    if p.account_due != nil
      dputs(4) { "p is #{p.full_name}" }
      dputs(4) { "account is #{p.account_due.get_path}" }
      amount = (p.account_due.total.to_f * 1000).to_i.separator
      name = p.full_name
      if name.length == 0
        name = p.login_name
      end
      [p.person_id, "#{amount.to_s.rjust(6)} - #{name}"]
    else
      [p.person_id, "0 - #{name}"]
    end
  }.sort { |a, b|
    a[1] <=> b[1]
  }.reverse
end
listp_responsible(session = nil) click to toggle source
# File Entities/Person.rb, line 401
def listp_responsible(session = nil)
  list = search_by_permissions('teacher')
  if session
    list = list.select { |p|
      p.login_name =~ /^#{session.owner.login_name}_/
    }.push(session.owner)
  end
  list.collect { |p|
    [p.person_id, p.full_name]
  }
end
login_to_full(login) click to toggle source
# File Entities/Person.rb, line 396
def login_to_full(login)
  p = match_by_login_name(login)
  p ? p.full_name : ''
end
migration_1(p) click to toggle source
# File Entities/Person.rb, line 116
def migration_1(p)
  if p.person_id == 0
    dputs(0) { 'Error: Oups, found person with id 0 - trying to change this' }
    p.person_id = Persons.new_id[:person_id]
    dputs(2) { "Putting person-id to #{p.person_id}" }
  end
end
migration_2_raw(p) click to toggle source
# File Entities/Person.rb, line 124
def migration_2_raw(p)
  dputs(2) { "p is #{p.class}" }
  p._internet_credit = p._credit
  p._account_total_due = p._credit_due
  p._account_name_due = p._account_due
end
migration_3(p) click to toggle source
# File Entities/Person.rb, line 131
def migration_3(p)
  if p.permissions.class != Array
    p.permissions = []
  end
end
migration_4(p) click to toggle source
# File Entities/Person.rb, line 137
def migration_4(p)
  p.gender = %w( n/a )
end
migration_5_raw(d) click to toggle source
# File Entities/Person.rb, line 145
def migration_5_raw(d)
  #dp d.inspect
  if d._account_name_due
    r = get_config('Root::Lending', :Accounting, :lending)
    d._account_due = fetch_account(r, d._account_name_due).id
    d._account_due_paid = fetch_account(r, "#{d._account_name_due}::Paid").id
  end
  if d._account_name_cash
    r = get_config('Root::Cash', :Accounting, :cash)
    d._account_cash = fetch_account(r, d._account_name_cash).id
  end
  #dp d.inspect
end
responsibles(force_update = false) click to toggle source
# File Entities/Person.rb, line 427
def responsibles(force_update = false)
  #dputs_func
  if force_update || @resps.size == 0
    dputs(3) { "Making responsible-cache with #{@data.size} entities" }
    @resps = Persons.responsibles_raw
    @resps = Persons.responsibles_sort(@resps)
  else
    dputs(3) { 'Lazily using responsible-cache' }
  end
  if force_update || @resps_course.size == 0
    @resps_course = Courses.search_all_.collect { |c| [c.teacher, c.responsible, c.assistant] }.
        flatten.compact.uniq
    @resps_course = Persons.responsibles_sort(@resps_course)
  end
  (@resps + @resps_course).uniq.sort_by { |p| p[1] }
end
responsibles_add(p) click to toggle source
# File Entities/Person.rb, line 444
def responsibles_add(p)
  e = [[p.person_id, p.full_name]]
  if not @resps.index(e)
    @resps = (@resps + e).sort { |a, b| a.last <=> b.last }
  end
end
responsibles_del(p) click to toggle source
# File Entities/Person.rb, line 451
def responsibles_del(p)
  e = [[p.person_id, p.full_name]]
  if @resps.index(e)
    @resps = (@resps - e).sort { |a, b| a.last <=> b.last }
  end
end
save_data(d) click to toggle source
Calls superclass method
# File Entities/Person.rb, line 345
def save_data(d)
  d = d.to_sym
  dputs(3) { "d is #{d.inspect}" }

  if !d[:first_name] and !d[:person_id]
    return {:first_name => 'user'}
  end

  [:first_name, :family_name].each { |n|
    d[n] && d[n].capitalize_all!
  }

  super(d)
end
setup_data() click to toggle source
# File Entities/Person.rb, line 30
def setup_data
  add_new_storage :LDAP

  value_block :address
  value_str_LDAP :first_name, :ldap_name => 'sn'
  value_str_LDAP :family_name, :ldap_name => 'givenname'
  value_list_drop :gender, '%w( male female n/a )'
  value_date :birthday
  value_str :address
  value_str_LDAP :phone, :ldap_name => 'mobile'
  value_str_LDAP :email, :ldap_name => 'mail'
  value_str_LDAP :town, :ldap_name => 'l'
  value_str_LDAP :country, :ldap_name => 'st'
  value_str :profession
  value_str :school_grade

  value_block :admin
  #value_str :account_name_due
  #value_str :account_name_cash
  value_str :role_diploma
  value_list :permissions, 'Permission.list.sort'

  value_block :accounts
  value_entity_account :account_due
  value_entity_account :account_due_paid
  value_entity_account :account_cash

  value_block :internet
  value_list :groups, '%w( freesurf sudo print localonly share ).sort'
  value_list_single :internet_none, '[]'

  value_block :read_only
  value_str_ro_LDAP :login_name, :ldap_name => 'uid'
  # credit -> internet_credit
  # credit_due -> account_total_due
  value_int_ro :internet_credit
  value_int_ro :account_total_due

  value_block :email_account
  value_str :acc_remote
  value_str :acc_pass
  value_list_drop :acc_proto, '%w( POP3 IMAP )'
  value_list_drop :acc_port, '%w( 110 993 995 )'
  value_list_drop :acc_supp, '["ssl keep", "ssl", "keep", ""]'

  value_block :hidden
  value_str :session_id
  value_str_LDAP :password, :ldap_name => 'userPassword'
  value_str :password_plain
  value_int_LDAP :person_id, :ldap_name => 'uidnumber'

  @resps = []
  @resps_course = []
  ConfigBases.add_observer(self, :update_config)
  update_config(nil, nil, nil)
end
update(session) click to toggle source
Calls superclass method
# File Entities/Person.rb, line 272
def update(session)
  super(session).merge({:account_total_due => session.owner.internet_credit})
end
update_config(action, value, old) click to toggle source
# File Entities/Person.rb, line 92
def update_config(action, value, old)
  dputs(3) { "Updating #{action} with #{value.inspect}" }
  case action
    when :function_add
      if value.index :accounting_courses
        search_all_.each { |p|
          dputs(3) { "Searching if #{p.login_name} needs new accounts" }
          p.update_accounts
        }
      end
    when :function_del
    else
      ddir = Courses.dir_diplomas
      cdir = "#{ddir}/cartes"
      if !File.exist? cdir
        FileUtils::mkdir_p(cdir)
      end
      @print_card_student = OpenPrint.new(
          ConfigBase.template_path(:card_student), cdir)
      @print_card_responsible = OpenPrint.new(
          ConfigBase.template_path(:card_responsible), cdir)
  end
end