traction 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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: