createsend-sendowlfork 6.1.0.pre.hashie5

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 (139) hide show
  1. checksums.yaml +7 -0
  2. data/.coveralls.yml +1 -0
  3. data/.gitignore +9 -0
  4. data/.travis.yml +7 -0
  5. data/CONTRIBUTING.md +8 -0
  6. data/Gemfile +3 -0
  7. data/HISTORY.md +299 -0
  8. data/LICENSE +19 -0
  9. data/README.md +220 -0
  10. data/RELEASE.md +53 -0
  11. data/Rakefile +24 -0
  12. data/createsend.gemspec +31 -0
  13. data/lib/createsend/administrator.rb +49 -0
  14. data/lib/createsend/cacert.pem +3849 -0
  15. data/lib/createsend/campaign.rb +202 -0
  16. data/lib/createsend/client.rb +224 -0
  17. data/lib/createsend/createsend.rb +291 -0
  18. data/lib/createsend/journey.rb +58 -0
  19. data/lib/createsend/list.rb +258 -0
  20. data/lib/createsend/person.rb +59 -0
  21. data/lib/createsend/segment.rb +81 -0
  22. data/lib/createsend/subscriber.rb +113 -0
  23. data/lib/createsend/template.rb +42 -0
  24. data/lib/createsend/transactional_classic_email.rb +32 -0
  25. data/lib/createsend/transactional_smart_email.rb +31 -0
  26. data/lib/createsend/transactional_timeline.rb +45 -0
  27. data/lib/createsend/version.rb +3 -0
  28. data/lib/createsend.rb +17 -0
  29. data/samples/authentication_sample.rb +64 -0
  30. data/samples/clients_sample.rb +79 -0
  31. data/samples/journey_sample.rb +87 -0
  32. data/samples/lists_sample.rb +51 -0
  33. data/samples/segments_sample.rb +21 -0
  34. data/samples/subscribers_sample.rb +51 -0
  35. data/test/administrator_test.rb +37 -0
  36. data/test/campaign_test.rb +296 -0
  37. data/test/client_test.rb +253 -0
  38. data/test/createsend_test.rb +321 -0
  39. data/test/fixtures/active_subscribers.json +87 -0
  40. data/test/fixtures/add_admin.json +3 -0
  41. data/test/fixtures/add_person.json +3 -0
  42. data/test/fixtures/add_subscriber.json +1 -0
  43. data/test/fixtures/admin_details.json +5 -0
  44. data/test/fixtures/admin_get_primary_contact.json +3 -0
  45. data/test/fixtures/admin_set_primary_contact.json +3 -0
  46. data/test/fixtures/administrators.json +12 -0
  47. data/test/fixtures/billingdetails.json +3 -0
  48. data/test/fixtures/bounced_subscribers.json +20 -0
  49. data/test/fixtures/campaign_bounces.json +25 -0
  50. data/test/fixtures/campaign_clicks.json +50 -0
  51. data/test/fixtures/campaign_listsandsegments.json +15 -0
  52. data/test/fixtures/campaign_opens.json +71 -0
  53. data/test/fixtures/campaign_recipients.json +91 -0
  54. data/test/fixtures/campaign_spam.json +16 -0
  55. data/test/fixtures/campaign_summary.json +16 -0
  56. data/test/fixtures/campaign_unsubscribes.json +17 -0
  57. data/test/fixtures/campaigns.json +37 -0
  58. data/test/fixtures/client_details.json +28 -0
  59. data/test/fixtures/client_get_primary_contact.json +3 -0
  60. data/test/fixtures/client_set_primary_contact.json +3 -0
  61. data/test/fixtures/clients.json +10 -0
  62. data/test/fixtures/countries.json +247 -0
  63. data/test/fixtures/create_campaign.json +1 -0
  64. data/test/fixtures/create_client.json +1 -0
  65. data/test/fixtures/create_custom_field.json +1 -0
  66. data/test/fixtures/create_list.json +1 -0
  67. data/test/fixtures/create_list_webhook.json +1 -0
  68. data/test/fixtures/create_segment.json +1 -0
  69. data/test/fixtures/create_template.json +1 -0
  70. data/test/fixtures/custom_api_error.json +4 -0
  71. data/test/fixtures/custom_fields.json +23 -0
  72. data/test/fixtures/deleted_subscribers.json +61 -0
  73. data/test/fixtures/drafts.json +26 -0
  74. data/test/fixtures/email_client_usage.json +38 -0
  75. data/test/fixtures/expired_oauth_token_api_error.json +4 -0
  76. data/test/fixtures/external_session.json +3 -0
  77. data/test/fixtures/import_subscribers.json +7 -0
  78. data/test/fixtures/import_subscribers_partial_success.json +17 -0
  79. data/test/fixtures/invalid_oauth_token_api_error.json +4 -0
  80. data/test/fixtures/journey_bounces.json +35 -0
  81. data/test/fixtures/journey_clicks.json +35 -0
  82. data/test/fixtures/journey_opens.json +55 -0
  83. data/test/fixtures/journey_recipients.json +27 -0
  84. data/test/fixtures/journey_summary.json +18 -0
  85. data/test/fixtures/journey_unsubscribes.json +26 -0
  86. data/test/fixtures/journeys.json +20 -0
  87. data/test/fixtures/list_details.json +8 -0
  88. data/test/fixtures/list_stats.json +26 -0
  89. data/test/fixtures/list_webhooks.json +18 -0
  90. data/test/fixtures/lists.json +10 -0
  91. data/test/fixtures/listsforemail.json +14 -0
  92. data/test/fixtures/oauth_exchange_token.json +5 -0
  93. data/test/fixtures/oauth_exchange_token_error.json +4 -0
  94. data/test/fixtures/oauth_refresh_token_error.json +4 -0
  95. data/test/fixtures/people.json +14 -0
  96. data/test/fixtures/person_details.json +6 -0
  97. data/test/fixtures/refresh_oauth_token.json +5 -0
  98. data/test/fixtures/revoked_oauth_token_api_error.json +4 -0
  99. data/test/fixtures/scheduled_campaigns.json +30 -0
  100. data/test/fixtures/segment_details.json +24 -0
  101. data/test/fixtures/segment_subscribers.json +27 -0
  102. data/test/fixtures/segments.json +12 -0
  103. data/test/fixtures/subscriber_details.json +23 -0
  104. data/test/fixtures/subscriber_details_with_track_and_sms_pref.json +25 -0
  105. data/test/fixtures/subscriber_history.json +45 -0
  106. data/test/fixtures/suppressionlist.json +41 -0
  107. data/test/fixtures/systemdate.json +3 -0
  108. data/test/fixtures/tags.json +10 -0
  109. data/test/fixtures/template_details.json +6 -0
  110. data/test/fixtures/templates.json +14 -0
  111. data/test/fixtures/timezones.json +99 -0
  112. data/test/fixtures/transfer_credits.json +4 -0
  113. data/test/fixtures/tx_classicemail_groups.json +14 -0
  114. data/test/fixtures/tx_message_details.json +36 -0
  115. data/test/fixtures/tx_message_details_with_statistics.json +72 -0
  116. data/test/fixtures/tx_messages.json +38 -0
  117. data/test/fixtures/tx_messages_classic.json +15 -0
  118. data/test/fixtures/tx_messages_smart.json +15 -0
  119. data/test/fixtures/tx_resend_message.json +6 -0
  120. data/test/fixtures/tx_send_multiple.json +12 -0
  121. data/test/fixtures/tx_send_single.json +7 -0
  122. data/test/fixtures/tx_smartemail_details.json +23 -0
  123. data/test/fixtures/tx_smartemails.json +15 -0
  124. data/test/fixtures/tx_statistics_classic.json +14 -0
  125. data/test/fixtures/tx_statistics_smart.json +14 -0
  126. data/test/fixtures/unconfirmed_subscribers.json +43 -0
  127. data/test/fixtures/unsubscribed_subscribers.json +61 -0
  128. data/test/fixtures/update_custom_field.json +1 -0
  129. data/test/helper.rb +79 -0
  130. data/test/journey_test.rb +156 -0
  131. data/test/list_test.rb +288 -0
  132. data/test/person_test.rb +39 -0
  133. data/test/segment_test.rb +74 -0
  134. data/test/subscriber_test.rb +177 -0
  135. data/test/template_test.rb +36 -0
  136. data/test/transactional_classic_email_test.rb +60 -0
  137. data/test/transactional_smart_email_test.rb +83 -0
  138. data/test/transactional_timeline_test.rb +110 -0
  139. metadata +431 -0
