blob: 80bae8b20b6497336477f5724cc0ca411df06222 [file] [log] [blame]
#!/usr/bin/env ruby
PAGETITLE = "Conflict of Interest Affirmations" # Wvisible:board,officers
$LOAD_PATH.unshift '/srv/whimsy/lib'
require 'wunderbar'
require 'wunderbar/bootstrap'
require 'whimsy/asf'
require 'mail'
require 'date'
require 'tmpdir'
coi_url = ASF::SVN.svnurl('conflict-of-interest')
COI_CURRENT_TEMPLATE_URL = File.join(coi_url, 'template.txt').untaint
YEAR = DateTime.now.strftime "%Y"
COI_CURRENT_URL = File.join(coi_url, YEAR).untaint
user = ASF::Person.find($USER)
USERID = user.id
USERNAME = user.cn.untaint
USERMAIL = "#{USERID}@apache.org".untaint
IDS = Hash.new {|h,k| h[k]=Array.new}
committees = ASF::Committee.officers + ASF::Committee.nonpmcs
chairs = committees.map do |committee|
committee.chairs.each do |chair|
IDS[chair[:id]] << committee.display_name
end
end
ASF::Service['board'].members.each do |member|
IDS[member.id] << 'Board member'
end
# Get the list of files in this year's directory
signerfileslist, err = ASF::SVN.svn('list', COI_CURRENT_URL, {user: $USER.dup.untaint, password: $PASSWORD.dup.untaint})
# Currently the documents directory has limited access.
# This includes ASF members, but does not include officers who are not members
# Let others down gently
unless signerfileslist
Wunderbar.warn err
print "Status: 404 Not found\r\n\r\n" # TODO better status
print "Sorry, cannot access COI documents\r\n"
exit
end
signerfiles = signerfileslist.split("\n")
# Create the hash of {signer: signerurl} and remember user's affirmation file
SIGNERS = Hash.new
user_affirmation_file = nil
signerfiles.each do |signerfile|
stem = File.basename(signerfile, ".*")
user_affirmation_file = signerfile if stem == USERID
SIGNERS[stem] = signerfile unless stem == 'template'
end
USER_AFFIRMATION_FILE = user_affirmation_file
# Determine if user should sign the affirmation form
user_is_required = IDS.include? USERID
not_required_message = user_is_required ?' required':' not required'
user_affirmation = SIGNERS.include? USERID
have_affirmed_message = user_affirmation ? ' have affirmed' : ' have not affirmed'
USER_IS_REQUIRED_BUT_NOT_AFFIRMED = (user_is_required and not user_affirmation)
current_timestamp = DateTime.now.strftime "%Y-%m-%d %H:%M:%S"
PANEL_MESSAGE = USER_IS_REQUIRED_BUT_NOT_AFFIRMED ?
'Sign Your Conflict of Interest Affirmation':
'Thank you for signing the Conflict of Interest Affirmation'
# Read the template and append the signature block
def get_affirmed_template(name, timestamp)
signature_block =
' I, the undersigned, acknowledge that I have received,
read and understood the Conflict of Interest policy;
I agree to comply with the policy;
I understand that ASF is charitable and in order to maintain
its federal tax exemption it must engage primarily in activities
which accomplish one or more of its tax-exempt purposes.
Signed: __
Date: __
Metadata: _______________Whimsy www/officers/coi.cgi________________'
template, err =
ASF::SVN.svn('cat', COI_CURRENT_TEMPLATE_URL, {user: $USER.dup.untaint, password: $PASSWORD.dup.untaint})
raise RuntimeError.new("Failed to read current template.txt -- %s" % err) unless template
centered_name = "#{name}".center(60, '_')
centered_date ="#{timestamp}".center(62, '_')
filled_signature_block = signature_block
.gsub('Signed: __', ('Signed: ' + centered_name))
.gsub('Date: __' , ( 'Date: ' + centered_date))
template + filled_signature_block
end
affirmers = IDS.map{|id, role| [ASF::Person.find(id), role]}
.sort_by{|affirmer, role| affirmer.public_name.split(' ').rotate(-1)}
_html do
_body? do
_whimsy_body(
title: PAGETITLE,
related: {
'http://www.apache.org/foundation/records/minutes/2020/board_minutes_2020_03_18.txt' =>
'Conflict of Interest Resolution Board minutes',
COI_CURRENT_TEMPLATE_URL => 'Conflict of Interest Resolution (March 2020)',
'http://www.apache.org/foundation/#who-runs-the-asf' =>
'BOARD MEMBERS and OFFICERS are required to sign',
COI_CURRENT_URL => "#{YEAR} affirmations",
},
helpblock: -> {
_p do
_ 'This page allows Board Members and Officers to sign their Conflict of Interest annual affirmation.'
end
if _.get?
_p 'The following are currently required to affirm the Conflict of Interest:'
_table.table.table_striped do
_thead do
_tr do
_th 'Name'
_th 'AvailId'
_th 'Role(s)'
_th 'Link to affirmation(s)'
end
end
_tbody do
affirmers.each do |affirmer, role|
_tr do
_td affirmer.cn
_td do
_a affirmer.id, href: "/roster/committer/#{affirmer.id}"
end
_td role.join(', ')
_td do
signerfile = SIGNERS[affirmer.id]
if signerfile
_a affirmer.id, href: "#{COI_CURRENT_URL}/#{signerfile}"
else
_ "Not signed in #{YEAR}"
end
end
end
end
end
end
_p
_p "You are signed in as #{USERNAME} (#{USERID}) at #{current_timestamp}."
_p {_ "You are ";_b "#{not_required_message}";_ " to affirm the Conflict of Interest policy for this year."}
_p {_ "You ";_b "#{have_affirmed_message}";_ "the Conflict of Interest policy for this year."}
if USER_AFFIRMATION_FILE
_a "Your Conflict of Interest affirmation",
href: "#{COI_CURRENT_URL}/#{USER_AFFIRMATION_FILE}"
end
if USER_IS_REQUIRED_BUT_NOT_AFFIRMED
_p {_b "You are invited to sign the affirmation below"}
end
end
}
) do
if _.get?
if USER_IS_REQUIRED_BUT_NOT_AFFIRMED
_whimsy_panel(PANEL_MESSAGE, style: 'panel-success') do
affirmed = get_affirmed_template(USERNAME, current_timestamp)
_pre affirmed
_form.form_horizontal method: 'post' do
_div.form_group do
_div.col_sm_offset_1.col_sm_10 do
_input.btn.btn_default type: 'submit',
value: 'Sign your Conflict of Interest Affirmation'
end
end
end
end
end
else # POST
_whimsy_panel('Sign Conflict of Interest Affirmation - Session Transcript',
style: 'panel-success') do
_div.transcript do
emit_post(_)
end
end
end
end
end
end
# Emit a record of a user's submission - POST
def emit_post(_)
# The only information in the POST is $USER and $PASSWORD
current_timestamp = DateTime.now.strftime "%Y-%m-%d %H:%M:%S"
affirmed = get_affirmed_template(USERNAME, current_timestamp)
user_filename = "#{USERID}.txt".untaint
# report on commit
_div.transcript do
Dir.mktmpdir do |tmpdir|
ASF::SVN.svn_!('checkout',[COI_CURRENT_URL, tmpdir.untaint], _,
{quiet: true, user: $USER.dup.untaint, password: $PASSWORD.dup.untaint})
Dir.chdir(tmpdir) do
# write affirmation form
File.write(user_filename, affirmed)
ASF::SVN.svn_!('add', user_filename, _)
ASF::SVN.svn_!('propset', ['svn:mime-type', 'text/plain; charset=utf-8', user_filename], _)
# commit
ASF::SVN.svn_!('commit',[user_filename], _,
{msg: "Affirm Conflict of Interest Policy for #{USERNAME}",
user: $USER.dup.untaint, password: $PASSWORD.dup.untaint})
end
end
# Send email to $USER, secretary@
ASF::Mail.configure
mail = Mail.new do
to "#{USERNAME}<#{USERMAIL}>"
cc "secretary@apache.org"
from "#{USERMAIL}"
subject "Conflict of Interest affirmation from #{USERNAME}"
text_part do
body "
This year's Conflict of Interest affirmation is attached.
It has been checked into the foundation repository at
#{COI_CURRENT_URL}/#{user_filename}.\n
Regards,\n
#{USERNAME}\n\n"
end
end
mail.attachments["#{USERID}.txt"] = affirmed
mail.deliver!
end
# Report on contents now that they're checked in
_h3! do
_span "You can review "
_a "Your Conflict of Interest affirmation",
href: "#{COI_CURRENT_URL}/#{$USER}.txt"
_span " as now checked in to svn."
_p {_ "Reload ";_a "this page",href: "coi.cgi";_span " to see the results."}
end
end