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/29 16:00:03 UTC

[whimsy.git] [1/1] Commit d104dd6: rough in server side of icla processing

Commit d104dd6dfb7dac0f629a7ee6400ce6ec1b5b6415:
    rough in server side of icla processing


Branch: refs/heads/secmail
Author: Sam Ruby <ru...@intertwingly.net>
Committer: Sam Ruby <ru...@intertwingly.net>
Pusher: rubys <ru...@apache.org>

------------------------------------------------------------
www/secmail/README                                           | + -
www/secmail/helpers.rb                                       | +++++++++++ 
www/secmail/models/attachment.rb                             | ++++++++++++++ 
www/secmail/models/mailbox.rb                                | ++++++++ 
www/secmail/models/message.rb                                | +++++++++++++++ 
www/secmail/server.rb                                        | + 
www/secmail/views/actions/burst.json.rb                      | + ----
www/secmail/views/actions/check-signature.json.rb            | + ----
www/secmail/views/actions/delete-attachment.json.rb          | + ----
www/secmail/views/actions/drop.json.rb                       | + ----
www/secmail/views/actions/icla.json.rb                       | +++++++++++++ 
www/secmail/views/actions/rotate-attachment.json.rb          | + ----
www/secmail/views/forms/icla.js.rb                           | + -
www/secmail/views/parts.js.rb                                | ++++++ ---
------------------------------------------------------------
148 changes: 121 additions, 27 deletions.
------------------------------------------------------------


diff --git a/www/secmail/README b/www/secmail/README
index 161a350..14ec74e 100644
--- a/www/secmail/README
+++ b/www/secmail/README
@@ -18,7 +18,7 @@ Notes:
 
   Secretary email archive currently requires about approximately 11 Gigabytes.
 
-  Some functions will require installations of imageMagick and pdftk.
+  Some functions will require installations of gpg, imageMagick and pdftk.
 
   OS X El Capitan users may want to look at:
     http://stackoverflow.com/a/33248310
diff --git a/www/secmail/helpers.rb b/www/secmail/helpers.rb
new file mode 100644
index 0000000..9987346
--- /dev/null
+++ b/www/secmail/helpers.rb
@@ -0,0 +1,11 @@
+helpers do
+  # update and restore an svn checkout to a clean state
+  def svn_reset(repos)
+    path = File.realpath(repos).untaint
+    out, err, rc = Open3.capture3 'svn', 'cleanup', path
+    out, err, rc = Open3.capture3 'svn', 'revert', '--recursive', path
+    out, err, rc = Open3.capture3 'svn', 'status', path
+    File.unlink *out.scan(/^\?\s+(.*)/).flatten.map(&:untaint)
+    out, err, rc = Open3.capture3 'svn', 'update', path
+  end
+end
diff --git a/www/secmail/models/attachment.rb b/www/secmail/models/attachment.rb
index 4035515..d2fbd83 100644
--- a/www/secmail/models/attachment.rb
+++ b/www/secmail/models/attachment.rb
@@ -53,4 +53,31 @@ def as_pdf
 
     return file
   end
+
+  # write a file out to svn
+  def write_svn(repos, file)
+    if file.start_with? '.' or file !~ /\A[-.\w]+\Z/
+      raise IOError.new("Invalid filename: #{file}")
+    end
+
+    filename = File.join(repos, file)
+
+    if Dir.exist? filename
+      if name.start_with? '.' or name !~ /\A[.\w]+\Z/
+        raise IOError.new("Invalid filename: #{name}")
+      end
+
+      filename = File.join(filename, name)
+      raise Errno::EEXIST.new(File.join(file, name)) if File.exist? filename
+    else
+      raise Errno::EEXIST.new(file) if File.exist? filename
+    end
+
+    File.write filename, body, encoding: Encoding::BINARY
+
+    system 'svn', 'add', filename
+    system 'svn', 'propset', 'svn:mime-type', content_type.untaint, filename
+
+    filename
+  end
 end
diff --git a/www/secmail/models/mailbox.rb b/www/secmail/models/mailbox.rb
index 197c32e..f945a59 100644
--- a/www/secmail/models/mailbox.rb
+++ b/www/secmail/models/mailbox.rb
@@ -107,6 +107,14 @@ def messages
   #
   # Find a message
   #
