You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@whimsical.apache.org by Sam Ruby <ru...@apache.org> on 2015/12/04 20:20:18 UTC
[whimsy.git] [33/50] Commit ddfb3cc: V3 of the mlreq interface
Commit ddfb3cc46a4863368a57e76632ae6919cf5684f7:
V3 of the mlreq interface
git-svn-id: https://svn.apache.org/repos/infra/infrastructure/trunk/projects/whimsy@820289 90ea9780-b833-de11-8433-001ec94261de
Branch: refs/heads/master
Author: Sam Ruby <ru...@apache.org>
Committer: Sam Ruby <ru...@apache.org>
Pusher: rubys <ru...@apache.org>
------------------------------------------------------------
www/incubator/asfmlreq.cgi | -------------
www/incubator/incmlreq.cgi | ---------
www/officers/mlreq.cgi | ++++++++++
------------------------------------------------------------
544 changes: 308 additions, 236 deletions.
------------------------------------------------------------
diff --git a/www/incubator/asfmlreq.cgi b/www/incubator/asfmlreq.cgi
deleted file mode 100755
index 08c0b5f..0000000
--- a/www/incubator/asfmlreq.cgi
+++ /dev/null
@@ -1,102 +0,0 @@
-#!/usr/bin/ruby1.9.1
-require 'wunderbar'
-require 'shellwords'
-
-_html do
- _head_ do
- _title 'ASF Mailing List Request'
- _script src: '/jquery-min.js'
- _style %{
- textarea, .mod, label {display: block}
- input[type=submit] {display: block; margin-top: 1em}
- legend {background: #141; color: #DFD; padding: 0.4em}
- .name {width: 6em}
- }
- end
-
- _body? do
- _form method: 'post' do
- _fieldset do
- _legend 'ASF Mailing List Request'
-
- _h3_ 'List name'
- _input.name name: 'subdomain', required: true, pattern: '^\w+$',
- placeholder: 'name'
- _ '@'
- _input.name name: 'localpart', required: true, pattern: '^\w+$',
- placeholder: 'pmc'
- _ '.'
- _input.name name: 'domain', value: 'apache.org', readonly: true
-
- _h3_ 'Replies'
- _label title: 'if set, will replies will go to the same list. ' +
- 'Except for commits, which will direct replies to the dev list.' do
- _input type: 'checkbox', name: 'replyto', value: 'true'
- _ 'Set Reply-To list header?'
- end
-
- _h3_ 'Moderation'
- _label do
- _input type: "radio", name: "muopts", value: "mu", required: 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
-
- _h3_ 'Moderators'
- _textarea name: 'mods'
-
- _input type: 'submit', value: 'Submit Request'
- end
- end
-
- if _.post?
- mods = params.select {|name,value| name =~ /^mod\d+$/ and value != ['']}.
- values.flatten.join(',')
- mods = @mods.gsub(/\s+/,',') if @mods
-
- vars = {
- subdomain: @subdomain,
- localpart: @localpart,
- domain: @domain,
- moderators: mods,
- muopts: @muopts,
- replytolist: @replyto || "false",
- notifyee: "#{$USER}@apache.org"
- }
-
- _h2 'What would be submitted'
- _pre vars.map {|name,value| "#{name}=#{Shellwords.shellescape value}"}.
- join("\n")
- else
- _p do
- _ "Looking to create a Incubator mailing list? Try"
- _a "ASF Incubator Mailing List Request", href: 'incmlreq'
- _ 'instead.'
- end
- end
-
- _script_ %{
- $('textarea').replaceWith('<input type="email" required="required" ' +
- 'class="mod" name="mod0" placeholder="email"/>')
-
- var fkeyup = function() {
- if ($(this).val() != '') {
- var input = $('<input type="email" class="mod" val=""/>');
- input.attr('name', 'mod' + $('.mod').length);
- input.bind('keyup paste', fkeyup);
- lastmod.after(input).unbind();
- lastmod = input;
- }
- }
- var lastmod = $('.mod:last');
- $('.mod').bind('keyup paste', fkeyup);
- }
- end
-end
diff --git a/www/incubator/incmlreq.cgi b/www/incubator/incmlreq.cgi
deleted file mode 100755
index e4cc783..0000000
--- a/www/incubator/incmlreq.cgi
+++ /dev/null
@@ -1,134 +0,0 @@
-#!/usr/bin/ruby1.9.1
-require 'wunderbar'
-require 'shellwords'
-
-_html do
- _head_ do
- _title 'ASF Incubator Mailing List Request'
- _script src: '/jquery-min.js'
- _style %{
- textarea, .mod, label {display: block}
- input[type=submit] {display: block; margin-top: 1em}
- legend {background: #141; color: #DFD; padding: 0.4em}
- .name {width: 6em}
- input:disabled {color: #000}
- }
- end
-
- _body? do
- _form method: 'post' do
- _fieldset do
- _legend 'ASF Incubator Mailing List Request'
-
- _h3_ 'Podling name'
- _input.name name: 'podling', required: true, pattern: '^\w+$',
- placeholder: 'name'
-
- _h3_ 'List name'
- _div.list do
- _input.name.podling disabled: true, value: '<podling>',
- placeholder: 'podling'
- _ '-'
- _input.name name: 'suffix1', required: true, placeholder: 'list',
- pattern: '^\w+(-\w+)?$'
- _ '@'
- _input.name.localpart disabled: true, value: 'incubator'
- _ '.'
- _input.name name: 'domain', value: 'apache.org', disabled: true
- end
-
- _h3_ 'Replies'
- _label title: 'if set, will replies will go to the same list. ' +
- 'Except for commits, which will direct replies to the dev list.' do
- _input type: 'checkbox', name: 'replyto', value: 'true'
- _ 'Set Reply-To list header?'
- end
-
- _h3_ 'Moderation'
- _label do
- _input type: "radio", name: "muopts", value: "mu", required: 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
-
- _h3_ 'Moderators'
- _textarea name: 'mods'
-
- _input type: 'submit', value: 'Submit Request'
- end
- end
-
- if _.post?
- mods = params.select {|name,value| name =~ /^mod\d+$/ and value != ['']}.
- values.flatten.join(',')
- mods = @mods.gsub(/\s+/,',') if @mods
-
- _h2 'What would be submitted'
- params.keys.grep(/^suffix\d+/).each do |suffix|
- suffix = params[suffix].first
- next if suffix.empty?
- vars = {
- subdomain: "#{@podling}-#{suffix}",
- localpart: 'incubator',
- domain: 'apache.org',
- moderators: mods,
- muopts: @muopts,
- replytolist: @replyto || "false",
- notifyee: "#{$USER}@apache.org"
- }
-
- _pre vars.map {|name,value| "#{name}=#{Shellwords.shellescape value}"}.
- join("\n")
- end
- else
- _p do
- _ "Looking to create a non-Incubator mailing list? Try"
- _a "ASF Mailing List Request", href: 'asfmlreq'
- _ 'instead.'
- end
- end
-
- _script_ %{
- $('textarea').replaceWith('<input type="email" required="required" ' +
- 'class="mod" name="mod0" placeholder="email"/>')
-
- var mkeyup = function() {
- if ($(this).val() != '') {
- var input = $('<input type="email" class="mod" val=""/>');
- input.attr('name', 'mod' + $('.mod').length);
- input.bind('keyup paste', mkeyup);
- lastmod.after(input).unbind();
- lastmod = input;
- }
- }
-
- var pkeyup = function() {
- if ($(this).val() != '') {
- var div = $(this).parent().clone();
- var input = $('input:not(:disabled)', div);
- input.attr('name', 'suffix' + ($('.list').length+1)).val('').
- attr('required', false).bind('keyup paste', pkeyup);
- lastpod.unbind().parent().after(div);
- lastpod = input;
- }
- }
-
- var lastmod = $('.mod:last');
- var lastpod = $('.list:last input[required]');
- lastmod.bind('keyup paste', mkeyup);
- lastpod.bind('keyup paste', pkeyup);
-
- $('.podling').val($('input[name=podling]').val());
- $('input[name=podling]').bind('keyup paste', function() {
- $('input.podling').val($(this).val());
- });
- }
- end
-end
diff --git a/www/officers/mlreq.cgi b/www/officers/mlreq.cgi
new file mode 100755
index 0000000..cd03992
--- /dev/null
+++ b/www/officers/mlreq.cgi
@@ -0,0 +1,308 @@
+#!/usr/bin/ruby1.9.1
+require 'wunderbar'
+require 'shellwords'
+require '/var/tools/asf'
+
+_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}
+ legend {background: #141; color: #DFD; padding: 0.4em}
+ .name {width: 6em}
+ }
+ end
+
+ _body? do
+ _form method: 'post' do
+ _fieldset do
+ if incubator
+ _legend 'ASF Incubator Mailing List Request'
+
+ _h3_ 'Podling name'
+ _input.name name: 'podling', required: true, pattern: '^\w+$',
+ placeholder: 'name'
+
+ _h3_ 'List name'
+ _div.list do
+ _input.name.podling disabled: true, value: '<podling>',
+ placeholder: 'podling'
+ _ '-'
+ _input.name.list name: 'suffix1', required: true,
+ placeholder: 'list', pattern: '^\w+(-\w+)?$'
+ _ '@'
+ _input.name.localpart disabled: true, value: 'incubator'
+ _ '.'
+ _input.name name: 'domain', value: 'apache.org', disabled: true
+ end
+ else
+ _legend 'ASF Mailing List Request'
+
+ _h3_ 'List name'
+ _input.name name: 'subdomain', required: true, pattern: '^\w+$',
+ placeholder: 'name'
+ _ '@'
+ _input.name name: 'localpart', required: true, pattern: '^\w+$',
+ placeholder: 'pmc'
+ _ '.'
+ _input.name name: 'domain', value: 'apache.org', disabled: true
+ end
+
+ _h3_ 'Replies'
+ _label title: 'if set, will replies will go to the same list. ' +
+ 'Except for commits, which will direct replies to the dev list.' do
+ _input type: 'checkbox', name: 'replyto', value: 'true'
+ _ 'Set Reply-To list header?'
+ end
+
+ _h3_ 'Moderation'
+ _label do
+ _input type: "radio", name: "muopts", value: "mu", required: 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
+
+ _h3_ 'Moderators'
+ _textarea name: 'mods'
+
+ _input type: 'submit', value: 'Submit Request'
+ end
+ end
+
+ if _.post?
+ # extract moderators from input fields or text area
+ mods = params.select {|name,value| name =~ /^mod\d+$/ and value != ['']}.
+ values.flatten.join(',')
+ mods = @mods.gsub(/\s+/,',') if @mods
+
+ queue = []
+
+ if @subdomain
+ queue << {
+ subdomain: @subdomain,
+ localpart: @localpart,
+ domain: @domain || 'apache.org',
+ moderators: mods,
+ muopts: @muopts,
+ replytolist: @replyto || "false",
+ notifyee: "#{$USER}@apache.org"
+ }
+ else
+ params.keys.grep(/^suffix\d+/).each do |suffix|
+ suffix = params[suffix].first
+ next if suffix.empty?
+ queue << {
+ subdomain: "#{@podling}-#{suffix}",
+ localpart: 'incubator',
+ domain: @domain || 'apache.org',
+ moderators: mods,
+ muopts: @muopts,
+ replytolist: @replyto || "false",
+ notifyee: "#{$USER}@apache.org"
+ }
+ end
+ end
+
+ _h2 'What would be submitted'
+ queue.each do |vars|
+ _h2 "#{vars[:localpart]}-#{vars[:subdomain]}".gsub(/[^-\w]/,'_')
+ vars.each {|name,value| vars[name] = Shellwords.shellescape(value)}
+ _pre vars.map {|name,value| "#{name}=#{value}"}.join("\n")
+ end
+ else
+ _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
+
+ _script_ %{
+ // replace email textarea with two input fields
+ $('textarea').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 (until podling is entered)
+ $('input[name=suffix1]').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() != '') {
+ 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);
+ lastpod.unbind().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
+ apmail_bin = ASF::SVN['infra/infrastructure/apmail/trunk/bin']
+ lists = File.read(File.join(apmail_bin, '.archives')).
+ scan(/^\s+"(\w[-\w]+)", "\/home\/apmail\//).flatten
+
+ 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.start_with? "incubator-#{@podling}-"}
+ _confirm "Podling #{@podling} not found. Treat as new?"
+ next _focus 'input[name=podling]'
+ end
+ end
+
+ # confirm if pmc is unknown
+ if @localpart != @confirmed_localpart
+ validated['confirmed_localpart'] = @localpart
+ if not ASF::Committee.list.map(&:name).include? @localpart
+ _confirm "PMC #{@localpart} not found. Treat as new?"
+ next _focus 'input[name=localpart]'
+ end
+ end
+
+ # alert if incubator list requested already exists
+ params.keys.grep(/^suffix\d+$/).each do |param|
+ next if params[param].first.empty?
+ subdomain = "#{@podling}-#{params[param].first}"
+ if lists.any? {|list| list == "incubator-#{subdomain}"}
+ _alert "List #{subdomain}@incubator.apache.org already exists."
+ _focus "input[name=#{param}]"
+ break
+ end
+ end
+
+ # alert if non-incubator list requested already exists
+ if @subdomain
+ if lists.any? {|list| list == "#{@localpart}-#{@subdomain}"}
+ _alert "List #{@subdomain}@#{@localpart}.apache.org already exists."
+ _focus "input[name=subdomain]"
+ 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}. Treat as new?"
+ _focus "input[name=#{param}]"
+ break
+ end
+ end
+
+ _ok 'OK' if not _['confirm']
+end