This is an automated email from the ASF dual-hosted git repository.
sebb pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/whimsy.git
The following commit(s) were added to refs/heads/master by this push:
new 8c04f272 board-nominate: add entry to board nominees
8c04f272 is described below
commit 8c04f272b5569014aaf0fb715ca2e60cd64d57d7
Author: Sebb <[email protected]>
AuthorDate: Sat Feb 18 23:25:39 2023 +0000
board-nominate: add entry to board nominees
---
lib/whimsy/asf/member-files.rb | 61 +++++++++++++++++++--
www/members/board-nominate.cgi | 117 +++++++++++++++++++++++++++++++++++++++++
www/members/index.cgi | 3 +-
www/members/nominations.cgi | 3 +-
www/members/watch.cgi | 2 +-
5 files changed, 180 insertions(+), 6 deletions(-)
diff --git a/lib/whimsy/asf/member-files.rb b/lib/whimsy/asf/member-files.rb
index 2ada7497..b529fcc7 100644
--- a/lib/whimsy/asf/member-files.rb
+++ b/lib/whimsy/asf/member-files.rb
@@ -9,7 +9,8 @@ module ASF
class MemberFiles
NOMINATED_MEMBERS = 'nominated-members.txt'
-
+ NOMINATED_BOARD = 'board_nominations.txt'
+
# get the latest meeting directory or nomination file
def self.latest_meeting(name=nil)
if name.nil? # we want the parent directory
@@ -74,7 +75,7 @@ module ASF
end
end
- # create a nomination entry in the standard format
+ # create a member nomination entry in the standard format
#
def self.make_member_nomination(fields = {})
availid = fields[:availid] or raise ArgumentError.new(":availid is
required")
@@ -97,6 +98,27 @@ module ASF
].compact.join("\n") + "\n"
end
+ # create a board nomination entry in the standard format
+ #
+ def self.make_board_nomination(fields = {})
+ availid = fields[:availid] or raise ArgumentError.new(":availid is
required")
+ publicname = ASF::Person[availid]&.cn or raise
ArgumentError.new(":availid #{availid} is invalid")
+ nomby = fields[:nomby] or raise ArgumentError.new(":nomby is required")
+ ASF::Person[nomby]&.dn or raise ArgumentError.new(":nomby is invalid")
+ secby = fields[:secby] || ''
+ statement = fields[:statement] or raise ArgumentError.new(":statement is
required")
+ [
+ '',
+ " #{publicname}",
+ " Nominated by: #{nomby}@apache.org",
+ " Seconded by: #{secby}",
+ '',
+ ' Nomination statement:',
+ ASFString.reflow(statement, 4, 80),
+ ''
+ ].compact.join("\n") + "\n"
+ end
+
# Sort the member_nominees, optionally adding new entries
def self.sort_member_nominees(contents, entries=nil)
sections = contents.split(%r{^-{10,}\n})
@@ -119,6 +141,30 @@ module ASF
[header, sections,
''].join("-----------------------------------------\n")
end
+ # Sort the board_nominees, optionally adding new entries
+ def self.sort_board_nominees(contents, entries=nil)
+ sections = contents.split(%r{^-{10,}\n})
+ header = sections.shift(2)
+ sections.pop if sections.last.strip == ''
+ sections.append(*entries) if entries # add new entries if any
+ names = {}
+ # replace 'each' by 'sort_by!' to sort by last name
+ sections.each do |s|
+ # sort by last name; check for duplicates
+ m = s.match %r{\s+(.+)}
+ if m
+ name = m[1]
+ raise ArgumentError.new("Duplicate id: #{name}") if names.include?
name
+ names[name] = 1
+ name.split.last
+ else
+ 'ZZ'
+ end
+ end
+ # reconstitute the file
+ [header, sections, ''].join("---------------------------------------\n")
+ end
+
# update the member nominees
def self.update_member_nominees(env, wunderbar, entries=nil, msg=nil,
opt={})
nomfile = latest_meeting(NOMINATED_MEMBERS)
@@ -128,6 +174,15 @@ module ASF
end
end
+ # update the board nominees
+ def self.update_board_nominees(env, wunderbar, entries=nil, msg=nil,
opt={})
+ nomfile = latest_meeting(NOMINATED_BOARD)
+ opt[:diff] = true unless opt.include? :diff # default to true
+ ASF::SVN.update(nomfile, msg || 'Updating board nominations', env,
wunderbar, opt) do |_tmpdir, contents|
+ sort_board_nominees(contents, entries)
+ end
+ end
+
# TODO: change to return arrays rather than hash.
# This would help detect duplicate entries
@@ -152,7 +207,7 @@ module ASF
# Return hash of board nominees
def self.board_nominees
nominees = {}
- ASF::MemberFiles.parse_file('board_nominations.txt') do |hdr, nominee|
+ ASF::MemberFiles.parse_file(NOMINATED_BOARD) do |hdr, nominee|
# for board, the header currently looks like this:
# <PUBLIC NAME>
id = ASF::Person.find_by_name!(hdr) || hdr # default to full name
diff --git a/www/members/board-nominate.cgi b/www/members/board-nominate.cgi
new file mode 100755
index 00000000..906357fa
--- /dev/null
+++ b/www/members/board-nominate.cgi
@@ -0,0 +1,117 @@
+#!/usr/bin/env ruby
+PAGETITLE = "Add entries to board nomination file" # Wvisible:tools
+# Note: PAGETITLE must be double quoted
+
+$LOAD_PATH.unshift '/srv/whimsy/lib'
+require 'wunderbar'
+require 'wunderbar/bootstrap'
+require 'whimsy/asf'
+require 'whimsy/asf/forms'
+require 'whimsy/asf/member-files'
+require 'whimsy/asf/wunderbar_updates'
+
+def emit_form(title, prev_data)
+ _whimsy_panel(title, style: 'panel-success') do
+ _form.form_horizontal method: 'post' do
+ _whimsy_forms_subhead(label: 'Nomination Form')
+ field = 'availid'
+ _whimsy_forms_input(
+ label: 'Nominee availid', name: field,
+ value: prev_data[field], helptext: 'Enter the availid of the potential
board member'
+ )
+ _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'
+ )
+ field = 'statement'
+ _whimsy_forms_input(label: 'Nomination statement', name: field, rows: 10,
+ value: prev_data[field], helptext: 'Reason for nomination'
+ )
+ _whimsy_forms_submit
+ 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']
+ chk = ASF::Person[uid]&.asf_member?
+ chk.nil? and return "Invalid availid: #{uid}"
+ already = ASF::MemberFiles.board_nominees
+ return "Already nominated: #{uid} 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: {})
+ statement = formdata['statement']
+
+ _h3 'Copy of statement to put in an email (if necessary)'
+ _pre statement
+
+ _hr
+
+ _h3 'Transcript of update to nomination file'
+ uid = formdata['availid']
+ entry = ASF::MemberFiles.make_board_nomination({
+ availid: uid,
+ nomby: $USER,
+ secby: formdata['secby'],
+ statement: statement
+ })
+
+ environ = Struct.new(:user, :password).new($USER, $PASSWORD)
+ ASF::MemberFiles.update_board_nominees(environ, wunderbar, [entry], "+=
#{uid}")
+ return true
+end
+
+# Produce HTML
+_html do
+ _body? do # The ? traps errors inside this block
+ _whimsy_body( # This emits the entire page shell: header, navbar, basic
styles, footer
+ title: PAGETITLE,
+ subtitle: 'About This Script',
+ related: {
+ ASF::SVN.svnpath!('Meetings') => 'Official Meeting Agenda Directory'
+ },
+ helpblock: -> {
+ _h3 'BETA - please report any errors to the Whimsy PMC!'
+ _p %{
+ This form can be used to ADD entries to the board-nominations.txt
file.
+ This is currently for use by the Nominator only, and does not send a
copy
+ of the nomination to the members list.
+ There is currently no support for updating an existing entry.
+ }
+ }
+ ) do
+
+ _div id: 'nomination-form' do
+ if _.post?
+ submission = _whimsy_params2formdata(params)
+ valid = validate_form(formdata: submission)
+ if valid == 'OK'
+ if process_form(formdata: submission, wunderbar: _)
+ _p.lead "Thanks for Using This Form!"
+ else
+ _div.alert.alert_warning role: 'alert' do
+ _p "SORRY! Your submitted form data failed process_form,
please try again."
+ end
+ end
+ else
+ _div.alert.alert_danger role: 'alert' do
+ _p "SORRY! Your submitted form data failed validate_form, please
try again."
+ _p valid
+ end
+ end
+ else # if _.post?
+ emit_form('Enter nomination data', {})
+ end
+ end
+ end
+ end
+end
diff --git a/www/members/index.cgi b/www/members/index.cgi
index 15e75e1d..5fdbc0ec 100755
--- a/www/members/index.cgi
+++ b/www/members/index.cgi
@@ -12,9 +12,10 @@ MEETING = {
'proxy.cgi' => "Assign a proxy for the (current) Member's meeting",
'watch.cgi' => "Potential Member Watch List - tracking candidates for future
nominations",
'memberless-pmcs.cgi' => "Crosscheck PMCs with few/no ASF Members, for
future nominations",
- 'member_nominations' => 'Update list of nominated members',
+ 'member_nominations' => 'Add entries to list of nominated members',
'nominations.cgi' => "Member's nominations cross-check - ensuring
nominations get on the ballot, etc.",
'board-nominations.cgi' => "Board nominations cross-check - ensuring
nominations get on the ballot, etc.",
+ 'board-nominate.cgi' => "Add entries to board nomination file",
'attendance-xcheck.cgi' => "Member's Meeting Attendance cross-check - who
attended when",
'non-participants.cgi' => "Active Members not participating in recent
meetings (to send a poll to)",
'inactive.cgi' => "Poll of Inactive Members - tool to query
non-participating members why",
diff --git a/www/members/nominations.cgi b/www/members/nominations.cgi
index e85628ae..d119a8bb 100755
--- a/www/members/nominations.cgi
+++ b/www/members/nominations.cgi
@@ -90,8 +90,9 @@ _html do
related: {
'/members/memberless-pmcs' => 'PMCs with no/few ASF Members',
'/members/watch' => 'Watch list for potential Member candidates',
- '/members/member_nominations' => 'Update list of nominated members',
+ '/members/member_nominations' => 'Add entries to list of nominated
members',
'board-nominations' => 'Board nominations cross-check',
+ 'board-nominate.cgi' => "Add entries to board nomination file",
ASF::SVN.svnpath!('Meetings') => 'Official Meeting Agenda Directory'
},
helpblock: -> {
diff --git a/www/members/watch.cgi b/www/members/watch.cgi
index b0334169..606dea31 100755
--- a/www/members/watch.cgi
+++ b/www/members/watch.cgi
@@ -20,7 +20,7 @@ _html do
title: PAGETITLE,
related: {
'/members/memberless-pmcs' => 'PMCs with no/few ASF Members',
- '/members/member_nominations' => 'Update list of nominated members',
+ '/members/member_nominations' => 'Add entries to list of nominated
members',
'/members/nominations' => 'Members Meeting Nomination Crosscheck',
ASF::SVN.svnpath!('Meetings') => 'Official Meeting Agenda Directory'
},