fb_graph 2.1.7 → 2.1.8
Sign up to get free protection for your applications and to get access to all the features.
- data/VERSION +1 -1
- data/lib/fb_graph.rb +8 -2
- data/lib/fb_graph/achievement.rb +44 -0
- data/lib/fb_graph/ad_account.rb +2 -0
- data/lib/fb_graph/ad_connection_object.rb +38 -0
- data/lib/fb_graph/application.rb +27 -6
- data/lib/fb_graph/broad_targeting_category.rb +13 -0
- data/lib/fb_graph/connections/achievements.rb +21 -0
- data/lib/fb_graph/connections/ad_connection_objects.rb +14 -0
- data/lib/fb_graph/connections/broad_targeting_categories.rb +14 -0
- data/lib/fb_graph/connections/mutual_friends.rb +22 -0
- data/lib/fb_graph/connections/user_achievements.rb +22 -0
- data/lib/fb_graph/exception.rb +41 -1
- data/lib/fb_graph/node.rb +2 -11
- data/lib/fb_graph/user.rb +2 -0
- data/lib/fb_graph/user_achievement.rb +35 -0
- data/spec/fb_graph/achievement_spec.rb +59 -0
- data/spec/fb_graph/ad_connection_object_spec.rb +30 -0
- data/spec/fb_graph/application_spec.rb +3 -1
- data/spec/fb_graph/broad_targeting_category_spec.rb +17 -0
- data/spec/fb_graph/connections/achievements_spec.rb +27 -0
- data/spec/fb_graph/connections/ad_connection_objects_spec.rb +20 -0
- data/spec/fb_graph/connections/broad_targeting_categories_spec.rb +18 -0
- data/spec/fb_graph/connections/mutual_friends_spec.rb +28 -0
- data/spec/fb_graph/connections/user_achievements_spec.rb +37 -0
- data/spec/fb_graph/exception_spec.rb +97 -1
- data/spec/fb_graph/user_achievement_spec.rb +53 -0
- data/spec/mock_json/ad_accounts/ad_connection_objects/test_connection_objects.json +34 -0
- data/spec/mock_json/ad_accounts/broad_targeting_categories/test_bct.json +19 -0
- data/spec/mock_json/applications/achievements/sample.json +24 -0
- data/spec/mock_json/users/mutual_friends/me_and_agektmr.json +126 -0
- data/spec/mock_json/users/user_achievements/created.json +1 -0
- data/spec/mock_json/users/user_achievements/sample.json +31 -0
- metadata +41 -2
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.1.
|
1
|
+
2.1.8
|
data/lib/fb_graph.rb
CHANGED
@@ -61,14 +61,17 @@ require 'fb_graph/venue'
|
|
61
61
|
require 'fb_graph/work'
|
62
62
|
|
63
63
|
require 'fb_graph/node'
|
64
|
+
require 'fb_graph/achievement'
|
64
65
|
require 'fb_graph/ad_account'
|
65
66
|
require 'fb_graph/ad_campaign'
|
66
67
|
require 'fb_graph/ad_campaign_stat'
|
68
|
+
require 'fb_graph/ad_connection_object'
|
67
69
|
require 'fb_graph/ad_group'
|
68
70
|
require 'fb_graph/ad_group_stat'
|
69
71
|
require 'fb_graph/ad_keyword'
|
70
72
|
require 'fb_graph/ad_keyword_suggestion'
|
71
73
|
require 'fb_graph/ad_keyword_valid'
|
74
|
+
require 'fb_graph/broad_targeting_category'
|
72
75
|
require 'fb_graph/reach_estimate.rb'
|
73
76
|
require 'fb_graph/album'
|
74
77
|
require 'fb_graph/app_request'
|
@@ -98,10 +101,13 @@ require 'fb_graph/tab'
|
|
98
101
|
require 'fb_graph/tag'
|
99
102
|
require 'fb_graph/thread'
|
100
103
|
require 'fb_graph/user'
|
101
|
-
require 'fb_graph/
|
102
|
-
require 'fb_graph/test_user' # Load after FbGraph::User
|
104
|
+
require 'fb_graph/user_achievement'
|
103
105
|
require 'fb_graph/video'
|
104
106
|
|
107
|
+
# Load after FbGraph::User
|
108
|
+
require 'fb_graph/ad_user'
|
109
|
+
require 'fb_graph/test_user'
|
110
|
+
|
105
111
|
require 'fb_graph/klass'
|
106
112
|
require 'fb_graph/project'
|
107
113
|
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module FbGraph
|
2
|
+
class Achievement < Node
|
3
|
+
attr_accessor :type, :application, :title, :url, :description, :image, :images, :data, :updated_time, :context, :points, :display_order
|
4
|
+
|
5
|
+
def initialize(identifier, attributes = {})
|
6
|
+
super
|
7
|
+
|
8
|
+
# TODO: Handle data, context in smarter way.
|
9
|
+
[:type, :title, :url, :description, :data, :context].each do |key|
|
10
|
+
send "#{key}=", attributes[key]
|
11
|
+
end
|
12
|
+
|
13
|
+
if self.data
|
14
|
+
@points = self.data[:points]
|
15
|
+
end
|
16
|
+
|
17
|
+
if self.context
|
18
|
+
@display_order = self.context[:display_order]
|
19
|
+
end
|
20
|
+
|
21
|
+
@images = []
|
22
|
+
if _images_ = attributes[:image]
|
23
|
+
_images_.each do |_image_|
|
24
|
+
@images << _image_[:url]
|
25
|
+
end
|
26
|
+
end
|
27
|
+
@image = @images.first
|
28
|
+
|
29
|
+
if application = attributes[:application]
|
30
|
+
application[:link] = application[:url] # for some reason, FB uses "url" only here..
|
31
|
+
@application = Application.new(application[:id], application)
|
32
|
+
end
|
33
|
+
|
34
|
+
if attributes[:updated_time]
|
35
|
+
@updated_time = Time.parse(attributes[:updated_time]).utc
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def destroy(options = {})
|
40
|
+
options[:access_token] ||= self.access_token
|
41
|
+
application.unregister_achievement!(url, options)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
data/lib/fb_graph/ad_account.rb
CHANGED
@@ -4,7 +4,9 @@ module FbGraph
|
|
4
4
|
include Connections::AdGroups
|
5
5
|
include Connections::AdCampaignStats
|
6
6
|
include Connections::AdGroupStats
|
7
|
+
include Connections::BroadTargetingCategories
|
7
8
|
include Connections::ReachEstimates
|
9
|
+
include Connections::AdConnectionObjects
|
8
10
|
|
9
11
|
attr_accessor :account_id, :name, :account_status, :daily_spend_limit, :users, :currency, :timezone_id, :timezone_name, :capabilities, :account_groups
|
10
12
|
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module FbGraph
|
2
|
+
class AdConnectionObject < Node
|
3
|
+
attr_accessor :name, :url, :type, :tabs, :picture, :object
|
4
|
+
|
5
|
+
TYPES = {
|
6
|
+
:page => 1,
|
7
|
+
:application => 2,
|
8
|
+
:event => 3,
|
9
|
+
:place => 6,
|
10
|
+
:domain => 7
|
11
|
+
}
|
12
|
+
|
13
|
+
def initialize(identifier, attributes = {})
|
14
|
+
super
|
15
|
+
|
16
|
+
%w(name url type tabs picture).each do |field|
|
17
|
+
send("#{field}=", attributes[field.to_sym])
|
18
|
+
end
|
19
|
+
|
20
|
+
self.object = if page?
|
21
|
+
FbGraph::Page.new(identifier)
|
22
|
+
elsif application?
|
23
|
+
FbGraph::Application.new(identifier)
|
24
|
+
elsif event?
|
25
|
+
FbGraph::Event.new(identifier)
|
26
|
+
elsif place?
|
27
|
+
FbGraph::Place.new(identifier)
|
28
|
+
elsif domain?
|
29
|
+
FbGraph::Domain.new(identifier)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# Defines methods for page?, application?, event? and so forth
|
34
|
+
TYPES.keys.each do |object_type|
|
35
|
+
define_method("#{object_type}?") { type == TYPES[object_type] }
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
data/lib/fb_graph/application.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
module FbGraph
|
2
2
|
class Application < Node
|
3
3
|
include Connections::Accounts
|
4
|
+
include Connections::Achievements
|
4
5
|
include Connections::Albums
|
5
6
|
include Connections::Events
|
6
7
|
include Connections::Feed
|
@@ -20,15 +21,35 @@ module FbGraph
|
|
20
21
|
# include Connections::Translations
|
21
22
|
include Connections::Videos
|
22
23
|
|
23
|
-
|
24
|
+
@@attributes = [
|
25
|
+
:name,
|
26
|
+
:description,
|
27
|
+
:canvas_name,
|
28
|
+
:category,
|
29
|
+
:company,
|
30
|
+
:icon_url,
|
31
|
+
:subcategory,
|
32
|
+
:link,
|
33
|
+
:logo_url,
|
34
|
+
:daily_active_users,
|
35
|
+
:weekly_active_users,
|
36
|
+
:monthly_active_users,
|
37
|
+
:secret
|
38
|
+
]
|
39
|
+
attr_accessor *@@attributes
|
24
40
|
|
25
41
|
def initialize(client_id, attributes = {})
|
26
42
|
super
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
43
|
+
@@attributes.each do |key|
|
44
|
+
# NOTE:
|
45
|
+
# For some reason, Graph API returns daily_active_users, weekly_active_users, monthly_active_users as JSON string.
|
46
|
+
value = if [:daily_active_users, :weekly_active_users, :monthly_active_users].include?(key)
|
47
|
+
attributes[key].to_i
|
48
|
+
else
|
49
|
+
attributes[key]
|
50
|
+
end
|
51
|
+
self.send("#{key}=", value)
|
52
|
+
end
|
32
53
|
end
|
33
54
|
|
34
55
|
def get_access_token(secret = nil)
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module FbGraph
|
2
|
+
class BroadTargetingCategory < Node
|
3
|
+
attr_accessor :name, :parent_category
|
4
|
+
|
5
|
+
def initialize(identifier, attributes = {})
|
6
|
+
super
|
7
|
+
|
8
|
+
%w(name parent_category).each do |field|
|
9
|
+
self.send("#{field}=", attributes[field.to_sym])
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module FbGraph
|
2
|
+
module Connections
|
3
|
+
module Achievements
|
4
|
+
def achievements(options = {})
|
5
|
+
options[:access_token] ||= self.access_token
|
6
|
+
achievements = self.connection(:achievements, options)
|
7
|
+
achievements.map! do |achievement|
|
8
|
+
Achievement.new(achievement[:id], achievement.merge(:access_token => options[:access_token]))
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def achievement!(achievement_url, options = {})
|
13
|
+
post options.merge(:connection => :achievements, :achievement => achievement_url)
|
14
|
+
end
|
15
|
+
|
16
|
+
def unregister_achievement!(achievement_url, options = {})
|
17
|
+
delete options.merge(:connection => :achievements, :achievement => achievement_url)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module FbGraph
|
2
|
+
module Connections
|
3
|
+
module AdConnectionObjects
|
4
|
+
def connection_objects(options = {})
|
5
|
+
connection_objects = self.connection(:connectionobjects, options)
|
6
|
+
connection_objects.map! do |connection_object|
|
7
|
+
AdConnectionObject.new(connection_object[:id], connection_object.merge(
|
8
|
+
:access_token => options[:access_token] || self.access_token
|
9
|
+
))
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module FbGraph
|
2
|
+
module Connections
|
3
|
+
module BroadTargetingCategories
|
4
|
+
def broad_targeting_categories(options = {})
|
5
|
+
broad_targeting_categories = self.connection(:broadtargetingcategories, options)
|
6
|
+
broad_targeting_categories.map! do |btc|
|
7
|
+
BroadTargetingCategory.new(btc[:id], btc.merge(
|
8
|
+
:access_token => options[:access_token] || self.access_token
|
9
|
+
))
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module FbGraph
|
2
|
+
module Connections
|
3
|
+
module MutualFriends
|
4
|
+
def mutual_friends(friend, options = {})
|
5
|
+
friends = self.connection(:mutualfriends, options.merge(:connection_scope => connection_scope(friend)))
|
6
|
+
friends.map! do |friend|
|
7
|
+
User.new(friend[:id], friend.merge(:access_token => options[:access_token] || self.access_token))
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def connection_scope(friend)
|
14
|
+
if friend.is_a?(User)
|
15
|
+
friend.identifier
|
16
|
+
else
|
17
|
+
friend
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module FbGraph
|
2
|
+
module Connections
|
3
|
+
module UserAchievements
|
4
|
+
def achievements(options = {})
|
5
|
+
options[:access_token] ||= self.access_token
|
6
|
+
achievements = self.connection(:achievements, options)
|
7
|
+
achievements.map! do |achievement|
|
8
|
+
UserAchievement.new(achievement[:id], achievement.merge(:access_token => options[:access_token]))
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def achieve!(achievement_url, options = {})
|
13
|
+
achievement = post options.merge(:connection => :achievements, :achievement => achievement_url)
|
14
|
+
UserAchievement.new achievement[:id], achievement
|
15
|
+
end
|
16
|
+
|
17
|
+
def unachieve!(achievement_url, options = {})
|
18
|
+
delete options.merge(:connection => :achievements, :achievement => achievement_url)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
data/lib/fb_graph/exception.rb
CHANGED
@@ -1,6 +1,40 @@
|
|
1
1
|
module FbGraph
|
2
2
|
class Exception < StandardError
|
3
3
|
attr_accessor :code, :type, :message
|
4
|
+
|
5
|
+
ERROR_HEADER_MATCHERS = {
|
6
|
+
/invalid_token/ => "InvalidToken",
|
7
|
+
/invalid_request/ => "InvalidRequest"
|
8
|
+
}
|
9
|
+
|
10
|
+
def self.handle_httpclient_error(response, headers)
|
11
|
+
return nil unless response[:error]
|
12
|
+
|
13
|
+
# Check the WWW-Authenticate header, since it seems to be more standardized than the response
|
14
|
+
# body error information.
|
15
|
+
if www_authenticate = headers["WWW-Authenticate"]
|
16
|
+
# Session expiration/invalidation is very common. Check for that first.
|
17
|
+
if www_authenticate =~ /invalid_token/ && response[:error][:message] =~ /session has been invalidated/
|
18
|
+
raise InvalidSession.new("#{response[:error][:type]} :: #{response[:error][:message]}")
|
19
|
+
end
|
20
|
+
|
21
|
+
ERROR_HEADER_MATCHERS.keys.each do |matcher|
|
22
|
+
if matcher =~ www_authenticate
|
23
|
+
exception_class = FbGraph::const_get(ERROR_HEADER_MATCHERS[matcher])
|
24
|
+
raise exception_class.new("#{response[:error][:type]} :: #{response[:error][:message]}")
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# If we can't match on WWW-Authenticate, use the type
|
30
|
+
case response[:error][:type]
|
31
|
+
when /OAuth/
|
32
|
+
raise Unauthorized.new("#{response[:error][:type]} :: #{response[:error][:message]}")
|
33
|
+
else
|
34
|
+
raise BadRequest.new("#{response[:error][:type]} :: #{response[:error][:message]}")
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
4
38
|
def initialize(code, message, body = '')
|
5
39
|
@code = code
|
6
40
|
if body.blank?
|
@@ -30,4 +64,10 @@ module FbGraph
|
|
30
64
|
super 404, message, body
|
31
65
|
end
|
32
66
|
end
|
33
|
-
|
67
|
+
|
68
|
+
class InvalidToken < Unauthorized; end
|
69
|
+
|
70
|
+
class InvalidSession < InvalidToken; end
|
71
|
+
|
72
|
+
class InvalidRequest < BadRequest; end
|
73
|
+
end
|
data/lib/fb_graph/node.rb
CHANGED
@@ -120,21 +120,12 @@ module FbGraph
|
|
120
120
|
_response_.map!(&:with_indifferent_access)
|
121
121
|
when Hash
|
122
122
|
_response_ = _response_.with_indifferent_access
|
123
|
-
handle_httpclient_error(_response_) if _response_[:error]
|
123
|
+
Exception.handle_httpclient_error(_response_, response.headers) if _response_[:error]
|
124
124
|
_response_
|
125
125
|
end
|
126
126
|
end
|
127
127
|
rescue JSON::ParserError
|
128
128
|
raise Exception.new(response.status, 'Unparsable Error Response')
|
129
129
|
end
|
130
|
-
|
131
|
-
def handle_httpclient_error(response)
|
132
|
-
case response[:error][:type]
|
133
|
-
when /OAuth/
|
134
|
-
raise Unauthorized.new("#{response[:error][:type]} :: #{response[:error][:message]}")
|
135
|
-
else
|
136
|
-
raise BadRequest.new("#{response[:error][:type]} :: #{response[:error][:message]}")
|
137
|
-
end
|
138
|
-
end
|
139
130
|
end
|
140
|
-
end
|
131
|
+
end
|
data/lib/fb_graph/user.rb
CHANGED
@@ -22,6 +22,7 @@ module FbGraph
|
|
22
22
|
include Connections::Links
|
23
23
|
include Connections::Movies
|
24
24
|
include Connections::Music
|
25
|
+
include Connections::MutualFriends
|
25
26
|
include Connections::Notes
|
26
27
|
include Connections::Outbox
|
27
28
|
include Connections::Payments
|
@@ -33,6 +34,7 @@ module FbGraph
|
|
33
34
|
include Connections::Tagged
|
34
35
|
include Connections::Television
|
35
36
|
include Connections::Threads
|
37
|
+
include Connections::UserAchievements
|
36
38
|
include Connections::Videos
|
37
39
|
extend Searchable
|
38
40
|
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module FbGraph
|
2
|
+
class UserAchievement < Node
|
3
|
+
include Connections::Comments
|
4
|
+
include Connections::Likes
|
5
|
+
|
6
|
+
attr_accessor :from, :created_time, :application, :achievement
|
7
|
+
|
8
|
+
def initialize(identifier, attributes = {})
|
9
|
+
super
|
10
|
+
|
11
|
+
if from = attributes[:from]
|
12
|
+
@from = User.new(from[:id], from)
|
13
|
+
end
|
14
|
+
if created_time = attributes[:created_time] || attributes[:publish_time]
|
15
|
+
@created_time = Time.parse(created_time).utc
|
16
|
+
end
|
17
|
+
if application = attributes[:application]
|
18
|
+
application[:link] = application[:url] # for some reason, FB uses "url" only here..
|
19
|
+
@application = Application.new(application[:id], application)
|
20
|
+
end
|
21
|
+
if achievement = attributes[:achievement]
|
22
|
+
@achievement = Achievement.new(achievement[:id], achievement)
|
23
|
+
end
|
24
|
+
|
25
|
+
# cached connection
|
26
|
+
@_likes_ = Collection.new(attributes[:likes])
|
27
|
+
@_comments_ = Collection.new(attributes[:comments])
|
28
|
+
end
|
29
|
+
|
30
|
+
def destroy(options = {})
|
31
|
+
options[:access_token] ||= self.access_token
|
32
|
+
from.unachieve!(achievement.url, options)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe FbGraph::Achievement do
|
4
|
+
subject { achievement }
|
5
|
+
let(:achievement) { FbGraph::Achievement.new(attributes[:id], attributes) }
|
6
|
+
let(:attributes) do
|
7
|
+
{
|
8
|
+
:id => "10150310611431721",
|
9
|
+
:url => "http:\/\/fbgraphsample.heroku.com\/achievements\/1",
|
10
|
+
:type => "game.achievement",
|
11
|
+
:title => "1st Achievement",
|
12
|
+
:image => [{
|
13
|
+
:url => "http:\/\/matake.jp\/images\/nov.gif"
|
14
|
+
}],
|
15
|
+
:description => "For testing purpose",
|
16
|
+
:data => {
|
17
|
+
:points => 50
|
18
|
+
},
|
19
|
+
:updated_time => "2011-09-27T08:06:59+0000",
|
20
|
+
:application => {
|
21
|
+
:id => "134145643294322",
|
22
|
+
:name => "gem sample",
|
23
|
+
:url => "http:\/\/www.facebook.com\/apps\/application.php?id=134145643294322"
|
24
|
+
},
|
25
|
+
:context => {
|
26
|
+
:display_order => 0
|
27
|
+
}
|
28
|
+
}
|
29
|
+
end
|
30
|
+
|
31
|
+
[:type, :title, :url, :description, :data, :context].each do |key|
|
32
|
+
its(key) { should == attributes[key] }
|
33
|
+
end
|
34
|
+
|
35
|
+
its(:image) { should == attributes[:image].first[:url] }
|
36
|
+
its(:images) { should == attributes[:image].collect { |h| h[:url] } }
|
37
|
+
its(:points) { should == 50 }
|
38
|
+
its(:display_order) { should == 0 }
|
39
|
+
its(:updated_time) { should == Time.parse(attributes[:updated_time]).utc }
|
40
|
+
describe 'application' do
|
41
|
+
subject { achievement.application }
|
42
|
+
its(:name) { should == attributes[:application][:name] }
|
43
|
+
its(:link) { should == attributes[:application][:url] }
|
44
|
+
end
|
45
|
+
|
46
|
+
describe '#destroy' do
|
47
|
+
it 'should call DELETE /:app_id/achievements' do
|
48
|
+
expect { achievement.destroy }.should request_to('134145643294322/achievements', :delete)
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'should delete achievement' do
|
52
|
+
mock_graph :delete, '134145643294322/achievements', 'true', :access_token => 'app_token', :params => {
|
53
|
+
:achievement => achievement.url
|
54
|
+
} do
|
55
|
+
achievement.destroy(:access_token => 'app_token').should be_true
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|