You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@whimsical.apache.org by ru...@apache.org on 2017/04/01 22:46:46 UTC

[whimsy] branch master updated: prep for final testing

This is an automated email from the ASF dual-hosted git repository.

rubys 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  290bb79   prep for final testing
290bb79 is described below

commit 290bb7956266b1ded4a856a9599a6d32a44701fa
Author: Sam Ruby <ru...@intertwingly.net>
AuthorDate: Sat Apr 1 18:46:35 2017 -0400

    prep for final testing
---
 www/secmail/templates/mem.erb            |   8 +-
 www/secmail/views/actions/memapp.json.rb | 242 +++++++++++++++++++++++++++++++
 www/secmail/views/forms/memapp.js.rb     |  47 +++++-
 3 files changed, 282 insertions(+), 15 deletions(-)

diff --git a/www/secmail/templates/mem.erb b/www/secmail/templates/mem.erb
index aed6045..dcd9df2 100644
--- a/www/secmail/templates/mem.erb
+++ b/www/secmail/templates/mem.erb
@@ -1,10 +1,4 @@
-to:   <%= @realname.inspect %> <<%= @memail %>>
-from: <%= @from %>
-cc:   secretary@apache.org
-bcc:  <%= @bcc %>
-subject: Your ASF Membership Application
-
-Dear <%= @realname %>,
+Dear <%= @fullname %>,
 
 This message acknowledges receipt of your membership application, which has been filed in the Apache Software Foundation records.
 
