Class: ASF::Person

Inherits:
Base
  • Object
show all
Defined in:
lib/whimsy/asf/auth.rb,
lib/whimsy/asf/icla.rb,
lib/whimsy/asf/ldap.rb,
lib/whimsy/asf/mail.rb,
lib/whimsy/asf/watch.rb,
lib/whimsy/asf/member.rb,
lib/whimsy/asf/person.rb,
lib/whimsy/asf/nominees.rb

Constant Summary collapse

SUFFIXES =
/^([Jj][Rr]\.?|I{2,3}|I?V|VI{1,3}|[A-Z]\.)$/

Instance Attribute Summary

Attributes inherited from Base

#name

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Base

#<=>, [], base, #base, collection, find, #id, #initialize, mod_add, mod_delete, mod_replace, new, #reference, #weakref

Constructor Details

This class inherits a constructor from ASF::Base

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(name, *args) ⇒ Object



526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
# File 'lib/whimsy/asf/ldap.rb', line 526

def method_missing(name, *args)
  if name.to_s.end_with? '=' and args.length == 1
    return modify(name.to_s[0..-2], args)
  end

  return super unless args.empty?
  result = self.attrs[name.to_s]
  return super unless result

  if result.empty?
    return nil
  else
    result.map! do |value|
      value = value.dup.force_encoding('utf-8') if String === value
      value
    end

    if result.length == 1
      result.first
    else
      result
    end
  end
end

Class Method Details

.asciize(name) ⇒ Object

sort support



10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# File 'lib/whimsy/asf/person.rb', line 10

def self.asciize(name)
  if name.match /[^\x00-\x7F]/
    # digraphs.  May be culturally sensitive
    name.gsub! /\u00df/, 'ss'
    name.gsub! /\u00e4|a\u0308/, 'ae'
    name.gsub! /\u00e5|a\u030a/, 'aa'
    name.gsub! /\u00e6/, 'ae'
    name.gsub! /\u00f1|n\u0303/, 'ny'
    name.gsub! /\u00f6|o\u0308/, 'oe'
    name.gsub! /\u00fc|u\u0308/, 'ue'

    # latin 1
    name.gsub! /\u00c9/, 'e'
    name.gsub! /\u00d3/, 'o'
    name.gsub! /[\u00e0-\u00e5]/, 'a'
    name.gsub! /\u00e7/, 'c'
    name.gsub! /[\u00e8-\u00eb]/, 'e'
    name.gsub! /[\u00ec-\u00ef]/, 'i'
    name.gsub! /[\u00f2-\u00f6]|\u00f8/, 'o'
    name.gsub! /[\u00f9-\u00fc]/, 'u'
    name.gsub! /[\u00fd\u00ff]/, 'y'

    # Latin Extended-A
    name.gsub! /[\u0100-\u0105]/, 'a'
    name.gsub! /[\u0106-\u010d]/, 'c'
    name.gsub! /[\u010e-\u0111]/, 'd'
    name.gsub! /[\u0112-\u011b]/, 'e'
    name.gsub! /[\u011c-\u0123]/, 'g'
    name.gsub! /[\u0124-\u0127]/, 'h'
    name.gsub! /[\u0128-\u0131]/, 'i'
    name.gsub! /[\u0132-\u0133]/, 'ij'
    name.gsub! /[\u0134-\u0135]/, 'j'
    name.gsub! /[\u0136-\u0138]/, 'k'
    name.gsub! /[\u0139-\u0142]/, 'l'
    name.gsub! /[\u0143-\u014b]/, 'n'
    name.gsub! /[\u014C-\u0151]/, 'o'
    name.gsub! /[\u0152-\u0153]/, 'oe'
    name.gsub! /[\u0154-\u0159]/, 'r'
    name.gsub! /[\u015a-\u0162]/, 's'
    name.gsub! /[\u0162-\u0167]/, 't'
    name.gsub! /[\u0168-\u0173]/, 'u'
    name.gsub! /[\u0174-\u0175]/, 'w'
    name.gsub! /[\u0176-\u0178]/, 'y'
    name.gsub! /[\u0179-\u017e]/, 'z'

    # denormalized diacritics
    name.gsub! /[\u0300-\u036f]/, ''
  end

  name.strip.gsub /[^\w]+/, '-'
end

.find_by_email(value) ⇒ Object



78
79
80
81
82
83
# File 'lib/whimsy/asf/mail.rb', line 78

def self.find_by_email(value)
  value.downcase!

  person = Mail.list[value]
  return person if person
end

.list(filter = 'uid=*') ⇒ Object



420
421
422
# File 'lib/whimsy/asf/ldap.rb', line 420

def self.list(filter='uid=*')
  ASF.search_one(base, filter, 'uid').flatten.map {|uid| find(uid)}
end

.member_nomineesObject



7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# File 'lib/whimsy/asf/nominees.rb', line 7

