blob: 998ddad92d2a925e09c445e3bde0f63e38401362 [file] [log] [blame]
# Utility methods and structs related to Member's Meetings
# NOTE: Assumes 21st century '2*'
require 'json'
class MeetingUtil
RECORDS = 'https://svn.apache.org/repos/private/foundation/Meetings'
MEETING_FILES = { # Filename in meeting dir, pathname to another deployed tool, or URL
'README.txt' => 'README For Meeting Process And Roll Call',
'nomination_of_board.txt' => 'How To Nominate Someone For Board',
'nomination_of_members.txt' => 'How To Nominate A New Member',
'/members/proxy.cgi' => 'How To Submit A Proxy/Check Your Proxies',
'https://www.apache.org/foundation/governance/meetings' => 'How Voting Via Email Works',
'agenda.txt' => 'Official Meeting Agenda',
'board_ballot.txt' => 'Official Board Candidate Ballots',
'nominated-members.txt' => 'Official New Member Nominees/Seconds',
'proxies' => 'Official List Of Meeting Proxies',
'record' => 'Official List Of Voting Members',
'attend' => 'Official List Of Meeting Attendees (afterwards)',
'voter-tally' => 'Official List Of Who Voted (afterwards)',
'raw_board_votes.txt' => 'Official List Of Votes For Board (afterwards)'
}
# Calculate how many members required to attend first half for quorum
def self.calculate_quorum(mtg_dir)
begin
num_members = File.read(File.join(mtg_dir, 'record')).each_line.count
quorum_need = num_members / 3
num_proxies = Dir[File.join(mtg_dir, 'proxies-received', '*')].count
attend_irc = quorum_need - num_proxies
rescue StandardError => e
# Ensure we can't break rest of script
puts "ERROR: #{e}"
return 0, 0, 0, 0
end
return num_members, quorum_need, num_proxies, attend_irc
end
# Get info about current users's proxying
# @return "help text", ["id | name (proxy)", ...] if they are a proxy for other(s)
# @return "You have already submitted a proxy form" to someone else
# @return nil otherwise
def self.is_user_proxied(mtg_dir, id)
user = ASF::Person.find(id)
lines = IO.read(File.join(mtg_dir, 'proxies'))
proxylist = lines.scan(/\s\s(.{25})(.*?)\((.*?)\)/) # [["Shane Curcuru ", "David Fisher ", "wave"], ...]
help = nil
copypasta = [] # theiravailid | Their Name in Rolls (proxy)
begin
proxylist.each do |arr|
if user.cn == arr[0].strip
copypasta << "#{arr[2].ljust(12)} | #{arr[1].strip} (proxy)"
elsif user.id == arr[2]
help = "NOTE: You have already submitted a proxy form for #{arr[0].strip} to mark your attendance (be sure they know to mark you at Roll Call)! "
end
end
rescue StandardError => e
(help ||= "") << "ERROR, could not read LDAP, proxy data may not be correct: #{e.message}"
end
if copypasta.empty?
return help
else
(help ||= "") << "During the meeting, to mark your proxies' attendance, AFTER the 2. Roll Call is called, you may copy/paste the below lines to mark your and your proxies attendance."
copypasta.unshift("#{user.id.ljust(12)} | #{user.cn}")
return help, copypasta
end
end
# Get the latest available Meetings dir
def self.get_latest(mtg_root)
return Dir[File.join(mtg_root, '2*')].sort.last
end
# Get the second latest available Meetings dir
def self.get_previous(mtg_root)
return Dir[File.join(mtg_root, '2*')].sort[-2]
end
# Read attendance.json file
def self.get_attendance(mtg_root)
return JSON.parse(IO.read(File.join(mtg_root, 'attendance.json')))
end
# Get a member's cohort (first meeting eligible to attend; typically year after they were elected)
# @param mtg_root local copy of RECORDS
# @param att_cache hash from attendance.json (see also attend-matrix.py elsewhere); Side effect is updated
# @param name of a Member (see also name mapping for various corrections)
def self.get_cohort(mtg_root, att_cache, name)
if att_cache.nil? or att_cache.empty?
att_cache = JSON.parse(IO.read(File.join(mtg_root, 'attendance.json')))
att_cache['cohorts'] = {}
# Precompute all cohorts, and leave cached
att_cache['members'].each do |date, names|
names.each do |nam|
att_cache['cohorts'][nam] = date
end
end
end
# TODO map any well-known mis-formatted names
return att_cache['cohorts'][name]
end
end