diff --git a/www/secmail/views/actions/memapp.json.rb b/www/secmail/views/actions/memapp.json.rb
new file mode 100644
index 0000000..b4b4059
--- /dev/null
+++ b/www/secmail/views/actions/memapp.json.rb
@@ -0,0 +1,242 @@
+#
+# File an membership application:
+#  - add files to documents/member_apps
+#  - add entry to foundation/members.txt
+#  - update memapp-received.txt
+#  - respond to original email
+#
+
+# extract message
+message = Mailbox.find(@message)
+
+# extract file extension
+fileext = File.extname(@selected).downcase if @signature.empty?
+
+# verify that a membership form under that name doesn't already exist
+if "#@filename#{fileext}" =~ /\w[-\w]*\.?\w*/
+  form = "#{ASF::SVN['private/documents/member_apps']}/#@filename#{fileext}"
+  if File.exist? form.untaint
+    _warn "documents/member_apps/#@filename#{fileext} already exists"
+  end
+end
+
+# obtain per-user information
+_personalize_email(env.user)
+
+# initialize commit message
+@document = "Membership Application for #{@fullname}"
+
+########################################################################
+#                         document/member_apps                         # 
+########################################################################
+
+# write attachment (+ signature, if present) to the documents/member_apps
+# directory
+task "svn commit documents/member_apps/#@filename#{fileext}" do
+  form do
+    _input value: @selected, name: 'selected'
+
+    if @signature and not @signature.empty?
+      _input value: @signature, name: 'signature'
+    end
+  end
+
+  complete do |dir|
+    # checkout empty directory
+    svn 'checkout', '--depth', 'empty',
+      'https://svn.apache.org/repos/private/documents/member_apps',
+      "#{dir}/member_apps"
+
+    # create/add file(s)
+    dest = message.write_svn("#{dir}/member_apps", @filename, @selected,
+      @signature)
+
+    # Show files to be added
+    svn 'status', "#{dir}/member_apps"
+
+    # commit changes
+    svn 'commit', "#{dir}/member_apps/#{@filename}#{fileext}", '-m', @document
+  end
+end
+
+########################################################################
+#                             members.txt                              #
+########################################################################
+
+# insert entry into members.txt
+task "svn commit foundation/members.txt" do
+  # construct line to be inserted
+  @entry = [
+    "#{@fullname}",
+    "#{@addr.gsub(/^/,'    ').gsub(/\r/,'')}",
+    ("    #{@country}"     unless @country.empty?),
+    "    Email: #{@email}",
+    ("      Tel: #{@tele}" unless @tele.empty?),
+    ("      Fax: #{@fax}"  unless @fax.empty?),
+    " Forms on File: ASF Membership Application",
+    " Avail ID: #{@availid}"
+  ].compact.join("\n") + "\n"
+
+  form do
+    _textarea @entry, name: 'entry', rows: @entry.split("\n").length
+  end
+
+  complete do |dir|
+    # checkout empty foundation directory
+    svn 'checkout', '--depth', 'empty',
+      'https://svn.apache.org/repos/private/foundation', "#{dir}/foundation"
+
+    # retrieve members.txt
+    dest = "#{dir}/foundation/members.txt"
+    svn 'update', dest
+
+    # update members.txt
+    pattern = /^Active.*?^=+\n+(.*?)^Emeritus/m
+    members_txt = open(dest).read
+    data = members_txt.scan(pattern).flatten.first
+    members = data.split(/^\s+\*\)\s+/)
+    members.shift
+    members.push @entry
+    members_txt[pattern,1] = " *) " + members.join("\n *) ")
+    members_txt[/We now number (\d+) active members\./,1] = members.length.to_s
+    File.write(dest, ASF::Member.sort(members_txt))
+
+    # show the changes
+    svn 'diff', dest
+
+    # commit changes
+    svn 'commit', dest, '-m', @document
+  end
+end
+
+########################################################################
+#             update cn=member,ou=groups,dc=apache,dc=org              #
+########################################################################
+
+task "update cn=member,ou=groups,dc=apache,dc=org in LDAP" do
+  form do
+    _input value: @availid, name: 'availid'
+  end
+
+  complete do
+    ldap = ASF.init_ldap(true)
+    ldap.bind("uid=#{env.user.untaint},ou=people,dc=apache,dc=org",
+      env.password.untaint)
+
+    ldap.modify "cn=#{member},ou=groups,dc=apache,dc=org",
+      [LDAP.mod(LDAP::LDAP_MOD_ADD, 'memberUid', [@availid])]
+
+    _pre "add member: #{ldap.err2string(ldap.err)} (#{ldap.err})",
+      class: (ldap.err == 0 ? '_stdout' : '_stderr')
+
+    ldap.unbind
+  end
+end
+
+########################################################################
+#                   subscribe to members@apache.org                    #
+########################################################################
+
+task "subscribe to members@apache.org" do
+  user = ASF::Person.find(@availid)
+  vars = {
+    version: 3, # This must match http://s.apache.org/008
+    availid: @availid,
+    addr: @email,
+    listkey: 'members',
+    member_p: true,
+    chair_p: ASF.pmc_chairs.include?(user),
+  }
+  @subreq = JSON.pretty_generate(vars) + "\n"
+
+  form do
+    _textarea @subreq, name: 'subreq', rows: @subreq.split("\n").length
+  end
+
+  complete do |dir|
+    # determine file name
+    fn = "#{@availid}-members-#{Time.now.strftime '%Y%m%d-%H%M%S-%L'}.json"
+    fn.untaint if @availid =~ /^\w[-.\w]+$/
+
+    # checkout empty directory
+    svn 'checkout', '--depth', 'empty',
+      "https://svn.apache.org/repos/infra/infrastructure/trunk/subreq",
+      "#{dir}/subreq"
+
+    # write out subscription request
+    File.write "#{dir}/subreq/#{fn}", @subreq
+    Kernel.system 'svn', 'add', "#{dir}/subreq/#{fn}"
+
+    # Show changes
+    svn 'diff', "#{dir}/subreq"
+
+    # commit changes
+    svn 'commit', "#{dir}/subreq", '-m', @document
+  end
+end
+
+########################################################################
+#                      update memapp-received.txt                      #
+########################################################################
+
+task "svn commit memapp-received.text" do
+  meetings = ASF::SVN['private/foundation/Meetings']
+  file = Dir["#{meetings}/2*/memapp-received.txt"].sort.last.untaint
+  received = File.read(file)
+  if received =~ /^no\s+\w+\s+\w+\s+\w+\s+#{@availid}\s/
+    received[/^(no )\s+\w+\s+\w+\s+\w+\s+#{@availid}\s/,1] = 'yes'
+  end
+  received[/(no )\s+\w+\s+\w+\s+#{@availid}\s/,1] = 'yes'
+  received[/(no )\s+\w+\s+#{@availid}\s/,1] = 'yes'
+  received[/(no )\s+#{@availid}\s/,1] = 'yes'
+  @line = received[/.*\s#{@availid}\s.*/]
+
+  form do
+    _input value: @line, name: 'line'
+  end
+
+  complete do |dir|
+    # checkout empty directory
+    meeting = file.split('/')[-2]
+    svn 'checkout', '--depth', 'empty',
+      "https://svn.apache.org/repos/private/foundation/Meetings/#{meeting}",
+      "#{dir}/#{meeting}"
+
+    # create/add file(s)
+    received = File.read("#{dir}/#{meeting}/memapp-received.txt")
+    received[/.*\s#{@availid}\s.*/] = @line
+    File.write("#{dir}/#{meeting}/memapp-received.txt", received)
+
+    # Show changes
+    svn 'diff', ""#{dir}/#{meeting}"
+
+    # commit changes
+    svn 'commit', "#{dir}/#{meeting}/memapp-received.txt", '-m', @document
+  end
+end
+
+########################################################################
+#                           email submitter                            #
+########################################################################
+
+# send confirmation email
+task "email #@email" do
+  # build mail from template
+  mail = message.reply(
+    subject: @document,
+    from: @from,
+    to: "#{@fullname.inspect} <#{@email}>",
+    cc: 'secretary@apache.org',
+    body: template('mem.erb')
+  )
+
+  # echo email
+  form do
+    _message mail.to_s
+  end
+
+  # deliver mail
+  complete do
+    mail.deliver!
+  end
+end
diff --git a/www/secmail/views/forms/memapp.js.rb b/www/secmail/views/forms/memapp.js.rb
index a00e84c..6e2bddd 100644
--- a/www/secmail/views/forms/memapp.js.rb
+++ b/www/secmail/views/forms/memapp.js.rb
@@ -1,6 +1,7 @@
 class MemApp < React
   def initialize
     @received = []
+    @filed = false
     @disabled = true
   end
 
@@ -9,6 +10,7 @@ class MemApp < React
 
     _form method: 'post', action: '../../tasklist/memapp', target: 'content' do
       _input type: 'hidden', name: 'message'
+      _input type: 'hidden', name: 'selected'
       _input type: 'hidden', name: 'signature', value: @@signature
 
       _table.form do
@@ -33,7 +35,8 @@ class MemApp < React
             _label 'Full Name', for: 'fullname'
           end
           _td do
-            _input type: :text, name: 'fullname', id: 'fullname', value: @name
+            _input type: :text, name: 'fullname', id: 'fullname', value: @name,
+              disabled: @filed
           end
         end
 
@@ -42,7 +45,7 @@ class MemApp < React
             _label 'Address', for: 'addr'
           end
           _td do
-            _textarea rows: 5, name: 'addr', id: 'addr'
+            _textarea rows: 5, name: 'addr', id: 'addr', disabled: @filed
           end
         end
 
@@ -51,7 +54,8 @@ class MemApp < React
             _label 'Country', for: 'country'
           end
           _td do
-            _input type: :text, name: 'country', id: 'country'
+            _input type: :text, name: 'country', id: 'country',
+              disabled: @filed
           end
         end
 
@@ -60,7 +64,7 @@ class MemApp < React
             _label 'Telephone', for: 'tele'
           end
           _td do
-            _input type: :text, name: 'tele', id: 'tele'
+            _input type: :text, name: 'tele', id: 'tele', disabled: @filed
           end
         end
 
@@ -69,7 +73,7 @@ class MemApp < React
             _label 'Fax', for: 'fax'
           end
           _td do
-            _input type: :text, name: 'fax', id: 'fax'
+            _input type: :text, name: 'fax', id: 'fax', disabled: @filed
           end
         end
 
@@ -78,7 +82,8 @@ class MemApp < React
             _label 'E-Mail', for: 'email'
           end
           _td do
-            _input type: :email, name: 'email', id: 'email', value: @email
+            _input type: :email, name: 'email', id: 'email', value: @email,
+              disabled: @filed
           end
         end
 
@@ -88,7 +93,7 @@ class MemApp < React
           end
           _td do
             _input type: :text, name: 'filename', id: 'filename',
-              value: @filename
+              value: @filename, disabled: @filed
           end
         end
       end
@@ -97,15 +102,27 @@ class MemApp < React
     end
   end
 
-  # on initial display, default email and fetch memapp-received.txt
+  # on initial display, wire up form, default email and fetch 
+  # memapp-received.txt
   def componentDidMount()
+    # wire up form
+    jQuery('form')[0].addEventListener('submit', self.file)
+    jQuery('input[name=message]').val(window.parent.location.pathname)
+    jQuery('input[name=selected]').val(@@selected)
+
+    # default email
     @email = @@headers.from
 
+    # fetch memapp-received information
     jQuery.getJSON('../../memapp.json') do |result|
       @received = result.received
     end
+
+    # watch for status updates
+    window.addEventListener 'message', self.status_update
   end
 
+  # when id is selected, default full name and filename
   def setid(event)
     id = event.target.value
     @received.each do |line|
@@ -116,4 +133,18 @@ class MemApp < React
       end
     end
   end
+
+  # handle membership application form submission
+  def file(event)
+    setTimeout 0 do
+      @disabled = true
+      @filed = true
+    end
+  end
+
+  # when tasks complete (or are aborted) reset form
+  def status_update(event)
+    @disabled = false
+    @filed = false
+  end
 end

-- 
To stop receiving notification emails like this one, please contact
['"commits@whimsical.apache.org" <co...@whimsical.apache.org>'].