express_pigeon 2.0.2 → 2.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/.hound.yml +3 -0
  4. data/CHANGELOG.md +15 -0
  5. data/CONTRIBUTING.md +9 -0
  6. data/Gemfile +1 -0
  7. data/Guardfile +2 -36
  8. data/README.md +57 -0
  9. data/lib/express_pigeon/auto_responders.rb +70 -0
  10. data/lib/express_pigeon/campaigns.rb +120 -0
  11. data/lib/express_pigeon/contacts.rb +15 -4
  12. data/lib/express_pigeon/messages.rb +83 -0
  13. data/lib/express_pigeon/templates.rb +24 -0
  14. data/lib/express_pigeon/version.rb +1 -1
  15. data/lib/express_pigeon.rb +4 -11
  16. data/spec/lib/express_pigeon/auto_responders_spec.rb +2 -0
  17. data/spec/lib/express_pigeon/campaigns_spec.rb +2 -0
  18. data/spec/{express_pigeon → lib/express_pigeon}/contacts_spec.rb +0 -0
  19. data/spec/{express_pigeon → lib/express_pigeon}/lists_spec.rb +0 -0
  20. data/spec/lib/express_pigeon/messages_spec.rb +37 -0
  21. data/spec/lib/express_pigeon/templates_spec.rb +43 -0
  22. data/spec/spec_helper.rb +3 -18
  23. data.tar.gz.sig +2 -2
  24. metadata +19 -22
  25. metadata.gz.sig +0 -0
  26. data/lib/express_pigeon/api/campaigns.rb +0 -62
  27. data/lib/express_pigeon/api/contacts.rb +0 -42
  28. data/lib/express_pigeon/api/lists.rb +0 -49
  29. data/lib/express_pigeon/api/messages.rb +0 -56
  30. data/lib/express_pigeon/api.rb +0 -66
  31. data/lib/express_pigeon/autoresponders.rb +0 -0
  32. data/lib/express_pigeon/meta_hash.rb +0 -20
  33. data/lib/express_pigeon/transactional_emails.rb +0 -4
  34. data/spec/express_pigeon/api/campaigns_spec.rb +0 -100
  35. data/spec/express_pigeon/api/contacts_spec.rb +0 -146
  36. data/spec/express_pigeon/api/lists_spec.rb +0 -23
  37. data/spec/express_pigeon/api/messages_spec.rb +0 -36
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4fff3380b88a30f5b07051dc8706bd011766c76c
4
- data.tar.gz: 7054faf25d532a29f68e927b73572b45b3baa033
3
+ metadata.gz: dec6639b9221476fba9c7129782bcafcd0f8865d
4
+ data.tar.gz: 013b35a5e0fd1c7d6649a7bfb8e9419c148cb849
5
5
  SHA512:
6
- metadata.gz: c0c5c02f47cbd144e218ddbd0c3dfdf429aeba130b3c5c204b14c42cf8a9774945359f0c3b2585c0ee00b9aea952cfff88268feff14625984f2240382631361d
7
- data.tar.gz: ac4bd28632697812bb4135f425314bf63931464c7d253aea717e6ce939ab552c639592b7a2354112f69e286d6f152b98ea81200926b635e93a40881fbc57062b
6
+ metadata.gz: 0179a1e751bb4a2724e2ba5235bf55fb40df81e11c9783c084770748f8014ec3d9f8844ebb2eb0857e4434eee2d38ea19637f577200cca0ea3e45fb01c9740bb
7
+ data.tar.gz: 2f67667b090857f6a0c793271879262d9a438a5258ea7a7c35f6603a285165b44f96ad5c492773affa5cb701e54067c0e0ee17211aef6ab588e5f2f8b7d9b8e8
checksums.yaml.gz.sig CHANGED
Binary file
data/.hound.yml ADDED
@@ -0,0 +1,3 @@
1
+ ruby:
2
+ enabled: true
3
+ config_file: config/.rubocop.yml
data/CHANGELOG.md ADDED
@@ -0,0 +1,15 @@
1
+ # 2.4.0
2
+
3
+ - Added AutoResponders
4
+
5
+ # 2.3.0
6
+
7
+ - Added Campaigns
8
+
9
+ # 2.2.0
10
+
11
+ - Added Messages aka Transactional Emails
12
+
13
+ # 2.1.0
14
+
15
+ - Added Templates
data/CONTRIBUTING.md CHANGED
@@ -3,6 +3,15 @@
3
3
  **DO _NOT_ RUN THE SPECS AGAINST YOUR PRODUCTION ACCOUNT. THEY ARE INTEGRATION TESTS AND WILL CREATE LISTS, CONTACTS, ETC INSIDE YOUR ACCOUNT.**
