www/members/nominate_member.cgi (212 lines of code) (raw):
#!/usr/bin/env ruby
PAGETITLE = "Nominate someone for ASF Member" # Wvisible:meeting
$LOAD_PATH.unshift '/srv/whimsy/lib'
require 'time'
require 'wunderbar'
require 'wunderbar/bootstrap'
require 'whimsy/asf'
require 'whimsy/asf/forms'
require 'whimsy/asf/member-files' # See for nomination file parsing
require 'whimsy/asf/wunderbar_updates'
require 'whimsy/asf/meeting-util'
require 'whimsy/asf/time-utils'
require 'mail'
MAILING_LIST = 'members@apache.org'
def emit_form(title, prev_data)
_whimsy_panel(title, style: 'panel-success') do
_form.form_horizontal method: 'post' do
field = 'availid'
_whimsy_forms_input(label: 'Nominee availid', name: field,
value: prev_data[field], helptext: 'Enter the availid of the committer you are nominating for ASF Membership'
)
_whimsy_forms_input(label: 'Nominated by', name: 'nomby', readonly: true, value: $USER
)
_whimsy_forms_input(
label: 'Seconded by', name: 'secby', helptext: 'Optional comma-separated list of seconds; ONLY if you have confirmed with the seconds directly'
)
field = 'statement'
_whimsy_forms_input(label: 'Nomination Statement', name: field, rows: 10,
value: prev_data[field], helptext: 'Explain why you believe this person would make a good ASF Member, and what projects/communities they work on at the ASF'
)
_whimsy_forms_submitwrap(
noicon: true, label: 'submit', name: 'submit', value: 'submit', helptext: 'Checkin this nomination and send email to members@'
)
end
end
end
# Validation as needed within the script
# Returns: 'OK' or a text message describing the problem
def validate_form(formdata: {})
uid = formdata['availid'].downcase
return "You MUST provide a nomination statement for Candidate #{uid}; blank was provided!" if formdata['statement'].empty?
chk = ASF::Person[uid]&.asf_member?
chk.nil? and return "Invalid availid supplied: (#{uid})\n\nStatement:\n#{formdata['statement']}"
# Allow renomination of Emeritus
pubname = ASF::Person[uid].public_name
chk && !chk.to_s.start_with?('Emeritus') and return "Your nominee #{pubname} (#{uid}) is already an ASF member!"
already = ASF::MemberFiles.member_nominees
return "Candidate (#{uid}) has already been nominated by #{already[uid]['Nominated by']}" if already.include? uid
return 'OK'
end
# Handle submission (checkout user's apacheid.json, write form data, checkin file)
# @return true if we think it succeeded; false in all other cases
def process_form(formdata: {}, wunderbar: {})
_h3 "Transcript of update to nomination file #{ASF::MemberFiles::NOMINATED_MEMBERS}"
entry = ASF::MemberFiles.make_member_nomination({
availid: formdata['availid'].downcase,
nomby: formdata['nomby'],
secby: formdata['secby'],
statement: formdata['statement']
})
environ = Struct.new(:user, :password).new($USER, $PASSWORD)
ASF::MemberFiles.update_member_nominees(environ, wunderbar, [entry], "+= #{formdata['availid'].downcase}")
return true
end
# Send email to members@ with this nomination's data
# Reports status to user in a _div
def send_nomination_mail(formdata: {})
uid = formdata['availid'].downcase
nomby = formdata['nomby']
public_name = ASF::Person.new(uid).public_name
secby = formdata.fetch('secby', nil)
secby.nil? || secby.empty? ? nomseconds = '' : nomseconds = "Nomination seconded by: #{secby}"
mail_body = <<-MAILBODY
This nomination for #{public_name} (#{uid}) as a New Member
Candidate has been added:
#{formdata['statement']}
#{nomseconds}
--
- #{ASF::Person[nomby].public_name}
Email generated by Whimsy (#{File.basename(__FILE__)})
MAILBODY
# See check_membernoms.cgi which parses this in list archives
mailsubject = "[MEMBER NOMINATION] #{ASF::Person.new(uid).public_name} (#{uid})"
ASF::Mail.configure
mail = Mail.new do
to MAILING_LIST
bcc 'notifications@whimsical.apache.org'
from "#{ASF::Person[nomby].public_name} <#{nomby}@apache.org>"
subject mailsubject
text_part do
body mail_body
end
end
begin
mail.deliver!
rescue StandardError => e
_div.alert.alert_danger role: 'alert' do
_p.strong "ERROR: email was NOT sent due to: #{e.message} #{e.backtrace[0]}"
_p do
_ "To: #{MAILING_LIST}"
_br
_ "Subject: #{mailsubject}"
_br
_ "#{mail_body}"
end
end
return
end
_div.alert.alert_success role: 'alert' do
_p "The following email was sent:"
_p do
_ "To: #{MAILING_LIST}"
_br
_ "Subject: #{mailsubject}"
_br
_ "#{mail_body}"
end
end
return
end
# Produce HTML
_html do
_body? do
# Countdown until nominations for current meeting close
latest_meeting_dir = ASF::MeetingUtil.latest_meeting_dir
timelines = ASF::MeetingUtil.get_timeline(latest_meeting_dir)
t_now = Time.now.to_i
t_end = Time.parse(timelines['nominations_close_iso']).to_i
nomclosed = t_now > t_end
_whimsy_body(
title: PAGETITLE,
subtitle: 'About This Script',
related: {
'meeting.cgi' => 'Member Meeting FAQ and info',
'/roster/committer/' => 'Lookup any committer availID',
'memberless-pmcs.cgi' => 'PMCs with no/few ASF Members',
'watch.cgi' => 'Watch list for potential Member candidates',
'check_membernoms.cgi' => 'Cross-check existing Member nominations',
ASF::SVN.svnpath!('Meetings') => 'Official Meeting Agenda Directory'
},
helpblock: -> {
_b "For: #{timelines['meeting_type']} Meeting on: #{timelines['meeting_iso']}"
_p do
_ %Q{
Use this form to nominate any Committer the new ASF Membership election.
It automatically adds a properly formatted nomination to the #{ASF::MemberFiles::NOMINATED_MEMBERS} file,
and will then
}
_strong "send an email to the #{MAILING_LIST} list"
_ ' from you with the nomination, '
_a 'as is tradition.', href: 'https://lists.apache.org/list?members@apache.org:2023-2:%22MEMBER%20NOMINATION%22'
_ ' This form only supports adding new nominations of existing committers; to add seconds or comments, please use SVN. To nominate a non-committer, add them manually and use use n/a for the id. '
_a 'Lookup committer availIDs', href: '/roster/committer/'
end
}
) do
if nomclosed
_h1 'Nominations are now closed!'
_p 'Sorry, no further nominations will be accepted for ballots at this meeting.'
else
_h3 "Nominations close in #{ASFTime.secs2text(t_end - t_now)} at #{Time.at(t_end).utc} for Meeting: #{timelines['meeting_iso']}"
end
_div id: 'nomination-form' do
if _.post?
unless nomclosed
submission = _whimsy_params2formdata(params)
valid = validate_form(formdata: submission)
end
if nomclosed
_div.alert.alert_warning role: 'alert' do
_p "Nominations have closed"
end
elsif valid == 'OK'
if process_form(formdata: submission, wunderbar: _)
_div.alert.alert_success role: 'alert' do
_p "Your nomination was submitted to svn; now sending email to #{MAILING_LIST}."
end
mailval = send_nomination_mail(formdata: submission)
_pre mailval
else
_div.alert.alert_danger role: 'alert' do
_p do
_span.strong "ERROR: Form data invalid in process_form(), update was NOT submitted!"
_br
_ "#{submission}"
end
end
end
else
_div.alert.alert_danger role: 'alert' do
_p do
_span.strong "ERROR: Form data invalid in validate_form(), update was NOT submitted!"
_br
_p valid
end
end
end
else # if _.post?
if nomclosed
_p do
_ 'Sorry, no further nominations will be accepted for ballots at this meeting.'
_br
_a 'See existing nominations.', href: '/members/check_membernoms.cgi'
end
else
emit_form('Enter your New Member nomination', {})
end
end
end
end
end
end