@@ -0,0 +1,291 @@
1
+ require 'cgi'
2
+ require 'uri'
3
+ require 'httparty'
4
+ require 'hashie'
5
+ require 'json'
6
+
7
+ module CreateSend
8
+
9
+ USER_AGENT_STRING = "createsend-ruby-#{VERSION}-#{RUBY_VERSION}-p#{RUBY_PATCHLEVEL}-#{RUBY_PLATFORM}"
10
+
11
+ # Represents a CreateSend API error. Contains specific data about the error.
12
+ class CreateSendError < StandardError
13
+ attr_reader :data
14
+ def initialize(data)
15
+ @data = data
16
+ # @data should contain Code, Message and optionally ResultData
17
+ extra = @data.ResultData ? "\nExtra result data: #{@data.ResultData}" : ""
18
+ super "The CreateSend API responded with the following error"\
19
+ " - #{@data.Code}: #{@data.Message}#{extra}"
20
+ end
21
+ end
22
+
23
+ # Raised for HTTP response codes of 400...500
24
+ class ClientError < StandardError; end
25
+ # Raised for HTTP response codes of 500...600
26
+ class ServerError < StandardError; end
27
+ # Raised for HTTP response code of 400
28
+ class BadRequest < CreateSendError; end
29
+ # Raised for HTTP response code of 401
30
+ class Unauthorized < CreateSendError; end
31
+ # Raised for HTTP response code of 404
32
+ class NotFound < ClientError; end
33
+
34
+ # Raised for HTTP response code of 401, specifically when an OAuth token
35
+ # in invalid (Code: 120, Message: 'Invalid OAuth Token')
36
+ class InvalidOAuthToken < Unauthorized; end
37
+ # Raised for HTTP response code of 401, specifically when an OAuth token
38
+ # has expired (Code: 121, Message: 'Expired OAuth Token')
39
+ class ExpiredOAuthToken < Unauthorized; end
40
+ # Raised for HTTP response code of 401, specifically when an OAuth token
41
+ # has been revoked (Code: 122, Message: 'Revoked OAuth Token')
42
+ class RevokedOAuthToken < Unauthorized; end
43
+
44
+ # Provides high level CreateSend functionality/data you'll probably need.
45
+ class CreateSend
46
+ include HTTParty
47
+ default_timeout 120
48
+
49
+ attr_reader :auth_details
50
+
51
+ # Specify cert authority file for cert validation
52
+ ssl_ca_file File.expand_path(File.join(File.dirname(__FILE__), 'cacert.pem'))
53
+
54
+ # Set a custom user agent string to be used when instances of
55
+ # CreateSend::CreateSend make API calls.
56
+ #
57
+ # user_agent - The user agent string to use in the User-Agent header when
58
+ # instances of this class make API calls. If set to nil, the
59
+ # default value of CreateSend::USER_AGENT_STRING will be used.
60
+ def self.user_agent(user_agent)
61
+ headers({'User-Agent' => user_agent || USER_AGENT_STRING})
62
+ end
63
+
64
+ # Get the authorization URL for your application, given the application's
65
+ # client_id, redirect_uri, scope, and optional state data.
66
+ def self.authorize_url(client_id, redirect_uri, scope, state=nil)
67
+ qs = "client_id=#{CGI.escape(client_id.to_s)}"
68
+ qs << "&redirect_uri=#{CGI.escape(redirect_uri.to_s)}"
69
+ qs << "&scope=#{CGI.escape(scope.to_s)}"
70
+ qs << "&state=#{CGI.escape(state.to_s)}" if state
71
+ "#{@@oauth_base_uri}?#{qs}"
72
+ end
73
+
74
+ # Exchange a provided OAuth code for an OAuth access token, 'expires in'
75
+ # value, and refresh token.
76
+ def self.exchange_token(client_id, client_secret, redirect_uri, code)
77
+ body = "grant_type=authorization_code"
78
+ body << "&client_id=#{CGI.escape(client_id.to_s)}"
79
+ body << "&client_secret=#{CGI.escape(client_secret.to_s)}"
80
+ body << "&redirect_uri=#{CGI.escape(redirect_uri.to_s)}"
81
+ body << "&code=#{CGI.escape(code.to_s)}"
82
+ options = {:body => body}
83
+ response = HTTParty.post(@@oauth_token_uri, options)
84
+ if response.has_key? 'error' and response.has_key? 'error_description'
85
+ err = "Error exchanging code for access token: "
86
+ err << "#{response['error']} - #{response['error_description']}"
87
+ raise err
88
+ end
89
+ r = Hashie::Mash.new(response)
90
+ [r.access_token, r.expires_in, r.refresh_token]
91
+ end
92
+
93
+ # Refresh an OAuth access token, given an OAuth refresh token.
94
+ # Returns a new access token, 'expires in' value, and refresh token.
95
+ def self.refresh_access_token(refresh_token)
96
+ options = {
97
+ :body => "grant_type=refresh_token&refresh_token=#{CGI.escape(refresh_token)}" }
98
+ response = HTTParty.post(@@oauth_token_uri, options)
99
+ if response.has_key? 'error' and response.has_key? 'error_description'
100
+ err = "Error refreshing access token: "
101
+ err << "#{response['error']} - #{response['error_description']}"
102
+ raise err
103
+ end
104
+ r = Hashie::Mash.new(response)
105
+ [r.access_token, r.expires_in, r.refresh_token]
106
+ end
107
+
108
+ def initialize(*args)
109
+ if args.size > 0
110
+ auth args.first # Expect auth details as first argument
111
+ end
112
+ end
113
+
114
+ @@base_uri = "https://api.createsend.com/api/v3.3"
115
+ @@oauth_base_uri = "https://api.createsend.com/oauth"
116
+ @@oauth_token_uri = "#{@@oauth_base_uri}/token"
117
+ headers({
118
+ 'User-Agent' => USER_AGENT_STRING,
119
+ 'Content-Type' => 'application/json; charset=utf-8'
120
+ })
121
+ base_uri @@base_uri
122
+
123
+ # Authenticate using either OAuth or an API key.
124
+ def auth(auth_details)
125
+ @auth_details = auth_details
126
+ end
127
+
128
+ # Refresh the current OAuth token using the current refresh token.
129
+ def refresh_token
130
+ if not @auth_details or
131
+ not @auth_details.has_key? :refresh_token or
132
+ not @auth_details[:refresh_token]
133
+ raise '@auth_details[:refresh_token] does not contain a refresh token.'
134
+ end
135
+
136
+ access_token, expires_in, refresh_token =
137
+ self.class.refresh_access_token @auth_details[:refresh_token]
138
+ auth({
139
+ :access_token => access_token,
140
+ :refresh_token => refresh_token})
141
+ [access_token, expires_in, refresh_token]
142
+ end
143
+
144
+ # Gets your clients.
145
+ def clients
146
+ response = get('/clients.json')
147
+ response.map{|item| Hashie::Mash.new(item)}
148
+ end
149
+
150
+ # Get your billing details.
151
+ def billing_details
152
+ response = get('/billingdetails.json')
153
+ Hashie::Mash.new(response)
154
+ end
155
+
156
+ # Gets valid countries.
157
+ def countries
158
+ response = get('/countries.json')
159
+ response.parsed_response
160
+ end
161
+
162
+ # Gets the current date in your account's timezone.
163
+ def systemdate
164
+ response = get('/systemdate.json')
165
+ Hashie::Mash.new(response)
166
+ end
167
+
168
+ # Gets valid timezones.
169
+ def timezones
170
+ response = get('/timezones.json')
171
+ response.parsed_response
172
+ end
173
+
174
+ # Gets the administrators for the account.
175
+ def administrators
176
+ response = get('/admins.json')
177
+ response.map{|item| Hashie::Mash.new(item)}
178
+ end
179
+
180
+ # Gets the primary contact for the account.
181
+ def get_primary_contact
182
+ response = get('/primarycontact.json')
183
+ Hashie::Mash.new(response)
184
+ end
185
+
186
+ # Set the primary contect for the account.
187
+ def set_primary_contact(email)
188
+ options = { :query => { :email => email } }
189
+ response = put("/primarycontact.json", options)
190
+ Hashie::Mash.new(response)
191
+ end
192
+
193
+ # Get a URL which initiates a new external session for the user with the
194
+ # given email.
195
+ # Full details: http://www.campaignmonitor.com/api/account/#single_sign_on
196
+ #
197
+ # email - The email address of the Campaign Monitor user for whom
198
+ # the login session should be created.
199
+ # chrome - Which 'chrome' to display - Must be either "all",
200
+ # "tabs", or "none".
201
+ # url - The URL to display once logged in. e.g. "/subscribers/"
202
+ # integrator_id - The integrator ID. You need to contact Campaign Monitor
203
+ # support to get an integrator ID.
204
+ # client_id - The Client ID of the client which should be active once
205
+ # logged in to the Campaign Monitor account.
206
+ #
207
+ # Returns An object containing a single field SessionUrl which represents
208
+ # the URL to initiate the external Campaign Monitor session.
209
+ def external_session_url(email, chrome, url, integrator_id, client_id)
210
+ options = { :body => {
211
+ :Email => email,
212
+ :Chrome => chrome,
213
+ :Url => url,
214
+ :IntegratorID => integrator_id,
215
+ :ClientID => client_id }.to_json }
216
+ response = put("/externalsession.json", options)
217
+ Hashie::Mash.new(response)
218
+ end
219
+
220
+ def get(*args)
221
+ args = add_auth_details_to_options(args)
222
+ handle_response CreateSend.get(*args)
223
+ end
224
+ alias_method :cs_get, :get
225
+
226
+ def post(*args)
227
+ args = add_auth_details_to_options(args)
228
+ handle_response CreateSend.post(*args)
229
+ end
230
+ alias_method :cs_post, :post
231
+
232
+ def put(*args)
233
+ args = add_auth_details_to_options(args)
234
+ handle_response CreateSend.put(*args)
235
+ end
236
+ alias_method :cs_put, :put
237
+
238
+ def delete(*args)
239
+ args = add_auth_details_to_options(args)
240
+ handle_response CreateSend.delete(*args)
241
+ end
242
+ alias_method :cs_delete, :delete
243
+
244
+ def add_auth_details_to_options(args)
245
+ if @auth_details
246
+ options = {}
247
+ if args.size > 1
248
+ options = args[1]
249
+ end
250
+ if @auth_details.has_key? :access_token
251
+ options[:headers] = {
252
+ "Authorization" => "Bearer #{@auth_details[:access_token]}" }
253
+ elsif @auth_details.has_key? :api_key
254
+ if not options.has_key? :basic_auth
255
+ options[:basic_auth] = {
256
+ :username => @auth_details[:api_key], :password => 'x' }
257
+ end
258
+ end
259
+ args[1] = options
260
+ end
261
+ args
262
+ end
263
+
264
+ def handle_response(response) # :nodoc:
265
+ case response.code
266
+ when 400
267
+ raise BadRequest.new(Hashie::Mash.new response)
268
+ when 401
269
+ data = Hashie::Mash.new(response)
270
+ case data.Code
271
+ when 120
272
+ raise InvalidOAuthToken.new data
273
+ when 121
274
+ raise ExpiredOAuthToken.new data
275
+ when 122
276
+ raise RevokedOAuthToken.new data
277
+ else
278
+ raise Unauthorized.new data
279
+ end
280
+ when 404
281
+ raise NotFound.new
282
+ when 400...500
283
+ raise ClientError.new
284
+ when 500...600
285
+ raise ServerError.new
286
+ else
287
+ response
288
+ end
289
+ end
290
+ end
291
+ end
@@ -0,0 +1,58 @@
1
+ module CreateSend
2
+ # Represents a journey and provides associated functionality
3
+ class Journey < CreateSend
4
+ attr_reader :journey_id
5
+
6
+ def initialize(auth, journey_id)
7
+ @journey_id = journey_id
8
+ super
9
+ end
10
+
11
+ # Get a full summary of a journey
12
+ def summary
13
+ response = get "/journeys/#{@journey_id}.json"
14
+ Hashie::Mash.new(response)
15
+ end
16
+
17
+ # Gets a list of all recipients of a particular email within a journey
18
+ def email_recipients(email_id="", date="", page=1, page_size=1000, order_direction='asc')
19
+ paged_result_by_date("recipients", email_id, date, page, page_size, order_direction)
20
+ end
21
+
22
+ # Gets a paged list of subscribers who opened a given journey email
23
+ def email_opens(email_id="", date="", page=1, page_size=1000, order_direction='asc')
24
+ paged_result_by_date("opens", email_id, date, page, page_size, order_direction)
25
+ end
26
+
27
+ # Gets a paged list of subscribers who clicked a given journey email
28
+ def email_clicks(email_id="", date="", page=1, page_size=1000, order_direction='asc')
29
+ paged_result_by_date("clicks", email_id, date, page, page_size, order_direction)
30
+ end
31
+
32
+ # Gets a paged result representing all subscribers who unsubscribed from a journey email
33
+ def email_unsubscribes(email_id="", date="", page=1, page_size=1000, order_direction='asc')
34
+ paged_result_by_date("unsubscribes", email_id, date, page, page_size, order_direction)
35
+ end
36
+
37
+ # Gets a paged result of all bounces for a journey email
38
+ def email_bounces(email_id="", date="", page=1, page_size=1000, order_direction='asc')
39
+ paged_result_by_date("bounces", email_id, date, page, page_size, order_direction)
40
+ end
41
+
42
+ private
43
+
44
+ def paged_result_by_date(resource, email_id, date, page, page_size, order_direction)
45
+ options = { :query => {
46
+ :date => date,
47
+ :page => page,
48
+ :pagesize => page_size,
49
+ :orderdirection => order_direction } }
50
+ response = get_journey_email_action email_id, resource, options
51
+ Hashie::Mash.new(response)
52
+ end
53
+
54
+ def get_journey_email_action(email_id, action, options = {})
55
+ get "/journeys/email/#{email_id}/#{action}.json", options
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,258 @@
1
+ module CreateSend
2
+ # Represents a subscriber list and associated functionality.
3
+ class List < CreateSend
4
+ attr_reader :list_id
5
+
6
+ def initialize(auth, list_id)
7
+ @list_id = list_id
8
+ super
9
+ end
10
+
11
+ # Creates a new list for a client.
12
+ # client_id - String representing the ID of the client for whom the list
13
+ # will be created
14
+ # title - String representing the list title/name
15
+ # unsubscribe_page - String representing the url of the unsubscribe
16
+ # confirmation page
17
+ # confirmed_opt_in - A Boolean representing whether this should be a
18
+ # confirmed opt-in (double opt-in) list
19
+ # confirmation_success_page - String representing the url of the
20
+ # confirmation success page
21
+ # unsubscribe_setting - A String which must be either "AllClientLists" or
22
+ # "OnlyThisList". See the documentation for details:
23
+ # http://www.campaignmonitor.com/api/lists/#creating_a_list
24
+ def self.create(auth, client_id, title, unsubscribe_page, confirmed_opt_in,
25
+ confirmation_success_page, unsubscribe_setting="AllClientLists")
26
+ options = { :body => {
27
+ :Title => title,
28
+ :UnsubscribePage => unsubscribe_page,
29
+ :ConfirmedOptIn => confirmed_opt_in,
30
+ :ConfirmationSuccessPage => confirmation_success_page,
31
+ :UnsubscribeSetting => unsubscribe_setting }.to_json }
32
+ cs = CreateSend.new auth
33
+ response = cs.post "/lists/#{client_id}.json", options
34
+ response.parsed_response
35
+ end
36
+
37
+ # Deletes this list.
38
+ def delete
39
+ super "/lists/#{list_id}.json", {}
40
+ end
41
+
42
+ # Creates a new custom field for this list.
43
+ # field_name - String representing the name to be given to the field
44
+ # data_type - String representing the data type of the field. Valid data
45
+ # types are 'Text', 'Number', 'MultiSelectOne', 'MultiSelectMany',
46
+ # 'Date', 'Country', and 'USState'.
47
+ # options - Array of Strings representing the options for the field if it
48
+ # is of type 'MultiSelectOne' or 'MultiSelectMany'.
49
+ # visible_in_preference_center - Boolean indicating whether or not the
50
+ # field should be visible in the subscriber preference center
51
+ def create_custom_field(field_name, data_type, options=[],
52
+ visible_in_preference_center=true)
53
+ options = { :body => {
54
+ :FieldName => field_name,
55
+ :DataType => data_type,
56
+ :Options => options,
57
+ :VisibleInPreferenceCenter => visible_in_preference_center }.to_json }
58
+ response = post "customfields", options
59
+ response.parsed_response
60
+ end
61
+
62
+ # Updates a custom field belonging to this list.
63
+ # custom_field_key - String which represents the key for the custom field
64
+ # field_name - String representing the name to be given to the field
65
+ # visible_in_preference_center - Boolean indicating whether or not the
66
+ # field should be visible in the subscriber preference center
67
+ def update_custom_field(custom_field_key, field_name,
68
+ visible_in_preference_center)
69
+ custom_field_key = CGI.escape(custom_field_key)
70
+ options = { :body => {
71
+ :FieldName => field_name,
72
+ :VisibleInPreferenceCenter => visible_in_preference_center }.to_json }
73
+ response = put "customfields/#{custom_field_key}", options
74
+ response.parsed_response
75
+ end
76
+
77
+ # Deletes a custom field associated with this list.
78
+ def delete_custom_field(custom_field_key)
79
+ custom_field_key = CGI.escape(custom_field_key)
80
+ cs_delete("/lists/#{list_id}/customfields/#{custom_field_key}.json", {})
81
+ end
82
+
83
+ # Updates the options of a multi-optioned custom field on this list.
84
+ def update_custom_field_options(custom_field_key, new_options,
85
+ keep_existing_options)
86
+ custom_field_key = CGI.escape(custom_field_key)
87
+ options = { :body => {
88
+ :Options => new_options,
89
+ :KeepExistingOptions => keep_existing_options }.to_json }
90
+ put "customfields/#{custom_field_key}/options", options
91
+ end
92
+
93
+ # Gets the details of this list.
94
+ def details
95
+ response = cs_get "/lists/#{list_id}.json"
96
+ Hashie::Mash.new(response)
97
+ end
98
+
99
+ # Gets the custom fields for this list.
100
+ def custom_fields
101
+ response = get "customfields"
102
+ response.map{|item| Hashie::Mash.new(item)}
103
+ end
104
+
105
+ # Gets the segments for this list.
106
+ def segments
107
+ response = get "segments"
108
+ response.map{|item| Hashie::Mash.new(item)}
109
+ end
110
+
111
+ # Gets the stats for this list.
112
+ def stats
113
+ response = get "stats"
114
+ Hashie::Mash.new(response)
115
+ end
116
+
117
+ # Gets the active subscribers for this list.
118
+ def active(date="", page=1, page_size=1000, order_field="email",
119
+ order_direction="asc", include_tracking_preference=false, include_sms_preference:false)
120
+ paged_result_by_date("active", date, page, page_size, order_field,
121
+ order_direction, include_tracking_preference, include_sms_preference)
122
+ end
123
+
124
+ # Gets the unconfirmed subscribers for this list.
125
+ def unconfirmed(date="", page=1, page_size=1000, order_field="email",
126
+ order_direction="asc", include_tracking_preference=false, include_sms_preference:false)
127
+ paged_result_by_date("unconfirmed", date, page, page_size, order_field,
128
+ order_direction, include_tracking_preference, include_sms_preference)
129
+ end
130
+
131
+ # Gets the bounced subscribers for this list.
132
+ def bounced(date="", page=1, page_size=1000, order_field="email",
133
+ order_direction="asc", include_tracking_preference=false, include_sms_preference:false)
134
+ paged_result_by_date("bounced", date, page, page_size, order_field,
135
+ order_direction, include_tracking_preference, include_sms_preference)
136
+ end
137
+
138
+ # Gets the unsubscribed subscribers for this list.
139
+ def unsubscribed(date="", page=1, page_size=1000, order_field="email",
140
+ order_direction="asc", include_tracking_preference=false, include_sms_preference:false)
141
+ paged_result_by_date("unsubscribed", date, page, page_size, order_field,
142
+ order_direction, include_tracking_preference, include_sms_preference)
143
+ end
144
+
145
+ # Gets the deleted subscribers for this list.
146
+ def deleted(date="", page=1, page_size=1000, order_field="email",
147
+ order_direction="asc", include_tracking_preference=false, include_sms_preference:false)
148
+ paged_result_by_date("deleted", date, page, page_size, order_field,
149
+ order_direction, include_tracking_preference, include_sms_preference)
150
+ end
151
+
152
+ # Updates this list.
153
+ # title - String representing the list title/name
154
+ # unsubscribe_page - String representing the url of the unsubscribe
155
+ # confirmation page
156
+ # confirmed_opt_in - A Boolean representing whether this should be a
157
+ # confirmed opt-in (double opt-in) list
158
+ # confirmation_success_page - String representing the url of the
159
+ # confirmation success page
160
+ # unsubscribe_setting - A String which must be either "AllClientLists" or
161
+ # "OnlyThisList". See the documentation for details:
162
+ # http://www.campaignmonitor.com/api/lists/#updating_a_list
163
+ # add_unsubscribes_to_supp_list - When unsubscribe_setting is
164
+ # "AllClientLists", a Boolean which represents whether unsubscribes from
165
+ # this list should be added to the suppression list
166
+ # scrub_active_with_supp_list - When unsubscribe_setting is
167
+ # "AllClientLists", a Boolean which represents whether active sunscribers
168
+ # should be scrubbed against the suppression list
169
+ def update(title, unsubscribe_page, confirmed_opt_in,
170
+ confirmation_success_page, unsubscribe_setting="AllClientLists",
171
+ add_unsubscribes_to_supp_list=false, scrub_active_with_supp_list=false)
172
+ options = { :body => {
173
+ :Title => title,
174
+ :UnsubscribePage => unsubscribe_page,
175
+ :ConfirmedOptIn => confirmed_opt_in,
176
+ :ConfirmationSuccessPage => confirmation_success_page,
177
+ :UnsubscribeSetting => unsubscribe_setting,
178
+ :AddUnsubscribesToSuppList => add_unsubscribes_to_supp_list,
179
+ :ScrubActiveWithSuppList => scrub_active_with_supp_list }.to_json }
180
+ cs_put "/lists/#{list_id}.json", options
181
+ end
182
+
183
+ # Gets the webhooks for this list.
184
+ def webhooks
185
+ response = get "webhooks"
186
+ response.map{|item| Hashie::Mash.new(item)}
187
+ end
188
+
189
+ # Creates a new webhook for the specified events (an array of strings).
190
+ # Valid events are "Subscribe", "Deactivate", and "Update".
191
+ # Valid payload formats are "json", and "xml".
192
+ def create_webhook(events, url, payload_format)
193
+ options = { :body => {
194
+ :Events => events,
195
+ :Url => url,
196
+ :PayloadFormat => payload_format }.to_json }
197
+ response = post "webhooks", options
198
+ response.parsed_response
199
+ end
200
+
201
+ # Tests that a post can be made to the endpoint specified for the webhook
202
+ # identified by webhook_id.
203
+ def test_webhook(webhook_id)
204
+ get "webhooks/#{webhook_id}/test"
205
+ true # An exception will be raised if any error occurs
206
+ end
207
+
208
+ # Deletes a webhook associated with this list.
209
+ def delete_webhook(webhook_id)
210
+ cs_delete("/lists/#{list_id}/webhooks/#{webhook_id}.json", {})
211
+ end
212
+
213
+ # Activates a webhook associated with this list.
214
+ def activate_webhook(webhook_id)
215
+ options = { :body => '' }
216
+ put "webhooks/#{webhook_id}/activate", options
217
+ end
218
+
219
+ # De-activates a webhook associated with this list.
220
+ def deactivate_webhook(webhook_id)
221
+ options = { :body => '' }
222
+ put "webhooks/#{webhook_id}/deactivate", options
223
+ end
224
+
225
+ private
226
+
227
+ def paged_result_by_date(resource, date, page, page_size, order_field,
228
+ order_direction, include_tracking_preference, include_sms_preference)
229
+ options = { :query => {
230
+ :date => date,
231
+ :page => page,
232
+ :pagesize => page_size,
233
+ :orderfield => order_field,
234
+ :orderdirection => order_direction,
235
+ :includetrackingpreference => include_tracking_preference,
236
+ :includesmspreference => include_sms_preference} }
237
+ response = get resource, options
238
+ Hashie::Mash.new(response)
239
+ end
240
+
241
+ def get(action, options = {})
242
+ super uri_for(action), options
243
+ end
244
+
245
+ def post(action, options = {})
246
+ super uri_for(action), options
247
+ end
248
+
249
+ def put(action, options = {})
250
+ super uri_for(action), options
251
+ end
252
+
253
+ def uri_for(action)
254
+ "/lists/#{list_id}/#{action}.json"
255
+ end
256
+
257
+ end
258
+ end
@@ -0,0 +1,59 @@
1
+ module CreateSend
2
+ # Represents a person and associated functionality.
3
+ class Person < CreateSend
4
+ attr_reader :client_id
5
+ attr_reader :email_address
6
+
7
+ def initialize(auth, client_id, email_address)
8
+ @client_id = client_id
9
+ @email_address = email_address
10
+ super
11
+ end
12
+
13
+ # Gets a person by client ID and email address.
14
+ def self.get(auth, client_id, email_address)
15
+ options = { :query => { :email => email_address } }
16
+ cs = CreateSend.new auth
17
+ response = cs.get "/clients/#{client_id}/people.json", options
18
+ Hashie::Mash.new(response)
19
+ end
20
+
21
+ # Adds a person to the client. Password is optional. If ommitted, an
22
+ # email invitation will be sent to the person
23
+ def self.add(auth, client_id, email_address, name, access_level, password)
24
+ options = { :body => {
25
+ :EmailAddress => email_address,
26
+ :Name => name,
27
+ :AccessLevel => access_level,
28
+ :Password => password }.to_json }
29
+ cs = CreateSend.new auth
30
+ response = cs.post "/clients/#{client_id}/people.json", options
31
+ Hashie::Mash.new(response)
32
+ end
33
+
34
+ # Updates the person details. password is optional and will only be
35
+ # updated if supplied
36
+ def update(new_email_address, name, access_level, password)
37
+ options = {
38
+ :query => { :email => @email_address },
39
+ :body => {
40
+ :EmailAddress => new_email_address,
41
+ :Name => name,
42
+ :AccessLevel => access_level,
43
+ :Password => password }.to_json }
44
+ put uri_for(client_id), options
45
+ # Update @email_address, so this object can continue to be used reliably
46
+ @email_address = new_email_address
47
+ end
48
+
49
+ # deletes this person from the client
50
+ def delete
51
+ options = { :query => { :email => @email_address } }
52
+ super uri_for(client_id), options
53
+ end
54
+
55
+ def uri_for(client_id)
56
+ "/clients/#{client_id}/people.json"
57
+ end
58
+ end
59
+ end