4
4
 
5
5
  - Create a "dummy" account on [https://expresspigeon.com](https://expresspigeon.com).
6
+
7
+ [![Create the test template](https://www.evernote.com/shard/s13/sh/75e1cdd7-456f-428a-8277-dba816463ac5/f831f96b6fe134bbd365fe979b4e7f10/deep/0/ExpressPigeon---Newsletters.png)](https://expresspigeon.com/newsletters/)
8
+
9
+ [![Configure the test template](https://www.evernote.com/shard/s13/sh/5748e40d-5620-4452-953d-36f874a69863/8fb550e3544c1ee94309c5ba45bf85a5/deep/0/ExpressPigeon---Create-Edit-Newsletter.png)](https://expresspigeon.com/newsletters/)
10
+
11
+ [![Extract the template id](https://www.evernote.com/shard/s13/sh/98ab5e45-df3d-4650-bbbb-95017b167453/f68c2c0e7158c358fe58a652aad30300/deep/0/Screenshot-12-26-14,-10-22-AM.png)](https://expresspigeon.com/newsletters/)
12
+
13
+ - Set the `TEST_TEMPLATE_ID` to the example newsletter template id.
14
+
6
15
  - Create three custom_fields on the account.
7
16
  - `my_custom_text_field` as `text` (no default)
8
17
  - `my_custom_number_field` as `number` (no default)
data/Gemfile CHANGED
@@ -8,6 +8,7 @@ group :development do
8
8
  gem 'pry-byebug'
9
9
 
10
10
  gem 'rubocop'
11
+ gem 'bundler-audit'
11
12
 
12
13
  gem 'colorize'
13
14
  end
data/Guardfile CHANGED
@@ -1,49 +1,15 @@
1
- # A sample Guardfile
2
- # More info at https://github.com/guard/guard#readme
3
-
4
- ## Uncomment and set this to only include directories you want to watch
5
- directories %w(. lib spec)
6
-
7
- ## Uncomment to clear the screen before every task
1
+ directories %w(. lib lib/express_pigeon spec spec/lib spec/lib/express_pigeon)
8
2
  clearing :on
9
3
 
10
- ## Make Guard exit when config is changed so it can be restarted
11
- #
12
- ## Note: if you want Guard to automatically start up again, run guard in a
13
- ## shell loop, e.g.:
14
- #
15
- # $ while bundle exec guard; do echo "Restarting Guard..."; done
16
- #
17
- ## Note: if you are using the `directories` clause above and you are not
18
- ## watching the project directory ('.'), the you will want to move the Guardfile
19
- ## to a watched dir and symlink it back, e.g.
20
- #
21
- # $ mkdir config
22
- # $ mv Guardfile config/
23
- # $ ln -s config/Guardfile .
24
- #
25
- # and, you'll have to watch "config/Guardfile" instead of "Guardfile"
26
- #
27
4
  watch ('Guardfile') do
28
5
  UI.info 'Exiting because Guard must be restarted for changes to take effect'
29
6
  exit 0
30
7
  end
31
8
 
32
- # Note: The cmd option is now required due to the increasing number of ways
33
- # rspec may be run, below are examples of the most common uses.
34
- # * bundler: 'bundle exec rspec'
35
- # * bundler binstubs: 'bin/rspec'
36
- # * spring: 'bin/rspec' (This will use spring if running and you have
37
- # installed the spring binstubs per the docs)
38
- # * zeus: 'zeus rspec' (requires the server to be started separately)
39
- # * 'just' rspec: 'rspec'
40
-
41
- guard :rspec, cmd: 'bundle exec rspec' do
9
+ guard :rspec, cmd: 'bundle exec rspec --warnings' do
42
10
  require 'guard/rspec/dsl'
43
11
  dsl = Guard::RSpec::Dsl.new(self)
44
12
 
45
- # Feel free to open issues for suggestions and improvements
46
-
47
13
  # RSpec files
48
14
  rspec = dsl.rspec
49
15
  watch(rspec.spec_helper) { rspec.spec_dir }
data/README.md CHANGED
@@ -1,5 +1,62 @@
1
1
  [![Build Status](https://semaphoreapp.com/api/v1/projects/3d4266af-fb45-45c5-bba9-0c5e825f3e84/316403/badge.png)](https://semaphoreapp.com/just3ws/express_pigeon)
2
2
  [![Code Climate](https://codeclimate.com/github/just3ws/express_pigeon/badges/gpa.svg)](https://codeclimate.com/github/just3ws/express_pigeon)
3
+ [![Gem Version](https://badge.fury.io/rb/express_pigeon.svg)](http://badge.fury.io/rb/express_pigeon)
4
+ [![Inline docs](http://inch-ci.org/github/just3ws/express_pigeon.svg?branch=master&style=flat)](http://inch-ci.org/github/just3ws/express_pigeon)
3
5
  [![Test Coverage](https://codeclimate.com/github/just3ws/express_pigeon/badges/coverage.svg)](https://codeclimate.com/github/just3ws/express_pigeon)
4
6
 
5
7
  Another Ruby client for ExpressPigeon.
8
+
9
+ [![If you ignore the CONTRIBUTING.md then you're going to have a bad time.](https://d8izdk6bl4gbi.cloudfront.net/https://d1015h9unskp4y.cloudfront.net/attachments/ea8fd905-5069-4377-abbb-9013db3f4507/CONTRIBUTING.jpg)](https://github.com/just3ws/express_pigeon/blob/master/CONTRIBUTING.md)
10
+
11
+ # ExpressPigeon API Endpoints
12
+
13
+ ## Implemented
14
+
15
+ ### ExpressPigeon::Contacts
16
+
17
+ - `#create` **POST** `https://api.expresspigeon.com/contacts`
18
+ - `#delete` **DELETE** `https://api.expresspigeon.com/contacts`
19
+ - `#find` **GET** `https://api.expresspigeon.com/contacts`
20
+ - `#move` **POST** `https://api.expresspigeon.com/contacts/move`
21
+
22
+ ### ExpressPigeon::Lists
23
+
24
+ - `#create` **POST** `https://api.expresspigeon.com/lists`
25
+ - `#delete` **DELETE** `https://api.expresspigeon.com/lists/{id}`
26
+ - `#download_csv` **GET** `https://api.expresspigeon.com/lists/{list_id}/csv`
27
+ - `#index` **GET** `https://api.expresspigeon.com/lists`
28
+ - `#update` **PUT** `https://api.expresspigeon.com/lists`
29
+ - `#upload_status` **GET** `https://api.expresspigeon.com/lists/upload_status/{id}`
30
+ - `#upload` **POST** `https://api.expresspigeon.com/lists/{id}/upload`
31
+
32
+ ### ExpressPigeon::Messages
33
+
34
+ - `#send` **POST** `https://api.expresspigeon.com/messages`
35
+ - `#status` **GET** `https://api.expresspigeon.com/messages/{id}`
36
+ - `#statuses` **GET** `https://api.expresspigeon.com/messages`
37
+
38
+ ### ExpressPigeon::Templates
39
+
40
+ - `#copy` **POST** `https://api.expresspigeon.com/templates/{template_id}/copy`
41
+
42
+ ### ExpressPigeon::Campaigns
43
+
44
+ - `#create` **POST** `https://api.expresspigeon.com/campaigns`
45
+ - `#index` **GET** `https://api.expresspigeon.com/campaigns`
46
+ - `#report_bounced` **GET** `https://api.expresspigeon.com/campaigns/{campaign_id}/bounced`
47
+ - `#report_clicked` **GET** `https://api.expresspigeon.com/campaigns/{campaign_id}/clicked`
48
+ - `#report_opened` **GET** `https://api.expresspigeon.com/campaigns/{campaign_id}/opened`
49
+ - `#report_spam` **GET** `https://api.expresspigeon.com/campaigns/{campaign_id}/spam`
50
+ - `#report_unsubscribed` **GET** `https://api.expresspigeon.com/campaigns/{campaign_id}/unsubscribed`
51
+ - `#report` **GET** `https://api.expresspigeon.com/campaigns/{campaign_id}`
52
+
53
+ ### ExpressPigeon::AutoResponders
54
+
55
+ - `#index` **GET** `https://api.expresspigeon.com/auto_responders`
56
+ - `#report_bounced` **GET** `https://api.expresspigeon.com/auto_responders/{auto_responder_id}/{auto_responder_part_id}/bounced`
57
+ - `#report_spam` **GET** `https://api.expresspigeon.com/auto_responders/{auto_responder_id}/{auto_responder_part_id}/unsubscribed`
58
+ - `#report_unsubscribed` **GET** `https://api.expresspigeon.com/auto_responders/{auto_responder_id}/{auto_responder_part_id}/spam`
59
+ - `#report` **GET** `https://api.expresspigeon.com/auto_responders/{auto_responder_id}`
60
+ - `#start` **POST** `https://api.expresspigeon.com/auto_responders/{auto_responder_id}/start`
61
+ - `#stop` **POST** `https://api.expresspigeon.com/auto_responders/{auto_responder_id}/stop`
62
+
@@ -0,0 +1,70 @@
1
+ module ExpressPigeon
2
+ # AutoResponders
3
+ class AutoResponders
4
+ include HTTParty
5
+ base_uri('https://api.expresspigeon.com/auto_responders')
6
+
7
+ # Get all autoresponders
8
+ #
9
+ # GET https://api.expresspigeon.com/auto_responders
10
+ def index
11
+ self.class.get('')
12
+ end
13
+
14
+ # Start for a contact
15
+ #
16
+ # POST https://api.expresspigeon.com/auto_responders/{auto_responder_id}/start
17
+ def start(auto_responder_id, email_address)
18
+ options = {}
19
+ options['email'] = email_address
20
+
21
+ self.class.post(
22
+ "/#{auto_responder_id}/start",
23
+ body: options.to_json,
24
+ headers: { 'Content-Type' => 'application/json' }
25
+ )
26
+ end
27
+
28
+ # Stop for a contact
29
+ #
30
+ # POST https://api.expresspigeon.com/auto_responders/{auto_responder_id}/stop
31
+ def stop(auto_responder_id, email_address)
32
+ options = {}
33
+ options['email'] = email_address
34
+
35
+ self.class.post(
36
+ "/#{auto_responder_id}/stop",
37
+ body: options.to_json,
38
+ headers: { 'Content-Type' => 'application/json' }
39
+ )
40
+ end
41
+
42
+ # Report for a single autoresponder
43
+ #
44
+ # GET https://api.expresspigeon.com/auto_responders/{auto_responder_id}
45
+ def report(auto_responder_id)
46
+ self.class.get("/#{auto_responder_id}")
47
+ end
48
+
49
+ # Get bounced contacts for autoresponder part
50
+ #
51
+ # GET https://api.expresspigeon.com/auto_responders/{auto_responder_id} /{auto_responder_part_id}/bounced
52
+ def report_bounced(auto_responder_id, auto_responder_part_id)
53
+ self.class.get("/#{auto_responder_id}/#{auto_responder_part_id}/bounced")
54
+ end
55
+
56
+ # Get unsubscribed contacts for autoresponder part
57
+ #
58
+ # GET https://api.expresspigeon.com/auto_responders/{auto_responder_id} /{auto_responder_part_id}/unsubscribed
59
+ def report_unsubscribed(auto_responder_id, auto_responder_part_id)
60
+ self.class.get("/#{auto_responder_id}/#{auto_responder_part_id}/unsubscribed")
61
+ end
62
+
63
+ # Get spam contacts for autoresponder part
64
+ #
65
+ # GET https://api.expresspigeon.com/auto_responders/{auto_responder_id} /{auto_responder_part_id}/spam
66
+ def report_spam(auto_responder_id, auto_responder_part_id)
67
+ self.class.get("/#{auto_responder_id}/#{auto_responder_part_id}/spam")
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,120 @@
1
+ module ExpressPigeon
2
+ # Campaigns
3
+ #
4
+ # Campaign API provides the same service as sending email campaigns from the
5
+ # website. A campaign consists of newsletter template, subject, from name,
6
+ # reply to, and a lists of contacts a campaign can be sent to.
7
+ class Campaigns
8
+ include HTTParty
9
+ base_uri('https://api.expresspigeon.com/campaigns')
10
+ debug_output($stderr)
11
+
12
+ # Campaigns creation
13
+ #
14
+ # POST https://api.expresspigeon.com/campaigns
15
+ #
16
+ # list_id: The id of a list the campaign is sent to. The list must
17
+ # be enabled.
18
+ # template_id: The id of a newsletter template used for the campaign.
19
+ # name: The name of a campaign. This name is for your reference
20
+ # only and will not be exposed to your audience. If you
21
+ # have Google Analytics turned on, this value will also be
22
+ # used for Google Analytics campaign.
23
+ # from_name: This parameter is displayed as "From" field in the email
24
+ # program when your recipients view your message. Use this
25
+ # value to clearly state your name or name of your organization.
26
+ # reply_to: This parameter specifies the email address which will
27
+ # be getting replies from your recipients should they
28
+ # choose to reply. The reply_to should be a valid email address.
29
+ # subject: The subject of a newsletter
30
+ # google_analytics: Indicates whether Google Analytics should be enabled
31
+ # for a campaign. Should be true or false.
32
+ # schedule_for: Specifies what time a campaign should be sent. If it
33
+ # is provided the campaign will be scheduled to this time,
34
+ # otherwise campaign is sent immediately. The schedule_for
35
+ # must be in ISO date format and should be in the future.
36
+ def create(list_id, template_id, name:, from_name:, reply_to:, subject:, google_analytics:, schedule_for: nil)
37
+ options = {}
38
+ options['list_id'] = list_id
39
+ options['template_id'] = template_id
40
+ options['name'] = name
41
+ options['from_name'] = from_name
42
+ options['reply_to'] = reply_to
43
+ options['subject'] = subject
44
+ options['google_analytics'] = google_analytics
45
+ options['schedule_for'] = schedule_for unless schedule_for.nil?
46
+
47
+ self.class.post(
48
+ '',
49
+ body: options.to_json,
50
+ headers: { 'Content-Type' => 'application/json' }
51
+ )
52
+ end
53
+
54
+ # List campaigns
55
+ #
56
+ # GET https://api.expresspigeon.com/campaigns
57
+ #
58
+ # Returns a list of at most 1000 created campaigns, to get the next batch use from_id parameter.
59
+ #
60
+ # from_id: id from where to get the next batch,
61
+ # e.g. the last id from the previous call
62
+ # from: start of the sending period
63
+ # (UTC, example: 2013-03-16T10:00:00.000+0000)
64
+ # to: end of the sending period
65
+ # (UTC, example: 2013-03-16T20:00:00.000+0000)
66
+ def index(from_id: nil, from: nil, to: nil)
67
+ options = {}
68
+ options['from_id'] = from_id unless from_id.nil?
69
+ options['from'] = from unless from.nil?
70
+ options['to'] = to unless to.nil?
71
+
72
+ self.class.get(
73
+ '',
74
+ query: options
75
+ )
76
+ end
77
+
78
+ # Report for a single campaign
79
+ #
80
+ # GET https://api.expresspigeon.com/campaigns/{campaign_id}
81
+ def report(campaign_id)
82
+ self.class.get("/#{campaign_id}")
83
+ end
84
+
85
+ # Get opened events for campaign
86
+ #
87
+ # GET https://api.expresspigeon.com/campaigns/{campaign_id}/opened
88
+ def report_opened(campaign_id)
89
+ self.class.get("/#{campaign_id}/opened")
90
+ end
91
+
92
+ # Get clicked events for campaign
93
+ #
94
+ # GET https://api.expresspigeon.com/campaigns/{campaign_id}/clicked
95
+ def report_clicked(campaign_id)
96
+ self.class.get("/#{campaign_id}/clicked")
97
+ end
98
+
99
+ # Get bounced contacts for campaign
100
+ #
101
+ # GET https://api.expresspigeon.com/campaigns/{campaign_id}/bounced
102
+ def report_bounced(campaign_id)
103
+ self.class.get("/#{campaign_id}/bounced")
104
+ end
105
+
106
+ # Get unsubscribed contacts for campaign
107
+ #
108
+ # GET https://api.expresspigeon.com/campaigns/{campaign_id}/unsubscribed
109
+ def report_unsubscribed(campaign_id)
110
+ self.class.get("/#{campaign_id}/unsubscribed")
111
+ end
112
+
113
+ # Get spam contacts for campaign
114
+ #
115
+ # GET https://api.expresspigeon.com/campaigns/{campaign_id}/spam
116
+ def report_spam(campaign_id)
117
+ self.class.get("/#{campaign_id}/spam")
118
+ end
119
+ end
120
+ end
@@ -35,9 +35,7 @@ module ExpressPigeon
35
35
  self.class.post(
36
36
  '/',
37
37
  body: options.to_json,
38
- headers: {
39
- 'Content-Type' => 'application/json'
40
- }
38
+ headers: { 'Content-Type' => 'application/json' }
41
39
  )
42
40
  end
43
41
  alias_method :update, :create
@@ -45,7 +43,20 @@ module ExpressPigeon
45
43
  # Delete a single contact
46
44
  #
47
45
  # DELETE https://api.expresspigeon.com/contacts
48
- def delete(_email_address)
46
+ #
47
+ # email: contact email to be deleted
48
+ # list_id: list id to remove contact from, if not provided contact will
49
+ # be deleted from system.
50
+ def delete(email_address, list_id: nil)
51
+ options = {}
52
+ options['email'] = email_address
53
+ options['list_id'] = list_id unless list_id.nil?
54
+
55
+ self.class.delete(
56
+ '',
57
+ body: options.to_json,
58
+ headers: { 'Content-Type' => 'application/json' }
59
+ )
49
60
  end
50
61
 
51
62
  # Move contacts between lists
@@ -0,0 +1,83 @@
1
+ module ExpressPigeon
2
+ # Messages
3
+ #
4
+ # Sending Transactional emails requires that newsletter templates for these
5
+ # emails are created prior to sending. Such template can have merge fields,
6
+ # in a format ${field_name}. This feature allows a high degree of flexibility
7
+ # for message customization.
8
+ #
9
+ # The newsletter to be sent can have a number of merge fields, with data for
10
+ # merging dynamically provided during a call.
11
+ class Messages
12
+ include HTTParty
13
+ base_uri('https://api.expresspigeon.com/messages')
14
+ debug_output(nil)
15
+
16
+ def initialize(auth_key)
17
+ self.class.headers('X-auth-key' => auth_key)
18
+ end
19
+
20
+ # Sending a single transactional email
21
+ #
22
+ # POST https://api.expresspigeon.com/messages
23
+ #
24
+ # template_id: newsletter template id to be sent
25
+ # to: email address to send message to
26
+ # reply_to: email address tp reply to
27
+ # from: from name, such as your name or name of your organization
28
+ # subject: email message subject
29
+ # merge_fields: values for merge fields
30
+ # view_online: generates online version of sent message. We will host
31
+ # this generated message on our servers, default is false
32
+ # click_tracking: overwrites all URLs in email to point to
33
+ # http://clicks.expresspigeon.com for click tracking.
34
+ # Setting it to false will preserve all URLs intact, but
35
+ # click tracking will not be available, default is true
36
+ # suppress_address: if true suppresses insertion of sender's physical
37
+ # address in the email, default is false
38
+ def send(template_id, to:, reply_to:, from:, subject:, merge_fields: {}, view_online: nil, click_tracking: nil, suppress_address: nil)
39
+ options = {}
40
+ options['template_id'] = template_id
41
+ options['to'] = to
42
+ options['from'] = from
43
+ options['reply_to'] = reply_to
44
+ options['subject'] = subject
45
+ options['merge_fields'] = merge_fields unless merge_fields.empty?
46
+ options['view_online'] = view_online unless view_online.nil?
47
+ options['click_tracking'] = click_tracking unless click_tracking.nil?
48
+ options['suppress_address'] = suppress_address unless suppress_address.nil?
49
+
50
+ self.class.post(
51
+ '',
52
+ body: options.to_json,
53
+ headers: { 'Content-Type' => 'application/json' }
54
+ )
55
+ end
56
+
57
+ # Report for a single message
58
+ #
59
+ # GET https://api.expresspigeon.com/messages/{id}
60
+ def status(message_id)
61
+ # NOTE: This appears to be sending a valid request but the response
62
+ # can contain many status reports. The intent seems to be to
63
+ # only return the status report for the id requested. We'll pass
64
+ # along the full response for now.
65
+ self.class.get('', query: { 'id' => message_id })
66
+ end
67
+
68
+ REPORTING_PERIODS = %i(last24hours last_week last_month)
69
+
70
+ # Report for multiple messages
71
+ #
72
+ # GET https://api.expresspigeon.com/messages
73
+ def statuses(from_id: nil, start_date: nil, end_date: nil, period: nil)
74
+ options = {}
75
+ options['from_id'] = from_id unless from_id.nil?
76
+ options['start_date'] = start_date unless start_date.nil?
77
+ options['end_date'] = end_date unless end_date.nil?
78
+ options['period'] = period unless period.nil?
79
+
80
+ self.class.get('', query: options)
81
+ end
82
+ end
83
+ end
@@ -1,4 +1,28 @@
1
1
  module ExpressPigeon
2
+ # Templates
2
3
  class Templates
4
+ include HTTParty
5
+ base_uri('https://api.expresspigeon.com/templates')
6
+ debug_output(nil)
7
+
8
+ def initialize(auth_key)
9
+ self.class.headers('X-auth-key' => auth_key)
10
+ end
11
+
12
+ # Copy template
13
+ #
14
+ # POST https://api.expresspigeon.com/templates/{template_id}/copy
15
+ #
16
+ # NOTE: It is important to use only single quotes in injected HTML
17
+ def copy(template_id, name:, merge_fields: {})
18
+ self.class.post(
19
+ "/#{template_id}/copy",
20
+ body: {
21
+ name: name,
22
+ merge_fields: merge_fields
23
+ }.to_json,
24
+ headers: { 'Content-Type' => 'application/json' }
25
+ )
26
+ end
3
27
  end
4
28
  end
@@ -1,3 +1,3 @@
1
1
  module ExpressPigeon
2
- VERSION = '2.0.2'.freeze
2
+ VERSION = '2.4.0'.freeze
3
3
  end
@@ -1,23 +1,16 @@
1
- require 'awesome_print'
2
-
3
- # require 'net/http'
4
1
  require 'json'
5
- # require 'uri'
6
2
 
7
3
  require 'httparty'
8
4
  require 'httmultiparty'
9
5
 
10
6
  require 'express_pigeon/version'
11
7
 
12
- require 'express_pigeon/lists'
8
+ require 'express_pigeon/auto_responders'
9
+ require 'express_pigeon/campaigns'
13
10
  require 'express_pigeon/contacts'
14
- require 'express_pigeon/transactional_emails'
11
+ require 'express_pigeon/lists'
12
+ require 'express_pigeon/messages'
15
13
  require 'express_pigeon/templates'
16
- require 'express_pigeon/autoresponders'
17
-
18
- AUTH_KEY = ENV['EXPRESS_PIGEON_AUTH_KEY']
19
- ROOT = 'https://api.expresspigeon.com/'
20
- USE_SSL = true
21
14
 
22
15
  module ExpressPigeon
23
16
  end
@@ -0,0 +1,2 @@
1
+ RSpec.describe ExpressPigeon::AutoResponders do
2
+ end
@@ -0,0 +1,2 @@
1
+ RSpec.describe ExpressPigeon::Campaigns do
2
+ end
@@ -0,0 +1,37 @@
1
+ RSpec.describe ExpressPigeon::Messages do
2
+ let(:auth_key) { ENV['EXPRESS_PIGEON_AUTH_KEY'] }
3
+ let(:client) { ExpressPigeon::Messages.new(auth_key) }
4
+ let(:test_template_id) { Integer(ENV['TEST_TEMPLATE_ID']) }
5
+
6
+ it 'sends a transactional email and gets a status report' do
7
+ response = client.send(
8
+ test_template_id,
9
+ to: 'mike+to@just3ws.com',
10
+ from: 'mike+from@just3ws',
11
+ reply_to: 'mike+reply_to@just3ws.com',
12
+ subject: 'Test sending EP transactional emails',
13
+ merge_fields: { 'test_merge_field' => 'sending transactional email via EP' })
14
+
15
+ expect(response['code']).to eq(200)
16
+ expect(response['message']).to eq('email queued')
17
+ message_id = response['id']
18
+ expect(message_id).to be_a(Fixnum)
19
+
20
+ # NOTE: Check the Inbox you configured for you Sandbox account to see the
21
+ # actual email as it was sent.
22
+
23
+ # cheating in specs and piggy-backing to test the status[es] requests
24
+
25
+ response = client.status(message_id)
26
+ expect(response.code).to eq(200)
27
+ report = response.select { |report| report['id'] == message_id }
28
+ expect(report.length).to eq(1)
29
+ expect(report.first['id']).to eq(message_id)
30
+
31
+ response = client.statuses(from_id: message_id - 1)
32
+ expect(response.code).to eq(200)
33
+ report = response.select { |report| report['id'] == message_id }
34
+ expect(report.length).to eq(1)
35
+ expect(report.first['id']).to eq(message_id)
36
+ end
37
+ end
@@ -0,0 +1,43 @@
1
+ RSpec.describe ExpressPigeon::Templates do
2
+ # WARN: This test requires setting up a template to use as the baseline for
3
+ # copying templates. You can use any existing template or create new
4
+ # template from scratch.
5
+ #
6
+ # Once you've selected a template to use check the URL for the template
7
+ # and extract the TEMPLATE_ID and update the `.env` file TEST_TEMPLATE_ID.
8
+ #
9
+ # Example:
10
+ #
11
+ # Given the URL `https://expresspigeon.com/newsletters/compose/26013`
12
+ # Then the .env file should be set to TEST_TEMPLATE_ID=26013
13
+ #
14
+ # You will need to clean up templates created by this test manually
15
+ # as the API doesn't support deleting templates at this time
16
+ #
17
+
18
+ let(:auth_key) { ENV['EXPRESS_PIGEON_AUTH_KEY'] }
19
+ let(:client) { ExpressPigeon::Templates.new(auth_key) }
20
+
21
+ let(:test_template_id) { Integer(ENV['TEST_TEMPLATE_ID']) }
22
+
23
+ it 'copies an existing template' do
24
+ response = client.copy(test_template_id, name: 'TEST copied template', merge_fields: {
25
+ test_merge_field: 'Hello, World!'
26
+ })
27
+
28
+ # NOTE: Since we can't see the actual merge result you'll need to log in
29
+ # to your ExpressPigeon account and check the result of the merge.
30
+
31
+ expect(response['code']).to eq(200)
32
+
33
+ # If this fails then check the response. We're dependant on the behavior
34
+ # of the env for this expectation. If we run the test multiple times then
35
+ # the autoincrement for the TEMPLATE_ID is offset further. Right now just
36
+ # expect it to be an integer greater than the initial template id.
37
+ expect(response['template_id']).to be_a(Integer)
38
+ next_template_id = Integer(response['template_id'])
39
+ expect(next_template_id).to be > test_template_id
40
+
41
+ expect(response['message']).to eq('template copied successfully')
42
+ end
43
+ end