class ASF::Person
An instance of this class represents a person. Data comes from a variety of sources: LDAP
, asf--authorization-template
, iclas.txt
, members.txt
, nominated-members.txt
, and potential-member-watch-list.txt
.
Constants
- DOUBLE_PFX
- MINIMUM_USER_UID
- NAMEHASH
- SINGLE_PFX
surname prefixes
- SUFFIXES
generational suffixes
- VALID_ATTRS
Public Class Methods
return person only if it actually exits
ASF::Base::[]
# File lib/whimsy/asf/ldap.rb, line 783 def self.[](id) person = super person.attrs['dn'] ? person : nil end
add a new person to LDAP
. Attrs must include uid, cn, and mail
# File lib/whimsy/asf/ldap.rb, line 1037 def self.add(attrs) # convert keys to strings attrs = attrs.map {|key, value| [key.to_s, value]}.to_h # verify required arguments are present %w(uid cn mail).each do |required| unless attrs.include? required raise ArgumentError.new("missing attribute #{required}") end end availid = attrs['uid'] # determine next uid and group, unless provided nextuid = attrs['uidNumber'] if nextuid raise ArgumentError.new("gidNumber #{gidNumber} != uidNumber #{uidNumber}") unless attrs['gidNumber'] == nextuid else nextuid = next_uidNumber end # fixed attributes attrs.merge!({ 'uidNumber' => nextuid.to_s, 'gidNumber' => nextuid.to_s, 'asf-committer-email' => "#{availid}@apache.org", 'objectClass' => %w(person top posixAccount organizationalPerson inetOrgPerson asf-committer hostObject ldapPublicKey) }) # defaults attrs['loginShell'] ||= '/bin/bash' # as per asfpy.ldap attrs['homeDirectory'] ||= File.join('/home', availid) attrs['host'] ||= 'home.apache.org' attrs['asf-sascore'] ||= '10' # parse name if sn has not been provided (givenName is optional) attrs = ASF::Person.ldap_name(attrs['cn']).merge(attrs) unless attrs['sn'] # user is expected to use id.apache.org to set their initial password attrs['userPassword'] = '{CRYPT}*' # invalid password (I assume) # create new LDAP person entry = attrs.map {|key, value| mod_add(key, value)} ASF::LDAP.add("uid=#{availid},#{base}", entry) # return person object; they must use id.apache.org to reset the password person = ASF::Person.find(availid) person end
Convert non-ASCII characters to equivalent ASCII optionally: replace any remaining non-word characters (e.g. ‘.’ and space) with ‘-’
# File lib/whimsy/asf/person.rb, line 16 def self.asciize(name, nonWord = '-') # Should agree with asciize.js.rb if name.match %r{[^\x00-\x7F]} # at least one non-ASCII character present # digraphs. May be culturally sensitive # Note that the combining accents require matching two characters name.gsub! %r{\u00df}, 'ss' name.gsub! %r{\u00e4|a\u0308}, 'ae' # 308 = combining diaeresis name.gsub! %r{\u00e5|a\u030a}, 'aa' # a with ring above: should this translate as 'a'? name.gsub! %r{\u00c5|A\u030a}, 'AA' # A with ring above: should this translate as 'A'? name.gsub! %r{\u00e6}, 'ae' # small letter ae name.gsub! %r{\u00c6}, 'AE' # large letter AE name.gsub! %r{\u00f1|n\u0303}, 'ny' # 303 = combining tilde name.gsub! %r{\u00d1|N\u0303}, 'NY' # 303 = combining tilde name.gsub! %r{\u00f6|o\u0308}, 'oe' # 308 = combining diaeresis name.gsub! %r{\u00d6|O\u0308}, 'OE' # 308 = combining diaeresis name.gsub! %r{\u00de}, 'TH' # thorn name.gsub! %r{\u00fe}, 'th' # thorn name.gsub! %r{\u00fc|u\u0308}, 'ue' # 308 = combining diaeresis name.gsub! %r{\u00dc|U\u0308}, 'UE' # 308 = combining diaeresis # latin 1 name.gsub! %r{[\u00e0-\u00e3]}, 'a' # a with various accents name.gsub! %r{[\u00c0-\u00c3]}, 'A' # A with various accents name.gsub! %r{\u00e7}, 'c' # c-cedilla name.gsub! %r{\u00c7}, 'C' # C-cedilla name.gsub! %r{\u00f0}, 'd' # eth name.gsub! %r{\u00d0}, 'D' # eth name.gsub! %r{[\u00e8-\u00eb]}, 'e' name.gsub! %r{[\u00c8-\u00cb]}, 'E' name.gsub! %r{[\u00ec-\u00ef]}, 'i' name.gsub! %r{[\u00cc-\u00cf]}, 'I' name.gsub! %r{[\u00f2-\u00f5\u00f8]}, 'o' name.gsub! %r{[\u00d2-\u00d5\u00d8]}, 'O' name.gsub! %r{[\u00f9-\u00fb]}, 'u' name.gsub! %r{[\u00d9-\u00db]}, 'U' name.gsub! %r{[\u00fd\u00ff]}, 'y' name.gsub! %r{[\u00dd\u0178]}, 'Y' # Latin Extended-A name.gsub! %r{[\u0100\u0102\u0104]}, 'A' name.gsub! %r{[\u0101\u0103\u0105]}, 'a' name.gsub! %r{[\u0106\u0108\u010A\u010C]}, 'C' name.gsub! %r{[\u0107\u0109\u010B\u010D]}, 'c' name.gsub! %r{[\u010E\u0110]}, 'D' name.gsub! %r{[\u010F\u0111]}, 'd' name.gsub! %r{[\u0112\u0114\u0116\u0118\u011A]}, 'E' name.gsub! %r{[\u0113\u0115\u0117\u0119\u011B]}, 'e' name.gsub! %r{[\u014A]}, 'ENG' name.gsub! %r{[\u014B]}, 'eng' name.gsub! %r{[\u011C\u011E\u0120\u0122]}, 'G' name.gsub! %r{[\u011D\u011F\u0121\u0123]}, 'g' name.gsub! %r{[\u0124\u0126]}, 'H' name.gsub! %r{[\u0125\u0127]}, 'h' name.gsub! %r{[\u0128\u012A\u012C\u012E\u0130]}, 'I' name.gsub! %r{[\u0129\u012B\u012D\u012F\u0131]}, 'i' name.gsub! %r{[\u0132]}, 'IJ' name.gsub! %r{[\u0133]}, 'ij' name.gsub! %r{[\u0134]}, 'J' name.gsub! %r{[\u0135]}, 'j' name.gsub! %r{[\u0136]}, 'K' name.gsub! %r{[\u0137]}, 'k' name.gsub! %r{[\u0138]}, 'kra' name.gsub! %r{[\u0139\u013B\u013D\u013F\u0141]}, 'L' name.gsub! %r{[\u013A\u013C\u013E\u0140\u0142]}, 'l' name.gsub! %r{[\u0143\u0145\u0147]}, 'N' name.gsub! %r{[\u0144\u0146\u0148\u0149]}, 'n' name.gsub! %r{[\u014C\u014E\u0150]}, 'O' name.gsub! %r{[\u014D\u014F\u0151\u01A1]}, 'o' name.gsub! %r{[\u0152]}, 'OE' name.gsub! %r{[\u0153]}, 'oe' name.gsub! %r{[\u0154\u0156\u0158]}, 'R' name.gsub! %r{[\u0155\u0157\u0159]}, 'r' name.gsub! %r{[\u015A\u015C\u015E\u0160]}, 'S' name.gsub! %r{[\u015B\u015D\u015F\u0161]}, 's' name.gsub! %r{[\u0162\u0164\u0166]}, 'T' name.gsub! %r{[\u0163\u0165\u0167]}, 't' name.gsub! %r{[\u0168\u016A\u016C\u016E\u0170\u0172]}, 'U' name.gsub! %r{[\u0169\u016B\u016D\u016F\u0171\u0173\u01B0]}, 'u' name.gsub! %r{[\u0174]}, 'W' name.gsub! %r{[\u0175]}, 'w' name.gsub! %r{[\u0176\u0178]}, 'Y' name.gsub! %r{[\u0177]}, 'y' name.gsub! %r{[\u0179\u017B\u017D]}, 'Z' name.gsub! %r{[\u017A\u017C\u017E]}, 'z' # Latin Extended Additional # N.B. Only ones seen in iclas.txt are included here name.gsub! %r{\u1ea0}, 'A' # A with combining dot below name.gsub! %r{\u1ea1}, 'a' # a with combining dot below name.gsub! %r{\u1ec4}, 'E' # E with circumflex and tilde name.gsub! %r{\u1ec5}, 'e' # e with circumflex and tilde # remove unhandled combining diacritics (some combinations are handled above) name.gsub! %r{[\u0300-\u036f]}, '' end if nonWord # deal with any remaining non-word characters name.strip.gsub %r{[^\w]+}, nonWord if nonWord else name end end
# File lib/whimsy/asf/ldap.rb, line 920 def self.dn(name) "uid=#{name},#{ASF::Person.base}" end
find a Person
by email address
# File lib/whimsy/asf/mail.rb, line 330 def self.find_by_email(value) person = Mail.list[value.downcase] return person if person end
Get a list of ids matching a name matches against ‘cn’, also ‘givenName’ and ‘sn’ if the former does not match returns an array of ids; may be empty Intended for use when matching a few people individually.
# File lib/whimsy/asf/ldap.rb, line 736 def self.find_by_name(name) res = listids("(cn=#{name})") if res.empty? parts = name.split(' ') res = listids("(&(givenName=#{parts[0]})(sn=#{parts[-1]}))") end res end
Get id matching a name, or nil matches against ‘cn’, also ‘givenName’ and ‘sn’ if the former does not match returns a single id, or nil if there is not a unique match Intended for use when matching a few people individually.
# File lib/whimsy/asf/ldap.rb, line 749 def self.find_by_name!(name) res = find_by_name(name) return nil unless res.size == 1 res.first end
parse a name into LDAP
fields
# File lib/whimsy/asf/person.rb, line 140 def self.ldap_name(name) words = name.gsub(',', '').split(' ') result = {'cn' => name} result['title'] = words.shift if words.first == 'Dr.' or words.first == 'Dr' result['initials'] = [] while words.first =~ %r{^[A-Z]\.$} result['initials'] << words.shift end if words.last =~ /^Ph\.D\.?/ title = words.pop # Always pop (||= short-circuits the pop) result['title'] ||= title end result['generationQualifier'] = words.pop if words.last =~ SUFFIXES result['givenName'] = words.shift if words.size > 1 # don't use remaining word as it must be sn # TODO givenName can have multiple entries # extract surnames like van Gogh etc if words.size >= 3 and DOUBLE_PFX.include? words[-3..-2].join(' ') result['sn'] = words[-3..-1].join(' ') result['unused'] = words[0..-4] elsif words.size >= 2 and SINGLE_PFX.include? words[-2] result['sn'] = words[-2..-1].join(' ') result['unused'] = words[0..-3] else result['sn'] = words.pop result['unused'] = words end result end
extract sn and givenName from cn (needed for LDAP
entries) returns sn, [givenName,…] Note that givenName is returned as an array (may be empty). This is because givenName is an optional attribute which may appear multiple times. It remains to be seen whether we want to create multiple attributes, or whether it is more appropriate to add at most one attribute containing all the givenName values. [The array can be joined to produce a single value]. DRAFT version: not for general use yet Does not handle multi-word family names or honorifics etc
# File lib/whimsy/asf/person.rb, line 178 def self.ldap_parse_cn_DRAFT(cn, familyFirst) words = cn.split(' ') if familyFirst sn = words.shift else sn = words.pop end return sn, words end
Return a hash of nominated members. Keys are ASF::Person
objects, values are the nomination text.
# File lib/whimsy/asf/nominees.rb, line 9 def self.member_nominees begin return Hash[@member_nominees.to_a] if @member_nominees rescue end meetings = ASF::SVN['Meetings'] nominations = Dir[File.join(meetings, '*', 'nominated-members.txt')].max # ensure non-UTF-8 chars don't cause a crash nominations = File.read(nominations).encode('utf-8', 'utf-8', :invalid => :replace).split(/^\s*---+--\s*/) nominations.shift(2) nominees = {} nominations.each do |nomination| # leading space is swallowed by the split; match against # <NOMINATED PERSON'S APACHE ID> <PUBLIC NAME> id = nomination[/\A(\S+)/, 1] 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
Return a hash of individuals in the member watch list. Keys are ASF::Person
objects, values are the text from potential-member-watch-list.txt
..
# File lib/whimsy/asf/watch.rb, line 8 def self.member_watch_list return @member_watch_list if @member_watch_list text = File.read File.join(ASF::SVN['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
# File lib/whimsy/asf/person.rb, line 216 def self.names_equivalent?(one, two) # index cannot be -1, cannot match if missing entries are set to -1 or nil return one == two || (NAMEHASH[one] || -1) == NAMEHASH[two] || one.start_with?("#{two} ") || two.start_with?("#{one} ") || (NAMEHASH[one.split(' ').first] || -1) == NAMEHASH[two.split(' ').first] end
Optionally return several free values as an array
# File lib/whimsy/asf/ldap.rb, line 1007 def self.next_uidNumber(count=1) raise ArgumentError.new "Count: #{count} is less than 1!" if count < 1 numbers = ASF.search_one(ASF::Person.base, 'uid=*', ['uidNumber', 'gidNumber']). map{|i| u=i['uidNumber'];g=i['gidNumber']; u == g ? u : [u,g]}.flatten.map(&:to_i). select{|i| i >= MINIMUM_USER_UID}.uniq.sort.lazy enum = Enumerator.new do |output| last = MINIMUM_USER_UID - 1 # in case no valid entries exist loop do curr = numbers.next if curr <= last + 1 last = curr else (last+1..curr-1).each {|i| output << i} last = curr end end # in case we ran off the end... loop do last = last+1 output << last end end if (count == 1) enum.first else enum.take(count) end end
pre-fetch a given set of attributes, for a given list of people
# File lib/whimsy/asf/ldap.rb, line 756 def self.preload(attributes, people=[]) list = Hash.new {|hash, name| hash[name] = find(name)} attributes = [attributes].flatten if people.empty? or people.length > 1000 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
remove a person from LDAP
# File lib/whimsy/asf/ldap.rb, line 1089 def self.remove(availid) ASF::LDAP.delete("uid=#{availid},#{base}") end
rearrange line in an order suitable for sorting
# File lib/whimsy/asf/person.rb, line 124 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! %r{^IJ}, 'Ij' name.unshift(suffix) if suffix name.map! {|word| asciize(word)} name.reverse.join(' ').downcase end
DRAFT return name suitable for a filename stem Should normally be applied to the legal name
# File lib/whimsy/asf/person.rb, line 227 def self.stem_DRAFT(name) # need to split before name = name.gsub(',', ' ').split(/ +/).map {|n| n.gsub(%r{^(Dr|Jr|Sr|[A-Z])\.$}, '\1')} asciize(name.join('-')).downcase.chomp('-') end
Public Instance Methods
Active emails: primary email address, alt email addresses, and member email addresses.
# File lib/whimsy/asf/mail.rb, line 353 def active_emails (mail + alt_email + member_emails).uniq end
All known email addresses: includes active, obsolete, and apache.org email addresses. (But don’t add notinavail@apache.org)
# File lib/whimsy/asf/mail.rb, line 359 def all_mail (active_emails + obsolete_emails + (id == 'notinavail' ? [] : ["#{id}@apache.org"])).uniq end
list all of the alternative emails for this person
# File lib/whimsy/asf/ldap.rb, line 843 def alt_email attrs['asf-altEmail'] || [] end
is argument an empty string on its own or in a singleton array?
# File lib/whimsy/asf/ldap.rb, line 986 def arg_empty?(arg) return arg.empty? || (arg.is_a?(Array) && arg.size == 1 && arg.first.empty?) end
determine if the person has asf-banned: yes. If scanning a large list, consider preloading the asf-banned
attributes for these people.
# File lib/whimsy/asf/ldap.rb, line 827 def asf_banned? # No idea what this means (yet) attrs['asf-banned']&.first == 'yes' end
Is this person listed in the committers LDAP
group?
# File lib/whimsy/asf/ldap.rb, line 807 def asf_committer? ASF::Group.new('committers').include? self end
Returns ASF
membership status according to members.txt: :current
if this person is listed as an ASF
member :emeritus
if this person is listed as an Emeritus ASF
member :deceased
if this person is listed as a Deceased ASF
member nil
otherwise (i.e. does not appear in members.txt)
# File lib/whimsy/asf/person.rb, line 283 def asf_member_status ASF::Member.member_status name end
list of LDAP
attributes for this person, populated lazily upon first reference.
# File lib/whimsy/asf/ldap.rb, line 796 def attrs @attrs ||= LazyHash.new {ASF.search_one(base, "uid=#{name}").first} end
return a list of ASF
authorizations that contain this individual
# File lib/whimsy/asf/auth.rb, line 64 def auth @auths ||= ASF::Authorization.find_by_id(name) end
determine if the person is banned. If scanning a large list, consider preloading the loginShell
attributes for these people.
# File lib/whimsy/asf/ldap.rb, line 813 def banned? # FreeBSD uses /usr/bin/false; Ubuntu uses /bin/false not attrs['loginShell'] or %w(/bin/false bin/nologin bin/no-cla).any? {|a| attrs['loginShell'].first.include? a} end
list of LDAP
committees that this individual is a member of TODO should this be deleted? It seems to be used partly as LDAP
membership and partly as PMC membership (which were originally generally the same) If the former, then it disappears. If the latter, then it needs to be derived from project_owners
filtered to keep only PMCs
# File lib/whimsy/asf/ldap.rb, line 867 def committees # legacy LDAP entries committees = [] # add in projects # Get list of project names where the person is an owner projects = self.projects.select {|prj| prj.owners.include? self}.map(&:name) committees += ASF::Committee.pmcs.select do |pmc| projects.include? pmc.name end # dedup committees.uniq end
# File lib/whimsy/asf/person.rb, line 250 def createDate createTimestamp[0..7] end
determine account creation date. Notes:
-
LDAP
info is not accurate for dates prior to 2009. See person/override-dates.rb -
createTimestamp isn’t loaded by default (but can either be preloaded or fetched explicitly)
# File lib/whimsy/asf/person.rb, line 243 def createTimestamp result = @@create_date[name] result ||= attrs['createTimestamp'][0] rescue nil # in case not loaded result ||= ASF.search_one(base, "uid=#{name}", 'createTimestamp')[0][0] result end
Designated Name from LDAP
# File lib/whimsy/asf/ldap.rb, line 916 def dn "uid=#{name},#{ASF::Person.base}" end
list of LDAP
groups that this individual is a member of
# File lib/whimsy/asf/ldap.rb, line 902 def groups weakref(:groups) do Group.list("memberUid=#{name}") end end
override the base version which does not work as it relies on search by ‘cn’ == id
# File lib/whimsy/asf/ldap.rb, line 790 def hasLDAP? !attrs['dn'].nil? end
ASF::ICLA
information for this person.
# File lib/whimsy/asf/icla.rb, line 311 def icla @icla ||= ASF::ICLA.find_by_id(name) end
setter for icla, should only be used by ASF::ICLA.preload
# File lib/whimsy/asf/icla.rb, line 316 def icla=(icla) @icla = icla end
does this individual have an ICLA
on file?
# File lib/whimsy/asf/icla.rb, line 321 def icla? @icla || ICLA.availids.include?(name) end
is the login marked as inactive?
# File lib/whimsy/asf/ldap.rb, line 833 def inactive? nologin? || asf_banned? end
primary mail addresses
# File lib/whimsy/asf/ldap.rb, line 838 def mail attrs['mail'] || [] end
email addresses from members.txt
# File lib/whimsy/asf/member.rb, line 378 def member_emails ASF::Member.emails(members_txt) end
Person’s name as found in members.txt
# File lib/whimsy/asf/member.rb, line 383 def member_name ASF::Member.get_name(members_txt) if members_txt end
Return the member nomination text for this individual
# File lib/whimsy/asf/nominees.rb, line 42 def member_nomination @member_nomination ||= Person.member_nominees[self] end
This person’s entry in potential-member-watch-list.txt
.
# File lib/whimsy/asf/watch.rb, line 35 def member_watch text = Person.member_watch_list[self] if text text.sub!(/\A\s*\n/,'') text.sub!(/\n---\Z/,'') end text end
text entry from members.txt
. If full
is true
, this will also include the text delimiters.
# File lib/whimsy/asf/member.rb, line 365 def members_txt(full = false) prefix, suffix = ' *) ', "\n\n" if full # Is the cached text still valid? unless @members_time == ASF::Member.mtime @members_txt = nil end # cache the text and its time (may be changed by the find operation) @members_txt ||= ASF::Member.find_text_by_id(id) @members_time = ASF::Member.mtime "#{prefix}#{@members_txt}#{suffix}" if @members_txt end
Allow arbitrary LDAP
attributes to be referenced as object properties. Example: ASF::Person.find('rubys').cn
. Can also be used to modify an LDAP
attribute.
# File lib/whimsy/asf/ldap.rb, line 959 def method_missing(name, *args) sname = name.to_s if sname.end_with? '=' and args.length == 1 return modify(name[0..-2], args) end return super unless args.empty? return super unless VALID_ATTRS.include? sname result = self.attrs[sname] if result.nil? || result.empty? return nil else result.map! do |value| value = value.dup.force_encoding('utf-8') if value.is_a? String value end if result.length == 1 result.first else result end end end
update an LDAP
attribute for this person. This needs to be run either inside or after ASF::LDAP.bind
.
# File lib/whimsy/asf/ldap.rb, line 992 def modify(attr, value) # OK to remove the attribute? Only support givenName for now... if attr == 'givenName' and arg_empty?(value) ASF::LDAP.modify(self.dn, [ASF::Base.mod_delete(attr.to_s, nil)]) attrs.delete(attr.to_s) # remove the cached entry else ASF::LDAP.modify(self.dn, [ASF::Base.mod_replace(attr.to_s, value)]) # attributes are expected to be arrays attrs[attr.to_s] = value.is_a?(String) ? [value] : value end end
determine if the person has no login. If scanning a large list, consider preloading the loginShell
attributes for these people.
# File lib/whimsy/asf/ldap.rb, line 820 def nologin? # FreeBSD uses /usr/bin/false; Ubuntu uses /bin/false not attrs['loginShell'] or %w(/bin/false bin/nologin bin/no-cla).any? {|a| attrs['loginShell'].first.include? a} end
List of inactive email addresses: currently only contains the address in iclas.txt
if it is not contained in the list of active email addresses.
# File lib/whimsy/asf/mail.rb, line 338 def obsolete_emails return @obsolete_emails if @obsolete_emails result = [] if icla icla.emails.each do |email| active_emails.none? {|mail| mail.downcase == email.downcase} result << email end end @obsolete_emails = result end
list all of the PGP key fingerprints
# File lib/whimsy/asf/ldap.rb, line 848 def pgp_key_fingerprints attrs['asf-pgpKeyFingerprint'] || [] end
list of Podlings that this individual is a member (owner) of
# File lib/whimsy/asf/ldap.rb, line 897 def podlings ASF::Podling.current.select {|pod| project_owners.map(&:name).include? pod.name} end
list of LDAP
projects that this individual is an owner of - i.e. on (P)PMC
# File lib/whimsy/asf/ldap.rb, line 890 def project_owners weakref(:project_owners) do Project.list("owner=uid=#{name},#{base}") end end
list of LDAP
projects that this individual is a member of
# File lib/whimsy/asf/ldap.rb, line 883 def projects weakref(:projects) do Project.list("member=uid=#{name},#{base}") end end
return person’s public name, searching a variety of sources, starting with iclas.txt, then LDAP
, and finally the archives.
# File lib/whimsy/asf/person.rb, line 256 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 all attributes from LDAP
# File lib/whimsy/asf/ldap.rb, line 801 def reload! @attrs = nil attrs end
Is this person in the secretary team?
# File lib/whimsy/asf/person.rb, line 288 def secretary? ASF::Service.find('asf-secretary').members.include? self end
list of LDAP
services that this individual is a member of
# File lib/whimsy/asf/ldap.rb, line 909 def services weakref(:services) do Service.listcns("(|(member=#{dn})(memberUid=#{name}))") end end
return public name in a sortable order (last name first)
# File lib/whimsy/asf/person.rb, line 234 def sortable_name Person.sortable_name(self.public_name) end
list all of the ssh public keys
# File lib/whimsy/asf/ldap.rb, line 853 def ssh_public_keys attrs['sshPublicKey'] || [] end
Is this person in the treasurer team?
# File lib/whimsy/asf/person.rb, line 293 def treasurer? ASF::AuthGroup.find('treasurer').members.include? self end
list all of the personal URLs
# File lib/whimsy/asf/ldap.rb, line 858 def urls attrs['asf-personalURL'] || [] end