login_radius 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (71) hide show
  1. data/.DS_Store +0 -0
  2. data/.gitignore +18 -0
  3. data/Gemfile +25 -0
  4. data/LICENSE +22 -0
  5. data/LoginRadiusTestApp/.gitignore +15 -0
  6. data/LoginRadiusTestApp/Gemfile +42 -0
  7. data/LoginRadiusTestApp/Gemfile.lock +136 -0
  8. data/LoginRadiusTestApp/README.rdoc +261 -0
  9. data/LoginRadiusTestApp/Rakefile +7 -0
  10. data/LoginRadiusTestApp/app/assets/images/rails.png +0 -0
  11. data/LoginRadiusTestApp/app/assets/javascripts/application.js +15 -0
  12. data/LoginRadiusTestApp/app/assets/stylesheets/application.css +13 -0
  13. data/LoginRadiusTestApp/app/controllers/application_controller.rb +17 -0
  14. data/LoginRadiusTestApp/app/helpers/application_helper.rb +2 -0
  15. data/LoginRadiusTestApp/app/mailers/.gitkeep +0 -0
  16. data/LoginRadiusTestApp/app/models/.gitkeep +0 -0
  17. data/LoginRadiusTestApp/app/views/application/callback.html.erb +1 -0
  18. data/LoginRadiusTestApp/app/views/application/index.html.erb +7 -0
  19. data/LoginRadiusTestApp/app/views/layouts/application.html.erb +14 -0
  20. data/LoginRadiusTestApp/config/application.rb +62 -0
  21. data/LoginRadiusTestApp/config/boot.rb +6 -0
  22. data/LoginRadiusTestApp/config/database.yml +25 -0
  23. data/LoginRadiusTestApp/config/environment.rb +5 -0
  24. data/LoginRadiusTestApp/config/environments/development.rb +37 -0
  25. data/LoginRadiusTestApp/config/environments/production.rb +67 -0
  26. data/LoginRadiusTestApp/config/environments/test.rb +37 -0
  27. data/LoginRadiusTestApp/config/initializers/backtrace_silencers.rb +7 -0
  28. data/LoginRadiusTestApp/config/initializers/inflections.rb +15 -0
  29. data/LoginRadiusTestApp/config/initializers/mime_types.rb +5 -0
  30. data/LoginRadiusTestApp/config/initializers/secret_token.rb +7 -0
  31. data/LoginRadiusTestApp/config/initializers/session_store.rb +8 -0
  32. data/LoginRadiusTestApp/config/initializers/wrap_parameters.rb +14 -0
  33. data/LoginRadiusTestApp/config/locales/en.yml +5 -0
  34. data/LoginRadiusTestApp/config/routes.rb +61 -0
  35. data/LoginRadiusTestApp/config.ru +4 -0
  36. data/LoginRadiusTestApp/db/seeds.rb +7 -0
  37. data/LoginRadiusTestApp/lib/assets/.gitkeep +0 -0
  38. data/LoginRadiusTestApp/lib/tasks/.gitkeep +0 -0
  39. data/LoginRadiusTestApp/log/.gitkeep +0 -0
  40. data/LoginRadiusTestApp/public/404.html +26 -0
  41. data/LoginRadiusTestApp/public/422.html +26 -0
  42. data/LoginRadiusTestApp/public/500.html +25 -0
  43. data/LoginRadiusTestApp/public/favicon.ico +0 -0
  44. data/LoginRadiusTestApp/public/robots.txt +5 -0
  45. data/LoginRadiusTestApp/script/rails +6 -0
  46. data/LoginRadiusTestApp/test/fixtures/.gitkeep +0 -0
  47. data/LoginRadiusTestApp/test/functional/.gitkeep +0 -0
  48. data/LoginRadiusTestApp/test/integration/.gitkeep +0 -0
  49. data/LoginRadiusTestApp/test/performance/browsing_test.rb +12 -0
  50. data/LoginRadiusTestApp/test/test_helper.rb +13 -0
  51. data/LoginRadiusTestApp/test/unit/.gitkeep +0 -0
  52. data/LoginRadiusTestApp/vendor/assets/javascripts/.gitkeep +0 -0
  53. data/LoginRadiusTestApp/vendor/assets/stylesheets/.gitkeep +0 -0
  54. data/LoginRadiusTestApp/vendor/plugins/.gitkeep +0 -0
  55. data/README.md +417 -0
  56. data/Rakefile +2 -0
  57. data/lib/hash.rb +13 -0
  58. data/lib/login_radius/exception.rb +4 -0
  59. data/lib/login_radius/messages.rb +102 -0
  60. data/lib/login_radius/user_profile.rb +102 -0
  61. data/lib/login_radius/user_profile_getters.rb +106 -0
  62. data/lib/login_radius/version.rb +3 -0
  63. data/lib/login_radius.rb +11 -0
  64. data/lib/string.rb +9 -0
  65. data/login_radius.gemspec +20 -0
  66. data/test/.DS_Store +0 -0
  67. data/test/basic_async_test.rb +29 -0
  68. data/test/unit/.DS_Store +0 -0
  69. data/test/unit/base_test.rb +11 -0
  70. data/test/unit/user_profile_test.rb +68 -0
  71. metadata +152 -0
