fuelsdk 0.0.1

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.
@@ -0,0 +1,142 @@
1
+ module FuelSDK
2
+ class ET_Response
3
+ # not doing accessor so user, can't update these values from response.
4
+ # You will see in the code some of these
5
+ # items are being updated via back doors and such.
6
+ attr_reader :code, :message, :results, :request_id, :body, :raw
7
+
8
+ # some defaults
9
+ def success
10
+ @success ||= false
11
+ end
12
+ alias :success? :success
13
+ alias :status :success # backward compatibility
14
+
15
+ def more
16
+ @more ||= false
17
+ end
18
+ alias :more? :more
19
+
20
+ def initialize raw, client
21
+ @client = client # keep connection with client in case we request more
22
+ @results = []
23
+ @raw = raw
24
+ @body = raw.body
25
+ unpack raw
26
+ rescue => ex # all else fails return raw
27
+ puts ex.message
28
+ raw
29
+ end
30
+
31
+ def continue
32
+ raise NotImplementedError
33
+ end
34
+
35
+ private
36
+ def unpack raw
37
+ raise NotImplementedError
38
+ end
39
+ end
40
+
41
+ class ET_Client
42
+ attr_accessor :debug, :access_token, :auth_token, :internal_token, :refresh_token,
43
+ :id, :secret, :signature
44
+
45
+ include FuelSDK::Soap
46
+ include FuelSDK::Rest
47
+
48
+ def jwt= encoded_jwt
49
+ raise 'Require app signature to decode JWT' unless self.signature
50
+ decoded_jwt = JWT.decode(encoded_jwt, self.signature, true)
51
+
52
+ self.auth_token = decoded_jwt['request']['user']['oauthToken']
53
+ self.internal_token = decoded_jwt['request']['user']['internalOauthToken']
54
+ self.refresh_token = decoded_jwt['request']['user']['refreshToken']
55
+ #@authTokenExpiration = Time.new + decoded_jwt['request']['user']['expiresIn']
56
+ end
57
+
58
+ def initialize(params={}, debug=false)
59
+ self.debug = debug
60
+ client_config = params['client']
61
+ if client_config
62
+ self.id = client_config["id"]
63
+ self.secret = client_config["secret"]
64
+ self.signature = client_config["signature"]
65
+ end
66
+
67
+ self.jwt = params['jwt'] if params['jwt']
68
+ self.refresh_token = params['refresh_token'] if params['refresh_token']
69
+
70
+ self.wsdl = params["defaultwsdl"] if params["defaultwsdl"]
71
+ end
72
+
73
+ def refresh force=false
74
+ raise 'Require Client Id and Client Secret to refresh tokens' unless (id && secret)
75
+
76
+ if (self.access_token.nil? || force)
77
+ payload = Hash.new.tap do |h|
78
+ h['clientId']= id
79
+ h['clientSecret'] = secret
80
+ h['refreshToken'] = refresh_token if refresh_token
81
+ h['accessType'] = 'offline'
82
+ end
83
+
84
+ options = Hash.new.tap do |h|
85
+ h['data'] = payload
86
+ h['content_type'] = 'application/json'
87
+ h['params'] = {'legacy' => 1}
88
+ end
89
+
90
+ response = post("https://auth.exacttargetapis.com/v1/requestToken", options)
91
+ raise "Unable to refresh token: #{response['message']}" unless response.has_key?('accessToken')
92
+
93
+ self.access_token = response['accessToken']
94
+ self.internal_token = response['legacyToken']
95
+ #@authTokenExpiration = Time.new + tokenResponse['expiresIn']
96
+ self.refresh_token = response['refreshToken'] if response.has_key?("refreshToken")
97
+ end
98
+ end
99
+
100
+ def refresh!
101
+ refresh true
102
+ end
103
+
104
+ #def AddSubscriberToList(emailAddress, listIDs, subscriberKey = nil)
105
+ # newSub = FuelSDK::ET_Subscriber.new
106
+ # newSub.authStub = self
107
+ # lists = []
108
+
109
+ # listIDs.each{ |p|
110
+ # lists.push({"ID"=> p})
111
+ # }
112
+
113
+ # newSub.props = {"EmailAddress" => emailAddress, "Lists" => lists}
114
+ # if !subscriberKey.nil? then
115
+ # newSub.props['SubscriberKey'] = subscriberKey;
116
+ # end
117
+
118
+ # # Try to add the subscriber
119
+ # postResponse = newSub.post
120
+
121
+ # if postResponse.status == false then
122
+ # # If the subscriber already exists in the account then we need to do an update.
123
+ # # Update Subscriber On List
124
+ # if postResponse.results[0][:error_code] == "12014" then
125
+ # patchResponse = newSub.patch
126
+ # return patchResponse
127
+ # end
128
+ # end
129
+ # return postResponse
130
+ #end
131
+
132
+ #def CreateDataExtensions(dataExtensionDefinitions)
133
+ # newDEs = FuelSDK::ET_DataExtension.new
134
+ # newDEs.authStub = self
135
+
136
+ # newDEs.props = dataExtensionDefinitions
137
+ # postResponse = newDEs.post
138
+
139
+ # return postResponse
140
+ #end
141
+ end
142
+ end
@@ -0,0 +1,79 @@
1
+ require 'open-uri'
2
+ require 'net/https'
3
+ require 'json'
4
+
5
+ module FuelSDK
6
+
7
+ class HTTPResponse < FuelSDK::ET_Response
8
+
9
+ def initialize raw, client, request
10
+ super raw, client
11
+ @request = request
12
+ end
13
+
14
+ def continue
15
+ rsp = nil
16
+ if more?
17
+ rsp = unpack @client.rest_get(@request['url'], @request['options'])
18
+ else
19
+ puts 'No more data'
20
+ end
21
+
22
+ rsp
23
+ end
24
+
25
+ def [] key
26
+ @results[key]
27
+ end
28
+
29
+ private
30
+ def unpack raw
31
+ @code = raw.code.to_i
32
+ @message = raw.message
33
+ @body = JSON.parse(raw.body) rescue {}
34
+ @results = @body
35
+ @more = ((@results['count'] || @results['totalCount']) > @results['page'] * @results['pageSize']) rescue false
36
+ @success = @message == 'OK'
37
+ end
38
+
39
+ # by default try everything against results
40
+ def method_missing method, *args, &block
41
+ @results.send(method, *args, &block)
42
+ end
43
+ end
44
+
45
+ module HTTPRequest
46
+
47
+ request_methods = ['get', 'post', 'patch', 'delete']
48
+ request_methods.each do |method|
49
+ class_eval <<-EOT, __FILE__, __LINE__ + 1
50
+ def #{method}(url, options={}) # def post(url, options)
51
+ request Net::HTTP::#{method.capitalize}, url, options # request Net::HTTP::Post, url, options
52
+ end # end
53
+ EOT
54
+ end
55
+
56
+ private
57
+
58
+ def generate_uri(url, params=nil)
59
+ uri = URI.parse(url)
60
+ uri.query = URI.encode_www_form(params) if params
61
+ uri
62
+ end
63
+
64
+ def request(method, url, options={})
65
+ uri = generate_uri url, options['params']
66
+
67
+ http = Net::HTTP.new(uri.host, uri.port)
68
+ http.use_ssl = true
69
+
70
+ data = options['data']
71
+ _request = method.new uri.request_uri
72
+ _request.body = data.to_json if data
73
+ _request.content_type = options['content_type'] if options['content_type']
74
+ response = http.request(_request)
75
+
76
+ HTTPResponse.new(response, self, :url => url, :options => options)
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,143 @@
1
+ module FuelSDK
2
+ module ET_SoapGet
3
+ def get
4
+ client.soap_get id, properties, filter
5
+ end
6
+
7
+ def info
8
+ client.soap_describe id
9
+ end
10
+ end
11
+
12
+ module ET_SoapCUD #create, update, delete
13
+ def post
14
+ client.soap_post id, properties
15
+ end
16
+
17
+ def patch
18
+ client.soap_patch id, properties
19
+ end
20
+
21
+ def delete
22
+ client.soap_delete id, properties
23
+ end
24
+ end
25
+
26
+ module ET_RestGet
27
+ def get
28
+ client.rest_get id, properties
29
+ end
30
+ end
31
+
32
+ module ET_RestCUD
33
+ def post
34
+ client.rest_post id, properties
35
+ end
36
+
37
+ def patch
38
+ client.rest_patch id, properties
39
+ end
40
+
41
+ def delete
42
+ client.rest_delete id, properties
43
+ end
44
+ end
45
+
46
+ class ET_Base
47
+ attr_accessor :filter, :properties, :client
48
+ attr_reader :id
49
+
50
+ alias props= properties= # backward compatibility
51
+ alias authStub= client= # backward compatibility
52
+
53
+ def id
54
+ self.class.name.split('::').pop.split('_').pop
55
+ end
56
+ end
57
+
58
+ class ET_BounceEvent < ET_Base
59
+ include ET_SoapGet
60
+ end
61
+
62
+ class ET_ClickEvent < ET_Base
63
+ include ET_SoapGet
64
+ end
65
+
66
+ class ET_ContentArea < ET_Base
67
+ include ET_SoapGet
68
+ include ET_SoapCUD
69
+ end
70
+
71
+ class ET_Folder < ET_Base
72
+ include ET_SoapGet
73
+ include ET_SoapCUD
74
+ def id
75
+ 'DataFolder'
76
+ end
77
+ end
78
+
79
+ class ET_Email < ET_Base
80
+ include ET_SoapGet
81
+ include ET_SoapCUD
82
+ end
83
+
84
+ class ET_List < ET_Base
85
+ include ET_SoapGet
86
+ include ET_SoapCUD
87
+
88
+ class Subscriber < ET_Base
89
+ include ET_SoapGet
90
+ def id
91
+ 'ListSubscriber'
92
+ end
93
+ end
94
+ end
95
+
96
+ class ET_OpenEvent < ET_Base
97
+ include ET_SoapGet
98
+ end
99
+
100
+ class ET_SentEvent < ET_Base
101
+ include ET_SoapGet
102
+ end
103
+
104
+ class ET_Subscriber < ET_Base
105
+ include ET_SoapGet
106
+ include ET_SoapCUD
107
+ end
108
+
109
+ class ET_UnsubEvent < ET_Base
110
+ include ET_SoapGet
111
+ end
112
+
113
+ class ET_Campaign < ET_Base
114
+ include ET_RestGet
115
+ include ET_RestCUD
116
+
117
+
118
+ def properties
119
+ @properties ||= {}
120
+ @properties.merge! 'id' => '' unless @properties.include? 'id'
121
+ @properties
122
+ end
123
+
124
+ def id
125
+ "https://www.exacttargetapis.com/hub/v1/campaigns/%{id}"
126
+ end
127
+
128
+ class Asset < ET_Base
129
+ include ET_RestGet
130
+ include ET_RestCUD
131
+
132
+ def properties
133
+ @properties ||= {}
134
+ @properties.merge! 'assetId' => '' unless @properties.include? 'assetId'
135
+ @properties
136
+ end
137
+
138
+ def id
139
+ 'https://www.exacttargetapis.com/hub/v1/campaigns/%{id}/assets/%{assetId}'
140
+ end
141
+ end
142
+ end
143
+ end
@@ -0,0 +1,84 @@
1
+ module FuelSDK
2
+ module Rest
3
+
4
+ include FuelSDK::Targeting
5
+
6
+ def rest_client
7
+ self
8
+ end
9
+
10
+ def normalize_keys obj
11
+ if obj and obj.is_a? Hash
12
+ obj.keys.each do |k|
13
+ obj[(k.to_sym rescue k) || k] = obj.delete(k)
14
+ end
15
+ end
16
+ obj
17
+ end
18
+
19
+ def get_url_properties url, properties
20
+ url_property_names = url.scan(/(%{(.+?)})/).collect{|frmt, name| name}
21
+ url_properties = {}
22
+ properties.keys.each do |k|
23
+ if url_property_names.include? k
24
+ url_properties[k] = properties.delete(k)
25
+ end
26
+ end
27
+ url_properties
28
+ end
29
+
30
+ def complete_url url, url_properties
31
+ normalize_keys(url_properties)
32
+ url = url % url_properties if url_properties
33
+ url.end_with?('/') ? url.chop : url
34
+ rescue KeyError => ex
35
+ raise "#{ex.message} to complete #{url}"
36
+ end
37
+
38
+ def parse_properties url, properties
39
+ url_properties = get_url_properties url, properties
40
+ url = complete_url url, url_properties
41
+ [url, properties]
42
+ end
43
+
44
+ def rest_get url, properties={}
45
+ url, properties = parse_properties url, properties
46
+ rest_request :get, url, {'params' => properties}
47
+ end
48
+
49
+ def rest_delete url, properties={}
50
+ url, properties = parse_properties url, properties
51
+ rest_request :delete, url
52
+ end
53
+
54
+ def rest_patch url, properties={}
55
+ url, payload = parse_properties url, properties
56
+ rest_request :patch, url, {'data' => payload,
57
+ 'content_type' => 'application/json'}
58
+ end
59
+
60
+ def rest_post url, properties={}
61
+ url, payload = parse_properties url, properties
62
+ rest_request :post, url, {'data' => payload,
63
+ 'content_type' => 'application/json'}
64
+ end
65
+
66
+ private
67
+ def rest_request action, url, options={}
68
+ retried = false
69
+ begin
70
+ (options['params'] ||= {}).merge! 'access_token' => access_token
71
+ rsp = rest_client.send(action, url, options)
72
+ raise 'Unauthorized' if rsp.message == 'Unauthorized'
73
+ rescue
74
+ raise if retried
75
+ self.refresh! # ask for forgiveness not, permission
76
+ retried = true
77
+ retry
78
+ end
79
+ rsp
80
+ rescue
81
+ rsp
82
+ end
83
+ end
84
+ end