def self.member_nominees
  begin
    return Hash[@member_nominees.to_a] if @member_nominees
  rescue
  end

  meetings = ASF::SVN['private/foundation/Meetings']
  nominations = Dir["#{meetings}/*/nominated-members.txt"].sort.last.untaint

  nominations = File.read(nominations).split(/^\s*---+\s*/)
  nominations.shift(2)

  nominees = {}
  nominations.each do |nomination|
    id = nomination[/^\s?\w+.*<(\S+)@apache.org>/,1]
    id ||= nomination[/^\s?\w+.*\((\S+)@apache.org\)/,1]
    id ||= nomination[/^\s?\w+.*\(([a-z]+)\)/,1]

    next unless id

    nominees[find(id)] = nomination
  end

  @member_nominees = WeakRef.new(nominees)
  nominees
end

.member_watch_listObject



5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# File 'lib/whimsy/asf/watch.rb', line 5

def self.member_watch_list
  return @member_watch_list if @member_watch_list

  foundation = ASF::SVN['private/foundation']
  text = File.read "#{foundation}/potential-member-watch-list.txt"

  nominations = text.scan(/^\s+\*\)\s+\w.*?\n\s*(?:---|\Z)/m)

  i = 0
  member_watch_list = {}
  nominations.each do |nomination|
    id = nil
    name = nomination[/\*\)\s+(.+?)\s+(\(|\<|$)/,1]
    id ||= nomination[/\*\)\s.+?\s\((.*?)\)/,1]
    id ||= nomination[/\*\)\s.+?\s<(.*?)@apache.org>/,1]

    unless id
      id = "notinavail_#{i+=1}"
      find(id).attrs['cn'] = name
    end

    member_watch_list[find(id)] = nomination
  end

  @member_watch_list = member_watch_list
end

.preload(attributes, people = {}) ⇒ Object

pre-fetch a given attribute, for a given list of people



425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
# File 'lib/whimsy/asf/ldap.rb', line 425

