diff --git a/lib/postman/message.rb b/lib/postman/message.rb new file mode 100644 index 0000000..c892bf8 --- /dev/null +++ b/lib/postman/message.rb @@ -0,0 +1,156 @@ +require 'postman/error' +require 'postman/header_set' +require 'postman/attachment' + +module Postman + class Message + + # + # Find a specific messsage with the given scope + # + def self.find_with_scope(scope, id) + api = scope.client.moonrope.messages.message(:id => id.to_i, :_expansions => scope.expansions) + if api.success? + Message.new(scope.client, api.data) + elsif api.status == 'error' && api.data['code'] == 'MessageNotFound' + raise MessageNotFound.new(id) + else + raise Error, "Couldn't load message from API (#{api.data})" + end + end + + # + # If methods are called directly on the Message class, we likely want to see if we can + # run them through the global client message scope. + # + def self.method_missing(name, *args, &block) + if MessageScope.instance_methods(false).include?(name) + Postman::Client.instance.messages.send(name, *args, &block) + else + super + end + end + + # + # Initialize a new message object with the client and a set of initial attributes. + # + def initialize(client, attributes) + @client = client + @attributes = attributes + end + + # + # Return the message ID + # + def id + @attributes['id'] + end + + # + # Return the message token + # + def token + @attributes['token'] + end + + # + # Set a has of all the attributes from the API that should be exposed through + # the Message class. + # + ATTRIBUTES = { + :status => [:status, :status], + :last_delivery_attempt => [:status, :last_delivery_attempt, :timestamp], + :held? => [:status, :held, :boolean], + :hold_expiry => [:status, :hold_expiry, :timestamp], + :rcpt_to => [:details, :rcpt_to], + :mail_from => [:details, :mail_from], + :subject => [:details, :subject], + :message_id => [:details, :message_id], + :timestamp => [:details, :timestamp, :timestamp], + :direction => [:details, :direction], + :size => [:details, :size], + :bounce? => [:details, :bounce, :boolean], + :bounce_for_id => [:details, :bounce], + :tag => [:details, :tag], + :received_with_ssl? => [:details, :received_with_ssl, :boolean], + :inspected? => [:inspection, :inspected, :boolean], + :spam? => [:inspection, :spam, :boolean], + :spam_score => [:inspection, :spam_score], + :threat? => [:inspection, :thret, :boolean], + :threat_details => [:inspection, :threat_details], + :plain_body => [:plain_body], + :html_body => [:html_body], + } + + # + # Catch calls to any of the default attributes for a message and return the + # data however we'd like it + # + def method_missing(name, *args, &block) + if mapping = ATTRIBUTES[name.to_sym] + expansion, attribute, type = mapping + value = from_expansion(expansion, attribute) + case type + when :timestamp + value ? Time.at(value) : nil + when :boolean + value == 1 + else + value + end + else + super + end + end + + # + # Return a set of headers which can be queried like a hash however looking up + # values using [] will be case-insensitive. + # + def headers + @headers ||= HeaderSet.new(from_expansion(:headers)) + end + + # + # Return an array of attachment objects + # + def attachments + @attachments ||= from_expansion(:attachments).map do |a| + Attachment.new(a) + end + end + + # + # Return the full raw message + # + def raw_message + @raw_message ||= Base64.decode64(from_expansion(:raw_message)) + end + + private + + def from_expansion(expansion, attribute = nil, loaded = false) + if @attributes.has_key?(expansion.to_s) || loaded + attribute ? @attributes[expansion.to_s][attribute.to_s] : @attributes[expansion.to_s] + else + load_expansions(expansion) + from_expansion(expansion, attribute, true) + end + end + + def load_expansions(*names) + puts "\e[31mLoading expansion #{names}\e[0m" + api = @client.moonrope.messages.message(:id => self.id, :_expansions => names) + if api.success? + names.each do |expansion_name| + if api.data.has_key?(expansion_name.to_s) + @attributes[expansion_name.to_s] = api.data[expansion_name.to_s] + end + end + else + raise Postman::Error, "Couldn't load expansion data (#{names.join(', ')}) for message ID '#{self.id}'" + end + end + + end +end diff --git a/lib/postman/send_message.rb b/lib/postman/send_message.rb new file mode 100644 index 0000000..a94ed79 --- /dev/null +++ b/lib/postman/send_message.rb @@ -0,0 +1,81 @@ +require 'base64' +require 'postman/send_result' + +module Postman + class SendMessage + + def initialize(client) + @client = client + @attributes = {} + end + + def send! + api = @client.moonrope.request(:send, :message, @attributes) + if api.success? + SendResult.new(@client, api.data) + elsif api.status == 'error' + raise SendError.new(api.data['code'], api.data['message']) + else + raise Error, "Couldn't send message" + end + end + + def from(address) + @attributes[:from] = address + end + + def sender(address) + @attributes[:sender] = address + end + + def to(*addresses) + @attributes[:to] ||= [] + @attributes[:to] += addresses + end + + def cc(*addresses) + @attributes[:cc] ||= [] + @attributes[:cc] += addresses + end + + def bcc(*addresses) + @attributes[:bcc] ||= [] + @attributes[:bcc] += addresses + end + + def subject(subject) + @attributes[:subject] = subject + end + + def tag(tag) + @attributes[:tag] = tag + end + + def reply_to(reply_to) + @attributes[:reply_to] = reply_to + end + + def plain_body(content) + @attributes[:plain_body] = content + end + + def html_body(content) + @attributes[:html_body] = content + end + + def header(key, value) + @attributes[:headers] ||= {} + @attributes[:headers][key.to_s] = value + end + + def attach(filename, content_type, data) + @attributes[:attachments] ||= [] + @attributes[:attachments] << { + :name => filename, + :content_type => content_type, + :data => Base64.encode64(data) + } + end + + end +end diff --git a/lib/postman/send_raw_message.rb b/lib/postman/send_raw_message.rb new file mode 100644 index 0000000..30aeaf7 --- /dev/null +++ b/lib/postman/send_raw_message.rb @@ -0,0 +1,37 @@ +require 'base64' +require 'postman/send_result' + +module Postman + class SendRawMessage + + def initialize(client) + @client = client + @attributes = {} + end + + def send! + api = @client.moonrope.request(:send, :raw, @attributes) + if api.success? + SendResult.new(@client, api.data) + elsif api.status == 'error' + raise SendError.new(api.data['code'], api.data['message']) + else + raise Error, "Couldn't send message" + end + end + + def mail_from(address) + @attributes[:mail_from] = address + end + + def rcpt_to(*addresses) + @attributes[:rcpt_to] ||= [] + @attributes[:rcpt_to] += addresses + end + + def data(data) + @attributes[:data] = Base64.encode64(data) + end + + end +end diff --git a/lib/postman/send_result.rb b/lib/postman/send_result.rb new file mode 100644 index 0000000..6166e3c --- /dev/null +++ b/lib/postman/send_result.rb @@ -0,0 +1,30 @@ +module Postman + class SendResult + + def initialize(client, result) + @client = client + @result = result + end + + def message_id + @result['message_id'] + end + + def recipients + @recipients ||= begin + @result['messages'].each_with_object({}) do |(recipient, message_details), hash| + hash[recipient.to_s.downcase] = Message.new(@client, message_details) + end + end + end + + def [](recipient) + recipients[recipient.to_s.downcase] + end + + def size + recipients.size + end + + end +end diff --git a/lib/postman/version.rb b/lib/postman/version.rb new file mode 100644 index 0000000..6381ef0 --- /dev/null +++ b/lib/postman/version.rb @@ -0,0 +1,3 @@ +module Postman + VERSION = '1.0.1' +end