mailcatcher/lib/mail_catcher/mail.rb

161 lines
5.8 KiB
Ruby
Raw Normal View History

2014-03-17 01:31:05 -04:00
require "eventmachine"
2016-04-23 03:45:49 -04:00
require "json"
2014-03-17 01:31:05 -04:00
require "mail"
require "sqlite3"
module MailCatcher::Mail extend self
2011-10-09 03:45:23 -04:00
def db
@__db ||= begin
2014-03-17 01:31:05 -04:00
SQLite3::Database.new(":memory:", :type_translation => true).tap do |db|
2011-10-09 03:45:23 -04:00
db.execute(<<-SQL)
CREATE TABLE message (
id INTEGER PRIMARY KEY ASC,
sender TEXT,
recipients TEXT,
subject TEXT,
source BLOB,
size TEXT,
type TEXT,
created_at DATETIME DEFAULT CURRENT_DATETIME
)
SQL
db.execute(<<-SQL)
CREATE TABLE message_part (
id INTEGER PRIMARY KEY ASC,
message_id INTEGER NOT NULL,
cid TEXT,
type TEXT,
is_attachment INTEGER,
filename TEXT,
charset TEXT,
body BLOB,
size INTEGER,
created_at DATETIME DEFAULT CURRENT_DATETIME
)
SQL
end
end
2011-10-09 03:45:23 -04:00
end
2011-06-09 23:21:39 -04:00
2011-10-09 03:45:23 -04:00
def add_message(message)
@add_message_query ||= db.prepare("INSERT INTO message (sender, recipients, subject, source, type, size, created_at) VALUES (?, ?, ?, ?, ?, ?, datetime('now'))")
2011-06-09 23:21:39 -04:00
2011-10-09 03:45:23 -04:00
mail = Mail.new(message[:source])
2016-04-23 03:45:49 -04:00
@add_message_query.execute(message[:sender], JSON.generate(message[:recipients]), mail.subject, message[:source], mail.mime_type || "text/plain", message[:source].length)
2011-10-09 03:45:23 -04:00
message_id = db.last_insert_row_id
parts = mail.all_parts
parts = [mail] if parts.empty?
parts.each do |part|
body = part.body.to_s
# Only parts have CIDs, not mail
cid = part.cid if part.respond_to? :cid
2014-03-17 01:31:05 -04:00
add_message_part(message_id, cid, part.mime_type || "text/plain", part.attachment? ? 1 : 0, part.filename, part.charset, body, body.length)
end
2011-10-09 03:45:23 -04:00
EventMachine.next_tick do
message = MailCatcher::Mail.message message_id
MailCatcher::Events::MessageAdded.push message
end
2011-10-09 03:45:23 -04:00
end
2011-06-09 23:21:39 -04:00
2011-10-09 03:45:23 -04:00
def add_message_part(*args)
@add_message_part_query ||= db.prepare "INSERT INTO message_part (message_id, cid, type, is_attachment, filename, charset, body, size, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, datetime('now'))"
@add_message_part_query.execute(*args)
2011-10-09 03:45:23 -04:00
end
2011-06-09 23:21:39 -04:00
2011-10-09 03:45:23 -04:00
def latest_created_at
@latest_created_at_query ||= db.prepare "SELECT created_at FROM message ORDER BY created_at DESC LIMIT 1"
@latest_created_at_query.execute.next
2011-10-09 03:45:23 -04:00
end
2011-06-09 23:21:39 -04:00
2011-10-09 03:45:23 -04:00
def messages
@messages_query ||= db.prepare "SELECT id, sender, recipients, subject, size, created_at FROM message ORDER BY created_at, id ASC"
@messages_query.execute.map do |row|
2011-10-09 03:45:23 -04:00
Hash[row.fields.zip(row)].tap do |message|
2016-04-23 03:45:49 -04:00
message["recipients"] &&= JSON.parse(message["recipients"])
2011-05-27 10:10:05 -04:00
end
end
2011-10-09 03:45:23 -04:00
end
2011-06-09 23:21:39 -04:00
2011-10-09 03:45:23 -04:00
def message(id)
@message_query ||= db.prepare "SELECT * FROM message WHERE id = ? LIMIT 1"
row = @message_query.execute(id).next
2011-10-09 03:45:23 -04:00
row && Hash[row.fields.zip(row)].tap do |message|
2016-04-23 03:45:49 -04:00
message["recipients"] &&= JSON.parse(message["recipients"])
end
2011-10-09 03:45:23 -04:00
end
2011-06-09 23:21:39 -04:00
2011-10-09 03:45:23 -04:00
def message_has_html?(id)
@message_has_html_query ||= db.prepare "SELECT 1 FROM message_part WHERE message_id = ? AND is_attachment = 0 AND type IN ('application/xhtml+xml', 'text/html') LIMIT 1"
2014-03-17 01:31:05 -04:00
(!!@message_has_html_query.execute(id).next) || ["text/html", "application/xhtml+xml"].include?(message(id)["type"])
2011-10-09 03:45:23 -04:00
end
2011-06-09 23:21:39 -04:00
2011-10-09 03:45:23 -04:00
def message_has_plain?(id)
@message_has_plain_query ||= db.prepare "SELECT 1 FROM message_part WHERE message_id = ? AND is_attachment = 0 AND type = 'text/plain' LIMIT 1"
(!!@message_has_plain_query.execute(id).next) || message(id)["type"] == "text/plain"
2011-10-09 03:45:23 -04:00
end
2011-06-09 23:21:39 -04:00
2011-10-09 03:45:23 -04:00
def message_parts(id)
@message_parts_query ||= db.prepare "SELECT cid, type, filename, size FROM message_part WHERE message_id = ? ORDER BY filename ASC"
@message_parts_query.execute(id).map do |row|
2011-10-09 03:45:23 -04:00
Hash[row.fields.zip(row)]
end
2011-10-09 03:45:23 -04:00
end
2011-06-09 23:21:39 -04:00
2011-10-09 03:45:23 -04:00
def message_attachments(id)
@message_parts_query ||= db.prepare "SELECT cid, type, filename, size FROM message_part WHERE message_id = ? AND is_attachment = 1 ORDER BY filename ASC"
@message_parts_query.execute(id).map do |row|
2011-10-09 03:45:23 -04:00
Hash[row.fields.zip(row)]
end
2011-10-09 03:45:23 -04:00
end
2011-06-09 23:21:39 -04:00
2011-10-09 03:45:23 -04:00
def message_part(message_id, part_id)
@message_part_query ||= db.prepare "SELECT * FROM message_part WHERE message_id = ? AND id = ? LIMIT 1"
row = @message_part_query.execute(message_id, part_id).next
2011-10-09 03:45:23 -04:00
row && Hash[row.fields.zip(row)]
end
2011-06-09 23:21:39 -04:00
2011-10-09 03:45:23 -04:00
def message_part_type(message_id, part_type)
@message_part_type_query ||= db.prepare "SELECT * FROM message_part WHERE message_id = ? AND type = ? AND is_attachment = 0 LIMIT 1"
row = @message_part_type_query.execute(message_id, part_type).next
2011-10-09 03:45:23 -04:00
row && Hash[row.fields.zip(row)]
end
2011-06-09 23:21:39 -04:00
2011-10-09 03:45:23 -04:00
def message_part_html(message_id)
part = message_part_type(message_id, "text/html")
part ||= message_part_type(message_id, "application/xhtml+xml")
part ||= begin
message = message(message_id)
2014-03-17 01:31:05 -04:00
message if message.present? and ["text/html", "application/xhtml+xml"].include? message["type"]
end
2011-10-09 03:45:23 -04:00
end
2011-06-09 23:21:39 -04:00
2011-10-09 03:45:23 -04:00
def message_part_plain(message_id)
message_part_type message_id, "text/plain"
end
def message_part_cid(message_id, cid)
2014-03-17 01:31:05 -04:00
@message_part_cid_query ||= db.prepare "SELECT * FROM message_part WHERE message_id = ?"
@message_part_cid_query.execute(message_id).map do |row|
2012-07-24 23:47:12 -04:00
Hash[row.fields.zip(row)]
2011-10-09 03:45:23 -04:00
end.find do |part|
part["cid"] == cid
end
2011-10-09 03:45:23 -04:00
end
2011-06-09 23:21:39 -04:00
2011-10-09 03:45:23 -04:00
def delete!
@delete_all_messages_query ||= db.prepare "DELETE FROM message"
@delete_all_message_parts_query ||= db.prepare "DELETE FROM message_part"
2011-06-09 23:21:39 -04:00
@delete_all_messages_query.execute and
@delete_all_message_parts_query.execute
end
2012-10-24 18:45:26 -04:00
def delete_message!(message_id)
2014-03-17 01:31:05 -04:00
@delete_messages_query ||= db.prepare "DELETE FROM message WHERE id = ?"
@delete_message_parts_query ||= db.prepare "DELETE FROM message_part WHERE message_id = ?"
2012-10-24 18:45:26 -04:00
@delete_messages_query.execute(message_id) and
@delete_message_parts_query.execute(message_id)
end
2011-06-09 23:21:39 -04:00
end