def self.preload(attributes, people={})
  list = Hash.new {|hash, name| hash[name] = find(name)}

  attributes = [attributes].flatten

  if people.empty?
    filter = "(|#{attributes.map {|attribute| "(#{attribute}=*)"}.join})"
  else
    filter = "(|#{people.map {|person| "(uid=#{person.name})"}.join})"
  end
  
  zero = Hash[attributes.map {|attribute| [attribute,nil]}]

  data = ASF.search_one(base, filter, attributes + ['uid'])
  data = Hash[data.map! {|hash| [list[hash['uid'].first], hash]}]
  data.each {|person, hash| person.attrs.merge!(zero.merge(hash))}

  if people.empty?
    (list.values - data.keys).each do |person|
      person.attrs.merge! zero
    end
  end

  list.values
end

.sortable_name(name) ⇒ Object

rearrange line in an order suitable for sorting



65
66
67
68
69
70
71
72
73
74
75
# File 'lib/whimsy/asf/person.rb', line 65

def self.sortable_name(name)
  name = name.split.reverse
  suffix = (name.shift if name.first =~ SUFFIXES)
  suffix += ' ' + name.shift if name.first =~ SUFFIXES
  name << name.shift
  # name << name.shift if name.first=='van'
  name.last.sub! /^IJ/, 'Ij'
  name.unshift(suffix) if suffix
  name.map! {|word| asciize(word)}
  name.reverse.join(' ').downcase
end

Instance Method Details

#active_emailsObject



96
97
98
# File 'lib/whimsy/asf/mail.rb', line 96

def active_emails
  (mail + alt_email + member_emails).uniq
end

#all_mailObject



100
101
102
# File 'lib/whimsy/asf/mail.rb', line 100

def all_mail
  active_emails + obsolete_emails
end

#alt_emailObject



488
489
490
# File 'lib/whimsy/asf/ldap.rb', line 488

def alt_email
  attrs['asf-altEmail'] || []
end

#asf_committer?Boolean

Returns:

  • (Boolean)


476
477
478
# File 'lib/whimsy/asf/ldap.rb', line 476

def asf_committer?
   ASF::Group.new('committers').include? self
end

#asf_member?Boolean

Returns:

  • (Boolean)


468
469
470
# File 'lib/whimsy/asf/ldap.rb', line 468

def asf_member?
  ASF::Member.status[name] or ASF.members.include? self
end

#asf_officer_or_member?Boolean

Returns:

  • (Boolean)


472
473
474
# File 'lib/whimsy/asf/ldap.rb', line 472

def asf_officer_or_member?
  asf_member? or ASF.pmc_chairs.include? self
end

#attrsObject



451
452
453
# File 'lib/whimsy/asf/ldap.rb', line 451

def attrs
  @attrs ||= LazyHash.new {ASF.search_one(base, "uid=#{name}").first}
end

#authObject



39
40
41
# File 'lib/whimsy/asf/auth.rb', line 39

def auth
  @auths ||= ASF::Authorization.find_by_id(name)
end

#banned?Boolean

Returns:

  • (Boolean)


480
481
482
# File 'lib/whimsy/asf/ldap.rb', line 480

def banned?
  not attrs['loginShell'] or %w(/usr/bin/false bin/nologin bin/no-cla).any? {|a| attrs['loginShell'].first.include? a}
end

#committeesObject



504
505
506
507
508
# File 'lib/whimsy/asf/ldap.rb', line 504

def committees
  weakref(:committees) do
    Committee.list("member=uid=#{name},#{base}")
  end
end

#dnObject



522
523
524
# File 'lib/whimsy/asf/ldap.rb', line 522

def dn
  "uid=#{name},#{ASF::Person.base}"
end

#groupsObject



510
511
512
513
514
# File 'lib/whimsy/asf/ldap.rb', line 510

def groups
  weakref(:groups) do
    Group.list("memberUid=#{name}")
  end
end

#iclaObject



152
153
154
# File 'lib/whimsy/asf/icla.rb', line 152

def icla
  @icla ||= ASF::ICLA.find_by_id(name)
end

#icla=(icla) ⇒ Object



156
157
158
# File 'lib/whimsy/asf/icla.rb', line 156

def icla=(icla)
  @icla = icla
end

#icla?Boolean

Returns:

  • (Boolean)


160
161
162
# File 'lib/whimsy/asf/icla.rb', line 160

def icla?
  @icla || ICLA.availids.include?(name)
end

#mailObject



484
485
486
# File 'lib/whimsy/asf/ldap.rb', line 484

def mail
  attrs['mail'] || []
end

#member_emailsObject



156
157
158
# File 'lib/whimsy/asf/member.rb', line 156

def member_emails
  ASF::Member.emails(members_txt)
end

#member_nameObject



160
161
162
# File 'lib/whimsy/asf/member.rb', line 160

def member_name
  members_txt[/(\w.*?)\s*(\/|$)/, 1] if members_txt
end

#member_nominationObject



34
35
36
# File 'lib/whimsy/asf/nominees.rb', line 34

def member_nomination
  @member_nomination ||= Person.member_nominees[self]
end

#member_watchObject



32
33
34
35
36
37
38
39
# File 'lib/whimsy/asf/watch.rb', line 32

def member_watch
  text = Person.member_watch_list[self]
  if text
    text.sub!(/\A\s*\n/,'')
    text.sub!(/\n---\Z/,'')
  end
  text
end

#members_txt(full = false) ⇒ Object



150
151
152
153
154
# File 'lib/whimsy/asf/member.rb', line 150

def members_txt(full = false)
  prefix, suffix = " *) ", "\n\n" if full
  @members_txt ||= ASF::Member.find_text_by_id(id)
  "#{prefix}#{@members_txt}#{suffix}" if @members_txt
end

#modify(attr, value) ⇒ Object



551
552
553
554
# File 'lib/whimsy/asf/ldap.rb', line 551

def modify(attr, value)
  ASF.ldap.modify(self.dn, [ASF::Base.mod_replace(attr.to_s, value)])
  attrs[attr.to_s] = value
end

#obsolete_emailsObject



85
86
87
88
89
90
91
92
93
94
# File 'lib/whimsy/asf/mail.rb', line 85

def obsolete_emails
  return @obsolete_emails if @obsolete_emails
  result = []
  if icla
    unless active_emails.any? {|mail| mail.downcase == icla.email.downcase}
      result << icla.email
    end
  end
  @obsolete_emails = result
end

#pgp_key_fingerprintsObject



492
493
494
# File 'lib/whimsy/asf/ldap.rb', line 492

def pgp_key_fingerprints
  attrs['asf-pgpKeyFingerprint'] || []
end

#public_nameObject



460
461
462
463
464
465
466
# File 'lib/whimsy/asf/ldap.rb', line 460

def public_name
  return icla.name if icla
  cn = [attrs['cn']].flatten.first
  cn.force_encoding('utf-8') if cn.respond_to? :force_encoding
  return cn if cn
  ASF.search_archive_by_id(name)
end

#reload!Object



455
456
457
458
# File 'lib/whimsy/asf/ldap.rb', line 455

def reload!
  @attrs = nil
  attrs
end

#servicesObject



516
517
518
519
520
# File 'lib/whimsy/asf/ldap.rb', line 516

def services
  weakref(:services) do
    Service.list("member=#{dn}")
  end
end

#sortable_nameObject



77
78
79
# File 'lib/whimsy/asf/person.rb', line 77

def sortable_name
  Person.sortable_name(self.public_name)
end

#ssh_public_keysObject



496
497
498
# File 'lib/whimsy/asf/ldap.rb', line 496

def ssh_public_keys
  attrs['sshPublicKey'] || []
end

#urlsObject



500
501
502
# File 'lib/whimsy/asf/ldap.rb', line 500

def urls
  attrs['asf-personalURL'] || []
end