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