fb_graph 2.1.7 → 2.1.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|