+  def self.find(message)
+    month, hash = message.match(%r{/(\d+)/(\w+)}).captures
+    Mailbox.new(month).find(hash)
+  end
+
+  #
+  # Find a message
+  #
   def find(hash)
     headers = YAML.load_file(yaml_file) rescue {}
     email = messages.find {|message| Mailbox.hash(message) == hash}
diff --git a/www/secmail/models/message.rb b/www/secmail/models/message.rb
index 0beab95..aa4ab4c 100644
--- a/www/secmail/models/message.rb
+++ b/www/secmail/models/message.rb
@@ -86,4 +86,34 @@ def write
       yaml[@hash] = @headers
     end
   end
+
+  # write one or more attachments to directory containing an svn checkout
+  def write_svn(repos, filename, *attachments)
+    attachments = attachments.flatten.compact
+
+    if attachments.length == 1
+      ext = File.extname(attachments.first).untaint
+      find(attachments.first).write_svn(repos, filename + ext)
+    else
+      # validate filename
+      if filename.start_with? '.' or filename !~ /\A[.\w]\Z/
+	 raise IOError.new("invalid filename: #{filename}")
+      end
+
+      # ensure directory doesn't exist
+      dest = File.join(iclas, filename).untaint
+      raise Errno::EEXIST.new(filename) if File.exist? dest
+
+      # create directory
+      Dir.mkdir dest
+      Kernel.system 'svn', 'add', dest
+
+      # write out selected attachment
+      attachments.each do |attachment|
+        find(attachment).write_svn(repos, dest)
+      end
+
+      File.join(repos, dest)
+    end
+  end
 end
diff --git a/www/secmail/server.rb b/www/secmail/server.rb
index 74e170d..9a0c096 100644
--- a/www/secmail/server.rb
+++ b/www/secmail/server.rb
@@ -9,6 +9,7 @@
 require 'ruby2js/filter/require'
 require 'sanitize'
 
+require_relative 'helpers'
 require_relative 'models/mailbox'
 
 # list of messages
diff --git a/www/secmail/views/actions/burst.json.rb b/www/secmail/views/actions/burst.json.rb
index 83933f1..802adeb 100644
--- a/www/secmail/views/actions/burst.json.rb
+++ b/www/secmail/views/actions/burst.json.rb
@@ -2,10 +2,7 @@
 # burst a document into separate pages
 #
 
-month, hash = @message.match(%r{/(\d+)/(\w+)}).captures
-
-mbox = Mailbox.new(month)
-message = mbox.find(hash)
+message = Mailbox.find(@message)
 
 attachments = []
 
diff --git a/www/secmail/views/actions/check-signature.json.rb b/www/secmail/views/actions/check-signature.json.rb
index 1565119..ab96bd5 100644
--- a/www/secmail/views/actions/check-signature.json.rb
+++ b/www/secmail/views/actions/check-signature.json.rb
@@ -2,10 +2,7 @@
 # check signature on an attachment
 #
 
-month, hash = @message.match(%r{/(\d+)/(\w+)}).captures
-
-mbox = Mailbox.new(month)
-message = mbox.find(hash)
+message = Mailbox.find(@message)
 
 begin
   # fetch attachment and signature
diff --git a/www/secmail/views/actions/delete-attachment.json.rb b/www/secmail/views/actions/delete-attachment.json.rb
index 9c6b578..07f1abf 100644
--- a/www/secmail/views/actions/delete-attachment.json.rb
+++ b/www/secmail/views/actions/delete-attachment.json.rb
@@ -2,10 +2,7 @@
 # delete an attachment
 #
 
-month, hash = @message.match(%r{/(\d+)/(\w+)}).captures
-
-mbox = Mailbox.new(month)
-message = mbox.find(hash)
+message = Mailbox.find(@message)
 
 message.delete_attachment @selected
 
diff --git a/www/secmail/views/actions/drop.json.rb b/www/secmail/views/actions/drop.json.rb
index 62c0308..830ce73 100644
--- a/www/secmail/views/actions/drop.json.rb
+++ b/www/secmail/views/actions/drop.json.rb
@@ -2,10 +2,7 @@
 # drop part of drag and drop
 #
 
