You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@whimsical.apache.org by se...@apache.org on 2020/06/10 14:21:21 UTC
[whimsy] branch master updated: Now handled by
https://selfserve.apache.org/mail.html
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 687cd78 Now handled by https://selfserve.apache.org/mail.html
687cd78 is described below
commit 687cd7816ee24b23623c21a52506fd72bc47fd0f
Author: Sebb <se...@apache.org>
AuthorDate: Wed Jun 10 15:21:11 2020 +0100
Now handled by https://selfserve.apache.org/mail.html
---
www/officers/mlreq.cgi | 527 -------------------------------------------------
1 file changed, 527 deletions(-)
diff --git a/www/officers/mlreq.cgi b/www/officers/mlreq.cgi
deleted file mode 100755
index 7f9c3ac..0000000
--- a/www/officers/mlreq.cgi
+++ /dev/null
@@ -1,527 +0,0 @@
-#!/usr/bin/env ruby
-PAGETITLE = "Apache Mailing list Request Form" # Wvisible:infra mail list
-$LOAD_PATH.unshift '/srv/whimsy/lib'
-require 'wunderbar'
-require 'shellwords'
-require 'mail'
-require 'whimsy/asf'
-require 'whimsy/asf/rack'
-require 'whimsy/asf/podlings'
-require 'tmpdir'
-require 'fileutils'
-
-# This is a version number check embedded in the json files.
-#
-# The script started generating format numbers on 2012-08-28 but had been
-# in production for some number before that.
-FORMAT_NUMBER = 4
-
-user = ASF::Auth.decode(env = {})
-
-AUTHORIZED = (user.asf_member? or ASF.pmc_chairs.include?(user))
-if !AUTHORIZED && env['REQUEST_METHOD'].to_s != 'GET'
- print "Status: 401 Unauthorized\r\n"
- print "WWW-Authenticate: Basic realm=\"ASF Members and Officers\"\r\n\r\n"
- exit
-end
-
-lists = ASF::Mail.lists
-pmcs = ASF::Committee.pmcs.map(&:mail_list)
-pmcs.delete_if {|pmc| not lists.include? "#{pmc}-private"}
-
-# INFRA-11555
-# The validation done by this script must agree with the validation done by
-# the script that processes the json files:
-# https://svn.apache.org/repos/infra/infrastructure/trunk/mlreq/queuerun.py
-
-MLID_PAT = '^[a-z0-9]+(-[a-z0-9]+)?$'
-# TLPs may include '-' in name e.g. empire-db
-# TODO tighten RE to match only a single non-leading '-'
-PROJ_PAT = '^[a-z][-a-z0-9]+$'
-# Podlings cannot include '-' (don't want any more hyphenated names)
-POD_PAT = '^[a-z][a-z0-9]+$'
-
-_html do
-
- incubator = (ENV['PATH_INFO'].to_s.include? 'incubator')
-
- _head_ do
- if incubator
- _title 'ASF Incubator Mailing List Request'
- else
- _title 'ASF Mailing List Request'
- end
- _script src: '/jquery-min.js'
- _style %{
- textarea, .mod, label {display: block}
- input[type=submit] {display: block; margin-top: 1em}
- input[name=podling], input[type=checkbox], input[type=radio], p, .mod, textarea {margin-left: 2em}
- .subdomain, .domain {color: #000}
- legend {background: #141; color: #DFD; padding: 0.4em}
- .name {width: 6em}
- ._stdin {color: #C000C0; margin-top: 1em}
- ._stdout {color: #000}
- .error, ._stderr {color: #F00}
- .request {background-color: #BDF}
- }
- end
-
- _body? do
- if _.post?
- tmpdir = Dir.mktmpdir
- at_exit { FileUtils.remove_entry tmpdir }
-
- _.system [
- 'svn', 'checkout', '--no-auth-cache', '--non-interactive',
- (['--username', env.user, '--password', env.password] if env.password),
- 'https://svn.apache.org/repos/infra/infrastructure/trunk/mlreq/input',
- tmpdir + '/mlreq'
- ]
-
- Dir.chdir tmpdir + '/mlreq'
-
- # extract moderators from input fields or text area
- mods = params.select {|name,value| name =~ /^mod\d+$/ and value != ['']}.
- values.flatten.join(',')
- mods = @mods.strip.gsub(/\s+/,',') if @mods
-
- # build a queue of requests
- queue = []
-
- unless incubator
- queue << {
- version: FORMAT_NUMBER,
- type: 'toplevel',
- private: (@private == 'true' || @localpart == 'private' || @localpart == 'security'),
- subdomain: @subdomain,
- localpart: @localpart,
- domain: @domain || 'apache.org',
- moderators: mods,
- muopts: @muopts,
- replytolist: (@replyto == "true"),
- notifyee: "private@#{@subdomain}.apache.org"
- }
- else # incubator request
- params.keys.grep(/^suffix\d+/).each do |name|
- suffix = params[name].first
- next if suffix.empty?
- queue << {
- version: FORMAT_NUMBER,
- type: 'podling',
- private: (params[name.sub('suffix','private')].first == 'true' || suffix == 'private' || suffix == 'security'),
- subdomain: @podling,
- outhost: "#{@podling}.incubator.apache.org",
- localpart: suffix,
- domain: @domain || 'apache.org',
- moderators: mods,
- muopts: @muopts,
- replytolist: (@replyto == "true"),
- notifyee: "private@incubator.apache.org"
- }
- end
- end
-
- # build a list of validation errors
- errors = []
-
- # TODO this list ought to be synchronized with the patterns applied to the HTML fields
- checks = {
- localpart: Regexp.new(MLID_PAT),
- subdomain: Regexp.new(PROJ_PAT),
- domain: /^apache[.]org$/,
- muopts: /^(mu|Mu|mU)$/,
- notifyee: /^\w+[@]\w+[.]apache[.]org$/
- }
-
- queue.each do |vars|
- checks.each do |name, pattern|
- if pattern and vars[name] !~ pattern
- errors << "Invalid #{name}: #{vars[name].inspect}"
- end
- end
-
- vars[:moderators].split(',').each do |email|
- begin
- if email != Mail::Address.new(email).address
- errors << "Invalid email: #{email.inspect}"
- end
- if email =~ /@apache\.org$/ and not ASF::Person.find_by_email(email)
- errors << "Account does not exist: #{email.inspect}"
- end
- rescue
- errors << "Invalid email: #{email.inspect}"
- end
- end
-
- unless incubator or pmcs.include? vars[:subdomain]
- errors << "Invalid PMC: #{vars[:subdomain]}"
- end
-
- mlreq = "#{vars[:subdomain]}-#{vars[:localpart]}".gsub(/[^-\w]/,'_')
- if File.exist? "#{mlreq.untaint}.json"
- errors << "Already submitted: " +
- "#{vars[:localpart]}@#{vars[:subdomain]}.#{vars[:domain]}"
- end
- end
-
- # output requests or errors
- tocommit = []
- if errors.empty?
- _h2_ "Submitted request(s)"
- queue.each do |vars|
- mlreq = "#{vars[:subdomain]}-#{vars[:localpart]}".
- gsub(/[^-\w]/,'_')
- vars[:message] = @message unless @message.empty?
- request = JSON.pretty_generate(vars) + "\n"
- _pre.request request
- vars[:mlreq] = "#{mlreq.untaint}.json"
- File.open(vars[:mlreq],'w') { |file| file.write request }
- _.system(['svn', 'add', '--', vars[:mlreq]])
- tocommit << vars[:mlreq]
- end
-
- if incubator
- # Use '+' so it sorts first.
- mlreq = "#{queue.first[:subdomain]}".gsub(/[^-\w]/,'_')
- mlreq = "#{mlreq.untaint}+.json"
- File.open(mlreq, 'w') { |file|
- file.write JSON.pretty_generate({
- version: FORMAT_NUMBER,
- type: 'dirs',
- subdomain: queue.first[:subdomain],
- }) + "\n"
- }
- _.system(['svn', 'add', '--', mlreq])
- tocommit << mlreq
- end
-
- if queue.length == 1
- vars = queue.first
- request = "#{vars[:localpart]}@#{vars[:subdomain]}.apache.org"
- else
- request = "#{@podling}-* (podling)"
- end
-
- _.system [
- 'svn', 'commit', '--no-auth-cache', '--non-interactive',
- '-m', "#{request} mailing list request by #{env.user} via " +
- ENV['SERVER_NAME'],
- (['--username', env.user, '--password', env.password] if env.password),
- '--', *tocommit
- ]
- _p do
- _strong "Next steps:"
- _ "We will create the lists and email"
- _ Hash[queue.map { |vars| [vars[:notifyee],1] }].
- keys.sort.join(', ')
- _ "once we have done that."
- _{"There is <em>no need</em> to file a JIRA."}
- end
- else
- _h2_.error 'Form not submitted due to errors'
- _ul do
- errors.each { |error| _li error }
- end
- end
- end
-
- unless _.post?
- _p do
- if incubator
- _ "Looking to create a non-Incubator mailing list? Try"
- _a "ASF Mailing List Request", href: '../mlreq'
- _ 'instead.'
- else
- _ "Looking to create a Incubator mailing list? Try"
- _a "ASF Incubator Mailing List Request", href: 'mlreq/incubator'
- _ 'instead.'
- end
- end
- end
-
- _form method: 'post' do
- _fieldset do
- if incubator
- _legend 'ASF Incubator Mailing List Request'
-
- _h3_ 'Podling name'
- _input.name name: 'podling', required: true, pattern: POD_PAT,
- placeholder: 'name'
-
- _h3_ 'List name'
- _div.list do
- _input type: 'checkbox', name: 'private1', value: 'true'
- _input.name.list name: 'suffix1', required: true,
- placeholder: 'list', pattern: MLID_PAT
- _ '@'
- _input.name.podling disabled: true, placeholder: '<podling>'
- _ '.'
- _input.name.subdomain value: 'incubator', disabled: true
- _ '.'
- _input.name.domain value: 'apache.org', disabled: true
- end
- _p "Check box next to lists which are to have private archives."
- else
- _legend 'ASF Mailing List Request'
-
- _h3_ 'List name'
- _input type: 'checkbox', name: 'private', value: 'true'
- _input.name name: 'localpart', required: true, pattern: MLID_PAT,
- placeholder: 'name'
- _ '@'
- _select name: 'subdomain' do
- pmcs.sort.each do |pmc|
- _option pmc unless pmc == 'incubator'
- end
- end
- _ '.'
- _input.name.domain value: 'apache.org', disabled: true
- _p "Check box if list archives are to be private."
- end
- _p do
- _ "Lists named "
- _code 'private'
- _ "or"
- _code 'security'
- _ "will always have private archives,"
- _ "whether or not the box is checked."
- end
-
- _h3_ 'Replies'
- _label do
- _input type: 'checkbox', name: 'replyto', value: 'true', checked: true
- _ 'Set Reply-To list header?'
- end
- _p! do
- _ "If checked, replies will go to the same list. "
- _ "Except for lists named "
- _code 'commits'
- _ ", which will direct replies to the corresponding "
- _code 'dev'
- _ " list."
- end
-
- _h3_ 'Moderation'
- _label do
- _input type: "radio", name: "muopts", value: "mu", required: true,
- checked: true
- _ 'allow subscribers to post, moderate all others'
- end
- _label do
- _input type: "radio", name: "muopts", value: "Mu"
- _ 'allow subscribers to post, reject all others'
- end
- _label do
- _input type: "radio", name: "muopts", value: "mU"
- _ 'moderate all posts'
- end
- _p do
- _ "Lists named"
- _code 'private'
- _ "always permit posts by non-subscribers."
- end
-
- _h3_ 'Moderators\' addresses'
- _textarea.mods! name: 'mods'
-
- _h3_ 'Notes'
- _textarea name: 'message', cols: 70
-
- if AUTHORIZED
- _input type: 'submit', value: 'Submit Request'
- else
- _input type: 'submit', value: 'Only ASF Members and Officers may submit mailing list requests', disabled: true
- end
- end
- end
-
- _script_ %{
- // replace moderator textarea with two input fields
- $('#mods').replaceWith('<input type="email" required="required" ' +
- 'class="mod" name="mod0" placeholder="email"/>')
- $('.mod:last').after('<input type="email" required="required" ' +
- 'class="mod" name="mod1" placeholder="email"/>')
-
- // initially disable suffix and private (until podling is entered)
- $('input[name=suffix1]').attr('disabled', true);
- $('input[name=private1]').attr('disabled', true);
-
- // process keystrokes for moderator input fields
- var mkeyup = function() {
- // when there are no more empty moderator fields, add one more
- if (!$('.mod').filter(function() {return $(this).val()==''}).length) {
- var input = $('<input type="email" class="mod" value=""/>');
- input.attr('name', 'mod' + $('.mod').length);
- input.bind('input', mkeyup);
- lastmod.after(input);
- lastmod = input;
- }
-
- // split on commas and spaces
- var comma = $(this).val().search(/[, ]/);
- if (comma != -1) {
- lastmod.val($(this).val().substr(comma+1)).focus().trigger('input');
- $(this).val($(this).val().substr(0,comma));
- } else if ($(this).val() == '' && this != lastmod[0]) {
- if (!$(this).attr('required')) $(this).remove();
- }
- }
-
- // process keystrokes for podling input fields
- var pkeyup = function() {
- if ($(this).val() != '') {
- $('input[type=checkbox]', $(this).parent()).removeAttr('disabled');
- var div = $(this).parent().clone();
- var input = $('input:not(:disabled)', div);
- input.attr('name', 'suffix' + ($('div.list').length+1)).val('').
- attr('required', false).bind('input', pkeyup);
- $('input[type=checkbox]', div).attr('disabled', true).
- prop('checked', false).
- attr('name', 'private' + ($('div.list').length+1));
- lastpod.unbind().bind('input', function() {
- if ($(this).val() == 'private' || $(this).val() == 'security') {
- $('input[type=checkbox]', $(this).parent()).prop('checked', true);
- }
- });
- lastpod.parent().after(div);
- lastpod = input;
- }
- }
-
- // initial bind of keystroke handlers
- var lastmod = $('.mod:last');
- var lastpod = $('div.list:last input[required]');
- $('.mod').bind('input', mkeyup);
- lastpod.bind('input', pkeyup);
-
- // whenever podling is set, copy values and enable suffix
- $('input[name=podling]').bind('input', function() {
- if ($(this).val() != '') {
- $('input.podling').val($(this).val()).css('color', '#000');
- $('input[name=suffix1]').removeAttr('disabled');
- }
- }).trigger('keyup');
-
- var message = $('<h2>Validating form fields</h2>');
- message.hide();
- $('p:last').after(message);
- validated = false;
-
- // prevalidate the form before actual submission
- $('form').submit(function() {
- message.show();
- if (!validated) {
- $.post('', $('form').serialize(), function(_) {
- var resubmit = false;
-
- // perform the server indicated actions
- if (_.ok) {
- validated = resubmit = true;
- } else if (_.confirm) {
- if (confirm(_.confirm)) {
- resubmit = true;
- } else {
- _.validated = {}
- }
- } else {
- alert(_.alert || _.exception || 'Server error');
- }
-
- // mark confirmed and checked fields as validated
- for (var name in _.validated) {
- if (!$('input[name='+name+']').length) {
- $('form').append('<input type="hidden" name="'+name+'"/>');
- }
- $('input[name='+name+']').val(_.validated[name]);
- }
-
- // complete the action, hide the message, and optionall resubmit
- if (_.focus) $(_.focus).focus();
- message.hide();
- if (resubmit) $('form').submit();
- }, 'json');
- return false;
- };
- });
- }
- end
-end
-
-_json do
- validated = {}
- _validated validated
-
- # confirm if podling is new (has no existing lists)
- if @podling != @confirmed_podling
- validated['confirmed_podling'] = @podling
- if not lists.any? {|list| list.sub(/^incubator-/, '').start_with? "#{@podling}-"}
-
- # extract the names of podlings (and aliases) from podlings.xml
- require 'nokogiri'
- incubator_content = ASF::SVN['incubator-content']
- current = Nokogiri::XML(File.read(File.join(incubator_content, 'podlings.xml'))).
- search('podling[status=current]')
- podlings = current.map {|podling| podling['resource']}
- podlings += current.map {|podling| podling['resourceAliases']}.compact.
- map {|names| names.split(/[, ]+/)}.flatten
-
- if not podlings.include? @podling
- _confirm "Podling #{@podling} not found. Continue?"
- next _focus 'input[name=podling]'
- end
- end
- end
-
- # confirm if pmc is unknown
- if @subdomain != @confirmed_localpart
- validated['confirmed_localpart'] = @subdomain
- if not pmcs.include? @subdomain
- _confirm "PMC #{@subdomain} not found. Continue?"
- next _focus 'input[name=subdomain]'
- end
- end
-
- # alert if incubator list requested already exists
- params.keys.grep(/^suffix\d+$/).each do |param|
- next if params[param].first.empty?
- localpart = "#{@podling}-#{params[param].first}"
- if lists.any? {|list| list == "incubator-#{localpart}"}
- _alert "List #{localpart}@incubator.apache.org already exists."
- _focus "input[name=#{param}]"
- break
- end
- if lists.any? {|list| list == localpart}
- _alert "List #{localpart}.apache.org already exists."
- _focus "input[name=#{param}]"
- break
- end
- end
-
- # alert if non-incubator list requested already exists
- if @localpart
- if lists.any? {|list| list == "#{@subdomain}-#{@localpart}"}
- _alert "List #{@localpart}@#{@subdomain}.apache.org already exists."
- _focus "input[name=localpart]"
- end
- end
-
- next if _['alert']
-
- # confirm if moderator email is unknown
- params.keys.grep(/^mod\d+$/).each do |param|
- email = params[param].first
- next if email.empty?
- next if params.any? do |key,value|
- key =~ /^confirmed_mod/ && value.first == email
- end
-
- validated["confirmed_#{param}"] = email
- if not ASF::Person.find_by_email(email)
- _confirm "Unknown E-mail #{email}. Proceed with a non-committer moderator?"
- _focus "input[name=#{param}]"
- break
- end
- end
-
- _ok 'OK' if not _['confirm']
-end