From 0bfd0c04e043f7d149cd7877df94242b707894a7 Mon Sep 17 00:00:00 2001
From: nikkel <nikkel@noreply.example.org>
Date: Fri, 20 Mar 2020 02:24:15 +0700
Subject: [PATCH] Upload files to 'lib/postman'

---
 lib/postman/message.rb          | 156 ++++++++++++++++++++++++++++++++
 lib/postman/send_message.rb     |  81 +++++++++++++++++
 lib/postman/send_raw_message.rb |  37 ++++++++
 lib/postman/send_result.rb      |  30 ++++++
 lib/postman/version.rb          |   3 +
 5 files changed, 307 insertions(+)
 create mode 100644 lib/postman/message.rb
 create mode 100644 lib/postman/send_message.rb
 create mode 100644 lib/postman/send_raw_message.rb
 create mode 100644 lib/postman/send_result.rb
 create mode 100644 lib/postman/version.rb

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