data/README.md ADDED
@@ -0,0 +1,417 @@
1
+ # LoginRadius
2
+
3
+ Ruby wrapper for the LoginRadius API. Get social graph information and send messages using LoginRadius'
4
+ many social network clients!
5
+
6
+ Optional Asynchronous EventMachine friendly option!
7
+
8
+ ## Installation
9
+
10
+ Add this line to your application's Gemfile:
11
+
12
+ gem 'login_radius'
13
+
14
+ And then execute:
15
+
16
+ $ bundle
17
+
18
+ Or install it yourself as:
19
+
20
+ $ gem install login_radius
21
+
22
+ ## Usage
23
+
24
+ Take a peek:
25
+
26
+ @user_profile = LoginRadius::UserProfile.new({
27
+ :token => "TOKEN",
28
+ :secret => "SECRET",
29
+ :async => false #Set to true if using EventMachine driven frameworks(must use Em Synchrony)
30
+ })
31
+ @user_profile.login
32
+ my_contacts = @user_profile.contacts
33
+
34
+ That's right, folks. It's that simple. In order to get access to LoginRadius API, you only
35
+ need to create a UserProfile object with a user's login token and your apps secret, and login.
36
+
37
+ ### How to get a token and actually make a client
38
+
39
+ On the LoginRadius website, you are able to enter your own callback URL for your app. You will need
40
+ to setup a route on whatever framework you use, maybe "/callback." Then, get the gem forward(www.forwardhq.com)
41
+ and use it to set up a public web address for your localhost server. Then, you can enter the callback on LoginRadius
42
+ as https://jordanmatthew.fwd.wf/callback, for instance.
43
+
44
+ Paste their example login stuff onto your index page, and then enter your FB/Twitter credentials on their site.
45
+
46
+ Now you're ready to go with testing!
47
+
48
+ When LoginRadius hits your callback after a user logs in, you'll see parameters like this:
49
+
50
+ Parameters: {"token"=>"yourtokenhere"}
51
+
52
+ This token is the token used in the above example. This is what you'll need to get your user's profile.
53
+ Just paste it into the code above, and you can immediately grab their user profile on the callback,
54
+ login, and grab their contacts.
55
+
56
+ ### Some examples
57
+
58
+ Below is just code exemplifying some of the more interesting methods and what they return.
59
+ Note if you have a user authed via facebook, and not twitter, methods like
60
+
61
+ @user_profile.twitter_timeline
62
+ => false
63
+
64
+ Will return false, indicating you don't have access to that stream.
65
+
66
+ #### Facebook Stuff
67
+
68
+ @user_profile.facebook_groups
69
+ => [{:id=>"11111", :name=>"Name"},
70
+ {:id=>"11111", :name=>"Name"},
71
+ {:id=>"11111", :name=>"Name"},
72
+ {:id=>"11111", :name=>"Name"},
73
+ {:id=>"11111", :name=>"Name"},
74
+ {:id=>"11111", :name=>"Name"},
75
+ {:id=>"11111", :name=>"Name"},
76
+ {:id=>"11111", :name=>"Name"},
77
+ {:id=>"11111", :name=>"Name"}]
78
+
79
+ @user_profile.facebook_groups
80
+ => [{:id=>"11111", :name=>"Name"},
81
+ {:id=>"11111", :name=>"Name"}]
82
+
83
+
84
+ @user_profile.facebook_events
85
+ => [{:id=>"11111",
86
+ :name=>"Name",
87
+ :start_time=>"3/14/2015 9:00:00 AM",
88
+ :rsvp_status=>"attending",
89
+ :location=>"Across the world!"}]
90
+
91
+ And, finally, you can also make facebook posts:
92
+
93
+ params = {
94
+ :title => "Testing",
95
+ :url => "www.loginradius.com",
96
+ :status => "Wizzup",
97
+ :caption => "Testly",
98
+ :description => "Testing"
99
+ }
100
+ @user_profile.make_facebook_post(params)
101
+ => true
102
+
103
+ Note that as of publishing, the :to option on facebook params does not work. You can't post to
104
+ other people's walls.
105
+
106
+ #### LinkedIn Stuff
107
+
108
+ To send messages over linked in:
109
+
110
+ @user_profile.send_linked_in_message(@user_profile.contacts.first[:id], "Testing", "This is a test.")
111
+ => true
112
+
113
+ Notice how I grabbed my first contact and used his :id property.
114
+
115
+ Also, you can grab a user's linked in companies:
116
+
117
+ @user_profile.linked_in_companies
118
+ => [{:id=>11111, :name=>"Name"}]
119
+
120
+ #### Twitter Stuff
121
+
122
+ To send messages over twitter:
123
+
124
+ @user_profile.send_linked_in_message(@user_profile.contacts.first[:id], "Testing", "This is a test.")
125
+ => true
126
+
127
+ Notice how I grabbed my first contact and used his :id property.
128
+
129
+ Grab your timelines and mentions:
130
+
131
+ @user_profile.twitter_timeline
132
+ => [{:id=>"11111",
133
+ :text=>"Stuff",
134
+ :date_time=>"5/20/2013 4:53:52 PM",
135
+ :likes=>0,
136
+ :place=>"",
137
+ :source=>
138
+ "<a href=\"http://twitterfeed.com\" rel=\"nofollow\">twitterfeed</a>",
139
+ :image_url=>nil,
140
+ :link_url=>nil,
141
+ :name=>"Name"}]
142
+
143
+ @user_profile.twitter_mentions
144
+ => [{:id=>"11111",
145
+ :text=>"Stuff",
146
+ :date_time=>"3/31/2013 7:54:10 PM",
147
+ :likes=>0,
148
+ :place=>"",
149
+ :source=>"web",
150
+ :image_url=>nil,
151
+ :link_url=>nil,
152
+ :name=>"Name"}]
153
+
154
+ #### Social Network Contacts
155
+
156
+ Note this is all the contacts from every social network the user is connected to.
157
+
158
+ @user_profile.contacts
159
+ => [{:name=>"Name",
160
+ :email_id=>"",
161
+ :phone_number=>"",
162
+ :id=>"11111",
163
+ :profile_url=>nil,
164
+ :image_url=>nil,
165
+ :status=>nil,
166
+ :industry=>nil,
167
+ :country=>nil,
168
+ :gender=>nil}]
169
+
170
+ #### User Profile Stuff
171
+
172
+ When you login, the API returns a hash of user profile information, which is then turned into methods
173
+ on the LoginRadius::UserProfile object for your accessing pleasure. A quick call to methods will show this.
174
+
175
+ @user_profile.methods
176
+ =>[:id,
177
+ :provider,
178
+ :prefix,
179
+ :first_name,
180
+ :middle_name,
181
+ :last_name,
182
+ :suffix,
183
+ :full_name,
184
+ :nick_name,
185
+ :profile_name,
186
+ :birth_date,
187
+ :gender,
188
+ :website,
189
+ :email,
190
+ :country,
191
+ ...]
192
+
193
+ Calling .methods on a user profile right after a successful login call will reveal these.
194
+ For more information, please read the section in caveats on the matter, as it's a bit esoteric.
195
+
196
+ ## Caveats
197
+
198
+ This section is for the nitpickers. It's got notes about the finer pickings of this API for those
199
+ who are wondering, but is not strictly necessary reading.
200
+
201
+ ### The Bang Methods
202
+
203
+ When authenticated, a method like contacts will return
204
+
205
+ @user_profile.authenticated?
206
+ => true
207
+ @user_profile.contacts
208
+ => [{:name=>"Name",
209
+ :email_id=>"",
210
+ :phone_number=>"",
211
+ :id=>"11111",
212
+ :profile_url=>nil,
213
+ :image_url=>nil,
214
+ :status=>nil,
215
+ :industry=>nil,
216
+ :country=>nil,
217
+ :gender=>nil},
218
+ ...
219
+
220
+ When unauthenticated, a method like contacts will return false.
221
+
222
+ @user_profile.authenticated?
223
+ => false
224
+ @user_profile.contacts
225
+ => false
226
+
227
+ However, if you want to be a bit more flammable, try using contacts!, the bang version. It still returns
228
+ the same results when authed, but when unauthed, will actually raise a LoginRadius::Exception.
229
+
230
+ ### The LoginRadius::UserProfile object before and after login
231
+
232
+ Once you've got a valid user_profile, you have many methods available to you. Let's quickly take a look
233
+ at the methods in a LoginRadius::UserProfile object that hasn't yet been authenticated:
234
+
235
+ @user_profile.authenticated?
236
+ => false
237
+
238
+ @user_profile.methods - Object.new.methods
239
+ => [:secret,
240
+ :secret=,
241
+ :token,
242
+ :token=,
243
+ :async,
244
+ :async=,
245
+ :guid_valid?,
246
+ :authenticated?,
247
+ :call_api,
248
+ :send_twitter_message,
249
+ :send_linkedin_message,
250
+ :make_facebook_post,
251
+ :login!,
252
+ :login,
253
+ :twitter_mentions!,
254
+ :twitter_mentions,
255
+ :twitter_timeline!,
256
+ :twitter_timeline,
257
+ :linked_in_companies!,
258
+ :linked_in_companies,
259
+ :contacts!,
260
+ :contacts,
261
+ :facebook_groups!,
262
+ :facebook_groups,
263
+ :facebook_posts!,
264
+ :facebook_posts,
265
+ :facebook_events!,
266
+ :facebook_events]
267
+
268
+ Notice we've got a lot of stuff we can access. But we're not yet authenticated. Running login and then checking
269
+ the new methods created, we see we have much more than before!
270
+
271
+ @user_profile.login
272
+ => true
273
+ @user_profile.authenticated?
274
+ => true
275
+ @user_profile.methods - Object.new.methods
276
+ => [:id,
277
+ :provider,
278
+ :prefix,
279
+ :first_name,
280
+ :middle_name,
281
+ :last_name,
282
+ :suffix,
283
+ :full_name,
284
+ :nick_name,
285
+ :profile_name,
286
+ :birth_date,
287
+ :gender,
288
+ :website,
289
+ :email,
290
+ :country,
291
+ :thumbnail_image_url,
292
+ :image_url,
293
+ :favicon,
294
+ :profile_url,
295
+ :home_town,
296
+ :state,
297
+ :city,
298
+ :industry,
299
+ :about,
300
+ :time_zone,
301
+ :local_language,
302
+ :language,
303
+ :verified,
304
+ :updated_time,
305
+ :positions,
306
+ :educations,
307
+ :phone_numbers,
308
+ :im_accounts,
309
+ :addresses,
310
+ :main_address,
311
+ :created,
312
+ :local_city,
313
+ :profile_city,
314
+ :local_country,
315
+ :profile_country,
316
+ :relationship_status,
317
+ :quota,
318
+ :interested_in,
319
+ :interests,
320
+ :religion,
321
+ :political,
322
+ :sports,
323
+ :inspirational_people,
324
+ :https_image_url,
325
+ :followers_count,
326
+ :friends_count,
327
+ :is_geo_enabled,
328
+ :total_statuses_count,
329
+ :associations,
330
+ :num_recommenders,
331
+ :honors,
332
+ :skills,
333
+ :current_status,
334
+ :certifications,
335
+ :courses,
336
+ :volunteer,
337
+ :recommendations_received,
338
+ :languages,
339
+ :public_repository,
340
+ :hireable,
341
+ :repository_url,
342
+ :age,
343
+ :patents,
344
+ :favorite_things,
345
+ :professional_headline,
346
+ :provider_access_credential,
347
+ :secret,
348
+ :secret=,
349
+ :token,
350
+ :token=,
351
+ :async,
352
+ :async=,
353
+ :guid_valid?,
354
+ :authenticated?,
355
+ :call_api,
356
+ :send_twitter_message,
357
+ :send_linkedin_message,
358
+ :make_facebook_post,
359
+ :login!,
360
+ :login,
361
+ :twitter_mentions!,
362
+ :twitter_mentions,
363
+ :twitter_timeline!,
364
+ :twitter_timeline,
365
+ :linked_in_companies!,
366
+ :linked_in_companies,
367
+ :contacts!,
368
+ :contacts,
369
+ :facebook_groups!,
370
+ :facebook_groups,
371
+ :facebook_posts!,
372
+ :facebook_posts,
373
+ :facebook_events!,
374
+ :facebook_events]
375
+
376
+ Holy moly we got a whole bunch of new methods! That's because on login, all the user profile information
377
+ returned by the API is turned into dynamically generated GETTERs on the object that you can then use later.
378
+
379
+ ### Running the tests in test/unit
380
+
381
+ The base_test.rb file isn't meant to be run, it is inherited by user_profile_test.rb. In that file
382
+ you'll notice the lines at the top of the file:
383
+
384
+ TOKEN = "yourtokenhere"
385
+ SECRET = "yoursecrethere"
386
+
387
+ These are meant to be changed to your API secret and some user's token. What I do is I run a dummy
388
+ rails app locally and use the forward gem so that it can receive requests from the internet. Then I setup
389
+ a callback route and login page on the app and use it to have LoginRadius ping me with tokens that I can
390
+ paste into this test file.
391
+
392
+ *Beware, LoginRadius invalidates any token after 15 minutes, so during testing, you'll have to repeat the token
393
+ creation A LOT*
394
+
395
+ To run the tests, do:
396
+
397
+ bundle exec ruby -Itest test/unit/user_profile_test.rb
398
+
399
+ If you login with a facebook user, for instance, you'll notice all the twitter/linked in tests failing.
400
+ This is to be expected, you don't have access to those streams!
401
+
402
+ ### Evented Frameworks
403
+
404
+ I've built this gem to work with frameworks like Cramp. I've done a little bit of testing by creating
405
+ a basic event loop script in basic_async_test.rb in the test folder, which you can run to see that
406
+ things work there.
407
+
408
+ I've also done some AB testing using a Cramp framework elsewhere, but you should take caution in using
409
+ this gem in evented frameworks and make sure to use apache bench to test it for nonblocking yourself.
410
+
411
+ ## Contributing
412
+
413
+ 1. Fork it
414
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
415
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
416
+ 4. Push to the branch (`git push origin my-new-feature`)
417
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
data/lib/hash.rb ADDED
@@ -0,0 +1,13 @@
1
+ class Hash
2
+ def self.lr_convert_hash_keys(value) #lr_ appended so no method naming conflicts with other gems
3
+ case value
4
+ when Array
5
+ value.map { |v| lr_convert_hash_keys(v) }
6
+ # or `value.map(&method(:convert_hash_keys))`
7
+ when Hash
8
+ Hash[value.map { |k, v| [k.to_s.lr_underscore, lr_convert_hash_keys(v)] }]
9
+ else
10
+ value
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,4 @@
1
+ module LoginRadius
2
+ class Exception < Exception
3
+ end
4
+ end
@@ -0,0 +1,102 @@
1
+ module LoginRadius
2
+ module Messages
3
+
4
+ # Sends a message to a person using twitter
5
+ #
6
+ # @param sendto [String] Social ID of person you're contacting from contact list
7
+ # @param subject [String]
8
+ # @param message [String]
9
+ # @return [Boolean] Whether or not message succeeded
10
+ def send_twitter_message(sendto, subject, message)
11
+ send_message({:sendto => sendto, :subject => subject, :message => message})
12
+ end
13
+
14
+ # Sends a message to a person using twitter
15
+ #
16
+ # @param sendto [String] Social ID of person you're contacting from contact list
17
+ # @param subject [String]
18
+ # @param message [String]
19
+ # @return [Boolean] Whether or not message succeeded
20
+ def send_twitter_message!(sendto, subject, message)
21
+ send_message({:sendto => sendto, :subject => subject, :message => message})
22
+ end
23
+
24
+ # Sends a message to a person using linkedin
25
+ #
26
+ # @param sendto [String] Social ID of person you're contacting from contact list
27
+ # @param subject [String]
28
+ # @param message [String]
29
+ # @return [Boolean] Whether or not message succeeded
30
+ def send_linked_in_message(sendto, subject, message)
31
+ send_message({:sendto => sendto, :subject => subject, :message => message})
32
+ end
33
+
34
+ # Sends a message to a person using linkedin
35
+ #
36
+ # @param sendto [String] Social ID of person you're contacting from contact list
37
+ # @param subject [String]
38
+ # @param message [String]
39
+ # @return [Boolean] Whether or not message succeeded
40
+ def send_linked_in_message!(sendto, subject, message)
41
+ send_message!({:sendto => sendto, :subject => subject, :message => message})
42
+ end
43
+
44
+ # Sends a message to a person using facebook. Params hash takes following keys:
45
+ # to(optional) :- Person's wall it's going to, if blank, is your own
46
+ # title :- [optional parameter] status message title
47
+ # url:- [optional parameter] any url that you want post in status message
48
+ # imageurl :- [optional parameter] any image url that you want post in status message
49
+ # status :- your status message
50
+ # caption : [optional parameter] caption that you want post in status message
51
+ # description :- [optional parameter] description that you want post in status message
52
+ #
53
+ # @param params [Hash]
54
+ # @return [Boolean] Whether or not message succeeded
55
+ def make_facebook_post!(params = {})
56
+ call_api("status/update/#{secret}/#{token}", params)
57
+ end
58
+
59
+ # Sends a message to a person using facebook. Params hash takes following keys:
60
+ # to(optional) :- Person's wall it's going to, if blank, is your own
61
+ # title :- [optional parameter] status message title
62
+ # url:- [optional parameter] any url that you want post in status message
63
+ # imageurl :- [optional parameter] any image url that you want post in status message
64
+ # status :- your status message
65
+ # caption : [optional parameter] caption that you want post in status message
66
+ # description :- [optional parameter] description that you want post in status message
67
+ #
68
+ # @param params [Hash]
69
+ # @return [Boolean] Whether or not message succeeded
70
+ def make_facebook_post(params = {})
71
+ make_facebook_post!(params)
72
+ rescue LoginRadius::Exception => e
73
+ false
74
+ end
75
+
76
+ private
77
+
78
+ # Sends a message to a person. Will use either twitter, facebook or linked in, depending
79
+ # on where the person you're sending it to came from, and the keys present in the hash.
80
+ # Other methods in this module describe the keys they use, they all call this method
81
+ # with the proper keys for their service type.
82
+ #
83
+ # @param params [Hash] Params hash describing what you'd like to send.
84
+ # @return [Boolean] Whether or not message succeeded
85
+ def send_message!(params = {})
86
+ call_api("directmessage/#{secret}/#{token}",params)
87
+ end
88
+
89
+ # Sends a message to a person. Will use either twitter, facebook or linked in, depending
90
+ # on where the person you're sending it to came from, and the keys present in the hash.
91
+ # Other methods in this module describe the keys they use, they all call this method
92
+ # with the proper keys for their service type.
93
+ #
94
+ # @param params [Hash] Params hash describing what you'd like to send.
95
+ # @return [Boolean] Whether or not message succeeded
96
+ def send_message(params = {})
97
+ send_message!(params)
98
+ rescue LoginRadius::Exception => e
99
+ false
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,102 @@
1
+ require 'net/http'
2
+ module LoginRadius
3
+ class UserProfile
4
+ include UserProfileGetters
5
+ include Messages
6
+
7
+ attr_accessor :secret, :token, :async
8
+
9
+ API_ROOT = "https://hub.loginradius.com/"
10
+
11
+ # Takes a hash of account secret, token, and connection type(net_http or em_http)
12
+ # and uses it to auth against the LoginRadius API. Then it returns the Account object. The
13
+ # async key is optional, if set to true, will use Em::HTTP instead of Net::HTTP.
14
+ #
15
+ # @param opts [Hash] Must have keys :token, :secret, and :async(optional)
16
+ # @return [LoginRadius::Account]
17
+ def initialize(opts = {})
18
+ self.token = opts[:token]
19
+ self.secret = opts[:secret]
20
+ self.async = opts[:async]
21
+ raise LoginRadius::Exception.new("Invalid Request") unless token
22
+ raise LoginRadius::Exception.new("Invalid Token") unless guid_valid?(token)
23
+ raise LoginRadius::Exception.new("Invalid Secret") unless guid_valid?(secret)
24
+ end
25
+
26
+ # Takes a guid and returns whether or not it is valid.
27
+ #
28
+ # @param guid [String]
29
+ # @return [Boolean]
30
+ def guid_valid?(guid)
31
+ guid.match(/^\{?[A-Z0-9]{8}-[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{12}\}?$/i)
32
+ end
33
+
34
+ # Returns whether or not this object is authed.
35
+ #
36
+ # @return [Boolean]
37
+ def authenticated?
38
+ respond_to?(:id)
39
+ end
40
+
41
+ # Generic GET call function that other submodules can use to hit the API.
42
+ #
43
+ # @param url [String] Target URL to fetch data from.
44
+ # @param params [Hash] Parameters to send
45
+ # @return data [Hash] Parsed JSON data from the call
46
+ def call_api(url, params = {})
47
+ url = API_ROOT+url unless url.match(/^#{API_ROOT}/) #in case api root is included,
48
+ #as would happen in a recursive redirect call.
49
+
50
+ if async
51
+ #UNTESTED
52
+ #if async is true, we expect you to be using EM::Synchrony submodule and to be in an eventloop,
53
+ #like with a thin server using the Cramp framework. Otherwise, this method blows up.
54
+ response = EM::Synchrony.sync EventMachine::HttpRequest.new(url).aget :redirects => 2, :query => params
55
+ response = response.response
56
+ else
57
+ #synchronous version of the call.
58
+ url_obj = URI.parse(url)
59
+ url_obj.query = URI.encode_www_form(params)
60
+
61
+ http = Net::HTTP.new(url_obj.host, url_obj.port)
62
+ http.use_ssl = true
63
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
64
+ response = http.get(url_obj.request_uri)
65
+
66
+ if response.is_a?(Net::HTTPTemporaryRedirect)
67
+ #for some reason, we always get redirected when calling server first time.
68
+ #so if we do, we scan body for the redirect url, and the scan returns
69
+ #an array of arrays. So we grab the array we know has what we need,
70
+ #and grab the first element.
71
+ redirect_url_array = response.body.scan(/<a href=\"([^>]+)\">/i)[1]
72
+ redirect_url = redirect_url_array.first
73
+ return call_api(redirect_url, params)
74
+ end
75
+
76
+ response = response.body
77
+ end
78
+
79
+ # For some reason, this API returns true/false instead of JSON responses for certain calls.
80
+ # We catch this here.
81
+ return true if response.match(/^true/i)
82
+ return false if response.match(/^false/i)
83
+
84
+ #We rescue this because sometimes the API returns HTML pages(which can't be JSON parsed)
85
+ #This mostly happens when people use expired tokens. So we go ahead and raise an exception
86
+ #About it if it gets caught.
87
+ begin
88
+ unconverted_response = JSON.parse(response)
89
+ #it's all String keys in CamelCase above, so...
90
+ # IF we got a hash back, convert it directly, if its an array, convert each item which is a hash
91
+ # into snake case
92
+ converted_response = unconverted_response.is_a?(Hash) ?
93
+ Hash.lr_convert_hash_keys(unconverted_response).symbolize_keys! :
94
+ unconverted_response.map { |item| Hash.lr_convert_hash_keys(item).symbolize_keys! }
95
+
96
+ return converted_response
97
+ rescue JSON::ParserError => e
98
+ raise LoginRadius::Exception.new("A JSON parsing error occured because the API returned an HTML page instead of JSON. This happens mostly when you're using an expired Token. Specifics: #{e.message}")
99
+ end
100
+ end
101
+ end
102
+ end