traction 0.1.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 3773e88b2b90c95b451b5f8dee4cbb77464f6679
4
+ data.tar.gz: d6a69298660e16aa1399e094ccc2d70e60848a36
5
+ SHA512:
6
+ metadata.gz: 995d56fccd80c6a9ba7e8161e516a3c0c3893f6b3a7887ad948f7e23d0f285d95c52da4c865deaf700fcd3f4cb049f64a9b6b405ce6e112397f222f570b68c93
7
+ data.tar.gz: 14e1d4f06de278bd2872d7626488c6f0deda647c2013b0f0546f3b2114af364386d8ece2617c32f5fe496780f0c29053ea2360c5b4f9899523289b9a8b2470a7
data/.gitignore ADDED
@@ -0,0 +1,33 @@
1
+ *.gem
2
+ *.rbc
3
+ /.config
4
+ /coverage/
5
+ /InstalledFiles
6
+ /pkg/
7
+ /spec/reports/
8
+ /test/tmp/
9
+ /test/version_tmp/
10
+ /tmp/
11
+
12
+ ## Documentation cache and generated files:
13
+ /.yardoc/
14
+ /_yardoc/
15
+ /doc/
16
+ /rdoc/
17
+
18
+ ## Environment normalisation:
19
+ /.bundle/
20
+ /lib/bundler/man/
21
+
22
+ # for a library or gem, you might want to ignore these files since the code is
23
+ # intended to run in multiple environments; otherwise, check them in:
24
+ Gemfile.lock
25
+ .ruby-version
26
+ .ruby-gemset
27
+
28
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
29
+ .rvmrc
30
+
31
+ *.swp
32
+ *.swo
33
+ *.swn
data/.travis.yml ADDED
@@ -0,0 +1,3 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.2.1
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in traction.gemspec
4
+ gemspec
data/README.md ADDED
@@ -0,0 +1,77 @@
1
+ # Traction
2
+
3
+ A Ruby wrapper of the <a href="https://tractiondigital.com/" target="_blank">Traction Digital</a> API. The wrapper contains only methods for endpoints for which previous access has been established. The addition of new methods when an API is created is encouraged.
4
+
5
+ Traction Digital <a href="https://int.tractionplatform.com/traction/help/int/webframe.html?Dynamic_API.html" target="_blank">API Documentation</a> requires an account and login. The documentation may be limited and/or out of date. Refer to the API Information associated with a particular function available in a specific campaign where possible for up to date information.
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'traction'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself using Rubygems:
20
+
21
+ $ gem install traction
22
+
23
+ ## Usage
24
+
25
+ Configure Traction with your API password and an object containing keys that become namespaces and paths associated with a "web connection" available to you in your Traction account. These paths are found in "API Information" in the Traction Account Dashboard, for a function within a given campaign.
26
+
27
+ The available methods in traction depend on the functions created in the traction dashboard for a given campaign. To confirm a method is available, ensure that a traction function exists with the method detailed in the API Information tab.
28
+
29
+ Using Rails, configuration can occur in an initializer:
30
+
31
+ ```ruby
32
+ # config/initializers/traction.rb
33
+
34
+ Traction.configure("<your_api_password>", {competition: "<web_connection_path>",
35
+ registration: "<web_connection_path>",
36
+ triggered: "<web_connection_path>"}
37
+ ```
38
+
39
+ Or, it could happen anywhere in your Ruby app before method call, either on app load or in a before hook will work fine.
40
+
41
+ Once you have completed configuration, use the gem methods to make api calls using the appropriate namespace you have created, associated with the traction function where that API is available:
42
+
43
+ ```ruby
44
+ Traction.registration.get_customer_by("EMAIL", "example@email.com", ["EMAIL", "MOBILE", "FIRSTNAME", "LASTNAME"]
45
+ #=>
46
+ #{
47
+ # data: {
48
+ # customer: {
49
+ # email: "example@email.com",
50
+ # mobile: "0412345678",
51
+ # firstname: "Jane",
52
+ # lastname: "Doe"
53
+ # }
54
+ # },
55
+ # success: true
56
+ #}
57
+
58
+ ```
59
+
60
+ For the full list of available methods, refer to the <a href="http://www.rubydoc.info/gems/traction" target="_blank">documentation</a>.
61
+
62
+ ## To Do
63
+ - provide some abstracted methods for removing subscriptions and groups etc
64
+ - add remaining methods when access is gained to new function in Traction Dashboard
65
+
66
+ ## Contributing
67
+
68
+ Contributions are fully encouraged as the Traction API documentation does not reveal all available methods and new methods are available only when a function is available in the Traction Account dashboard. Simple wrappers and abstractions are welcome.
69
+
70
+ Particularly, given that traction functions exist for which no method has been made available yet, it is highly encouraged to add a method to this gem (using consistent style) if a user gains access to a function not yet wrapped by this gem.
71
+
72
+ 1. Fork it ( https://github.com/hardhatdigital/traction/fork )
73
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
74
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
75
+ 4. Push to the branch (`git push origin my-new-feature`)
76
+ 5. Create a new Pull Request
77
+ 6. Party
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "traction"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
data/bin/setup ADDED
@@ -0,0 +1,7 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
6
+
7
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,4 @@
1
+ module Traction
2
+ VERSION = "0.1.0"
3
+ DATE = "2016-02-19"
4
+ end
@@ -0,0 +1,328 @@
1
+ require "json"
2
+ require "net/http"
3
+
4
+ module Traction
5
+
6
+ # Creates a new WebConnection object to contain wrapped API methods associated with a particular
7
+ # WebConnection, or Function, in Traction API terminology.
8
+ #
9
+ # Method examples use the hypothetical namespaces from the configuration example.
10
+ class WebConnection
11
+ DOMAIN = "int.api.tractionplatform.com"
12
+
13
+ def initialize(path, password)
14
+ @path = path
15
+ @password = password
16
+ end
17
+
18
+ # Registration method for retrieving attributes for a customer, searching against a given field.
19
+ #
20
+ # @param field [String] The field to search against.
21
+ # @param value [String] The value to search for.
22
+ # @param attributes [Array] The retrieved customer fields on a successful result.
23
+ #
24
+ # @example
25
+ # Traction.registration.get_customer_by("EMAIL", "example@email.com", ["EMAIL", "MOBILE", "FIRSTNAME", "LASTNAME"]
26
+ # #=>
27
+ # #{
28
+ # # data: {
29
+ # # customer: {
30
+ # # email: "example@email.com",
31
+ # # mobile: "0412345678",
32
+ # # firstname: "John",
33
+ # # lastname: "Doe"
34
+ # # }
35
+ # # },
36
+ # # success: true
37
+ # #}
38
+ # # OR
39
+ # #=>
40
+ # #{
41
+ # # error: {
42
+ # # code: 1010,
43
+ # # description: "Customer not found",
44
+ # # cause: [{
45
+ # # "field": "customer.EMAIL"
46
+ # # }]
47
+ # # }
48
+ # #}
49
+ def get_customer_by(field, value, attributes=[])
50
+ body = {customerLookup: {field => value},
51
+ customerAttributes: attributes}
52
+
53
+ get_response_for(body)
54
+ end
55
+
56
+ # Registration method for adding a customer to the campaign customer list.
57
+ #
58
+ # @param details [Hash] The customer details to add.
59
+ # @param optional_data [Hash] Optional. Data available in triggered emails to the customer.
60
+ #
61
+ # @example
62
+ # Traction.registration.add_customer("EMAIL" => "example@email.com", "MOBILE" => "0412345678", "FIRSTNAME" => "John", "LASTNAME" => "Doe")
63
+ # #=> {data: {}, success: true}
64
+ # # OR
65
+ # #=>
66
+ # #{
67
+ # # error: {
68
+ # # code: 1000,
69
+ # # description: "Invalid Parameter Data",
70
+ # # cause: [{
71
+ # # field: "customer.EMAIL",
72
+ # # message: "invalid email address"
73
+ # # }]
74
+ # # },
75
+ # # success: false
76
+ # #}
77
+ def add_customer(details, optional_data={})
78
+ body = {customer: details,
79
+ transData: optional_data}
80
+
81
+ get_response_for(body)
82
+ end
83
+
84
+ # Registration method for adding a customer to the campaign customer list, and associating the customer
85
+ # with (or dissociating a customer from) groups and/or subscriptions.
86
+ #
87
+ # @param details [Hash] The customer details to add.
88
+ # @param groups [Hash] Optional. Groups to associate or dissociate with; true associates, false dissociates.
89
+ # @param subscriptions [Hash] Optional. Subscriptions to associate or dissociate with; "SUBSCRIBE" associates, "UNSUBSCRIBE" dissociates.
90
+ #
91
+ # @example
92
+ # Traction.registration.add_customer_with_group_and_subscription({"EMAIL" => "example@email.com", "MOBILE" => "0412345678", "FIRSTNAME" => "John", "LASTNAME" => "Doe"}, {"12345" => true, "12346" => true, "23456" => false}, {"9876543210" => "SUBSCRIBE", "9876543211" => "SUBSCRIBE", "9876543212" => "UNSUBSCRIBE"})
93
+ # #=> {data: {}, success: true}
94
+ # # OR
95
+ # #=>
96
+ # #{
97
+ # # error: {
98
+ # # code: 1150,
99
+ # # description: "Invalid Group ID, please confirm group exists",
100
+ # # cause: "Group Id [12345] should be pre-existing"
101
+ # # },
102
+ # # success: false
103
+ # #}
104
+ def add_customer_with_group_and_subscription(details, groups={}, subscriptions={})
105
+ body = {customer: details,
106
+ groups: groups,
107
+ subscriptions: subscriptions}
108
+
109
+ get_response_for(body)
110
+ end
111
+
112
+ # Registration method for adding a customer directly to an associated email list, selected on creation
113
+ # of the function in traction.
114
+ #
115
+ # @param details [Hash] The customer details to add.
116
+ # @param optional_data [Hash] Optional. Data available in triggered emails to the customer.
117
+ #
118
+ # @example
119
+ # Traction.registration.add_customer("EMAIL" => "example@email.com", "MOBILE" => "0412345678", "FIRSTNAME" => "John", "LASTNAME" => "Doe")
120
+ # #=> {data: {}, success: true}
121
+ # # OR
122
+ # #=>
123
+ # #{
124
+ # # error: {
125
+ # # code: 1000,
126
+ # # description: "Invalid Parameter Data",
127
+ # # cause: [{
128
+ # # field: "customer.EMAIL",
129
+ # # message: "invalid email address"
130
+ # # }]
131
+ # # },
132
+ # # success: false
133
+ # #}
134
+ def web_registration(details, optional_data={})
135
+ body = {customer: details,
136
+ transData: optional_data}
137
+
138
+ get_response_for(body)
139
+ end
140
+
141
+ # Competition method for validating a potential entry to a competition.
142
+ #
143
+ # @param field [String] The relevant customer field to validate with.
144
+ # @param value [String] The value associated with the field.
145
+ # @param entry_code [String] The entry code to validate.
146
+ #
147
+ # @example
148
+ # Traction.competition.validate_entry("EMAIL", "example@email.com", "ABC123")
149
+ # #=> {data: {}, success: true}
150
+ # # OR
151
+ # #=>
152
+ # #{
153
+ # # error: {
154
+ # # code: 2040,
155
+ # # description: "Entry Code Used",
156
+ # # cause: [{
157
+ # # field: "entryCode",
158
+ # # message: "[ABC123] has already been used"
159
+ # # }]
160
+ # # },
161
+ # # success: false
162
+ # #}
163
+ def validate_entry(field, value, entry_code)
164
+ body = {mode: "VALIDATE",
165
+ customer: {field => value},
166
+ entryCode: entry_code}
167
+
168
+ get_response_for(body)
169
+ end
170
+
171
+ # Competition method for adding an entrant to (or removing an entrant from) a competition.
172
+ #
173
+ # @param details [Hash] The customer details to add.
174
+ # @param entry_code [String] The entry code for the entrant.
175
+ # @param subscribe [Boolean] Optional. Subscribe (true) or unsubscribe (false) from the competition. Defaults to true.
176
+ # @param optional_data [Hash] Optional. Data available in triggered emails to the customer.
177
+ #
178
+ # @example
179
+ # Traction.competition.add_competition_entrant({"EMAIL" => "example@email.com", "MOBILE" => "0412345678", "FIRSTNAME" => "Jane", "LASTNAME" => "Doe"}, "XYZ123")
180
+ # #=> {data: {}, success: true}
181
+ # # OR
182
+ # #=>
183
+ # #{
184
+ # # error: {
185
+ # # code: 2040,
186
+ # # description: "Entry Code Used",
187
+ # # cause: [{
188
+ # # field: "entryCode",
189
+ # # message: "[XYZ123] has already been used"
190
+ # # }]
191
+ # # },
192
+ # # success: false
193
+ # #}
194
+ def add_competition_entrant(details, entry_code, subscribe=true, optional_data={})
195
+ body = {customer: details,
196
+ entryCode: entry_code,
197
+ subscribe: subscribe,
198
+ transData: optional_data}
199
+
200
+ get_response_for(body)
201
+ end
202
+
203
+ # Competition method for drawing the competition winner/s.
204
+ #
205
+ # @param venues_ids [Array] Optional. List of venues for which the winner is drawn from. Defaults to all venues.
206
+ #
207
+ # @example
208
+ # Traction.competition.draw
209
+ # #=> {data: {}, success: true}
210
+ # # OR
211
+ # #=>
212
+ # #{
213
+ # # error: {
214
+ # # code: 2140,
215
+ # # description: "Draw already done",
216
+ # # cause: null
217
+ # # },
218
+ # # success: false
219
+ # #}
220
+ def draw_competition(venue_ids=[])
221
+ body = {mode: "DRAW"}
222
+ body[:venueIdList] = venue_ids if venue_ids.any?
223
+
224
+ get_response_for(body)
225
+ end
226
+
227
+ # Competition method for providing redemption code to a winner.
228
+ #
229
+ # @param field [String] The field to search against.
230
+ # @param value [String] The value to search for.
231
+ # @param venues_id [String] Id of venue for which redemption code and customer apply.
232
+ # @param redemption_code [String] The redemption code for the winner.
233
+ # @param optional_data [Hash] Optional. Data available in triggered emails to the customer.
234
+ #
235
+ # @example
236
+ # Traction.competition.redeem_winner("EMAIL", "example@email.com", "XYZ", "ABC123")
237
+ # #=>
238
+ # #{
239
+ # # data: {
240
+ # # numWinners: 8,
241
+ # # numWinnersNoRedemptionCode: 2
242
+ # # },
243
+ # # success: true
244
+ # #}
245
+ # # OR
246
+ # #=>
247
+ # #{
248
+ # # error: {
249
+ # # code: 2120,
250
+ # # description: "Claim code invalid",
251
+ # # cause: null
252
+ # # },
253
+ # # success: false
254
+ # #}
255
+ def redeem_winner(field, value, venue_id, redemption_code, optional_data={})
256
+ body = {mode: "REDEEM",
257
+ customer: {field => value},
258
+ venueId: venue_id,
259
+ redemptionCode: redemption_code,
260
+ transData: optional_data}
261
+
262
+ get_response_for(body)
263
+ end
264
+
265
+ # Triggered Message method for sending a triggered email to a subscriber. The content of the email
266
+ # can be personalised with optional data, but should already exist in traction.
267
+ #
268
+ # @param email [String] The email to search against.
269
+ # @param optional_data [Hash] Optional. Data available in triggered emails to the customer.
270
+ #
271
+ # @example
272
+ # Traction.triggered.send_triggered_email("example@email.com")
273
+ # #=> {data: {}, success: true}
274
+ # # OR
275
+ # #=>
276
+ # #{
277
+ # # error: {
278
+ # # code: 1000,
279
+ # # description: "Invalid Parameter Data",
280
+ # # cause: [{
281
+ # # field: "customer.Email",
282
+ # # message: "Invalid Email Address"
283
+ # # }]
284
+ # # },
285
+ # # success: false
286
+ # #}
287
+ def send_triggered_email(email, optional_data={})
288
+ body = {customer: {EMAIL: email},
289
+ transData: optional_data}
290
+
291
+ get_response_for(body)
292
+ end
293
+
294
+ private
295
+
296
+ def get_response_for(body)
297
+ handle_response(
298
+ make_request(body))
299
+ end
300
+
301
+ def make_request(body)
302
+ uri = make_uri()
303
+
304
+ Net::HTTP.post_form(uri, {data: body.to_json, password: @password})
305
+ end
306
+
307
+ def handle_response(response)
308
+ case response.code
309
+ when "200"
310
+ JSON.parse(response.body)
311
+ when "401"
312
+ { success: false, error: { code: 401, description: "Unauthorised Access", cause: "The API call was not authorised. Check your URL and password details." } }
313
+ when "404"
314
+ { success: false, error: { code: 404, description: "Invalid URL", cause: "The URL was incorrect. Check your URL and password details." } }
315
+ when "503"
316
+ { success: false, error: { code: 503, description: "API Unavailable", cause: "The API is currently unavailable for upgrade or maintenance." } }
317
+ when "500"
318
+ { success: false, error: { code: 500, description: "Other", cause: "Unrecoverable or unknown error - API server may be down" } }
319
+ else
320
+ { success: false, error: { code: 000, description: "Unknown", cause: "Unknown error, possibly internal to gem." } }
321
+ end
322
+ end
323
+
324
+ def make_uri
325
+ URI.parse("https://#{DOMAIN}/#{@path}")
326
+ end
327
+ end
328
+ end
data/lib/traction.rb ADDED
@@ -0,0 +1,31 @@
1
+ require "traction/web_connection"
2
+
3
+ # The Traction module houses methods to interact with the Traction API.
4
+ module Traction
5
+
6
+ # Configure Traction with your API password and an object containing keys that become namespaces
7
+ # and paths associated with a "web connection" available to you in your Traction account.
8
+ # These paths are found in "API Information" in the Traction Account Dashboard, for a function
9
+ # within a given campaign.
10
+ #
11
+ # An ArgumentError is raised if you attempt to create a web connection name using a reserved word.
12
+ #
13
+ # The below example generates the namespaces Traction.competition and Traction.registration for
14
+ # functions available in the traction dashboard. The methods available to these namespaces will
15
+ # depend on the functions that were created in the traction dashboard.
16
+ #
17
+ # @param password [String] Your API password. You might want to keep this a secret.
18
+ # @param web_connection_paths [Hash] The namespaces and paths for each "function" eg. "/wkf/81h2ehc781hjd"
19
+ #
20
+ # @example
21
+ # Traction.configure("<your_api_password>", {competition: "<web_connection_path>",
22
+ # registration: "<web_connection_path>",
23
+ # triggered: "<web_connection_path>"}
24
+ def self.configure(password, web_connection_paths={})
25
+ web_connection_paths.each do |name, path|
26
+ raise ArgumentError, "!ERROR: Unable to define a web_connection_paths path with name: #{name} as this is a reserved name." if self.class.respond_to?(name)
27
+ self.class.send(:define_method, name, -> { WebConnection.new(path, password) })
28
+ end
29
+ end
30
+
31
+ end
data/traction.gemspec ADDED
@@ -0,0 +1,27 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'traction/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "traction"
8
+ spec.version = Traction::VERSION
9
+ spec.date = Traction::DATE
10
+
11
+ spec.summary = ""
12
+ spec.description = ""
13
+
14
+ spec.authors = [""]
15
+ spec.email = [""]
16
+ spec.homepage = ""
17
+
18
+ spec.license = "MIT"
19
+
20
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
21
+ spec.bindir = "exe"
22
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
23
+ spec.require_paths = ["lib"]
24
+
25
+ spec.add_development_dependency "bundler", "~> 1.9"
26
+ spec.add_development_dependency "rake", "~> 10.0"
27
+ end
metadata ADDED
@@ -0,0 +1,84 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: traction
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - ''
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2016-02-19 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.9'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.9'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ description: ''
42
+ email:
43
+ - ''
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - ".gitignore"
49
+ - ".travis.yml"
50
+ - Gemfile
51
+ - README.md
52
+ - Rakefile
53
+ - bin/console
54
+ - bin/setup
55
+ - lib/traction.rb
56
+ - lib/traction/version.rb
57
+ - lib/traction/web_connection.rb
58
+ - traction.gemspec
59
+ homepage: ''
60
+ licenses:
61
+ - MIT
62
+ metadata: {}
63
+ post_install_message:
64
+ rdoc_options: []
65
+ require_paths:
66
+ - lib
67
+ required_ruby_version: !ruby/object:Gem::Requirement
68
+ requirements:
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ version: '0'
72
+ required_rubygems_version: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ requirements: []
78
+ rubyforge_project:
79
+ rubygems_version: 2.4.6
80
+ signing_key:
81
+ specification_version: 4
82
+ summary: ''
83
+ test_files: []
84
+ has_rdoc: