rgigya 1.0.2 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +13 -5
- data/VERSION +1 -1
- data/lib/rgigya/base.rb +340 -0
- data/lib/rgigya/hash.rb +19 -0
- data/lib/rgigya/sig_utils.rb +98 -0
- data/lib/rgigya.rb +3 -193
- data/rgigya.gemspec +8 -3
- data/spec/helpers.rb +26 -0
- data/spec/rgigya_secure_spec.rb +18 -0
- data/spec/rgigya_shared_examples.rb +315 -0
- data/spec/rgigya_signature_spec.rb +62 -0
- data/spec/spec_helper.rb +4 -5
- data/test/dummy/Gemfile +0 -1
- data/test/dummy/Gemfile.lock +8 -9
- data/test/dummy/config/environments/development.rb +6 -2
- data/test/dummy/log/development.log +300 -0
- metadata +21 -16
- data/spec/rgigya_spec.rb +0 -310
data/README.rdoc
CHANGED
@@ -23,8 +23,12 @@ You will need to setup your own dev site on the gigya platform for testing.
|
|
23
23
|
|
24
24
|
require 'RGigya'
|
25
25
|
|
26
|
-
|
27
|
-
|
26
|
+
RGigya.config({
|
27
|
+
:api_key => "<add api key here>",
|
28
|
+
:api_secret => "<add api secret here>",
|
29
|
+
:use_ssl => false,
|
30
|
+
:domain => "us1"
|
31
|
+
})
|
28
32
|
|
29
33
|
RGigya.socialize_notifyLogin({:siteUID => '1'})
|
30
34
|
|
@@ -34,8 +38,12 @@ You will need to setup your own dev site on the gigya platform for testing.
|
|
34
38
|
Edit your config/environments/development.rb file and add the following constants
|
35
39
|
|
36
40
|
|
37
|
-
|
38
|
-
|
41
|
+
RGigya.config({
|
42
|
+
:api_key => "<add api key here>",
|
43
|
+
:api_secret => "<add api secret here>",
|
44
|
+
:use_ssl => false,
|
45
|
+
:domain => "us1"
|
46
|
+
})
|
39
47
|
|
40
48
|
Then add your api calls in your controllers, models, libraries, etc.
|
41
49
|
|
@@ -90,7 +98,7 @@ Edit spec/spec_helper.rb
|
|
90
98
|
=== Running tests
|
91
99
|
|
92
100
|
cd <root of the project>
|
93
|
-
rspec
|
101
|
+
rspec
|
94
102
|
|
95
103
|
|
96
104
|
== Rails dummy site
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.0
|
1
|
+
1.1.0
|
data/lib/rgigya/base.rb
ADDED
@@ -0,0 +1,340 @@
|
|
1
|
+
#
|
2
|
+
# Quick sdk for the gigya api
|
3
|
+
#
|
4
|
+
# You can reference api calls at http://developers.gigya.com/037_API_reference
|
5
|
+
#
|
6
|
+
# Example call
|
7
|
+
# RGigya.socialize_setStatus(:uid => @user.id,:status => 'hello')
|
8
|
+
#
|
9
|
+
# We split the method name by the underscore and then map
|
10
|
+
# the first token to the correct url
|
11
|
+
# The example above calls the url https://socialize.gigya.com/socialize.setStatus
|
12
|
+
#
|
13
|
+
# @author Scott Sampson
|
14
|
+
# @author Michael Orr
|
15
|
+
|
16
|
+
|
17
|
+
#
|
18
|
+
# Constants to be used for the gigya key and secret.
|
19
|
+
# These should be commented out and set in your environments for your rails project.
|
20
|
+
# Uncomment below for testing without rails
|
21
|
+
#
|
22
|
+
# RGigya.config({
|
23
|
+
# :api_key => "12345",
|
24
|
+
# :api_secret => "12345,
|
25
|
+
# :use_ssl => false,
|
26
|
+
# :domain => "us1"
|
27
|
+
# })
|
28
|
+
|
29
|
+
|
30
|
+
|
31
|
+
module RGigya
|
32
|
+
|
33
|
+
# List of Available API methods
|
34
|
+
@@valid_methods = [:socialize, :gm, :comments, :accounts, :reports, :chat, :ds]
|
35
|
+
|
36
|
+
# Used to compare when we get a bad signature, mainly for debugging but helpful
|
37
|
+
@@base_signature_string = ""
|
38
|
+
@@signature = ""
|
39
|
+
|
40
|
+
#
|
41
|
+
# Custom Exceptions so we know it came from the library
|
42
|
+
# When in use please namespace them appropriately RGigya::ResponseError for readability
|
43
|
+
#
|
44
|
+
exceptions = %w[ UIDParamIsNil SiteUIDParamIsNil ResponseError BadParamsOrMethodName ErrorCodeReturned MissingApiKey MissingApiSecret]
|
45
|
+
exceptions.each { |e| const_set(e, Class.new(StandardError)) }
|
46
|
+
RGigya::JSONParseError = Class.new(JSON::ParserError)
|
47
|
+
|
48
|
+
class << self
|
49
|
+
|
50
|
+
|
51
|
+
#
|
52
|
+
# Sets the config data to be used in the api call
|
53
|
+
#
|
54
|
+
# @param [Hash] config_dat Hash of key value pairs passed to the gigya api
|
55
|
+
#
|
56
|
+
# @author Scott Sampson
|
57
|
+
def config(config_data)
|
58
|
+
@@api_key = config_data[:api_key]
|
59
|
+
@@api_secret = config_data[:api_secret]
|
60
|
+
@@use_ssl = config_data[:use_ssl] || false
|
61
|
+
@@domain = config_data[:domain] || "us1"
|
62
|
+
|
63
|
+
verify_config_data
|
64
|
+
end
|
65
|
+
|
66
|
+
# Validates that we have required config data
|
67
|
+
#
|
68
|
+
# @author Scott Sampson
|
69
|
+
def verify_config_data
|
70
|
+
if(!defined?(@@api_key))
|
71
|
+
raise RGigya::MissingApiKey, "Please provide a Gigya api key in the config data"
|
72
|
+
end
|
73
|
+
if(!defined?(@@api_secret))
|
74
|
+
raise RGigya::MissingApiSecret, "Please provide a Gigya api secret in the config data"
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
#
|
79
|
+
# Adds the required params for all api calls
|
80
|
+
#
|
81
|
+
def required_parameters
|
82
|
+
params = "apiKey=#{CGI.escape(@@api_key)}"
|
83
|
+
params += "&secret=#{CGI.escape(@@api_secret)}"
|
84
|
+
params += "&format=json"
|
85
|
+
end
|
86
|
+
|
87
|
+
#
|
88
|
+
# builds the url to be sent to the api
|
89
|
+
#
|
90
|
+
# @param [String] method The method name to be called in the gigya api
|
91
|
+
# @param [Hash] options Hash of key value pairs passed to the gigya api
|
92
|
+
#
|
93
|
+
# @return [String] the full url to be sent to the api
|
94
|
+
#
|
95
|
+
# @author Scott Sampson
|
96
|
+
def build_url(method, http_method, options = {})
|
97
|
+
if options && options.has_key?(:uid) && options[:uid].nil?
|
98
|
+
raise RGigya::UIDParamIsNil, ""
|
99
|
+
end
|
100
|
+
|
101
|
+
if options && options.has_key?(:siteUID) && options[:siteUID].nil?
|
102
|
+
raise RGigya::SiteUIDParamIsNil, ""
|
103
|
+
end
|
104
|
+
|
105
|
+
method_type,method_name = method.split(".")
|
106
|
+
if(http_method == "GET")
|
107
|
+
url = "https://#{method_type}.#{@@domain}.gigya.com/#{method}?#{required_parameters}"
|
108
|
+
if(options)
|
109
|
+
options.each do |key,value|
|
110
|
+
url += "&#{key}=#{CGI.escape(value.to_s)}"
|
111
|
+
end
|
112
|
+
end
|
113
|
+
else
|
114
|
+
url = "http://#{method_type}.#{@@domain}.gigya.com/#{method}"
|
115
|
+
end
|
116
|
+
url
|
117
|
+
end
|
118
|
+
|
119
|
+
#
|
120
|
+
# sends the https call to gigya and parses the result
|
121
|
+
# This is used for https get requests
|
122
|
+
#
|
123
|
+
# @param [String] method The method name to be called in the gigya api
|
124
|
+
# @param [Hash] options Hash of key value pairs passed to the gigya api
|
125
|
+
#
|
126
|
+
# @return [Hash] hash of the api results in key/value format
|
127
|
+
#
|
128
|
+
# @author Scott Sampson
|
129
|
+
def parse_results_secure(method,options)
|
130
|
+
# options = {} if options.is_a?(String) && options.blank?
|
131
|
+
begin
|
132
|
+
response = HTTParty.get(build_url(method, "GET", options),{:timeout => 10})
|
133
|
+
rescue SocketError,Timeout::Error => e
|
134
|
+
raise RGigya::ResponseError, e.message
|
135
|
+
end
|
136
|
+
return false if response.nil? || response.body == "Bad Request"
|
137
|
+
|
138
|
+
begin
|
139
|
+
doc = JSON(response.body)
|
140
|
+
rescue JSON::ParserError => e
|
141
|
+
raise RGigya::JSONParseError, e.message
|
142
|
+
end
|
143
|
+
doc
|
144
|
+
end
|
145
|
+
|
146
|
+
|
147
|
+
#
|
148
|
+
# Orders the params hash for the signature
|
149
|
+
# Changes boolean values to their string equivalent
|
150
|
+
#
|
151
|
+
# @param [Hash] h Hash of key value pairs passed to the gigya api
|
152
|
+
#
|
153
|
+
# @return [Hash] hash of the params being passed to the gigya api with their keys in alpha order
|
154
|
+
#
|
155
|
+
# @author Scott Sampson
|
156
|
+
def prepare_for_signature(h)
|
157
|
+
ordered_hash = {} #insert order with hash is preserved since ruby 1.9.2
|
158
|
+
h = h.inject({}){|p,(k,v)| p[k.to_sym] = v; p}
|
159
|
+
h.keys.sort.each do |key|
|
160
|
+
value = h[key]
|
161
|
+
if(!!value == value) #duck typeing.......quack
|
162
|
+
ordered_hash[key] = value.to_s
|
163
|
+
else
|
164
|
+
ordered_hash[key] = value
|
165
|
+
end
|
166
|
+
end
|
167
|
+
return ordered_hash
|
168
|
+
end
|
169
|
+
|
170
|
+
|
171
|
+
#
|
172
|
+
# Adds Timestamp, nonce and signatures to the params hash
|
173
|
+
#
|
174
|
+
# @param [String] request_uri the url we are using for the api call
|
175
|
+
# @param [Hash] params Hash of key value pairs passed to the gigya api
|
176
|
+
#
|
177
|
+
# @return [Hash] hash of the params being passed to the gigya api
|
178
|
+
# with timestamp, nonce and signature added
|
179
|
+
#
|
180
|
+
# @author Scott Sampson
|
181
|
+
def params_with_signature(request_uri,params)
|
182
|
+
timestamp = Time.now.utc.strftime("%s")
|
183
|
+
nonce = SigUtils::current_time_in_milliseconds()
|
184
|
+
|
185
|
+
params = {} if params.nil?
|
186
|
+
|
187
|
+
params[:format] = "json"
|
188
|
+
params[:timestamp] = timestamp
|
189
|
+
params[:nonce] = nonce
|
190
|
+
params[:apiKey] = @@api_key
|
191
|
+
|
192
|
+
normalized_url = CGI.escape(request_uri)
|
193
|
+
|
194
|
+
query_string = CGI.escape(prepare_for_signature(params).to_query)
|
195
|
+
|
196
|
+
# signature_string = SECRET + request_uri + timestamp
|
197
|
+
@@base_signature_string = "POST&#{normalized_url}&#{query_string}"
|
198
|
+
|
199
|
+
digest = SigUtils::calculate_signature(@@base_signature_string,@@api_secret)
|
200
|
+
@@signature = digest.to_s
|
201
|
+
params[:sig] = @@signature
|
202
|
+
return params
|
203
|
+
end
|
204
|
+
|
205
|
+
#
|
206
|
+
# sends the http call with signature to gigya and parses the result
|
207
|
+
# This is for http post requests
|
208
|
+
#
|
209
|
+
# @param [String] method The method name to be called in the gigya api
|
210
|
+
# @param [Hash] options Hash of key value pairs passed to the gigya api
|
211
|
+
#
|
212
|
+
# @return [Hash] hash of the api results in key/value format
|
213
|
+
#
|
214
|
+
# @author Scott Sampson
|
215
|
+
|
216
|
+
def parse_results_with_signature(method, options)
|
217
|
+
request_uri = build_url(method, "POST", options)
|
218
|
+
begin
|
219
|
+
response = HTTParty.post(request_uri, { :body => params_with_signature(request_uri,options) })
|
220
|
+
rescue URI::InvalidURIError
|
221
|
+
# need to treat this like method missing
|
222
|
+
return false
|
223
|
+
rescue SocketError,Timeout::Error => e
|
224
|
+
raise RGigya::ResponseError, e.message
|
225
|
+
end
|
226
|
+
|
227
|
+
|
228
|
+
begin
|
229
|
+
doc = JSON(response.body)
|
230
|
+
rescue JSON::ParserError => e
|
231
|
+
raise RGigya::JSONParseError, e.message
|
232
|
+
end
|
233
|
+
doc
|
234
|
+
end
|
235
|
+
|
236
|
+
|
237
|
+
#
|
238
|
+
# sends the api call to gigya and parses the result with appropriate method
|
239
|
+
#
|
240
|
+
# @param [String] method The method name to be called in the gigya api
|
241
|
+
# @param [Hash] options Hash of key value pairs passed to the gigya api
|
242
|
+
#
|
243
|
+
# @return [Hash] hash of the api results in key/value format
|
244
|
+
#
|
245
|
+
# @author Scott Sampson
|
246
|
+
def parse_results(method, options = {})
|
247
|
+
verify_config_data
|
248
|
+
return @@use_ssl ? parse_results_secure(method,options) : parse_results_with_signature(method,options)
|
249
|
+
end
|
250
|
+
|
251
|
+
#
|
252
|
+
# Error handling of the results
|
253
|
+
#
|
254
|
+
# @param [String] The method name to be called in the gigya api
|
255
|
+
# @param [Hash] results Hash of key value pairs returned by the results
|
256
|
+
#
|
257
|
+
# @return [String] hash of a successful api call
|
258
|
+
#
|
259
|
+
# TODO: Shouldn't fail so hard. If there is a temporary connectivity problem we should fail more gracefully.
|
260
|
+
# You can find a list of response codes at http://developers.gigya.com/037_API_reference/zz_Response_Codes_and_Errors
|
261
|
+
#
|
262
|
+
# @author Scott Sampson
|
263
|
+
def check_for_errors(results)
|
264
|
+
case results['errorCode'].to_s
|
265
|
+
when '0'
|
266
|
+
return results
|
267
|
+
when '400124'
|
268
|
+
#Limit Reached error - don't fail so bad
|
269
|
+
when '400002'
|
270
|
+
raise RGigya::BadParamsOrMethodName, results['errorDetails']
|
271
|
+
when '403003'
|
272
|
+
log("RGigya returned Error code #{results['errorCode']}.\n\nError Message: #{results['errorMessage']}\n\nError Details: #{results['errorDetails']}\n\n")
|
273
|
+
log("Rgigya base_signature_string = #{@@base_signature_string}\n\n")
|
274
|
+
log("Gigya base_signature_string = #{results['baseString']}\n\n\n")
|
275
|
+
log("Rgigya signature = #{@@signature}\n\n")
|
276
|
+
log("Gigya signature = #{results['expectedSignature']}\n\n")
|
277
|
+
raise RGigya::ErrorCodeReturned, "returned Error code #{results['errorCode']}: #{results['errorMessage']}"
|
278
|
+
else
|
279
|
+
log("RGigya returned Error code #{results['errorCode']}.\n\nError Message: #{results['errorMessage']}\n\nError Details: #{results['errorDetails']}")
|
280
|
+
raise RGigya::ErrorCodeReturned, "returned Error code #{results['errorCode']}: #{results['errorMessage']}"
|
281
|
+
end
|
282
|
+
end
|
283
|
+
|
284
|
+
##
|
285
|
+
# Override method_missing so we don't have to write all the dang methods
|
286
|
+
#
|
287
|
+
# @param [Symbol] sym The method symbol
|
288
|
+
# @param [*Array] args The splatted array of method arguments passed in
|
289
|
+
#
|
290
|
+
# @author Scott Sampson
|
291
|
+
def method_missing(sym, *args)
|
292
|
+
|
293
|
+
method = sym.to_s.gsub("_",".")
|
294
|
+
method_type,method_name = method.split(".")
|
295
|
+
|
296
|
+
if(@@valid_methods.include?(method_type.to_sym))
|
297
|
+
results = parse_results(method, args.first)
|
298
|
+
else
|
299
|
+
results = false
|
300
|
+
end
|
301
|
+
|
302
|
+
if results
|
303
|
+
return check_for_errors(results)
|
304
|
+
else
|
305
|
+
super
|
306
|
+
end
|
307
|
+
end
|
308
|
+
|
309
|
+
|
310
|
+
##
|
311
|
+
# Override respond_to? We can't really give an accurate return here
|
312
|
+
# I am only allowing those methods that start with the methods listed in the @@valid_methods array
|
313
|
+
#
|
314
|
+
# @param [Symbol] sym The method symbol
|
315
|
+
# @param [Boolean] include_private Whether you want to include private or not.
|
316
|
+
#
|
317
|
+
# @author Scott Sampson
|
318
|
+
def respond_to?(sym, include_private = false)
|
319
|
+
method = sym.to_s.gsub("_",".")
|
320
|
+
method_type,method_name = method.split(".")
|
321
|
+
return @@valid_methods.include?(method_type.to_sym)
|
322
|
+
end
|
323
|
+
|
324
|
+
|
325
|
+
|
326
|
+
#
|
327
|
+
# Custom log method, if we are in rails we should log any errors for debugging purposes
|
328
|
+
#
|
329
|
+
# @param [String] log_str string to log
|
330
|
+
#
|
331
|
+
# @author Scott Sampson
|
332
|
+
def log(log_str)
|
333
|
+
if Object.const_defined?('Rails')
|
334
|
+
Rails.logger.info(log_str)
|
335
|
+
else
|
336
|
+
puts log_str
|
337
|
+
end
|
338
|
+
end
|
339
|
+
end
|
340
|
+
end
|
data/lib/rgigya/hash.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
#
|
2
|
+
# Mixin for ruby's Hash class
|
3
|
+
#
|
4
|
+
#
|
5
|
+
# @author Scott Sampson
|
6
|
+
# @author Michael Orr
|
7
|
+
|
8
|
+
class Hash
|
9
|
+
|
10
|
+
|
11
|
+
# returns a query string
|
12
|
+
#
|
13
|
+
# @return [String] concated string of key value pairs in the hash
|
14
|
+
#
|
15
|
+
# @author Scott Sampson
|
16
|
+
def to_query
|
17
|
+
self.map{|k,v| "#{CGI.escape(k.to_s)}=#{CGI.escape(v)}"}.join("&")
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
#
|
2
|
+
# Utility class to help with signatures when sending api calls to gigya
|
3
|
+
#
|
4
|
+
#
|
5
|
+
# @author Scott Sampson
|
6
|
+
# @author Michael Orr
|
7
|
+
|
8
|
+
|
9
|
+
#if you think about it as a namespace the include RGigya below doesn't seem weird at all
|
10
|
+
module RGigya
|
11
|
+
|
12
|
+
class SigUtils
|
13
|
+
include RGigya
|
14
|
+
|
15
|
+
class << self
|
16
|
+
|
17
|
+
# validates the signature from the api calls having to do with authentication
|
18
|
+
# http://developers.gigya.com/010_Developer_Guide/87_Security#Validate_the_UID_Signature_in_the_Social_Login_Process
|
19
|
+
#
|
20
|
+
# @param [String] uid The id for the user who's friends you are getting
|
21
|
+
# @param [String] timestamp The signatureTimestamp passed along with api call
|
22
|
+
# @param [String] signature the UIDSignature we are verifying against
|
23
|
+
#
|
24
|
+
# @return [Boolean] true or false on whether the signature is valid
|
25
|
+
#
|
26
|
+
# @author Scott Sampson
|
27
|
+
def validate_user_signature(uid, timestamp, signature)
|
28
|
+
base = "#{timestamp}_#{uid}"
|
29
|
+
expected_signature = calculate_signature(base, @@api_secret)
|
30
|
+
return expected_signature == signature
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
# validates the signature from the api calls having to do with friends
|
35
|
+
# http://developers.gigya.com/010_Developer_Guide/87_Security#Validate_Friendship_Signatures_when_required
|
36
|
+
#
|
37
|
+
#
|
38
|
+
# @param [String] uid The id for the user who's friends you are getting
|
39
|
+
# @param [String] timestamp The signatureTimestamp passed along with each friend to verify the signature
|
40
|
+
# @param [String] friend_uid gigya's user_id for the friend
|
41
|
+
# @param [String] signature the friendshipSignature we are verifying against
|
42
|
+
#
|
43
|
+
# @return [Boolean] true or false on whether the signature is valid
|
44
|
+
#
|
45
|
+
# @author Scott Sampson
|
46
|
+
def validate_friend_signature(uid, timestamp, friend_uid, signature)
|
47
|
+
base = "#{timestamp}_#{friend_uid}_#{uid}"
|
48
|
+
expected_signature = calculate_signature(base, @@api_secret)
|
49
|
+
return expected_signature == signature
|
50
|
+
end
|
51
|
+
|
52
|
+
# generates the value for the session expiration cookie
|
53
|
+
# http://developers.gigya.com/010_Developer_Guide/87_Security#Defining_a_Session_Expiration_Cookie
|
54
|
+
#
|
55
|
+
# You want to use this if you want to terminate a session in the future
|
56
|
+
#
|
57
|
+
# @param [String] glt_cookie The login token received from Gigya after successful Login.
|
58
|
+
# Gigya stores the token in a cookie named: "glt_" + <Your API Key>
|
59
|
+
# @param [Integer] timeout_in_seconds The expiration time in seconds since Jan. 1st 1970 and in GMT/UTC timezone.
|
60
|
+
#
|
61
|
+
# @return [String] value you want to set in the cookie
|
62
|
+
#
|
63
|
+
# @author Scott Sampson
|
64
|
+
def get_dynamic_session_signature(glt_cookie, timeout_in_seconds)
|
65
|
+
expiration_time_unix_ms = (current_time_in_milliseconds().to_i/1000) + timeout_in_seconds
|
66
|
+
expiration_time_unix = expiration_time_unix_ms.floor.to_s
|
67
|
+
unsigned_expiration = "#{glt_cookie}_#{expiration_time_unix}"
|
68
|
+
signed_expiration = calculate_signature(unsigned_expiration,@@api_secret)
|
69
|
+
return "#{expiration_time_unix}_#{signed_expiration}"
|
70
|
+
end
|
71
|
+
|
72
|
+
|
73
|
+
# Returns the current utc time in milliseconds
|
74
|
+
#
|
75
|
+
# @return [String] current time in milliseconds
|
76
|
+
#
|
77
|
+
# @author Scott Sampson
|
78
|
+
def current_time_in_milliseconds()
|
79
|
+
return DateTime.now.strftime("%Q")
|
80
|
+
end
|
81
|
+
|
82
|
+
# Calulates the signature to be passed with the api calls
|
83
|
+
#
|
84
|
+
# @param [Strsing] base string that we are basing the signature off of
|
85
|
+
# @param [String] key The key we are using the encode the signature
|
86
|
+
#
|
87
|
+
# @return [String] value of the signature
|
88
|
+
#
|
89
|
+
# @author Scott Sampson
|
90
|
+
def calculate_signature(base,key)
|
91
|
+
base = base.encode('UTF-8')
|
92
|
+
raw = OpenSSL::HMAC.digest('sha1',Base64.decode64(key), base)
|
93
|
+
return Base64.encode64(raw).chomp.gsub(/\n/,'')
|
94
|
+
end
|
95
|
+
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
data/lib/rgigya.rb
CHANGED
@@ -1,196 +1,6 @@
|
|
1
1
|
require 'json'
|
2
2
|
require 'httparty'
|
3
3
|
require 'CGI'
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
#
|
8
|
-
# You can reference api calls at http://developers.gigya.com/037_API_reference
|
9
|
-
#
|
10
|
-
# Example call
|
11
|
-
# RGigya.socialize_setStatus(:uid => @user.id,:status => 'hello')
|
12
|
-
#
|
13
|
-
# We split the method name by the underscore and then map
|
14
|
-
# the first token to the correct url using the @@urls class variable
|
15
|
-
# The example above calls the url https://socialize.gigya.com/socialize.setStatus
|
16
|
-
#
|
17
|
-
# @author Scott Sampson
|
18
|
-
|
19
|
-
|
20
|
-
#
|
21
|
-
# Constants to be used for the gigya key and secret.
|
22
|
-
# These should be commented out and set in your environments for your rails project.
|
23
|
-
# Uncomment below for testing without rails
|
24
|
-
#
|
25
|
-
# GIGYA_API_KEY = "12345"
|
26
|
-
# GIGYA_API_SECRET = "12345"
|
27
|
-
|
28
|
-
|
29
|
-
class RGigya
|
30
|
-
|
31
|
-
# Mapping to different urls based on api groupings
|
32
|
-
@@urls = {
|
33
|
-
socialize: "https://socialize-api.gigya.com",
|
34
|
-
gm: "https://gm.gigya.com",
|
35
|
-
comments: "https://comments.gigya.com",
|
36
|
-
accounts: "https://accounts.gigya.com",
|
37
|
-
reports: "https://reports.gigya.com",
|
38
|
-
chat: "https://chat.gigya.com",
|
39
|
-
ds: "https://ds.gigya.com"
|
40
|
-
}
|
41
|
-
|
42
|
-
#
|
43
|
-
# Custom Exceptions so we know it came from the library
|
44
|
-
# When in use please namespace them appropriately RGigya::ResponseError for readability
|
45
|
-
#
|
46
|
-
exceptions = %w[ UIDParamIsNil SiteUIDParamIsNil ResponseError BadParamsOrMethodName ErrorCodeReturned ]
|
47
|
-
exceptions.each { |e| const_set(e, Class.new(StandardError)) }
|
48
|
-
RGigya::JSONParseError = Class.new(JSON::ParserError)
|
49
|
-
|
50
|
-
class << self
|
51
|
-
|
52
|
-
#
|
53
|
-
# Adds the required params for all api calls
|
54
|
-
#
|
55
|
-
def required_parameters
|
56
|
-
params = "apiKey=#{CGI.escape(GIGYA_API_KEY)}"
|
57
|
-
params += "&secret=#{CGI.escape(GIGYA_API_SECRET)}"
|
58
|
-
params += "&format=json"
|
59
|
-
end
|
60
|
-
|
61
|
-
#
|
62
|
-
# builds the url to be sent to the api
|
63
|
-
#
|
64
|
-
# @param [String] method The method name to be called in the gigya api
|
65
|
-
# @param [Hash] options Hash of key value pairs passed to the gigya api
|
66
|
-
#
|
67
|
-
# @return [String] the full url to be sent to the api
|
68
|
-
#
|
69
|
-
# @author Scott Sampson
|
70
|
-
def build_url(method, options = {})
|
71
|
-
if options && options.has_key?(:uid) && options[:uid].nil?
|
72
|
-
raise RGigya::UIDParamIsNil, ""
|
73
|
-
end
|
74
|
-
|
75
|
-
if options && options.has_key?(:siteUID) && options[:siteUID].nil?
|
76
|
-
raise RGigya::SiteUIDParamIsNil, ""
|
77
|
-
end
|
78
|
-
|
79
|
-
method_type,method_name = method.split(".")
|
80
|
-
url = "#{@@urls[method_type.to_sym]}/#{method}?#{required_parameters}"
|
81
|
-
if(options)
|
82
|
-
options.each do |key,value|
|
83
|
-
url += "&#{key}=#{CGI.escape(value.to_s)}"
|
84
|
-
end
|
85
|
-
end
|
86
|
-
url
|
87
|
-
end
|
88
|
-
|
89
|
-
#
|
90
|
-
# sends the https call to gigya and parses the result
|
91
|
-
#
|
92
|
-
# @param [String] method The method name to be called in the gigya api
|
93
|
-
# @param [Hash] options Hash of key value pairs passed to the gigya api
|
94
|
-
#
|
95
|
-
# @return [Hash] hash of the api results in key/value format
|
96
|
-
#
|
97
|
-
# @author Scott Sampson
|
98
|
-
def parse_results(method, options = {})
|
99
|
-
# options = {} if options.is_a?(String) && options.blank?
|
100
|
-
begin
|
101
|
-
response = HTTParty.get(build_url(method, options),{:timeout => 10})
|
102
|
-
rescue SocketError,Timeout::Error => e
|
103
|
-
raise RGigya::ResponseError, e.message
|
104
|
-
end
|
105
|
-
return false if response.nil? || response.body == "Bad Request"
|
106
|
-
|
107
|
-
begin
|
108
|
-
doc = JSON(response.body)
|
109
|
-
rescue JSON::ParserError => e
|
110
|
-
raise RGigya::JSONParseError, e.message
|
111
|
-
end
|
112
|
-
doc
|
113
|
-
end
|
114
|
-
|
115
|
-
#
|
116
|
-
# Error handling of the results
|
117
|
-
#
|
118
|
-
# @param [String] The method name to be called in the gigya api
|
119
|
-
# @param [Hash] results Hash of key value pairs returned by the results
|
120
|
-
#
|
121
|
-
# @return [String] hash of a successful api call
|
122
|
-
#
|
123
|
-
# TODO: Shouldn't fail so hard. If there is a temporary connectivity problem we should fail more gracefully.
|
124
|
-
# You can find a list of response codes at http://developers.gigya.com/037_API_reference/zz_Response_Codes_and_Errors
|
125
|
-
#
|
126
|
-
# @author Scott Sampson
|
127
|
-
def check_for_errors(results)
|
128
|
-
case results['errorCode'].to_s
|
129
|
-
when '0'
|
130
|
-
return results
|
131
|
-
when '400124'
|
132
|
-
#Limit Reached error - don't fail so bad
|
133
|
-
when '400002'
|
134
|
-
raise RGigya::BadParamsOrMethodName, results['errorDetails']
|
135
|
-
else
|
136
|
-
log("RGigya returned Error code #{results['errorCode']}.\n\nError Message: #{results['errorMessage']}\n\nError Details: #{results['errorDetails']}")
|
137
|
-
raise RGigya::ErrorCodeReturned, "returned Error code #{results['errorCode']}: #{results['errorMessage']}"
|
138
|
-
end
|
139
|
-
end
|
140
|
-
|
141
|
-
##
|
142
|
-
# Override method_missing so we don't have to write all the dang methods
|
143
|
-
#
|
144
|
-
# @param [Symbol] sym The method symbol
|
145
|
-
# @param [*Array] args The splatted array of method arguments passed in
|
146
|
-
#
|
147
|
-
# @author Scott Sampson
|
148
|
-
def method_missing(sym, *args)
|
149
|
-
|
150
|
-
method = sym.to_s.gsub("_",".")
|
151
|
-
method_type,method_name = method.split(".")
|
152
|
-
if(@@urls.has_key?(method_type.to_sym))
|
153
|
-
results = parse_results(method, args.first)
|
154
|
-
else
|
155
|
-
results = false
|
156
|
-
end
|
157
|
-
|
158
|
-
if results
|
159
|
-
return check_for_errors(results)
|
160
|
-
else
|
161
|
-
super
|
162
|
-
end
|
163
|
-
end
|
164
|
-
|
165
|
-
|
166
|
-
##
|
167
|
-
# Override respond_to? We can't really give an accurate return here
|
168
|
-
# I am only allowing those methods that start with those methods in the @urls hash
|
169
|
-
#
|
170
|
-
# @param [Symbol] sym The method symbol
|
171
|
-
# @param [Boolean] include_private Whether you want to include private or not.
|
172
|
-
#
|
173
|
-
# @author Scott Sampson
|
174
|
-
def respond_to?(sym, include_private = false)
|
175
|
-
method = sym.to_s.gsub("_",".")
|
176
|
-
method_type,method_name = method.split(".")
|
177
|
-
return @@urls.has_key?(method_type.to_sym)
|
178
|
-
end
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
##
|
183
|
-
# Custom log method, if we are in rails we should log any errors for debugging purposes
|
184
|
-
#
|
185
|
-
# @param [String] log_str string to log
|
186
|
-
#
|
187
|
-
# @author Scott Sampson
|
188
|
-
def log(log_str)
|
189
|
-
if Object.const_defined?('Rails')
|
190
|
-
Rails.logger.info(log_str)
|
191
|
-
else
|
192
|
-
puts log_str
|
193
|
-
end
|
194
|
-
end
|
195
|
-
end
|
196
|
-
end
|
4
|
+
require File.dirname(__FILE__)+"/rgigya/base.rb"
|
5
|
+
require File.dirname(__FILE__)+"/rgigya/sig_utils.rb"
|
6
|
+
require File.dirname(__FILE__)+"/rgigya/hash.rb"
|