constantcontact-ruby 2.2.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.
- checksums.yaml +7 -0
- data/.rspec +2 -0
- data/README.md +136 -0
- data/constantcontact-ruby.gemspec +31 -0
- data/lib/constantcontact/api.rb +1012 -0
- data/lib/constantcontact/auth/oauth2.rb +105 -0
- data/lib/constantcontact/auth/session_data_store.rb +69 -0
- data/lib/constantcontact/components/account/account_address.rb +26 -0
- data/lib/constantcontact/components/account/account_info.rb +38 -0
- data/lib/constantcontact/components/account/verified_email_address.rb +26 -0
- data/lib/constantcontact/components/activities/activity.rb +43 -0
- data/lib/constantcontact/components/activities/activity_error.rb +26 -0
- data/lib/constantcontact/components/activities/add_contacts.rb +127 -0
- data/lib/constantcontact/components/activities/add_contacts_import_data.rb +46 -0
- data/lib/constantcontact/components/activities/export_contacts.rb +30 -0
- data/lib/constantcontact/components/component.rb +48 -0
- data/lib/constantcontact/components/contacts/address.rb +27 -0
- data/lib/constantcontact/components/contacts/contact.rb +92 -0
- data/lib/constantcontact/components/contacts/contact_list.rb +26 -0
- data/lib/constantcontact/components/contacts/custom_field.rb +26 -0
- data/lib/constantcontact/components/contacts/email_address.rb +33 -0
- data/lib/constantcontact/components/contacts/note.rb +26 -0
- data/lib/constantcontact/components/email_marketing/campaign.rb +83 -0
- data/lib/constantcontact/components/email_marketing/campaign_preview.rb +29 -0
- data/lib/constantcontact/components/email_marketing/click_through_details.rb +27 -0
- data/lib/constantcontact/components/email_marketing/message_footer.rb +29 -0
- data/lib/constantcontact/components/email_marketing/schedule.rb +27 -0
- data/lib/constantcontact/components/email_marketing/test_send.rb +45 -0
- data/lib/constantcontact/components/event_spot/contact.rb +27 -0
- data/lib/constantcontact/components/event_spot/event.rb +69 -0
- data/lib/constantcontact/components/event_spot/event_address.rb +29 -0
- data/lib/constantcontact/components/event_spot/event_fee.rb +27 -0
- data/lib/constantcontact/components/event_spot/event_item.rb +36 -0
- data/lib/constantcontact/components/event_spot/event_item_attribute.rb +26 -0
- data/lib/constantcontact/components/event_spot/event_track.rb +31 -0
- data/lib/constantcontact/components/event_spot/guest.rb +31 -0
- data/lib/constantcontact/components/event_spot/guest_section.rb +34 -0
- data/lib/constantcontact/components/event_spot/notification_option.rb +27 -0
- data/lib/constantcontact/components/event_spot/online_meeting.rb +28 -0
- data/lib/constantcontact/components/event_spot/payment_address.rb +29 -0
- data/lib/constantcontact/components/event_spot/payment_summary.rb +33 -0
- data/lib/constantcontact/components/event_spot/promocode.rb +25 -0
- data/lib/constantcontact/components/event_spot/registrant.rb +52 -0
- data/lib/constantcontact/components/event_spot/registrant_fee.rb +29 -0
- data/lib/constantcontact/components/event_spot/registrant_field.rb +27 -0
- data/lib/constantcontact/components/event_spot/registrant_order.rb +39 -0
- data/lib/constantcontact/components/event_spot/registrant_promo_code.rb +31 -0
- data/lib/constantcontact/components/event_spot/registrant_promo_code_info.rb +27 -0
- data/lib/constantcontact/components/event_spot/registrant_section.rb +34 -0
- data/lib/constantcontact/components/event_spot/sale_item.rb +29 -0
- data/lib/constantcontact/components/library/file/library_file.rb +27 -0
- data/lib/constantcontact/components/library/folder/library_folder.rb +26 -0
- data/lib/constantcontact/components/library/info/library_summary.rb +26 -0
- data/lib/constantcontact/components/library/info/move_results.rb +26 -0
- data/lib/constantcontact/components/library/info/upload_status.rb +26 -0
- data/lib/constantcontact/components/result_set.rb +50 -0
- data/lib/constantcontact/components/tracking/bounce_activity.rb +28 -0
- data/lib/constantcontact/components/tracking/click_activity.rb +26 -0
- data/lib/constantcontact/components/tracking/forward_activity.rb +26 -0
- data/lib/constantcontact/components/tracking/open_activity.rb +26 -0
- data/lib/constantcontact/components/tracking/send_activity.rb +27 -0
- data/lib/constantcontact/components/tracking/tracking_activity.rb +26 -0
- data/lib/constantcontact/components/tracking/tracking_summary.rb +27 -0
- data/lib/constantcontact/components/tracking/unsubscribe_activity.rb +27 -0
- data/lib/constantcontact/exceptions/ctct_exception.rb +25 -0
- data/lib/constantcontact/exceptions/illegal_argument_exception.rb +11 -0
- data/lib/constantcontact/exceptions/oauth2_exception.rb +11 -0
- data/lib/constantcontact/exceptions/webhooks_exception.rb +11 -0
- data/lib/constantcontact/services/account_service.rb +39 -0
- data/lib/constantcontact/services/activity_service.rb +136 -0
- data/lib/constantcontact/services/base_service.rb +68 -0
- data/lib/constantcontact/services/campaign_schedule_service.rb +101 -0
- data/lib/constantcontact/services/campaign_tracking_service.rb +152 -0
- data/lib/constantcontact/services/contact_service.rb +105 -0
- data/lib/constantcontact/services/contact_tracking_service.rb +152 -0
- data/lib/constantcontact/services/email_marketing_service.rb +94 -0
- data/lib/constantcontact/services/event_spot_service.rb +448 -0
- data/lib/constantcontact/services/library_service.rb +281 -0
- data/lib/constantcontact/services/list_service.rb +81 -0
- data/lib/constantcontact/util/config.rb +180 -0
- data/lib/constantcontact/util/helpers.rb +27 -0
- data/lib/constantcontact/version.rb +12 -0
- data/lib/constantcontact/webhooks/helpers/validator.rb +30 -0
- data/lib/constantcontact/webhooks/models/billing_change_notification.rb +27 -0
- data/lib/constantcontact/webhooks/webhooks_util.rb +45 -0
- data/lib/constantcontact.rb +124 -0
- data/spec/constantcontact/api_spec.rb +1560 -0
- data/spec/constantcontact/auth/oauth2_spec.rb +125 -0
- data/spec/constantcontact/components/contacts/address_spec.rb +18 -0
- data/spec/constantcontact/components/contacts/contact_list_spec.rb +18 -0
- data/spec/constantcontact/components/contacts/contact_spec.rb +18 -0
- data/spec/constantcontact/components/contacts/custom_field_spec.rb +18 -0
- data/spec/constantcontact/components/contacts/email_address_spec.rb +18 -0
- data/spec/constantcontact/sdk_spec.rb +24 -0
- data/spec/constantcontact/services/account_service_spec.rb +46 -0
- data/spec/constantcontact/services/activity_service_spec.rb +244 -0
- data/spec/constantcontact/services/base_service_spec.rb +50 -0
- data/spec/constantcontact/services/campaign_schedule_service_spec.rb +115 -0
- data/spec/constantcontact/services/campaign_tracking_service_spec.rb +131 -0
- data/spec/constantcontact/services/contact_service_spec.rb +111 -0
- data/spec/constantcontact/services/contact_tracking_service_spec.rb +131 -0
- data/spec/constantcontact/services/email_marketing_spec.rb +100 -0
- data/spec/constantcontact/services/event_spot_spec.rb +423 -0
- data/spec/constantcontact/services/library_service_spec.rb +252 -0
- data/spec/constantcontact/services/list_service_spec.rb +89 -0
- data/spec/constantcontact/webhooks/webhooks_spec.rb +26 -0
- metadata +243 -0
@@ -0,0 +1,281 @@
|
|
1
|
+
#
|
2
|
+
# library_service.rb
|
3
|
+
# ConstantContact
|
4
|
+
#
|
5
|
+
# Copyright (c) 2013 Constant Contact. All rights reserved.
|
6
|
+
|
7
|
+
module ConstantContact
|
8
|
+
module Services
|
9
|
+
class LibraryService < BaseService
|
10
|
+
class << self
|
11
|
+
|
12
|
+
# Retrieve MyLibrary usage information
|
13
|
+
# @return [LibrarySummary]
|
14
|
+
def get_library_info()
|
15
|
+
url = Util::Config.get('endpoints.base_url') + Util::Config.get('endpoints.library_info')
|
16
|
+
|
17
|
+
response = RestClient.get(url, get_headers())
|
18
|
+
Components::LibrarySummary.create(JSON.parse(response.body).first)
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
# Retrieve a list of MyLibrary folders
|
23
|
+
# @param [Hash] params - hash of query parameters and values to append to the request.
|
24
|
+
# Allowed parameters include:
|
25
|
+
# sort_by - The method to sort by, valid values are :
|
26
|
+
# CREATED_DATE - sorts by date folder was added, ascending (earliest to latest)
|
27
|
+
# CREATED_DATE_DESC - (default) sorts by date folder was added, descending (latest to earliest)
|
28
|
+
# MODIFIED_DATE - sorts by date folder was last modified, ascending (earliest to latest)
|
29
|
+
# MODIFIED_DATE_DESC - sorts by date folder was last modified, descending (latest to earliest)
|
30
|
+
# NAME - sorts alphabetically by folder name, a to z
|
31
|
+
# NAME_DESC - sorts alphabetically by folder name, z to a
|
32
|
+
# limit - Specifies the number of results displayed per page of output, from 1 - 50, default = 50.
|
33
|
+
# @return [ResultSet<LibraryFolder>]
|
34
|
+
def get_library_folders(params)
|
35
|
+
url = Util::Config.get('endpoints.base_url') + Util::Config.get('endpoints.library_folders')
|
36
|
+
url = build_url(url, params)
|
37
|
+
response = RestClient.get(url, get_headers())
|
38
|
+
folders = []
|
39
|
+
body = JSON.parse(response.body)
|
40
|
+
body['results'].each do |folder|
|
41
|
+
folders << Components::LibraryFolder.create(folder)
|
42
|
+
end
|
43
|
+
Components::ResultSet.new(folders, body['meta'])
|
44
|
+
end
|
45
|
+
|
46
|
+
|
47
|
+
# Create a new MyLibrary folder
|
48
|
+
# @param [LibraryFolder] folder - MyLibrary folder to be created
|
49
|
+
# @return [LibraryFolder]
|
50
|
+
def add_library_folder(folder)
|
51
|
+
url = Util::Config.get('endpoints.base_url') + Util::Config.get('endpoints.library_folders')
|
52
|
+
url = build_url(url)
|
53
|
+
payload = folder.to_json
|
54
|
+
response = RestClient.post(url, payload, get_headers())
|
55
|
+
Components::LibraryFolder.create(JSON.parse(response.body))
|
56
|
+
end
|
57
|
+
|
58
|
+
|
59
|
+
# Retrieve a specific MyLibrary folder using the folder_id path parameter
|
60
|
+
# @param [String] folder_id - The ID for the folder to return
|
61
|
+
# @return [LibraryFolder]
|
62
|
+
def get_library_folder(folder_id)
|
63
|
+
url = Util::Config.get('endpoints.base_url') + sprintf(Util::Config.get('endpoints.library_folder'), folder_id)
|
64
|
+
url = build_url(url)
|
65
|
+
response = RestClient.get(url, get_headers())
|
66
|
+
Components::LibraryFolder.create(JSON.parse(response.body))
|
67
|
+
end
|
68
|
+
|
69
|
+
|
70
|
+
# Update a specific MyLibrary folder
|
71
|
+
# @param [LibraryFolder] folder - MyLibrary folder to be updated
|
72
|
+
# @return [LibraryFolder]
|
73
|
+
def update_library_folder(folder)
|
74
|
+
url = Util::Config.get('endpoints.base_url') +
|
75
|
+
sprintf(Util::Config.get('endpoints.library_folder'), folder.id)
|
76
|
+
url = build_url(url)
|
77
|
+
payload = folder.to_json
|
78
|
+
response = RestClient.put(url, payload, get_headers())
|
79
|
+
Components::LibraryFolder.create(JSON.parse(response.body))
|
80
|
+
end
|
81
|
+
|
82
|
+
|
83
|
+
# Delete a MyLibrary folder
|
84
|
+
# @param [String] folder_id - The ID for the MyLibrary folder to delete
|
85
|
+
# @return [Boolean]
|
86
|
+
def delete_library_folder(folder_id)
|
87
|
+
url = Util::Config.get('endpoints.base_url') + sprintf(Util::Config.get('endpoints.library_folder'), folder_id)
|
88
|
+
url = build_url(url)
|
89
|
+
response = RestClient.delete(url, get_headers())
|
90
|
+
response.code == 204
|
91
|
+
end
|
92
|
+
|
93
|
+
|
94
|
+
# Retrieve all files in the Trash folder
|
95
|
+
# @param [Hash] params - hash of query parameters and values to append to the request.
|
96
|
+
# Allowed parameters include:
|
97
|
+
# type - Specifies the type of files to retrieve, valid values are : ALL, IMAGES, or DOCUMENTS
|
98
|
+
# sort_by - The method to sort by, valid values are :
|
99
|
+
# ADDED_DATE - sorts by date folder was added, ascending (earliest to latest)
|
100
|
+
# ADDED_DATE_DESC - (default) sorts by date folder was added, descending (latest to earliest)
|
101
|
+
# MODIFIED_DATE - sorts by date folder was last modified, ascending (earliest to latest)
|
102
|
+
# MODIFIED_DATE_DESC - sorts by date folder was last modified, descending (latest to earliest)
|
103
|
+
# NAME - sorts alphabetically by file name, a to z
|
104
|
+
# NAME_DESC - sorts alphabetically by file name, z to a
|
105
|
+
# SIZE - sorts by file size, smallest to largest
|
106
|
+
# SIZE_DESC - sorts by file size, largest to smallest
|
107
|
+
# DIMENSION - sorts by file dimensions (hxw), smallest to largest
|
108
|
+
# DIMENSION_DESC - sorts by file dimensions (hxw), largest to smallest
|
109
|
+
# limit - Specifies the number of results displayed per page of output, from 1 - 50, default = 50.
|
110
|
+
# @return [ResultSet<LibraryFile>]
|
111
|
+
def get_library_trash(params)
|
112
|
+
url = Util::Config.get('endpoints.base_url') + Util::Config.get('endpoints.library_folder_trash')
|
113
|
+
url = build_url(url, params)
|
114
|
+
response = RestClient.get(url, get_headers())
|
115
|
+
files = []
|
116
|
+
body = JSON.parse(response.body)
|
117
|
+
body['results'].each do |file|
|
118
|
+
files << Components::LibraryFile.create(file)
|
119
|
+
end
|
120
|
+
Components::ResultSet.new(files, body['meta'])
|
121
|
+
end
|
122
|
+
|
123
|
+
|
124
|
+
# Permanently deletes all files in the Trash folder
|
125
|
+
# @return [Boolean]
|
126
|
+
def delete_library_trash()
|
127
|
+
url = Util::Config.get('endpoints.base_url') + Util::Config.get('endpoints.library_folder_trash')
|
128
|
+
url = build_url(url)
|
129
|
+
response = RestClient.delete(url, get_headers())
|
130
|
+
response.code == 204
|
131
|
+
end
|
132
|
+
|
133
|
+
|
134
|
+
# Retrieve a collection of MyLibrary files in the Constant Contact account
|
135
|
+
# @param [Hash] params - hash of query parameters and values to append to the request.
|
136
|
+
# Allowed parameters include:
|
137
|
+
# type - Specifies the type of files to retrieve, valid values are : ALL, IMAGES, or DOCUMENTS
|
138
|
+
# source - Specifies to retrieve files from a particular source, valid values are :
|
139
|
+
# ALL - (default) files from all sources
|
140
|
+
# MyComputer
|
141
|
+
# StockImage
|
142
|
+
# Facebook
|
143
|
+
# Instagram
|
144
|
+
# Shutterstock
|
145
|
+
# Mobile
|
146
|
+
# limit - Specifies the number of results displayed per page of output, from 1 - 1000, default = 50.
|
147
|
+
# @return [ResultSet<LibraryFile>]
|
148
|
+
def get_library_files(params = {})
|
149
|
+
url = Util::Config.get('endpoints.base_url') + Util::Config.get('endpoints.library_files')
|
150
|
+
url = build_url(url, params)
|
151
|
+
response = RestClient.get(url, get_headers())
|
152
|
+
files = []
|
153
|
+
body = JSON.parse(response.body)
|
154
|
+
body['results'].each do |file|
|
155
|
+
files << Components::LibraryFile.create(file)
|
156
|
+
end
|
157
|
+
Components::ResultSet.new(files, body['meta'])
|
158
|
+
end
|
159
|
+
|
160
|
+
|
161
|
+
# Retrieves all files from a MyLibrary folder specified by the folder_id path parameter
|
162
|
+
# @param [String] folder_id - Specifies the folder from which to retrieve files
|
163
|
+
# @param [Hash] params - hash of query parameters and values to append to the request.
|
164
|
+
# Allowed parameters include:
|
165
|
+
# limit - Specifies the number of results displayed per page of output, from 1 - 50, default = 50.
|
166
|
+
# @return [ResultSet<LibraryFile>]
|
167
|
+
def get_library_files_by_folder(folder_id, params = {})
|
168
|
+
url = Util::Config.get('endpoints.base_url') +
|
169
|
+
sprintf(Util::Config.get('endpoints.library_files_by_folder'), folder_id)
|
170
|
+
url = build_url(url, params)
|
171
|
+
response = RestClient.get(url, get_headers())
|
172
|
+
files = []
|
173
|
+
body = JSON.parse(response.body)
|
174
|
+
body['results'].each do |file|
|
175
|
+
files << Components::LibraryFile.create(file)
|
176
|
+
end
|
177
|
+
Components::ResultSet.new(files, body['meta'])
|
178
|
+
end
|
179
|
+
|
180
|
+
|
181
|
+
# Retrieve a MyLibrary file using the file_id path parameter
|
182
|
+
# @param [String] file_id - Specifies the MyLibrary file for which to retrieve information
|
183
|
+
# @return [LibraryFile]
|
184
|
+
def get_library_file(file_id)
|
185
|
+
url = Util::Config.get('endpoints.base_url') + sprintf(Util::Config.get('endpoints.library_file'), file_id)
|
186
|
+
url = build_url(url)
|
187
|
+
response = RestClient.get(url, get_headers())
|
188
|
+
Components::LibraryFile.create(JSON.parse(response.body))
|
189
|
+
end
|
190
|
+
|
191
|
+
|
192
|
+
# Adds a new MyLibrary file using the multipart content-type
|
193
|
+
# @param [String] file_name - The name of the file (ie: dinnerplate-special.jpg)
|
194
|
+
# @param [String] folder_id - Folder id to add the file to
|
195
|
+
# @param [String] description - The description of the file provided by user
|
196
|
+
# @param [String] source - indicates the source of the original file;
|
197
|
+
# image files can be uploaded from the following sources :
|
198
|
+
# MyComputer, StockImage, Facebook - MyLibrary Plus customers only,
|
199
|
+
# Instagram - MyLibrary Plus customers only, Shutterstock, Mobile
|
200
|
+
# @param [String] file_type - Specifies the file type, valid values are: JPEG, JPG, GIF, PDF, PNG
|
201
|
+
# @param [String] contents - The content of the file
|
202
|
+
# @return [LibraryFile]
|
203
|
+
def add_library_file(file_name, folder_id, description, source, file_type, contents)
|
204
|
+
url = Util::Config.get('endpoints.base_url') + Util::Config.get('endpoints.library_files')
|
205
|
+
url = build_url(url)
|
206
|
+
|
207
|
+
payload = { :file_name => file_name, :folder_id => folder_id,
|
208
|
+
:description => description, :source => source, :file_type => file_type,
|
209
|
+
:data => contents, :multipart => true }
|
210
|
+
|
211
|
+
response = RestClient.post(url, payload, get_headers())
|
212
|
+
location = response.headers[:location] || ''
|
213
|
+
location.split('/').last
|
214
|
+
end
|
215
|
+
|
216
|
+
|
217
|
+
# Update information for a specific MyLibrary file
|
218
|
+
# @param [LibraryFile] file - Library File to be updated
|
219
|
+
# @return [LibraryFile]
|
220
|
+
def update_library_file(file)
|
221
|
+
url = Util::Config.get('endpoints.base_url') + sprintf(Util::Config.get('endpoints.library_file'), file.id)
|
222
|
+
url = build_url(url)
|
223
|
+
payload = file.to_json
|
224
|
+
response = RestClient.put(url, payload, get_headers())
|
225
|
+
Components::LibraryFile.create(JSON.parse(response.body))
|
226
|
+
end
|
227
|
+
|
228
|
+
|
229
|
+
# Delete one or more MyLibrary files specified by the fileId path parameter;
|
230
|
+
# separate multiple file IDs with a comma.
|
231
|
+
# Deleted files are moved from their current folder into the system Trash folder, and its status is set to Deleted.
|
232
|
+
# @param [String] file_id - Specifies the MyLibrary file to delete
|
233
|
+
# @return [Boolean]
|
234
|
+
def delete_library_file(file_id)
|
235
|
+
url = Util::Config.get('endpoints.base_url') + sprintf(Util::Config.get('endpoints.library_file'), file_id)
|
236
|
+
url = build_url(url)
|
237
|
+
response = RestClient.delete(url, get_headers())
|
238
|
+
response.code == 204
|
239
|
+
end
|
240
|
+
|
241
|
+
|
242
|
+
# Retrieve the upload status for one or more MyLibrary files using the file_id path parameter;
|
243
|
+
# separate multiple file IDs with a comma
|
244
|
+
# @param [String] file_id - Specifies the files for which to retrieve upload status information
|
245
|
+
# @return [Array<UploadStatus>]
|
246
|
+
def get_library_files_upload_status(file_id)
|
247
|
+
url = Util::Config.get('endpoints.base_url') +
|
248
|
+
sprintf(Util::Config.get('endpoints.library_file_upload_status'), file_id)
|
249
|
+
url = build_url(url)
|
250
|
+
response = RestClient.get(url, get_headers())
|
251
|
+
statuses = []
|
252
|
+
JSON.parse(response.body).each do |status|
|
253
|
+
statuses << Components::UploadStatus.create(status)
|
254
|
+
end
|
255
|
+
statuses
|
256
|
+
end
|
257
|
+
|
258
|
+
|
259
|
+
# Move one or more MyLibrary files to a different folder in the user's account
|
260
|
+
# specify the destination folder using the folder_id path parameter.
|
261
|
+
# @param [String] folder_id - Specifies the destination MyLibrary folder to which the files will be moved
|
262
|
+
# @param [String] file_id - Specifies the files to move, in a string of comma separated file ids (e.g. 8,9)
|
263
|
+
# @return [Array<MoveResults>]
|
264
|
+
def move_library_files(folder_id, file_id)
|
265
|
+
url = Util::Config.get('endpoints.base_url') +
|
266
|
+
sprintf(Util::Config.get('endpoints.library_file_move'), folder_id)
|
267
|
+
url = build_url(url)
|
268
|
+
|
269
|
+
payload = file_id.split(',').map {|id| id.strip}.to_json
|
270
|
+
response = RestClient.put(url, payload, get_headers())
|
271
|
+
results = []
|
272
|
+
JSON.parse(response.body).each do |result|
|
273
|
+
results << Components::MoveResults.create(result)
|
274
|
+
end
|
275
|
+
results
|
276
|
+
end
|
277
|
+
|
278
|
+
end
|
279
|
+
end
|
280
|
+
end
|
281
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
#
|
2
|
+
# list_service.rb
|
3
|
+
# ConstantContact
|
4
|
+
#
|
5
|
+
# Copyright (c) 2013 Constant Contact. All rights reserved.
|
6
|
+
|
7
|
+
module ConstantContact
|
8
|
+
module Services
|
9
|
+
class ListService < BaseService
|
10
|
+
class << self
|
11
|
+
|
12
|
+
# Get lists within an account
|
13
|
+
# @param [Hash] params - query parameters to be appended to the request
|
14
|
+
# @return [Array<ContactList>]
|
15
|
+
def get_lists(params = {})
|
16
|
+
url = Util::Config.get('endpoints.base_url') + Util::Config.get('endpoints.lists')
|
17
|
+
url = build_url(url, params)
|
18
|
+
response = RestClient.get(url, get_headers())
|
19
|
+
lists = []
|
20
|
+
JSON.parse(response.body).each do |contact|
|
21
|
+
lists << Components::ContactList.create(contact)
|
22
|
+
end
|
23
|
+
lists
|
24
|
+
end
|
25
|
+
|
26
|
+
|
27
|
+
# Add a new list to the Constant Contact account
|
28
|
+
# @param [ContactList] list
|
29
|
+
# @return [ContactList]
|
30
|
+
def add_list(list)
|
31
|
+
url = Util::Config.get('endpoints.base_url') + Util::Config.get('endpoints.lists')
|
32
|
+
url = build_url(url)
|
33
|
+
payload = list.to_json
|
34
|
+
response = RestClient.post(url, payload, get_headers())
|
35
|
+
Components::ContactList.create(JSON.parse(response.body))
|
36
|
+
end
|
37
|
+
|
38
|
+
|
39
|
+
# Update a Contact List
|
40
|
+
# @param [ContactList] list - ContactList to be updated
|
41
|
+
# @return [ContactList]
|
42
|
+
def update_list(list)
|
43
|
+
url = Util::Config.get('endpoints.base_url') + sprintf(Util::Config.get('endpoints.list'), list.id)
|
44
|
+
url = build_url(url)
|
45
|
+
payload = list.to_json
|
46
|
+
response = RestClient.put(url, payload, get_headers())
|
47
|
+
Components::ContactList.create(JSON.parse(response.body))
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
# Get an individual contact list
|
52
|
+
# @param [Integer] list_id - list id
|
53
|
+
# @return [ContactList]
|
54
|
+
def get_list(list_id)
|
55
|
+
url = Util::Config.get('endpoints.base_url') + sprintf(Util::Config.get('endpoints.list'), list_id)
|
56
|
+
url = build_url(url)
|
57
|
+
response = RestClient.get(url, get_headers())
|
58
|
+
Components::ContactList.create(JSON.parse(response.body))
|
59
|
+
end
|
60
|
+
|
61
|
+
|
62
|
+
# Get all contacts from an individual list
|
63
|
+
# @param [Integer] list_id - list id to retrieve contacts for
|
64
|
+
# @param [Hash] params - query parameters to attach to request
|
65
|
+
# @return [Array<Contact>]
|
66
|
+
def get_contacts_from_list(list_id, params = nil)
|
67
|
+
url = Util::Config.get('endpoints.base_url') + sprintf(Util::Config.get('endpoints.list_contacts'), list_id)
|
68
|
+
url = build_url(url, params)
|
69
|
+
response = RestClient.get(url, get_headers())
|
70
|
+
contacts = []
|
71
|
+
body = JSON.parse(response.body)
|
72
|
+
body['results'].each do |contact|
|
73
|
+
contacts << Components::Contact.create(contact)
|
74
|
+
end
|
75
|
+
Components::ResultSet.new(contacts, body['meta'])
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,180 @@
|
|
1
|
+
#
|
2
|
+
# config.rb
|
3
|
+
# ConstantContact
|
4
|
+
#
|
5
|
+
# Copyright (c) 2013 Constant Contact. All rights reserved.
|
6
|
+
|
7
|
+
module ConstantContact
|
8
|
+
module Util
|
9
|
+
class Config
|
10
|
+
|
11
|
+
# Return a hash of configuration strings
|
12
|
+
# @return [Hash] - hash of configuration properties
|
13
|
+
@props = {
|
14
|
+
# REST endpoints
|
15
|
+
:endpoints => {
|
16
|
+
:api_url => 'https://api.constantcontact.com',
|
17
|
+
:base_url => 'https://api.constantcontact.com/v2/',
|
18
|
+
|
19
|
+
:activity => 'activities/%s',
|
20
|
+
:activities => 'activities',
|
21
|
+
:export_contacts_activity => 'activities/exportcontacts',
|
22
|
+
:clear_lists_activity => 'activities/clearlists',
|
23
|
+
:remove_from_lists_activity => 'activities/removefromlists',
|
24
|
+
:add_contacts_activity => 'activities/addcontacts',
|
25
|
+
|
26
|
+
:account_verified_addresses => 'account/verifiedemailaddresses',
|
27
|
+
:account_info => 'account/info',
|
28
|
+
|
29
|
+
:contact => 'contacts/%s',
|
30
|
+
:contacts => 'contacts',
|
31
|
+
:lists => 'lists',
|
32
|
+
:list => 'lists/%s',
|
33
|
+
:list_contacts => 'lists/%s/contacts',
|
34
|
+
:contact_lists => 'contacts/%s/lists',
|
35
|
+
:contact_list => 'contacts/%s/lists/%s',
|
36
|
+
|
37
|
+
:campaigns => 'emailmarketing/campaigns',
|
38
|
+
:campaign => 'emailmarketing/campaigns/%s',
|
39
|
+
:campaign_preview => 'emailmarketing/campaigns/%s/preview',
|
40
|
+
:campaign_schedules => 'emailmarketing/campaigns/%s/schedules',
|
41
|
+
:campaign_schedule => 'emailmarketing/campaigns/%s/schedules/%s',
|
42
|
+
:campaign_test_sends => 'emailmarketing/campaigns/%s/tests',
|
43
|
+
:campaign_tracking_summary => 'emailmarketing/campaigns/%s/tracking/reports/summary',
|
44
|
+
:campaign_tracking_bounces => 'emailmarketing/campaigns/%s/tracking/bounces',
|
45
|
+
:campaign_tracking_clicks => 'emailmarketing/campaigns/%s/tracking/clicks',
|
46
|
+
:campaign_tracking_forwards => 'emailmarketing/campaigns/%s/tracking/forwards',
|
47
|
+
:campaign_tracking_opens => 'emailmarketing/campaigns/%s/tracking/opens',
|
48
|
+
:campaign_tracking_sends => 'emailmarketing/campaigns/%s/tracking/sends',
|
49
|
+
:campaign_tracking_unsubscribes => 'emailmarketing/campaigns/%s/tracking/unsubscribes',
|
50
|
+
:campaign_tracking_link => 'emailmarketing/campaigns/%s/tracking/clicks/%s',
|
51
|
+
|
52
|
+
:events => 'eventspot/events',
|
53
|
+
:event => 'eventspot/events/%s',
|
54
|
+
:event_fees => 'eventspot/events/%s/fees',
|
55
|
+
:event_fee => 'eventspot/events/%s/fees/%s',
|
56
|
+
:event_registrants => 'eventspot/events/%s/registrants',
|
57
|
+
:event_registrant => 'eventspot/events/%s/registrants/%s',
|
58
|
+
:event_items => 'eventspot/events/%s/items',
|
59
|
+
:event_item => 'eventspot/events/%s/items/%s',
|
60
|
+
:event_item_attributes => 'eventspot/events/%s/items/%s/attributes',
|
61
|
+
:event_item_attribute => 'eventspot/events/%s/items/%s/attributes/%s',
|
62
|
+
:event_promocodes => 'eventspot/events/%s/promocodes',
|
63
|
+
:event_promocode => 'eventspot/events/%s/promocodes/%s',
|
64
|
+
|
65
|
+
:contact_tracking_summary => 'contacts/%s/tracking/reports/summary',
|
66
|
+
:contact_tracking_bounces => 'contacts/%s/tracking/bounces',
|
67
|
+
:contact_tracking_clicks => 'contacts/%s/tracking/clicks',
|
68
|
+
:contact_tracking_forwards => 'contacts/%s/tracking/forwards',
|
69
|
+
:contact_tracking_opens => 'contacts/%s/tracking/opens',
|
70
|
+
:contact_tracking_sends => 'contacts/%s/tracking/sends',
|
71
|
+
:contact_tracking_unsubscribes => 'contacts/%s/tracking/unsubscribes',
|
72
|
+
:contact_tracking_link => 'contacts/%s/tracking/clicks/%s',
|
73
|
+
|
74
|
+
:library_info => 'library/info',
|
75
|
+
:library_files => 'library/files',
|
76
|
+
:library_files_by_folder => 'library/folders/%s/files',
|
77
|
+
:library_folders => 'library/folders',
|
78
|
+
:library_folder => 'library/folders/%s',
|
79
|
+
:library_folder_trash => 'library/folders/trash/files',
|
80
|
+
:library_file => 'library/files/%s',
|
81
|
+
:library_file_upload_status => 'library/files/uploadstatus/%s',
|
82
|
+
:library_file_move => 'library/folders/%s/files'
|
83
|
+
},
|
84
|
+
|
85
|
+
# OAuth2 Authorization related configuration options
|
86
|
+
:auth => {
|
87
|
+
:base_url => 'https://oauth2.constantcontact.com/oauth2/',
|
88
|
+
:response_type_code => 'code',
|
89
|
+
:response_type_token => 'token',
|
90
|
+
:authorization_code_grant_type => 'authorization_code',
|
91
|
+
:authorization_endpoint => 'oauth/siteowner/authorize',
|
92
|
+
:token_endpoint => 'oauth/token',
|
93
|
+
:token_info => 'tokeninfo.htm',
|
94
|
+
:api_key => '',
|
95
|
+
:api_secret => '',
|
96
|
+
:redirect_uri => ''
|
97
|
+
},
|
98
|
+
|
99
|
+
# Column names used with bulk activities
|
100
|
+
:activities_columns => {
|
101
|
+
:email => 'EMAIL',
|
102
|
+
:first_name => 'FIRST NAME',
|
103
|
+
:middle_name => 'MIDDLE NAME',
|
104
|
+
:last_name => 'LAST NAME',
|
105
|
+
:birthday_day => 'BIRTHDAY_DAY',
|
106
|
+
:birthday_month => 'BIRTHDAY_MONTH',
|
107
|
+
:anniversary => 'ANNIVERSARY',
|
108
|
+
:job_title => 'JOB TITLE',
|
109
|
+
:company_name => 'COMPANY NAME',
|
110
|
+
:work_phone => 'WORK PHONE',
|
111
|
+
:home_phone => 'HOME PHONE',
|
112
|
+
:address1 => 'ADDRESS LINE 1',
|
113
|
+
:address2 => 'ADDRESS LINE 2',
|
114
|
+
:address3 => 'ADDRESS LINE 3',
|
115
|
+
:city => 'CITY',
|
116
|
+
:state => 'STATE',
|
117
|
+
:state_province => 'US STATE/CA PROVINCE',
|
118
|
+
:country => 'COUNTRY',
|
119
|
+
:postal_code => 'ZIP/POSTAL CODE',
|
120
|
+
:sub_postal_code => 'SUB ZIP/POSTAL CODE',
|
121
|
+
:custom_field_1 => 'CUSTOM FIELD 1',
|
122
|
+
:custom_field_2 => 'CUSTOM FIELD 2',
|
123
|
+
:custom_field_3 => 'CUSTOM FIELD 3',
|
124
|
+
:custom_field_4 => 'CUSTOM FIELD 4',
|
125
|
+
:custom_field_5 => 'CUSTOM FIELD 5',
|
126
|
+
:custom_field_6 => 'CUSTOM FIELD 6',
|
127
|
+
:custom_field_7 => 'CUSTOM FIELD 7',
|
128
|
+
:custom_field_8 => 'CUSTOM FIELD 8',
|
129
|
+
:custom_field_9 => 'CUSTOM FIELD 9',
|
130
|
+
:custom_field_10 => 'CUSTOM FIELD 10',
|
131
|
+
:custom_field_11 => 'CUSTOM FIELD 11',
|
132
|
+
:custom_field_12 => 'CUSTOM FIELD 12',
|
133
|
+
:custom_field_13 => 'CUSTOM FIELD 13',
|
134
|
+
:custom_field_14 => 'CUSTOM FIELD 14',
|
135
|
+
:custom_field_15 => 'CUSTOM FIELD 15'
|
136
|
+
},
|
137
|
+
|
138
|
+
# Errors to be returned for various exceptions
|
139
|
+
:errors => {
|
140
|
+
:api_key_missing => 'api_key required either explicitly or in configuration.',
|
141
|
+
:access_token_missing => 'access_token required explicitly.',
|
142
|
+
:id_or_object => 'Only an id or %s object are allowed for this method.',
|
143
|
+
:invalid_webhook => 'Invalid Webhook. The x-ctct-hmac-sha256 does not correspond to message encryption.',
|
144
|
+
:api_secret_missing => 'The api_secret is missing in explicit call or configuration.'
|
145
|
+
}
|
146
|
+
}
|
147
|
+
|
148
|
+
class << self
|
149
|
+
attr_accessor :props
|
150
|
+
|
151
|
+
def configure
|
152
|
+
yield props if block_given?
|
153
|
+
end
|
154
|
+
|
155
|
+
# Get a configuration property given a specified location, example usage: Config::get('auth.token_endpoint')
|
156
|
+
# @param [String] index - location of the property to obtain
|
157
|
+
# @return [String]
|
158
|
+
def get(index)
|
159
|
+
properties = index.split('.')
|
160
|
+
get_value(properties, props)
|
161
|
+
end
|
162
|
+
|
163
|
+
private
|
164
|
+
|
165
|
+
# Navigate through a config array looking for a particular index
|
166
|
+
# @param [Array] index The index sequence we are navigating down
|
167
|
+
# @param [Hash, String] value The portion of the config array to process
|
168
|
+
# @return [String]
|
169
|
+
def get_value(index, value)
|
170
|
+
index = index.is_a?(Array) ? index : [index]
|
171
|
+
key = index.shift.to_sym
|
172
|
+
value.is_a?(Hash) and value[key] and value[key].is_a?(Hash) ?
|
173
|
+
get_value(index, value[key]) :
|
174
|
+
value[key]
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
#
|
2
|
+
# helpers.rb
|
3
|
+
# ConstantContact
|
4
|
+
#
|
5
|
+
# Copyright (c) 2013 Constant Contact. All rights reserved.
|
6
|
+
|
7
|
+
module ConstantContact
|
8
|
+
module Util
|
9
|
+
class Helpers
|
10
|
+
class << self
|
11
|
+
|
12
|
+
# Build the HTTP query from the given parameters
|
13
|
+
# @param [Hash] params
|
14
|
+
# @return [String] query string
|
15
|
+
def http_build_query(params)
|
16
|
+
params.collect{ |k,v| "#{k.to_s}=#{encode(v.to_s)}" }.reverse.join('&')
|
17
|
+
end
|
18
|
+
|
19
|
+
# Escape special characters
|
20
|
+
# @param [String] str
|
21
|
+
def encode(str)
|
22
|
+
CGI.escape(str).gsub('.', '%2E').gsub('-', '%2D')
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
#
|
2
|
+
# validator.rb
|
3
|
+
# ConstantContact
|
4
|
+
#
|
5
|
+
# Copyright (c) 2013 Constant Contact. All rights reserved.
|
6
|
+
|
7
|
+
module ConstantContact
|
8
|
+
module Webhooks
|
9
|
+
module Helpers
|
10
|
+
class Validator
|
11
|
+
class << self
|
12
|
+
|
13
|
+
# Validate the request received from Constant Contact.
|
14
|
+
# Compute the HMAC digest and compare it to the value in the x-ctct-hmac-sha256 header.
|
15
|
+
# If they match, you can be sure that the webhook was sent by Constant Contact and the message has not been compromised.
|
16
|
+
# @param [String] secret The Constant Contact secret key
|
17
|
+
# @param [String] hmac The value received in the x-ctct-hmac-sha256 header.
|
18
|
+
# @param [String] data The body message from the POST received from ConstantContact in Webhook callback.
|
19
|
+
# @return true if the computed vs. received values match; false otherwise.
|
20
|
+
def validate(secret, hmac, data)
|
21
|
+
digest = OpenSSL::Digest.new('sha256')
|
22
|
+
calculated_hmac = Base64.encode64(OpenSSL::HMAC.digest(digest, secret, data)).strip
|
23
|
+
calculated_hmac == hmac
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
#
|
2
|
+
# billing_change_notification.rb
|
3
|
+
# ConstantContact
|
4
|
+
#
|
5
|
+
# Copyright (c) 2013 Constant Contact. All rights reserved.
|
6
|
+
|
7
|
+
module ConstantContact
|
8
|
+
module Webhooks
|
9
|
+
module Models
|
10
|
+
class BillingChangeNotification
|
11
|
+
attr_accessor :event_type, :url
|
12
|
+
|
13
|
+
# Factory method to create a BillingChangeNotification model object from a hash
|
14
|
+
# @param [Hash] props - hash of properties to create object from
|
15
|
+
# @return [BillingChangeNotification]
|
16
|
+
def self.create(props)
|
17
|
+
obj = BillingChangeNotification.new
|
18
|
+
props.each do |key, value|
|
19
|
+
key = key.to_s
|
20
|
+
obj.send("#{key}=", value) if obj.respond_to? key
|
21
|
+
end if props
|
22
|
+
obj
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|