mailjet 0.0.5 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +81 -259
  3. data/Rakefile +5 -4
  4. data/lib/mailjet.rb +7 -11
  5. data/lib/mailjet/api_error.rb +9 -5
  6. data/lib/mailjet/collection_proxy.rb +15 -0
  7. data/lib/mailjet/configuration.rb +4 -8
  8. data/lib/mailjet/connection.rb +72 -0
  9. data/lib/mailjet/gem_extensions/rest_client.rb +19 -0
  10. data/lib/mailjet/mailer.rb +37 -2
  11. data/lib/mailjet/message_delivery.rb +9 -0
  12. data/lib/mailjet/reporting.rb +10 -7
  13. data/lib/mailjet/resource.rb +199 -0
  14. data/lib/mailjet/resources/apikey.rb +12 -0
  15. data/lib/mailjet/resources/apikeyaccess.rb +12 -0
  16. data/lib/mailjet/resources/apikeytotals.rb +14 -0
  17. data/lib/mailjet/resources/apitoken.rb +12 -0
  18. data/lib/mailjet/resources/batchjob.rb +12 -0
  19. data/lib/mailjet/resources/bouncestatistics.rb +14 -0
  20. data/lib/mailjet/resources/campaign.rb +12 -0
  21. data/lib/mailjet/resources/campaignstatistics.rb +14 -0
  22. data/lib/mailjet/resources/clickstatistics.rb +14 -0
  23. data/lib/mailjet/resources/contact.rb +12 -0
  24. data/lib/mailjet/resources/contactdata.rb +12 -0
  25. data/lib/mailjet/resources/contactfilter.rb +12 -0
  26. data/lib/mailjet/resources/contacthistorydata.rb +12 -0
  27. data/lib/mailjet/resources/contactmetadata.rb +12 -0
  28. data/lib/mailjet/resources/contactslist.rb +12 -0
  29. data/lib/mailjet/resources/contactslistsignup.rb +12 -0
  30. data/lib/mailjet/resources/contactstatistics.rb +14 -0
  31. data/lib/mailjet/resources/csvimport.rb +12 -0
  32. data/lib/mailjet/resources/domainstatistics.rb +14 -0
  33. data/lib/mailjet/resources/eventcallbackurl.rb +12 -0
  34. data/lib/mailjet/resources/geostatistics.rb +14 -0
  35. data/lib/mailjet/resources/graphstatistics.rb +14 -0
  36. data/lib/mailjet/resources/listrecipient.rb +12 -0
  37. data/lib/mailjet/resources/listrecipientstatistics.rb +14 -0
  38. data/lib/mailjet/resources/liststatistics.rb +14 -0
  39. data/lib/mailjet/resources/manycontacts.rb +12 -0
  40. data/lib/mailjet/resources/message.rb +12 -0
  41. data/lib/mailjet/resources/messagehistory.rb +14 -0
  42. data/lib/mailjet/resources/messageinformation.rb +14 -0
  43. data/lib/mailjet/resources/messagesentstatistics.rb +14 -0
  44. data/lib/mailjet/resources/messagestate.rb +12 -0
  45. data/lib/mailjet/resources/messagestatistics.rb +14 -0
  46. data/lib/mailjet/resources/metadata.rb +14 -0
  47. data/lib/mailjet/resources/metasender.rb +12 -0
  48. data/lib/mailjet/resources/myprofile.rb +12 -0
  49. data/lib/mailjet/resources/newsletter.rb +12 -0
  50. data/lib/mailjet/resources/newsletterblock.rb +12 -0
  51. data/lib/mailjet/resources/newsletterproperties.rb +12 -0
  52. data/lib/mailjet/resources/newslettertemplate.rb +12 -0
  53. data/lib/mailjet/resources/newslettertemplateblock.rb +12 -0
  54. data/lib/mailjet/resources/newslettertemplatecategory.rb +12 -0
  55. data/lib/mailjet/resources/newslettertemplateproperties.rb +12 -0
  56. data/lib/mailjet/resources/openinformation.rb +14 -0
  57. data/lib/mailjet/resources/openstatistics.rb +14 -0
  58. data/lib/mailjet/resources/parseroute.rb +12 -0
  59. data/lib/mailjet/resources/preferences.rb +12 -0
  60. data/lib/mailjet/resources/sender.rb +12 -0
  61. data/lib/mailjet/resources/senderstatistics.rb +14 -0
  62. data/lib/mailjet/resources/toplinkclicked.rb +14 -0
  63. data/lib/mailjet/resources/trigger.rb +12 -0
  64. data/lib/mailjet/resources/user.rb +12 -0
  65. data/lib/mailjet/resources/useragentstatistics.rb +14 -0
  66. data/lib/mailjet/resources/widget.rb +12 -0
  67. data/lib/mailjet/resources/widgetcustomvalue.rb +12 -0
  68. data/lib/mailjet/version.rb +1 -1
  69. metadata +155 -44
  70. data/lib/mailjet/api.rb +0 -20
  71. data/lib/mailjet/api_request.rb +0 -70
  72. data/lib/mailjet/campaign.rb +0 -67
  73. data/lib/mailjet/click.rb +0 -15
  74. data/lib/mailjet/contact.rb +0 -18
  75. data/lib/mailjet/email.rb +0 -4
  76. data/lib/mailjet/list.rb +0 -58
  77. data/lib/mailjet/template_category.rb +0 -13
  78. data/lib/mailjet/template_model.rb +0 -13
  79. data/test/mailjet/api_request_test.rb +0 -72
  80. data/test/mailjet/api_test.rb +0 -13
  81. data/test/mailjet/campaign_test.rb +0 -66
  82. data/test/mailjet/configuration_test.rb +0 -16
  83. data/test/mailjet/contact_test.rb +0 -24
  84. data/test/mailjet/list_test.rb +0 -67
  85. data/test/mailjet/rack/endpoint_test.rb +0 -30
  86. data/test/mailjet/reporting_test.rb +0 -26
  87. data/test/mailjet/template_category_test.rb +0 -13
  88. data/test/mailjet/template_model_test.rb +0 -13
  89. data/test/mailjet_test.rb +0 -17
  90. data/test/minitest_helper.rb +0 -22