-month, hash = @message.match(%r{/(\d+)/(\w+)}).captures
-
-mbox = Mailbox.new(month)
-message = mbox.find(hash)
+message = Mailbox.find(@message)
 
 begin
   source = message.find(@source).as_pdf
diff --git a/www/secmail/views/actions/icla.json.rb b/www/secmail/views/actions/icla.json.rb
index 520a360..35f7fbc 100644
--- a/www/secmail/views/actions/icla.json.rb
+++ b/www/secmail/views/actions/icla.json.rb
@@ -1 +1,26 @@
+#
+# File an ICLA
+#
+
+message = Mailbox.find(@message)
+iclas = ASF::SVN['private/documents/iclas']
+
+# write attachment (+ signature, if present) to the documents/iclas directory
+svn_reset iclas
+dest = message.write_svn(iclas, @filename, @selected, @signature)
+
+# construct line to be inserted
+insert = [
+  'notinavail',
+  @realname.strip,
+  @pubname.strip,
+  @email.strip,
+  "Signed CLA; #{@filename}"
+].join(':')
+
+# update iclas.txt
+svn_reset ASF::ICLA::OFFICERS
+iclas_txt = ASF::ICLA.sort(File.read(ASF::ICLA::SOURCE) + insert + "\n")
+File.write ASF::ICLA::SOURCE, iclas_txt
+
 {result: "stub for ICLA, filename: #{@filename}"}
diff --git a/www/secmail/views/actions/rotate-attachment.json.rb b/www/secmail/views/actions/rotate-attachment.json.rb
index 3e0244e..d61000b 100644
--- a/www/secmail/views/actions/rotate-attachment.json.rb
+++ b/www/secmail/views/actions/rotate-attachment.json.rb
@@ -2,10 +2,7 @@
 # drop part of drag and drop
 #
 
-month, hash = @message.match(%r{/(\d+)/(\w+)}).captures
-
-mbox = Mailbox.new(month)
-message = mbox.find(hash)
+message = Mailbox.find(@message)
 
 begin
   selected = message.find(@selected).as_pdf
diff --git a/www/secmail/views/forms/icla.js.rb b/www/secmail/views/forms/icla.js.rb
index 004b36f..d96c41e 100644
--- a/www/secmail/views/forms/icla.js.rb
+++ b/www/secmail/views/forms/icla.js.rb
@@ -104,7 +104,7 @@ def componentDidUpdate()
 
   # generate file name from the public name
   def genfilename()
-    @filename ||= @pubname.downcase().gsub(/\W/, '-') + '.pdf'
+    @filename ||= @pubname.downcase().gsub(/\W/, '-')
   end
 
   # show new account request window with fields filled in
diff --git a/www/secmail/views/parts.js.rb b/www/secmail/views/parts.js.rb
index c371f20..a78c894 100644
--- a/www/secmail/views/parts.js.rb
+++ b/www/secmail/views/parts.js.rb
@@ -37,9 +37,7 @@ def render
         options[:className] = 'dragging'
       elsif attachment == @selected
         options[:className] = 'selected'
-      elsif attachment == @selected + '.asc'
-        options[:className] = 'signature'
-      elsif attachment == @selected + '.sig'
+      elsif attachment == @selected + '.asc' or attachment == @selected + '.sig'
         options[:className] = 'signature'
       else
         options[:className] = nil
@@ -251,13 +249,22 @@ def submit(event)
     event.preventDefault()
     form = event.currentTarget
 
-    data = {}
+    # collect up name of selected attachment and all input fields
+    data = {message: window.parent.location.pathname, selected: @selected}
     Array(form.querySelectorAll('input')).each do |field|
       data[field.name] = field.value if field.name
     end
 
+    # add signature (if present)
+    @attachments.each do |attachment|
+      if attachment == @selected + '.asc' or attachment == @selected + '.sig'
+        data.signature = attach
+      end
+    end
+
+    # submit HTTP post request
     @busy = true
-    HTTP(post form.action, data).then {|response|
+    HTTP.post(form.action, data).then {|response|
       @busy = false
       alert response.result
     }.catch {|error|