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

rubys pushed a commit to branch master
in repository https://git-dual.apache.org/repos/asf/whimsy.git

The following commit(s) were added to refs/heads/master by this push:
       new  f45e56e   rough in CCLA
f45e56e is described below

commit f45e56e04b84bed78ea90a9d087db1af1c5ac44f
Author: Sam Ruby <ru...@intertwingly.net>
AuthorDate: Sat Sep 17 16:01:18 2016 -0400

    rough in CCLA
---
 www/secmail/templates/ccla.erb         |   8 +-
 www/secmail/views/actions/ccla.json.rb | 143 ++++++++++++++++++++++++++++++++
 www/secmail/views/forms/ccla.js.rb     | 146 ++++++++++++++++++++++++++++++++-
 www/secmail/views/message.html.rb      |   2 +-
 4 files changed, 290 insertions(+), 9 deletions(-)

diff --git a/www/secmail/templates/ccla.erb b/www/secmail/templates/ccla.erb
index 88c1462..4936390 100644
--- a/www/secmail/templates/ccla.erb
+++ b/www/secmail/templates/ccla.erb
@@ -1,13 +1,7 @@
-to:   <%= @contact.inspect %> <<%= @cemail %>>
-from: <%= @from %>
-cc:   secret...@apache.org
-bcc:  <%= @bcc %>
-subject: Your CCLA sent to Apache Secretary
-
 Dear <%= @contact %>,
 
 This message acknowledges receipt of the following document, which has been 
filed in the Apache Software Foundation records:
 
-  <%= @commit_message %>
+  <%= @document %>
 
 <%= @sig %>
