polar-renren 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.markdown +71 -0
- data/lib/polar.rb +21 -0
- data/lib/polar/authentication.rb +47 -0
- data/lib/polar/base.rb +21 -0
- data/lib/polar/client.rb +55 -0
- data/lib/polar/cursor.rb +59 -0
- data/lib/polar/error/api_error.rb +15 -0
- data/lib/polar/error/http_error.rb +14 -0
- data/lib/polar/request.rb +69 -0
- data/lib/polar/response.rb +11 -0
- data/lib/polar/signature_calculator.rb +15 -0
- data/lib/polar/user.rb +15 -0
- data/spec/authentication_spec.rb +169 -0
- data/spec/client_spec.rb +55 -0
- data/spec/cursor_spec.rb +26 -0
- data/spec/signature_calculator_spec.rb +22 -0
- data/spec/spec_helper.rb +24 -0
- data/spec/stub_manager.rb +56 -0
- metadata +73 -0
data/README.markdown
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
Polar
|
2
|
+
===================
|
3
|
+
|
4
|
+
### About
|
5
|
+
Polar is an API wrapper for the Renren social network. This gem is a fork of the renren-api gem. Thanks to Lei Zhi-Qiang for the great work on the renren-api gem. This fork does a number of things differently such as using faraday under the hood and always returning domain objects in preference to hashes.
|
6
|
+
|
7
|
+
### Installation
|
8
|
+
Polar is a cool name(excuse the pun) but it was already taken on ruby gems so you will have to install polar with the following line in your Gemfile.
|
9
|
+
|
10
|
+
```ruby
|
11
|
+
gem "polar-renren", :require => "polar"
|
12
|
+
```
|
13
|
+
|
14
|
+
Not using bundler? Well you should but thats cool.
|
15
|
+
|
16
|
+
```ruby
|
17
|
+
gem intsall polar-renren
|
18
|
+
#then in your code
|
19
|
+
require 'polar'
|
20
|
+
```
|
21
|
+
|
22
|
+
### Useage
|
23
|
+
In polar you use the client object to interact with the api. To create the client you will need to know three different things. Firstly you will need an application key and an application secret. To get these you will need to visit the renren developer site and create an application. Once you have created the application you can go in to the applications control panel and grab the secret and key. As well as these you will need a session key. To get a session key you must login first. This can be done with OAuth2 as renren provides this feature. There is an omni-auth stragity that exists provided by Scott Ballantyne that works well.
|
24
|
+
|
25
|
+
```ruby
|
26
|
+
client = Polar::Client.new(app_key, app_secret, session_key)
|
27
|
+
```
|
28
|
+
Now that we have a client object we can query the renren api. To get all friends call the friends method of the client object.
|
29
|
+
```ruby
|
30
|
+
friends = client.get_friends
|
31
|
+
```
|
32
|
+
Get friends will return an array of ```Polar::User``` objects. These objects have their data bound to dot methods so we can get information from them as follows
|
33
|
+
```ruby
|
34
|
+
friends.each do |friend|
|
35
|
+
puts friend.name
|
36
|
+
end
|
37
|
+
```
|
38
|
+
|
39
|
+
Renren's API for some end points will simply return a result = 1 when the operation is successful. Set status is one such endpoint. In this case if the API call does not raise an error then Polar will return an object of class ```Polar::Result```. This object will have success = true.
|
40
|
+
|
41
|
+
```ruby
|
42
|
+
client = Polar::Client.new(app_key, app_secret, session_key)
|
43
|
+
result = client.set_status("Hey welcome to renren.")
|
44
|
+
if(result.success)
|
45
|
+
puts "woo hoo. The gem works"
|
46
|
+
else
|
47
|
+
puts "Gem dead. Give up"
|
48
|
+
end
|
49
|
+
```
|
50
|
+
|
51
|
+
Polar also supports cursors to iterate over pages of results. Next page returns true while there is a new set of results to iterate over.
|
52
|
+
```ruby
|
53
|
+
client = Polar::Client.new(app_key, app_secret, session_key)
|
54
|
+
cursor = client.get_friends
|
55
|
+
while cursor.next_page?
|
56
|
+
cursor.each do |user|
|
57
|
+
puts user.name
|
58
|
+
end
|
59
|
+
end
|
60
|
+
```
|
61
|
+
|
62
|
+
### Pull Requests
|
63
|
+
The changes are that what you want to do with the API is not supported. Let me know if that is the case and I will add support for anything you need to do. I will also accept any pull requests with new features included.
|
64
|
+
|
65
|
+
License
|
66
|
+
===================
|
67
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
68
|
+
|
69
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
70
|
+
|
71
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/lib/polar.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
require 'polar/signature_calculator'
|
4
|
+
require 'polar/authentication'
|
5
|
+
require 'polar/request'
|
6
|
+
require 'polar/base'
|
7
|
+
require 'polar/user'
|
8
|
+
require 'polar/client'
|
9
|
+
require 'polar/cursor'
|
10
|
+
require 'polar/response'
|
11
|
+
require 'polar/error/http_error'
|
12
|
+
require 'polar/error/api_error'
|
13
|
+
|
14
|
+
module Polar
|
15
|
+
BASE_URL = "http://api.renren.com/restserver.do"
|
16
|
+
VERSION = [0, 0, 1]
|
17
|
+
|
18
|
+
def self.version
|
19
|
+
VERSION * "."
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require "rack"
|
2
|
+
require_relative "signature_calculator"
|
3
|
+
|
4
|
+
module Polar
|
5
|
+
class Authentication
|
6
|
+
|
7
|
+
def initialize(app, api_key, secret_key, &failed_handler)
|
8
|
+
@app = app
|
9
|
+
@api_key = api_key
|
10
|
+
@secret_key = secret_key
|
11
|
+
@signature_calculator = SignatureCalculator.new(@secret_key)
|
12
|
+
@required_keys = %w{user session_key ss expires}.collect { |e| @api_key + "_" + e } << @api_key
|
13
|
+
@failed_handler = block_given? ? failed_handler : proc { [401, {"Content-Type" => "text/plain"}, ["Unauthorized!"]] }
|
14
|
+
end
|
15
|
+
|
16
|
+
def call(env)
|
17
|
+
request = Rack::Request.new(env)
|
18
|
+
if %r{^/people/(?<person_id>\d+)} =~ request.path_info
|
19
|
+
cookies = request.cookies
|
20
|
+
if valid?(cookies) && cookies["#{@api_key}_user"] == person_id
|
21
|
+
@app.call(env)
|
22
|
+
else
|
23
|
+
@failed_handler.call(env)
|
24
|
+
end
|
25
|
+
else
|
26
|
+
@app.call(env)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def valid?(cookies)
|
33
|
+
@required_keys.each do |k|
|
34
|
+
return false unless cookies.has_key?(k)
|
35
|
+
end
|
36
|
+
return false if cookies["#{@api_key}_expires"].to_i < Time.now.to_i
|
37
|
+
cookies[@api_key] == @signature_calculator.calculate(filter(cookies))
|
38
|
+
end
|
39
|
+
|
40
|
+
def filter(cookies)
|
41
|
+
hash = {}
|
42
|
+
%w{user session_key ss expires}.each { |e| hash[e] = cookies["#{@api_key}_#{e}"] }
|
43
|
+
hash
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
end
|
data/lib/polar/base.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
module Polar
|
2
|
+
class Base
|
3
|
+
|
4
|
+
def initialize(data)
|
5
|
+
@data = data
|
6
|
+
end
|
7
|
+
|
8
|
+
def method_missing(method_name, *attrs)
|
9
|
+
if @data.has_key?(method_name.to_s)
|
10
|
+
return @data[method_name.to_s]
|
11
|
+
else
|
12
|
+
raise("No data for: #{method_name}")
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def to_h
|
17
|
+
@data
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
data/lib/polar/client.rb
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
module Polar
|
2
|
+
class Client
|
3
|
+
|
4
|
+
def initialize(api_key, secret_key, session_key)
|
5
|
+
@api_key, @secret_key, @session_key = api_key, secret_key, session_key
|
6
|
+
end
|
7
|
+
|
8
|
+
def get_friends
|
9
|
+
params = {
|
10
|
+
:method => "friends.getFriends",
|
11
|
+
:v => "1.0"
|
12
|
+
}
|
13
|
+
|
14
|
+
Polar::Cursor.new(@api_key, @secret_key, @session_key, Polar::User, params)
|
15
|
+
end
|
16
|
+
|
17
|
+
def get_info(uids, fields)
|
18
|
+
params = {
|
19
|
+
:method => "users.getInfo",
|
20
|
+
:v => "1.0",
|
21
|
+
:fields => fields * ",",
|
22
|
+
:uids => uids * ","
|
23
|
+
}
|
24
|
+
|
25
|
+
user_info = request(params)
|
26
|
+
if user_info.count == 1
|
27
|
+
return Polar::User.new(user_info.first)
|
28
|
+
else
|
29
|
+
friend_list = []
|
30
|
+
user_info.each { |current_user| friend_list << Polar::User.new(current_user) }
|
31
|
+
return friend_list
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def set_status(status)
|
36
|
+
params = {
|
37
|
+
:method => "status.set",
|
38
|
+
:v => "1.0",
|
39
|
+
:status => status
|
40
|
+
}
|
41
|
+
Polar::Response.new request(params)
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def request(params)
|
47
|
+
Polar::Request.new(@api_key, @secret_key, @session_key, params).response
|
48
|
+
end
|
49
|
+
|
50
|
+
def current_time_in_milliseconds
|
51
|
+
"%.3f" % Time.now.to_f
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
end
|
data/lib/polar/cursor.rb
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
module Polar
|
2
|
+
class Cursor
|
3
|
+
include Enumerable
|
4
|
+
ITEMS_PER_PAGE = 500
|
5
|
+
|
6
|
+
def initialize(api_key, secret_key, session_key, domain_klass, params)
|
7
|
+
@api_key, @secret_key, @session_key, @domain_klass, @params = api_key, secret_key, session_key, domain_klass, params
|
8
|
+
@current_page = 0
|
9
|
+
@fetched_current_page = false
|
10
|
+
end
|
11
|
+
|
12
|
+
#Each will return the first page of results
|
13
|
+
def each(&block)
|
14
|
+
@current_page += 1
|
15
|
+
fetch_current_page if !@fetched_current_page
|
16
|
+
@items.each { |i| block.call i }
|
17
|
+
@fetched_current_page = false
|
18
|
+
end
|
19
|
+
|
20
|
+
def next_page?
|
21
|
+
if @items
|
22
|
+
return @items.count <= ITEMS_PER_PAGE
|
23
|
+
elsif !@items && @current_page == 0
|
24
|
+
return true
|
25
|
+
else
|
26
|
+
raise("Items are nil and they should not be.")
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def total_items
|
31
|
+
fetch_current_page if @total_items.nil?
|
32
|
+
@total_items
|
33
|
+
end
|
34
|
+
|
35
|
+
def [](index)
|
36
|
+
fetch_current_page if !@fetched_current_page
|
37
|
+
@items[index]
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def page_request(params)
|
43
|
+
request = Polar::Request.new(@api_key, @secret_key, @session_key, params)
|
44
|
+
request.response
|
45
|
+
end
|
46
|
+
|
47
|
+
def fetch_current_page
|
48
|
+
params = @params.merge({ :page => @current_page, :count => ITEMS_PER_PAGE })
|
49
|
+
response = page_request(params)
|
50
|
+
|
51
|
+
@items = []
|
52
|
+
response.each do |response_item|
|
53
|
+
@items << @domain_klass.new(response_item)
|
54
|
+
end
|
55
|
+
@fetched_current_page = true
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module RenrenAPI
|
2
|
+
module Error
|
3
|
+
class APIError < StandardError
|
4
|
+
|
5
|
+
def initialize(error_response)
|
6
|
+
@code, @message = error_response["error_code"], error_response["error_msg"]
|
7
|
+
end
|
8
|
+
|
9
|
+
def to_s
|
10
|
+
"The Renren API has returned an Error:(#{@code} - #{@message})"
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
require "json"
|
3
|
+
require "faraday"
|
4
|
+
require "faraday_middleware"
|
5
|
+
|
6
|
+
module Polar
|
7
|
+
class Request
|
8
|
+
|
9
|
+
attr_reader :response
|
10
|
+
|
11
|
+
def initialize(api_key, secret_key, session_key, params)
|
12
|
+
@api_key, @session_key, @secret_key = api_key, session_key, secret_key
|
13
|
+
|
14
|
+
conn = Faraday.new(:url => Polar::BASE_URL) do |c|
|
15
|
+
c.use Faraday::Request::UrlEncoded
|
16
|
+
c.use Faraday::Adapter::NetHttp
|
17
|
+
end
|
18
|
+
|
19
|
+
conn.headers["Content-Type"] = ["application/x-www-form-urlencoded"];
|
20
|
+
params[:api_key] = @api_key
|
21
|
+
params[:call_id] = Time.now.to_i
|
22
|
+
params[:session_key] = @session_key
|
23
|
+
params[:format] = "JSON"
|
24
|
+
params[:sig] = SignatureCalculator.new(@secret_key).calculate(params)
|
25
|
+
|
26
|
+
raw_response = conn.post do |request|
|
27
|
+
request.body = urlencode_params(params)
|
28
|
+
end
|
29
|
+
|
30
|
+
raise RenrenAPI::Error::HTTPError.new(raw_response.status) if (400..599).include?(raw_response.status)
|
31
|
+
@response = JSON.parse(raw_response.body)
|
32
|
+
raise RenrenAPI::Error::APIError.new(@response) if renren_api_error?
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def urlencode_params(params_hash)
|
38
|
+
params = ''
|
39
|
+
stack = []
|
40
|
+
|
41
|
+
params_hash.each do |k, v|
|
42
|
+
if v.is_a?(Hash)
|
43
|
+
stack << [k,v]
|
44
|
+
else
|
45
|
+
params << "#{k}=#{v}&"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
stack.each do |parent, hash|
|
50
|
+
hash.each do |k, v|
|
51
|
+
if v.is_a?(Hash)
|
52
|
+
stack << ["#{parent}[#{k}]", v]
|
53
|
+
else
|
54
|
+
params << "#{parent}[#{k}]=#{v}&"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
params.chop! # trailing &
|
60
|
+
params
|
61
|
+
end
|
62
|
+
|
63
|
+
def renren_api_error?
|
64
|
+
return false if @response.class == Array
|
65
|
+
@response.has_key?("error_code") && @response.has_key?("error_msg")
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require "digest/md5"
|
2
|
+
|
3
|
+
module Polar
|
4
|
+
class SignatureCalculator
|
5
|
+
|
6
|
+
def initialize(secret_key)
|
7
|
+
@secret_key = secret_key
|
8
|
+
end
|
9
|
+
|
10
|
+
def calculate(hash)
|
11
|
+
Digest::MD5.hexdigest(hash.collect { |(k, v)| "#{k}=#{v}" }.sort * "" << @secret_key)
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
end
|
data/lib/polar/user.rb
ADDED
@@ -0,0 +1,169 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
class Rack::MockResponse
|
4
|
+
def unauthorized?
|
5
|
+
@status == 401
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
describe Polar::Authentication do
|
10
|
+
include Rack::Test::Methods
|
11
|
+
include Helpers
|
12
|
+
|
13
|
+
def app
|
14
|
+
Polar::Authentication.new(lambda { |env| [200, {}, ["OK"]] }, "8802f8e9b2cf4eb993e8c8adb1e02b06", "34d3d1e26cd44c05a0c450c0a0f8147b") do |env|
|
15
|
+
[401, {}, ["Get out of #{env["PATH_INFO"]}!"]]
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
subject { request(path, @env); last_response }
|
20
|
+
before { @env = {} }
|
21
|
+
|
22
|
+
context "when path does not have prefix /people/{person-id}" do
|
23
|
+
let(:path) { "/" }
|
24
|
+
%w{GET POST PUT DELETE}.each do |m|
|
25
|
+
context(m) do
|
26
|
+
before { @env[:method] = m }
|
27
|
+
it { should be_ok }
|
28
|
+
its(:body) { should == "OK" }
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
context "when path has prefix /people/{person-id}" do
|
34
|
+
let(:path) { "/people/#{person_id}" }
|
35
|
+
let(:person_id) { rand(9999).to_s }
|
36
|
+
|
37
|
+
context "when no login information provided" do
|
38
|
+
%w{GET POST PUT DELETE}.each do |m|
|
39
|
+
context(m) do
|
40
|
+
before { @env[:method] = m }
|
41
|
+
it { should be_unauthorized }
|
42
|
+
its(:body) { should == "Get out of #{path}!" }
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
context "when correct login information provided" do
|
48
|
+
before { @env[:cookie] = generate_cookie(secret_key, api_key, hash) }
|
49
|
+
let(:secret_key) { "34d3d1e26cd44c05a0c450c0a0f8147b" }
|
50
|
+
let(:api_key) { "8802f8e9b2cf4eb993e8c8adb1e02b06" }
|
51
|
+
let(:hash) do
|
52
|
+
{
|
53
|
+
"user" => person_id,
|
54
|
+
"session_key" => "session_key",
|
55
|
+
"ss" => "session_key_secret",
|
56
|
+
"expires" => (Time.now.to_i + rand(9999) + 1).to_s
|
57
|
+
}
|
58
|
+
end
|
59
|
+
%w{GET POST PUT DELETE}.each do |m|
|
60
|
+
context(m) do
|
61
|
+
before { @env[:method] = m }
|
62
|
+
it { should be_ok }
|
63
|
+
its(:body) { should == "OK" }
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
context "when incorrect login information provided" do
|
69
|
+
before { @env[:cookie] = generate_cookie("xxxx", api_key, hash) }
|
70
|
+
let(:api_key) { "8802f8e9b2cf4eb993e8c8adb1e02b06" }
|
71
|
+
let(:hash) do
|
72
|
+
{
|
73
|
+
"user" => person_id,
|
74
|
+
"session_key" => "session_key",
|
75
|
+
"ss" => "session_key_secret",
|
76
|
+
"expires" => (Time.now.to_i + rand(9999) + 1).to_s
|
77
|
+
}
|
78
|
+
end
|
79
|
+
%w{GET POST PUT DELETE}.each do |m|
|
80
|
+
context(m) do
|
81
|
+
before { @env[:method] = m }
|
82
|
+
it { should be_unauthorized }
|
83
|
+
its(:body) { should == "Get out of #{path}!" }
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
91
|
+
|
92
|
+
describe Polar::Authentication, "no failed handler is provided" do
|
93
|
+
include Rack::Test::Methods
|
94
|
+
include Helpers
|
95
|
+
def app
|
96
|
+
Polar::Authentication.new(lambda { |env| [200, {}, ["OK"]] }, "8802f8e9b2cf4eb993e8c8adb1e02b06", "34d3d1e26cd44c05a0c450c0a0f8147b")
|
97
|
+
end
|
98
|
+
subject { request(path, @env); last_response }
|
99
|
+
before { @env = {} }
|
100
|
+
|
101
|
+
context "when path does not have prefix /people/{person-id}" do
|
102
|
+
let(:path) { "/" }
|
103
|
+
%w{GET POST PUT DELETE}.each do |m|
|
104
|
+
context(m) do
|
105
|
+
before { @env[:method] = m }
|
106
|
+
it { should be_ok }
|
107
|
+
its(:body) { should == "OK" }
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
context "when path has prefix /people/{person-id}" do
|
113
|
+
let(:path) { "/people/#{person_id}" }
|
114
|
+
let(:person_id) { rand(9999).to_s }
|
115
|
+
context "when no login information provided" do
|
116
|
+
%w{GET POST PUT DELETE}.each do |m|
|
117
|
+
context(m) do
|
118
|
+
before { @env[:method] = m }
|
119
|
+
it { should be_unauthorized }
|
120
|
+
its(:content_type) { should == "text/plain"}
|
121
|
+
its(:body) { should == "Unauthorized!" }
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
context "when correct login information provided" do
|
127
|
+
before { @env[:cookie] = generate_cookie(secret_key, api_key, hash) }
|
128
|
+
let(:secret_key) { "34d3d1e26cd44c05a0c450c0a0f8147b" }
|
129
|
+
let(:api_key) { "8802f8e9b2cf4eb993e8c8adb1e02b06" }
|
130
|
+
let(:hash) do
|
131
|
+
{
|
132
|
+
"user" => person_id,
|
133
|
+
"session_key" => "session_key",
|
134
|
+
"ss" => "session_key_secret",
|
135
|
+
"expires" => (Time.now.to_i + rand(9999) + 1).to_s
|
136
|
+
}
|
137
|
+
end
|
138
|
+
%w{GET POST PUT DELETE}.each do |m|
|
139
|
+
context(m) do
|
140
|
+
before { @env[:method] = m }
|
141
|
+
it { should be_ok }
|
142
|
+
its(:body) { should == "OK" }
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
context "when incorrect login information provided" do
|
148
|
+
before { @env[:cookie] = generate_cookie("xxxx", api_key, hash) }
|
149
|
+
let(:api_key) { "8802f8e9b2cf4eb993e8c8adb1e02b06" }
|
150
|
+
let(:hash) do
|
151
|
+
{
|
152
|
+
"user" => person_id,
|
153
|
+
"session_key" => "session_key",
|
154
|
+
"ss" => "session_key_secret",
|
155
|
+
"expires" => (Time.now.to_i + rand(9999) + 1).to_s
|
156
|
+
}
|
157
|
+
end
|
158
|
+
%w{GET POST PUT DELETE}.each do |m|
|
159
|
+
context(m) do
|
160
|
+
before { @env[:method] = m }
|
161
|
+
it { should be_unauthorized }
|
162
|
+
its(:content_type) { should == "text/plain" }
|
163
|
+
its(:body) { should == "Unauthorized!" }
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
end
|
data/spec/client_spec.rb
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
require "spec_helper"
|
3
|
+
|
4
|
+
describe Polar::Client, "#get_friends" do
|
5
|
+
let(:api_key) { "api_key" }
|
6
|
+
let(:secret_key) { "secret_key" }
|
7
|
+
let(:session_key) { "session_key" }
|
8
|
+
|
9
|
+
subject { described_class.new(api_key, secret_key, session_key).get_friends }
|
10
|
+
before { Stubs::GetFriends.new }
|
11
|
+
|
12
|
+
it do
|
13
|
+
subject.class.should eql Polar::Cursor
|
14
|
+
subject.first.class.should eql Polar::User
|
15
|
+
subject.first.avatar.should eql "http://hdn.xnimg.cn/photos/hdn521/20120508/0915/h_tiny_768l_5f460007d2ae2f75.jpg"
|
16
|
+
subject.first.to_h["avatar"].should eql "http://hdn.xnimg.cn/photos/hdn521/20120508/0915/h_tiny_768l_5f460007d2ae2f75.jpg"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe Polar::Client, "#get_info" do
|
21
|
+
let(:api_key) { "api_key" }
|
22
|
+
let(:secret_key) { "secret_key" }
|
23
|
+
let(:session_key) { "session_key" }
|
24
|
+
subject { described_class.new(api_key, secret_key, session_key).get_info(uids, fields) }
|
25
|
+
before { Stubs::GetUser.new }
|
26
|
+
|
27
|
+
let(:fields) do
|
28
|
+
%w{uid name tinyurl}
|
29
|
+
end
|
30
|
+
|
31
|
+
let(:uids) do
|
32
|
+
[449545842]
|
33
|
+
end
|
34
|
+
|
35
|
+
it do
|
36
|
+
subject.class.should eql Polar::User
|
37
|
+
subject.avatar.should eql "http://hdn.xnimg.cn/photos/hdn321/20120430/0850/h_tiny_7KQT_563e0006d3dc2f76.jpg"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe Polar::Client, "#status_set" do
|
42
|
+
let(:api_key) { "api_key" }
|
43
|
+
let(:secret_key) { "secret_key" }
|
44
|
+
let(:session_key) { "session_key" }
|
45
|
+
|
46
|
+
let(:status) { "Hello, how are you toady?" }
|
47
|
+
before { Stubs::SetStatus.new }
|
48
|
+
|
49
|
+
subject { described_class.new(api_key, secret_key, session_key).set_status(status) }
|
50
|
+
|
51
|
+
it do
|
52
|
+
subject.class.should eql Polar::Response
|
53
|
+
subject.success.should eql true
|
54
|
+
end
|
55
|
+
end
|
data/spec/cursor_spec.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Polar::Cursor do
|
4
|
+
let(:api_key) { "api_key" }
|
5
|
+
let(:secret_key) { "secret_key" }
|
6
|
+
let(:session_key) { "session_key" }
|
7
|
+
|
8
|
+
subject { Polar::Client.new(api_key, secret_key, session_key).get_friends }
|
9
|
+
|
10
|
+
before do
|
11
|
+
Timecop.freeze(Time.now)
|
12
|
+
Stubs::GetLotsOfFriends.new
|
13
|
+
end
|
14
|
+
|
15
|
+
it do
|
16
|
+
subject.class.should eql Polar::Cursor
|
17
|
+
|
18
|
+
total_users = Array.new
|
19
|
+
while subject.next_page?
|
20
|
+
subject.each do |user|
|
21
|
+
total_users << user
|
22
|
+
end
|
23
|
+
end
|
24
|
+
total_users.count.should eql 500 * 50
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Polar::SignatureCalculator do
|
4
|
+
let(:calculator) { Polar::SignatureCalculator.new(secret_key) }
|
5
|
+
describe "#calculate" do
|
6
|
+
subject { calculator.calculate(hash) }
|
7
|
+
context "when secret_key is 7fbf9791036749cb82e74efd62e9eb38" do
|
8
|
+
let(:secret_key) { "7fbf9791036749cb82e74efd62e9eb38" }
|
9
|
+
example_hash = {
|
10
|
+
"v" => "1.0",
|
11
|
+
"api_key" => "ec9e57913c5b42b282ab7b743559e1b0",
|
12
|
+
"method" => "xiaonei.users.getLoggedInUser",
|
13
|
+
"call_id" => 1232095295656,
|
14
|
+
"session_key" => "L6Xe8dXVGISZ17LJy7GzZaeYGpeGfeNdqEPLNUtCJfxPCxCRLWT83x+s/Ur94PqP-700001044"
|
15
|
+
}
|
16
|
+
context "when hash is #{example_hash.inspect}" do
|
17
|
+
let(:hash) { example_hash }
|
18
|
+
it { should == "66f332c08191b8a5dd3477d36f3af49f" }
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../lib/polar')
|
2
|
+
|
3
|
+
require 'rack/test'
|
4
|
+
require 'ruby-debug'
|
5
|
+
require 'webmock'
|
6
|
+
require 'webmock/rspec'
|
7
|
+
require "polar"
|
8
|
+
require "stub_manager"
|
9
|
+
require "timecop"
|
10
|
+
|
11
|
+
#require each stub file
|
12
|
+
Dir[File.dirname(__FILE__) + '/stubs/*'].each { |file| require file }
|
13
|
+
|
14
|
+
module Helpers
|
15
|
+
def generate_hash(secret_key, api_key, hash = {})
|
16
|
+
auth_code = Digest::MD5.hexdigest(hash.sort.collect { |e| e * "=" } * "" << secret_key)
|
17
|
+
Hash[hash.collect { |k, v| [api_key + "_" + k, v] }].merge!(api_key => auth_code)
|
18
|
+
end
|
19
|
+
|
20
|
+
def generate_cookie(secret_key, api_key, hash = {})
|
21
|
+
generate_hash(secret_key, api_key, hash).collect { |(k, v)| "#{k}=#{v}" }
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'webmock'
|
2
|
+
|
3
|
+
class EndPointStub
|
4
|
+
include WebMock::API
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
WebMock.reset!
|
8
|
+
if @pages
|
9
|
+
@pages.times do |count|
|
10
|
+
stub_request(:post, "http://api.renren.com/restserver.do").with(:body => request_body_with_page(count + 1)).to_return(response(count + 1))
|
11
|
+
end
|
12
|
+
else
|
13
|
+
stub_request(:post, "http://api.renren.com/restserver.do").to_return(response(1))
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def with
|
18
|
+
{}
|
19
|
+
end
|
20
|
+
|
21
|
+
def response
|
22
|
+
raise("Abstract Method")
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def request_body_with_page
|
28
|
+
raise("Abstract Method")
|
29
|
+
end
|
30
|
+
|
31
|
+
def urlencode_params(params_hash)
|
32
|
+
params = ''
|
33
|
+
stack = []
|
34
|
+
|
35
|
+
params_hash.each do |k, v|
|
36
|
+
if v.is_a?(Hash)
|
37
|
+
stack << [k,v]
|
38
|
+
else
|
39
|
+
params << "#{k}=#{v}&"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
stack.each do |parent, hash|
|
44
|
+
hash.each do |k, v|
|
45
|
+
if v.is_a?(Hash)
|
46
|
+
stack << ["#{parent}[#{k}]", v]
|
47
|
+
else
|
48
|
+
params << "#{parent}[#{k}]=#{v}&"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
params.chop! # trailing &
|
54
|
+
params
|
55
|
+
end
|
56
|
+
end
|
metadata
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: polar-renren
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Lei, Zhi-Qiang, Stewart Matheson
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-05-17 00:00:00.000000000Z
|
13
|
+
dependencies: []
|
14
|
+
description: ! ' Polar is an API wrapper for the Renren social network.
|
15
|
+
|
16
|
+
'
|
17
|
+
email: stew@rtmatheson.com
|
18
|
+
executables: []
|
19
|
+
extensions: []
|
20
|
+
extra_rdoc_files:
|
21
|
+
- README.markdown
|
22
|
+
files:
|
23
|
+
- lib/polar/authentication.rb
|
24
|
+
- lib/polar/base.rb
|
25
|
+
- lib/polar/client.rb
|
26
|
+
- lib/polar/cursor.rb
|
27
|
+
- lib/polar/error/api_error.rb
|
28
|
+
- lib/polar/error/http_error.rb
|
29
|
+
- lib/polar/request.rb
|
30
|
+
- lib/polar/response.rb
|
31
|
+
- lib/polar/signature_calculator.rb
|
32
|
+
- lib/polar/user.rb
|
33
|
+
- lib/polar.rb
|
34
|
+
- spec/authentication_spec.rb
|
35
|
+
- spec/client_spec.rb
|
36
|
+
- spec/cursor_spec.rb
|
37
|
+
- spec/signature_calculator_spec.rb
|
38
|
+
- spec/spec_helper.rb
|
39
|
+
- spec/stub_manager.rb
|
40
|
+
- README.markdown
|
41
|
+
homepage: https://github.com/stewartmatheson/polar
|
42
|
+
licenses:
|
43
|
+
- BSD
|
44
|
+
post_install_message:
|
45
|
+
rdoc_options: []
|
46
|
+
require_paths:
|
47
|
+
- lib
|
48
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
segments:
|
55
|
+
- 0
|
56
|
+
hash: 2819554415476033239
|
57
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
58
|
+
none: false
|
59
|
+
requirements:
|
60
|
+
- - ! '>='
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '0'
|
63
|
+
requirements: []
|
64
|
+
rubyforge_project:
|
65
|
+
rubygems_version: 1.8.19
|
66
|
+
signing_key:
|
67
|
+
specification_version: 3
|
68
|
+
summary: Polar is a wrapper around the Renren social network's restful api.
|
69
|
+
test_files:
|
70
|
+
- spec/authentication_spec.rb
|
71
|
+
- spec/client_spec.rb
|
72
|
+
- spec/cursor_spec.rb
|
73
|
+
- spec/signature_calculator_spec.rb
|