@@ -1,19 +1,23 @@
1
1
  # encoding: utf-8
2
2
  require 'active_support'
3
3
 
4
- module Mailjet
4
+ module Mailjet
5
5
  class ApiError < StandardError
6
+
7
+ attr_accessor :code
8
+
6
9
  def initialize(code, res, request, request_path, params)
10
+ self.code = code
7
11
  # code is ugly, output is pretty
8
- super("error #{code} while sending #{request.inspect} to #{request_path} with #{params.inspect}\n\n" +
9
- (res['errors'].present? ?
12
+ super("error #{code} while sending #{request.inspect} to #{request_path} with #{params.inspect}\n\n" +
13
+ (res['errors'].present? ?
10
14
  [(res['errors'] || [])].flatten.map do |param, text|
11
15
  [param, text].map(&:to_s).reject(&:blank?).join(': ')
12
- end.join("\n") :
16
+ end.join("\n") :
13
17
  res.inspect
14
18
  ) +
15
19
  "\n\nPlease see http://api.mailjet.com/0.1/HelpStatus for more informations on error numbers.\n\n"
16
20
  )
17
21
  end
18
22
  end
19
- end
23
+ end
@@ -0,0 +1,15 @@
1
+ module Mailjet
2
+ class CollectionProxy
3
+ attr_accessor :count
4
+
5
+ def intialize(response = {})
6
+ self.count = response['Total']
7
+ @proxy = response['Data'] ? Array.new(response['Data']) : []
8
+ end
9
+
10
+ def method_missing(name, *args, &block)
11
+ @proxy.send(name, *args, &block)
12
+ end
13
+
14
+ end
15
+ end
@@ -2,15 +2,11 @@ require 'active_support/core_ext/module/attribute_accessors'
2
2
 
3
3
  module Mailjet
4
4
  module Configuration
5
- mattr_accessor :api_version
6
5
  mattr_accessor :api_key
7
6
  mattr_accessor :secret_key
8
- mattr_accessor :use_https
9
- mattr_accessor :domain
7
+ mattr_accessor :end_point
10
8
  mattr_accessor :default_from
11
-
12
- @@use_https = true
13
- @@api_version = 0.1
14
- @@domain = ''
9
+
10
+ @@end_point = 'https://api.mailjet.com'
15
11
  end
16
- end
12
+ end
@@ -0,0 +1,72 @@
1
+ require 'rest_client'
2
+ require 'mailjet/gem_extensions/rest_client'
3
+ require 'active_support/core_ext/module/delegation'
4
+
5
+ module Mailjet
6
+ class Connection
7
+
8
+ attr_accessor :adapter, :public_operations, :read_only
9
+ alias :read_only? :read_only
10
+
11
+ delegate :options, :concat_urls, :url, to: :adapter
12
+
13
+ def [](suburl, &new_block)
14
+ self.class.new(concat_urls(url, suburl), options[:user], options[:password], options)
15
+ end
16
+
17
+ def initialize(end_point, api_key, secret_key, options = {})
18
+ adapter_class = options[:adapter_class] || RestClient::Resource
19
+
20
+ self.public_operations = options[:public_operations] || []
21
+ self.read_only = options[:read_only]
22
+ self.adapter = adapter_class.new(end_point, options.merge(user: api_key, password: secret_key))
23
+ end
24
+
25
+ def get(additional_headers = {}, &block)
26
+ handle_api_call(:get, additional_headers, &block)
27
+ end
28
+
29
+ def post(payload, additional_headers = {}, &block)
30
+ handle_api_call(:post, additional_headers, payload, &block)
31
+ end
32
+
33
+ def put(payload, additional_headers = {}, &block)
34
+ handle_api_call(:put, additional_headers, payload, &block)
35
+ end
36
+
37
+ def delete(additional_headers = {}, &block)
38
+ handle_api_call(:delete, additional_headers, &block)
39
+ end
40
+
41
+ private
42
+
43
+ def handle_api_call(method, additional_headers = {}, payload = {}, &block)
44
+ raise Mailjet::MethodNotAllowed unless method_allowed(method)
45
+
46
+ if [:get, :delete].include?(method)
47
+ @adapter.send(method, additional_headers, &block)
48
+ else
49
+ @adapter.send(method, payload, additional_headers, &block)
50
+ end
51
+ rescue RestClient::Exception => e
52
+ handle_exeception(e, additional_headers, payload)
53
+ end
54
+
55
+ def method_allowed(method)
56
+ method = method.to_sym
57
+ public_operations.include?(method) && (method == :get || !read_only?)
58
+ end
59
+
60
+ def handle_exeception(e, additional_headers, payload = {})
61
+ params = additional_headers[:params] || {}
62
+ params = params.merge(payload)
63
+
64
+ raise Mailjet::ApiError.new(e.http_code, e.http_body, @adapter, @adapter.url, params)
65
+ end
66
+
67
+ end
68
+
69
+ class MethodNotAllowed < StandardError
70
+
71
+ end
72
+ end
@@ -0,0 +1,19 @@
1
+ module RestClient
2
+ module Payload
3
+ class Base
4
+ def flatten_params_array value, calculated_key
5
+ result = []
6
+ value.each do |elem|
7
+ if elem.is_a? Hash
8
+ result += flatten_params(elem, calculated_key)
9
+ elsif elem.is_a? Array
10
+ result += flatten_params_array(elem, calculated_key)
11
+ else
12
+ result << ["#{calculated_key}", elem]
13
+ end
14
+ end
15
+ result
16
+ end
17
+ end
18
+ end
19
+ end
@@ -2,10 +2,10 @@ require 'action_mailer'
2
2
  require 'mail'
3
3
 
4
4
  class Mailjet::Mailer < ::Mail::SMTP
5
- def initialize options = {}
5
+ def initialize(options = {})
6
6
  ActionMailer::Base.default(:from => Mailjet.config.default_from) if Mailjet.config.default_from.present?
7
7
  super({
8
- :address => "in.mailjet.com",
8
+ :address => "in-v3.mailjet.com",
9
9
  :port => 587,
10
10
  :authentication => 'plain',
11
11
  :user_name => Mailjet.config.api_key,
@@ -16,3 +16,38 @@ class Mailjet::Mailer < ::Mail::SMTP
16
16
  end
17
17
 
18
18
  ActionMailer::Base.add_delivery_method :mailjet, Mailjet::Mailer
19
+
20
+
21
+
22
+ class Mailjet::APIMailer
23
+ def initialize(options = {})
24
+ ActionMailer::Base.default(:from => Mailjet.config.default_from) if Mailjet.config.default_from.present?
25
+ @delivery_method_options = options.slice(:'mj-prio', :'mj-campaign', :'mj-deduplicatecampaign', :'mj-trackopen', :'mj-trackclick', :'header')
26
+ end
27
+
28
+ def deliver!(mail)
29
+ if mail.multipart?
30
+ content = {
31
+ text: mail.text_part.try(:decoded),
32
+ html: mail.html_part.try(:decoded),
33
+ attachment: mail.attachments.select{ |a| !a.inline? }.try(:decoded),
34
+ inlineattachment: mail.attachments.select{ |a| !a.inline? }.try(:decoded)
35
+ }
36
+ else
37
+ content = (mail.mime_type == "text/html") ? {html: mail.body.decoded} : {text: mail.body.decoded}
38
+ end
39
+
40
+ payload = {
41
+ from: mail.from || Mailjet.config.default_from,
42
+ sender: mail.sender,
43
+ to: mail.to,
44
+ cc: mail.cc,
45
+ bcc: mail.bcc,
46
+ subject: mail.subject
47
+ }.merge(content).merge(@delivery_method_options)
48
+
49
+ Mailjet::MessageDelivery.create(payload)
50
+ end
51
+ end
52
+
53
+ ActionMailer::Base.add_delivery_method :mailjet_api, Mailjet::APIMailer
@@ -0,0 +1,9 @@
1
+ require 'mailjet/resource'
2
+
3
+ module Mailjet
4
+ class MessageDelivery
5
+ include Mailjet::Resource
6
+ self.resource_path = 'v3/send'
7
+ self.public_operations = [:post]
8
+ end
9
+ end
@@ -9,33 +9,36 @@ module Mailjet
9
9
  Mailjet::Click.new(click)
10
10
  end
11
11
  end
12
-
12
+
13
13
  def domains(options = {})
14
14
  (options.delete(:api) || Mailjet::Api.singleton).reportDomain(options)["domains"] || []
15
15
  end
16
-
16
+
17
17
  def clients(options = {})
18
18
  (options.delete(:api) || Mailjet::Api.singleton).reportEmailclients(options)["email_clients"] || []
19
19
  end
20
-
20
+
21
21
  def emails(options = {})
22
22
  ((options.delete(:api) || Mailjet::Api.singleton).reportEmailsent(options)["emails"] || []).map do |email|
23
23
  Mailjet::Email.new(email)
24
24
  end
25
25
  end
26
-
26
+
27
+ def bounce(options = {})
28
+ (options.delete(:api) || Mailjet::Api.singleton).reportEmailbounce(options)["bounces"] || []
29
+ end
30
+
27
31
  def statistics(options = {})
28
32
  (options.delete(:api) || Mailjet::Api.singleton).reportEmailstatistics(options)["stats"]
29
33
  end
30
-
34
+
31
35
  def geolocation(options = {})
32
36
  (options.delete(:api) || Mailjet::Api.singleton).reportGeoip(options)["geos"]
33
37
  end
34
-
38
+
35
39
  def agents(options = {})
36
40
  (options.delete(:api) || Mailjet::Api.singleton).reportUseragents(options)["user_agents"] || []
37
41
  end
38
42
  end
39
43
  end
40
44
  end
41
-
@@ -0,0 +1,199 @@
1
+ require 'mailjet/connection'
2
+ require 'mailjet/resource'
3
+ require 'active_support/hash_with_indifferent_access'
4
+ require 'active_support/core_ext/class'
5
+ require 'active_support/core_ext/string'
6
+ require 'active_support/core_ext/module/delegation'
7
+ require 'active_support/concern'
8
+ require 'active_support/json/decoding'
9
+
10
+ ActiveSupport.parse_json_times = true
11
+
12
+ module Mailjet
13
+ module Resource
14
+ extend ActiveSupport::Concern
15
+
16
+ included do
17
+ cattr_accessor :resource_path, :public_operations, :read_only, :filters, :properties
18
+ cattr_writer :connection
19
+
20
+ def self.connection
21
+ class_variable_get(:@@connection) || default_connection
22
+ end
23
+
24
+ def self.default_connection
25
+ Mailjet::Connection.new(
26
+ "#{Mailjet.config.end_point}/#{resource_path}",
27
+ Mailjet.config.api_key,
28
+ Mailjet.config.secret_key,
29
+ public_operations: public_operations,
30
+ read_only: read_only)
31
+ end
32
+ end
33
+
34
+ module ClassMethods
35
+ def first(params = {})
36
+ all(params.merge!(limit: 1)).first
37
+ end
38
+
39
+ def all(params = {})
40
+ params = format_params(params)
41
+ attribute_array = parse_api_json(connection.get(params: params))
42
+ attribute_array.map{ |attributes| instanciate_from_api(attributes) }
43
+ end
44
+
45
+ def count
46
+ response_json = connection.get(params: {limit: 1, countrecords: 1})
47
+ response_hash = ActiveSupport::JSON.decode(response_json)
48
+ response_hash['Total']
49
+ end
50
+
51
+ def find(id)
52
+ attributes = parse_api_json(connection[id].get).first
53
+ instanciate_from_api(attributes)
54
+ rescue RestClient::ResourceNotFound
55
+ nil
56
+ end
57
+
58
+ def create(attributes = {})
59
+ self.new(attributes).tap do |resource|
60
+ resource.save!
61
+ resource.persisted = true
62
+ end
63
+ end
64
+
65
+ def delete(id)
66
+ connection[id].delete
67
+ end
68
+
69
+ def instanciate_from_api(attributes = {})
70
+ self.new(attributes.merge(persisted: true))
71
+ end
72
+
73
+ def parse_api_json(response_json)
74
+ response_hash = ActiveSupport::JSON.decode(response_json)
75
+ response_data_array = response_hash['Data']
76
+ response_data_array.map{ |response_data| underscore_keys(response_data) }
77
+ end
78
+
79
+ def format_params(params)
80
+ if params[:sort]
81
+ params[:sort] = params[:sort].map do |attribute, direction|
82
+ attribute = attribute.to_s.camelcase
83
+ direction = direction.to_s.upcase
84
+ "#{attribute} #{direction}"
85
+ end.join(', ')
86
+ end
87
+ params
88
+ end
89
+
90
+ def camelcase_keys(hash)
91
+ map_keys(hash, :camelcase)
92
+ end
93
+
94
+ def underscore_keys(hash)
95
+ map_keys(hash, :underscore)
96
+ end
97
+
98
+ def map_keys(hash, method)
99
+ hash.inject({}) do |_hash, (key, value)|
100
+ new_key = key.to_s.send(method)
101
+ _hash[new_key] = value
102
+ _hash
103
+ end
104
+ end
105
+ end
106
+
107
+ attr_accessor :attributes, :persisted
108
+
109
+ def initialize(_attributes = nil)
110
+ @attributes = ActiveSupport::HashWithIndifferentAccess.new(_attributes.reverse_merge(persisted: false))
111
+ end
112
+
113
+ def persisted?
114
+ attributes[:persisted]
115
+ end
116
+
117
+ def save
118
+ if persisted?
119
+ response = connection[id].put(formatted_payload)
120
+ else
121
+ response = connection.post(formatted_payload)
122
+ end
123
+
124
+ self.attributes = parse_api_json(response).first
125
+ return true
126
+ rescue Mailjet::ApiError => e
127
+ if e.code.to_s == "304"
128
+ return true # When you save a record twice it should not raise error
129
+ else
130
+ raise e
131
+ end
132
+ end
133
+
134
+ def save!
135
+ save || raise(StandardError.new("Resource not persisted"))
136
+ end
137
+
138
+ def attributes=(attribute_hash = {})
139
+ attribute_hash.each do |attribute_name, value|
140
+ self.send("#{attribute_name}=", value)
141
+ end
142
+ end
143
+
144
+ def update_attributes(attribute_hash = {})
145
+ self.attributes = attribute_hash
146
+ save
147
+ end
148
+
149
+ def delete
150
+ self.class.delete(id)
151
+ end
152
+
153
+ private
154
+
155
+ def connection
156
+ self.class.connection
157
+ end
158
+
159
+ def formatted_payload
160
+ payload = attributes.reject { |k,v| v.blank? }
161
+ payload = payload.slice(*properties)
162
+ payload = camelcase_keys(payload)
163
+ payload.inject({}) do |h, (k, v)|
164
+ v = v.utc.as_json if v.respond_to? :utc
165
+ h.merge!({k => v})
166
+ end
167
+ end
168
+
169
+ def camelcase_keys(hash)
170
+ self.class.camelcase_keys(hash)
171
+ end
172
+
173
+ def underscore_keys(hash)
174
+ self.class.underscore_keys(hash)
175
+ end
176
+
177
+ def parse_api_json(response_json)
178
+ self.class.parse_api_json(response_json)
179
+ end
180
+
181
+ def method_missing(method_symbol, *arguments) #:nodoc:
182
+ method_name = method_symbol.to_s
183
+
184
+ if method_name =~ /(=|\?)$/
185
+ case $1
186
+ when "="
187
+ attributes[$`] = arguments.first
188
+ when "?"
189
+ attributes[$`]
190
+ end
191
+ else
192
+ return attributes[method_name] if attributes.include?(method_name)
193
+ # not set right now but we know about it
194
+ # return nil if known_attributes.include?(method_name)
195
+ super
196
+ end
197
+ end
198
+ end
199
+ end