diff --git a/www/secmail/views/actions/ccla.json.rb 
b/www/secmail/views/actions/ccla.json.rb
new file mode 100644
index 0000000..df40163
--- /dev/null
+++ b/www/secmail/views/actions/ccla.json.rb
@@ -0,0 +1,143 @@
+#
+# File an ICLA:
+#  - add files to documents/cclas
+#  - add entry to officers/cclas.txt
+#  - respond to original email
+#
+
+# extract message
+message = Mailbox.find(@message)
+
+# extract file extension
+fileext = File.extname(@selected) if @signature.empty?
+
+# extract/verify project
+if @project and not @project.empty?
+  pmc = ASF::Committee[@project]
+
+  if not pmc
+    podling = ASF::Podling.find(@project)
+
+    if podling and not %w(graduated retired).include? podling.status
+      pmc = ASF::Committee['incubator']
+    end
+  end
+
+  if not pmc
+    _warn "#{@project} is not an active PMC or podling"
+  end
+end
+
+# obtain per-user information
+_personalize_email(env.user)
+
+# initialize commit message
+@document = "CCLA from #{@company}"
+
+########################################################################
+#                            document/cclas                            #
+########################################################################
+
+# write attachment (+ signature, if present) to the documents/cclas directory
+task "svn commit documents/cclas/#@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/cclas', "#{dir}/cclas"
+
+    # create/add file(s)
+    dest = message.write_svn("#{dir}/cclas", @filename, @selected, @signature)
+
+    # Show files to be added
+    svn 'status', "#{dir}/cclas"
+
+    # commit changes
+    svn 'commit', "#{dir}/cclas/#{@filename}#{fileext}", '-m', @document
+  end
+end
+
+########################################################################
+#                          officers/cclas.txt                          #
+########################################################################
+
+# insert line into iclas.txt
+task "svn commit foundation/officers/cclas.txt" do
+  # construct line to be inserted
+  @cclalines = "notinavail:" + @company.strip
+
+  unless @contact.empty?
+    @cclalines += " - #{@contact.strip}"
+  end
+
+  @cclalines += ":#{@email.strip}:Signed Corp CLA"
+
+  unless @employees.empty?
+    @cclalines += " for #{@employees.strip.gsub(/\s*\n\s*/, ', ')}"
+  end
+
+  unless @product.empty?
+    @cclalines += " for #{@product.strip}"
+  end
+
+  form do
+    _input value: @cclalines, name: 'cclalines'
+  end
+
+  complete do |dir|
+    # checkout empty officers directory
+    svn 'checkout', '--depth', 'empty',
+      'https://svn.apache.org/repos/private/foundation/officers', 
+      "#{dir}/officers"
+
+    # retrieve cclas.txt
+    dest = "#{dir}/officers/cclas.txt"
+    svn 'update', dest
+
+    # update cclas.txt
+    File.write dest, File.read(dest) + @cclalines + "\n"
+
+    # show the changes
+    svn 'diff', dest
+
+    # commit changes
+    svn 'commit', dest, '-m', @document
+  end
+end
+
+########################################################################
+#                           email submitter                            #
+########################################################################
+
+# send confirmation email
+task "email #@email" do
+  # build mail from template
+  @email = message.from
+  mail = message.reply(
+    from: @from,
+    to: @email.addrs,
+    cc: [
+      'secret...@apache.org',
+      ("private@#{pmc.mail_list}.apache.org" if pmc), # copy pmc
+      (podling.private_mail_list if podling) # copy podling
+    ],
+    body: template('ccla.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/ccla.js.rb 
b/www/secmail/views/forms/ccla.js.rb
index afa4f10..76bb578 100644
--- a/www/secmail/views/forms/ccla.js.rb
+++ b/www/secmail/views/forms/ccla.js.rb
@@ -1,5 +1,149 @@
 class CCLA < React
+  def initialize
+    @filed = false
+    @submitted = false
+  end
+
   def render
-    _p 'CCLA'
+    _h4 'CCLA'
+
+    _div.buttons do
+      _button 'clear form', onClick: -> {@contact = @email = ''}
+    end
+
+    _form method: 'post', action: '../../tasklist/ccla', target: 'content' do
+      _input type: 'hidden', name: 'message'
+      _input type: 'hidden', name: 'selected'
+      _input type: 'hidden', name: 'signature', value: @@signature
+
+      _table.form do
+        _tr do
+          _th 'Corporation'
+          _td do
+            _input name: 'company', value: @company, required: true,
+               disabled: @filed, onChange: self.changeCompany
+          end
+        end
+
+        _tr do
+          _th 'Product'
+          _td do
+            _input name: 'product', value: @product, disabled: @filed,
+              onChange: self.changeProduct
+          end
+        end
+
+        _tr do
+          _th 'Contact'
+          _td do
+            _input name: 'contact', value: @contact, required: true,
+              disabled: @filed
+          end
+        end
+
+        _tr do
+          _th 'E-mail'
+          _td do
+            _input name: 'email', value: @email, required: true, type: 'email',
+              disabled: @filed
+          end
+        end
+
+        _tr do
+          _th 'Employees'
+          _td do
+            _textarea name: 'employees', value: @employees, rows: 5,
+              disabled: @filed
+          end
+        end
+
+        _tr do
+          _th 'File Name'
+          _td do
+            _input name: 'filename', value: @filename, required: true,
+              pattern: '[a-zA-Z][-\w]+(\.[a-z]+)?', disabled: @filed
+          end
+        end
+
+        _tr do
+          _th 'Project'
+          _td do
+            _input name: 'project', value: @project, disabled: @filed
+          end
+        end
+      end
+
+      _input.btn.btn_primary value: 'File', type: 'submit', ref: 'file'
+    end
+  end
+
+  # on initial display, default various fields based on headers, and update
+  # state 
+  def componentDidMount()
+    name = @@headers.name
+ 
+    # reorder name if there is a single comma present
+    parts = name.split(',')
+    if parts.length == 2 and parts[1] !~ /^\s*(jr|ph\.d)\.?$/i
+      name = "#{parts[1].strip()} #{parts[0]}" 
+    end
+
+    @contact = name
+    @email = @@headers.from
+    self.componentDidUpdate()
+
+    # watch for status updates
+    window.addEventListener 'message', self.status_update
+  end
+
+  def componentWillUnmount()
+    window.removeEventListener 'message', self.status_update
+  end
+
+  # as fields change, enable/disable the associated buttons and adjust
+  # input requirements.
+  def componentDidUpdate()
+    # CCLA file form
+    valid = %w(company product contact email).all? do |name|
+      document.querySelector("input[name=#{name}]").validity.valid
+    end
+
+    $file.disabled = !valid or @filed or @submitted
+
+    # 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)
+  end
+
+  def changeCompany(event)
+    @company = event.target.value;
+    @filename = self.genfilename(event.target.value, @product)
+  end
+
+  def changeProduct(event)
+    @product = event.target.value;
+    @filename = self.genfilename(@company, event.target.value)
+  end
+
+  # generate file name from the real name
+  def genfilename(company, product)
+    basename = company
+    basename += '-' + product if product
+    return asciize(basename.strip()).downcase().gsub(/\W+/, '-')
+  end
+
+  # handle CCLA form submission
+  def file(event)
+    setTimeout 0 do
+      @submitted = true
+      @filed = true
+    end
+  end
+
+  # when tasks complete (or are aborted) reset form
+  def status_update(event)
+    @submitted = false
+    @filed = false
   end
 end
diff --git a/www/secmail/views/message.html.rb 
b/www/secmail/views/message.html.rb
index 01e53a1..83873d6 100644
--- a/www/secmail/views/message.html.rb
+++ b/www/secmail/views/message.html.rb
@@ -5,7 +5,7 @@
 _html do
   _title 'ASF Secretary Mail'
 
-  _frameset cols: '20%, 70%' do
+  _frameset cols: '25%, 70%' do
     _frame src: '_index_'
     _frame name: 'content', src: '_body_'
   end

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

Reply via email to