www/roster/models/nonpmc.rb (175 lines of code) (raw):

class NonPMC def self.serialize(id, env) cttee = ASF::Committee.find(id) return unless cttee.nonpmc? hasLDAP = !ASF::Project[cttee.name].nil? # TODO this check perhaps belongs in the library code members = cttee.owners committers = cttee.committers # Hack to fix unusual mail_list values e.g. press@apache.org mail_list = cttee.mail_list.sub(/@apache\.org/,'') mail_list = 'legal' if mail_list =~ /^legal-/ && cttee.name != 'dataprivacy' mail_list = 'fundraising' if mail_list =~ /^fundraising-/ ASF::Committee.load_committee_info # We'll be needing the mail data later ASF::Person.preload(['cn', 'mail', 'asf-altEmail', 'githubUsername'], (members + committers).uniq) image = ASF::SiteImage.find(id) moderators = nil modtime = nil subscribers = nil # we get the counts only here subtime = nil pSubs = [] # private@ subscribers unMatchedSubs = [] # unknown private@ subscribers unMatchedSecSubs = [] # unknown security@ subscribers currentUser = ASF::Person.find(env.user) # Might make sense for non-PMCs - remove the code later if not analysePrivateSubs = false # whether to show missing private@ subscriptions if cttee.roster.include? env.user or currentUser.asf_member? require 'whimsy/asf/mlist' moderators, modtime = ASF::MLIST.list_moderators(mail_list) subscribers, subtime = ASF::MLIST.list_subs(mail_list) # counts only, no archivers if mail_list == 'press' # SPECIAL %w{markpub announce}.each do |alt_list| mods, _ = ASF::MLIST.list_moderators(alt_list) moderators.merge! mods subs, _ = ASF::MLIST.list_subs(alt_list) subscribers.merge! subs end end # TODO: do any non-PMCs have private lists? analysePrivateSubs = currentUser.asf_member? unless analysePrivateSubs # check for private moderator if not already allowed access user_mail = currentUser.all_mail || [] pMods = moderators["private@#{mail_list}.apache.org"] || [] analysePrivateSubs = !(pMods & user_mail).empty? end if analysePrivateSubs pSubs = ASF::MLIST.private_subscribers(mail_list)[0]||[] unMatchedSubs=Set.new(pSubs) # init ready to remove matched mails pSubs.map!(&:downcase) # for matching sSubs = ASF::MLIST.security_subscribers(mail_list)[0]||[] unMatchedSecSubs = Set.new(sSubs) # init ready to remove matched mails end lists = ASF::MLIST.domain_lists(mail_list, true) else lists = ASF::MLIST.domain_lists(mail_list, false) end roster = ASF.dup(cttee.roster) # if the roster is empty, then add the chair(s) if roster.empty? cttee.chairs.each do |ch| roster[ch[:id]] = {name: ch[:name], date: 'unknown'} # it is used to flag CI data so must be true in JavaScript end end cttee_members = roster.keys # get the potentially updated list # now add the status info roster.each {|_, info| info[:role] = 'Committee member'} members.each do |person| roster[person.id] ||= { name: person.public_name, role: 'Committee member' } if analysePrivateSubs allMail = person.all_mail.map(&:downcase) roster[person.id]['notSubbed'] = true if (allMail & pSubs).empty? unMatchedSubs.delete_if {|k| allMail.include? k.downcase} unMatchedSecSubs.delete_if {|k| allMail.include? k.downcase} end roster[person.id]['ldap'] = true end committers.each do |person| roster[person.id] ||= { name: person.public_name, role: 'Committer' } end roster.each do |k, v| person = ASF::Person.find(k) v[:member] = person.asf_member? v['githubUsername'] = (person.attrs['githubUsername'] || []).join(', ') end if cttee.chair and roster[cttee.chair.id] roster[cttee.chair.id]['role'] = 'Committee chair' end # separate out the known ASF members and extract any matching committer details unknownSubs = [] # unknown private@ subscribers: not PMC or ASF asfMembers = [] unknownSecSubs = [] # unknown security@ subscribers: not PMC or ASF # Also look for non-ASF mod emails nonASFmails = {} moderators&.each { |_, mods| mods.each {|m| nonASFmails[m] = '' unless m.end_with? '@apache.org'} } if unMatchedSubs.length > 0 or nonASFmails.length > 0 or unMatchedSecSubs.length > 0 load_emails # set up @people unMatchedSubs.each { |addr| who = nil @people.each do |person| if person[:mail].any? {|mail| mail.downcase == addr.downcase} who = person end end if who if who[:member] asfMembers << { addr: addr, person: who } else unknownSubs << { addr: addr, person: who } end else unknownSubs << { addr: addr, person: nil } end } nonASFmails.each {|k, v| @people.each do |person| if person[:mail].any? {|mail| ASF::Mail.to_canonical(mail.downcase) == ASF::Mail.to_canonical(k.downcase)} nonASFmails[k] = person[:id] end end } unMatchedSecSubs.each { |addr| who = nil @people.each do |person| if person[:mail].any? {|mail| mail.downcase == addr.downcase} who = person end end if who unless who[:member] unknownSecSubs << { addr: addr, person: who } end else unknownSecSubs << { addr: addr, person: nil } end } end return { id: id, chair: cttee.chair&.id, display_name: cttee.display_name, description: cttee.description, schedule: cttee.schedule, report: cttee.report, site: cttee.site, established: cttee.established, hasLDAP: hasLDAP, ldap: members.map(&:id), members: cttee_members, committers: committers.map(&:id), roster: roster, mail: lists.sort.to_h, moderators: moderators, modtime: modtime, subscribers: subscribers, subtime: subtime, nonASFmails: nonASFmails, image: image, analysePrivateSubs: analysePrivateSubs, unknownSubs: unknownSubs, asfMembers: asfMembers, unknownSecSubs: unknownSecSubs, } end private def self.load_emails # recompute index if the data is 5 minutes old or older @people = nil if not @people_time or Time.now-@people_time >= 300 unless @people # bulk loading the mail information makes things go faster mail = ASF::Mail.list.group_by(&:last).transform_values {|list| list.map(&:first)} # build a list of people, their public-names, and email addresses @people = ASF::Person.list.map {|person| result = {id: person.id, name: person.public_name, mail: mail[person]} result[:member] = true if person.asf_member? result } # cache @people_time = Time.now end @people end end