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/22 17:37:21 UTC
[whimsy.git] [1/1] Commit 83a28dc: more progress towards drag/drop
Commit 83a28dcc7a02a2c5893e7daf1ba978744ae0e651:
more progress towards drag/drop
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/models/attachment.rb | +++++++++ -
www/secmail/models/mailbox.rb | + -
www/secmail/models/message.rb | ++++++++ -
www/secmail/server.rb | +++ ---
www/secmail/views/actions/drop.json.rb | ++++++++++ ---
www/secmail/views/parts.js.rb | ++++++++++ ---
------------------------------------------------------------
139 changes: 116 additions, 23 deletions.
------------------------------------------------------------
diff --git a/www/secmail/README b/www/secmail/README
index d18715f..161a350 100644
--- a/www/secmail/README
+++ b/www/secmail/README
@@ -1,6 +1,7 @@
This directory contains a script that fetches and parsed secretary emails
and a server that will enable exploration of those emails.
+
Usage:
rake fetch
@@ -17,6 +18,11 @@ Notes:
Secretary email archive currently requires about approximately 11 Gigabytes.
+ Some functions will require installations of imageMagick and pdftk.
+
+ OS X El Capitan users may want to look at:
+ http://stackoverflow.com/a/33248310
+
Overview of files:
Gemfile: Ruby configuration (installation of gems)
@@ -46,7 +52,9 @@ Overview of control flow:
html views: Method names that start with an underscore generate HTML.
This HTML may pull in scripts, stylesheets, and have
- inline code that renders other views.
+ inline code that renders other views. Views in the
+ actions subdirectory produce responses to HTTP post
+ requests.
js views: This code is converted from Ruby to JavaScript.
This conversion is aware of React.js and will perform
diff --git a/www/secmail/models/attachment.rb b/www/secmail/models/attachment.rb
index aed6bde..eae4613 100644
--- a/www/secmail/models/attachment.rb
+++ b/www/secmail/models/attachment.rb
@@ -1,14 +1,45 @@
class Attachment
- def initialize(headers, part)
+ IMAGE_TYPES = %w(.gif, .jpg, .jpeg, .png)
+ attr_reader :headers
+
+ def initialize(message, headers, part)
+ @message = message
@headers = headers
@part = part
end
def content_type
- @part.content_type
+ headers[:mine] || @part.content_type
end
def body
- @part.body
+ headers[:content] || @part.body
+ end
+
+ def safe_name
+ name = @part.filename
+ name.gsub! /^\W/, ''
+ name.gsub! /[^\w.]/, '_'
+ name.untaint
+ end
+
+ def as_pdf
+ file = Tempfile.new([safe_name, '.pdf'], encoding: Encoding::BINARY)
+ file.write(body)
+ file.rewind
+
+ return file if content_type.end_with? '/pdf'
+ return file if @part.filename.end_with? '.pdf'
+
+ ext = File.extname(@part.filename).downcase
+
+ if IMAGE_TYPES.include? ext or content_type.start_with? 'image/'
+ pdf = Tempfile.new([safe_name, '.pdf'], encoding: Encoding::BINARY)
+ system 'convert', file.path, pdf.path
+ file.unlink
+ return pdf
+ end
+
+ return file
end
end
diff --git a/www/secmail/models/mailbox.rb b/www/secmail/models/mailbox.rb
index ab82d0c..148cc1b 100644
--- a/www/secmail/models/mailbox.rb
+++ b/www/secmail/models/mailbox.rb
@@ -110,7 +110,7 @@ def messages
def find(hash)
headers = YAML.load_file(yaml_file) rescue {}
email = messages.find {|message| Mailbox.hash(message) == hash}
- Message.new(headers[hash], email) if email
+ Message.new(self, hash, headers[hash], email) if email
end
#
diff --git a/www/secmail/models/message.rb b/www/secmail/models/message.rb
index 2247b59..af66139 100644
--- a/www/secmail/models/message.rb
+++ b/www/secmail/models/message.rb
@@ -1,5 +1,7 @@
class Message
- def initialize(headers, email)
+ def initialize(mailbox, hash, headers, email)
+ @hash = hash
+ @mailbox = mailbox
@headers = headers
@email = email
end
@@ -14,8 +16,8 @@ def find(name)
attach.filename == name or attach['Content-ID'].to_s == name
end
- if part
- Attachment.new(headers, part)
+ if headers
+ Attachment.new(self, headers, part)
end
end
@@ -46,4 +48,30 @@ def html_part
def text_part
mail.html_part
end
+
+ def attachments
+ @headers[:attachments].map {|attachment| attachment[:name]}
+ end
+
+ def update_attachment name, values
+ attachment = find(name)
+ if attachment
+ attachment.headers.merge! values
+ write
+ end
+ end
+
+ def delete_attachment name
+ attachment = find(name)
+ if attachment
+ @headers[:attachments].delete attachment.headers
+ write
+ end
+ end
+
+ def write
+ @mailbox.update do |yaml|
+ yaml[@hash] = @headers
+ end
+ end
end
diff --git a/www/secmail/server.rb b/www/secmail/server.rb
index 1b211a9..00dcff8 100644
--- a/www/secmail/server.rb
+++ b/www/secmail/server.rb
@@ -78,9 +78,9 @@
# list of parts for a single message
get %r{^/(\d{6})/(\w+)/_index_$} do |month, hash|
- @message = Mailbox.new(month).headers[hash]
- pass unless @message
- @attachments = @message[:attachments]
+ message = Mailbox.new(month).find(hash)
+ pass unless message
+ @attachments = message.attachments
_html :parts
end
diff --git a/www/secmail/views/actions/drop.json.rb b/www/secmail/views/actions/drop.json.rb
index 32cb2c2..3f25943 100644
--- a/www/secmail/views/actions/drop.json.rb
+++ b/www/secmail/views/actions/drop.json.rb
@@ -6,12 +6,25 @@
mbox = Mailbox.new(month)
message = mbox.find(hash)
-source = message.find(@source)
-target = message.find(@target)
-STDERR.puts source.inspect
-STDERR.puts target.inspect
-FileUtils.mkdir_p "work/#@message"
+begin
+ source = message.find(@source).as_pdf
+ target = message.find(@target).as_pdf
+ output = Tempfile.new('output')
-{success: true}
+ Kernel.system 'pdftk', target.path, source.path, 'cat', 'output',
+ output.path
+
+ message.update_attachment @target, content: output.read,
+ mime: 'application/pdf'
+
+ message.delete_attachment @source
+
+ensure
+ source.unlink if source
+ target.unlink if target
+ output.unlink if output
+end
+
+{attachments: message.attachments, selected: @target}
diff --git a/www/secmail/views/parts.js.rb b/www/secmail/views/parts.js.rb
index 14bb4d5..80120b0 100644
--- a/www/secmail/views/parts.js.rb
+++ b/www/secmail/views/parts.js.rb
@@ -2,6 +2,7 @@ class Parts < React
def initialize
@selected = nil
@busy = false
+ @attachments = []
end
def render
@@ -15,12 +16,13 @@ def render
onDragEnd: self.dragEnd,
onDrop: self.drop,
onContextMenu: self.menu,
+ onClick: self.select
}
- _ul @@attachments, ref: 'attachments' do |attachment|
+ _ul @attachments, ref: 'attachments' do |attachment|
+ options[:className] = ('selected' if attachment == @selected)
_li options do
- _a attachment.name, href: attachment.name, target: 'content',
- draggable: 'false'
+ _a attachment, href: attachment, target: 'content', draggable: 'false'
end
end
@@ -33,10 +35,15 @@ def render
_img.spinner src: '../../rotatingclock-slow2.gif' if @busy
end
+ # initialize attachments list with the data from the server
+ def componentWillMount()
+ @attachments = @@attachments
+ end
+
# disable context menu and register mouse and keyboard handlers
def componentDidMount()
$menu.style.display = :none
- window.onmousedown = self.click
+ window.onmousedown = self.window_click
# register keyboard handler on parent window and all frames
window.parent.onkeydown = self.keydown
@@ -57,16 +64,19 @@ def menu(event)
end
# hide context menu whenever a click is received outside the menu
- def click(event)
+ def window_click(event)
target = event.target
while target
return if target.class == 'contextMenu'
target = target.parentNode
end
- console.log 'click'
$menu.style.display = :none
end
+ def select(event)
+ @selected = event.currentTarget.querySelector('a').getAttribute('href')
+ end
+
def keydown(event)
if event.keyCode == 8 or event.keyCode == 46 # backspace or delete
if event.metaKey
@@ -135,8 +145,11 @@ def drop(event)
@busy = true
@drag = nil
HTTP.post '../../actions/drop', data do |response|
+ @attachments = response.attachments
+ @selected = href
@busy = false
target.classList.remove 'drop-target'
+ window.parent.frames.content.location.href=response.selected
end
end