rb_facebook 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (2) hide show
  1. data/lib/rb_facebook.rb +335 -0
  2. metadata +87 -0
@@ -0,0 +1,335 @@
1
+ module RbFacebook
2
+
3
+ VERSION = '0.0.4'
4
+ class Api
5
+
6
+ attr_accessor :access_token, :app_id, :app_secret
7
+
8
+ STATS_METRICS = ["impressions", "clicks", "spent", "social_impressions", "social_clicks", "social_spent", "actions", "unique_impressions", "social_unique_impressions", "unique_clicks", "social_unique_clicks", "connections"]
9
+
10
+ def logged_in_user
11
+ graph_api_parse('me')
12
+ end
13
+
14
+ def ads_accounts
15
+ rest_api_parse('ads.getAccounts')
16
+ end
17
+
18
+ def user_accounts
19
+ graph_api_parse('me/accounts')['data']
20
+ end
21
+
22
+ def ads_campaigns(args = {})
23
+ account_id = args[:account_id]
24
+ params = {'account_id' => account_id}
25
+ params[:campaign_ids] = "[#{args[:campaign_ids].join(',')}]" if args[:campaign_ids]
26
+ rest_api_parse('ads.getCampaigns', :params => params, :log_call_url => true)
27
+ end
28
+
29
+ def insight_metrics(args = {})
30
+
31
+ metrics = args[:metrics]
32
+ object_id = args[:object_id]
33
+ start_date = args[:start_date]
34
+ end_date = args[:end_date]
35
+
36
+ data_calls = []
37
+ metrics_data = {}
38
+
39
+ metrics.each do |metric|
40
+ metrics_data[metric] = {}
41
+ current_date = start_date + 1.day
42
+ period = 1.day.seconds
43
+ while current_date <= end_date
44
+ data_calls << {
45
+ :fql_query =>
46
+ "SELECT object_id, metric, end_time, period, value FROM insights
47
+ WHERE object_id = #{object_id}
48
+ AND metric = '#{metric}'
49
+ AND end_time = end_time_date('#{current_date.strftime("%Y-%m-%d")}')
50
+ AND period = #{period}",
51
+ :metric => metric,
52
+ :date => current_date - 1.day
53
+ }
54
+ current_date += 1.day
55
+ end
56
+ end
57
+
58
+ data_calls.each_slice(50) do |call_slice|
59
+ call_slice.map do |call|
60
+ Thread.new do
61
+ #Rails.logger.warn(call)
62
+ result = rest_api_parse('fql.query', :params => {:query => call[:fql_query]})
63
+ #Rails.logger.warn(result)
64
+ Thread.exclusive do
65
+ begin
66
+ #Rails.logger.warn "RESULT: #{result.inspect}"
67
+ metrics_data[call[:metric]][call[:date]] = (result.first || {})['value'] || 0
68
+ rescue
69
+ Rails.logger.warn "ERROR THROWN: #{result.inspect}"
70
+ raise
71
+ end
72
+ end
73
+ end
74
+ end.each(&:join)
75
+ end
76
+
77
+ metrics_data
78
+ end
79
+
80
+ def ads_campaign_stats(args = {})
81
+ account_id = args[:account_id]
82
+ campaign_id = args[:campaign_id]
83
+ include_deleted = args[:include_deleted]
84
+ start_date = args[:start_date]
85
+ end_date = args[:end_date]
86
+ period = args[:interval]
87
+
88
+ data_calls = []
89
+ metrics_data = {}
90
+
91
+ current_date = start_date
92
+
93
+ while current_date <= end_date
94
+ metrics_data[current_date] = {}
95
+ data_calls << {
96
+ :start_date => current_date.strftime('%s'),
97
+ :end_date => (current_date + period).strftime('%s'),
98
+ :date => current_date
99
+ }
100
+ current_date += period
101
+ end
102
+
103
+ data_calls.each_slice(50) do |call_slice|
104
+ call_slice.map do |call|
105
+ Thread.new do
106
+ date_param = {"time_range" => {"time_start" => call[:start_date], "time_stop" => call[:end_date]}}.to_json
107
+ result = rest_api_parse('ads.getCampaignStats', :params => {
108
+ :account_id => account_id,
109
+ :campaign_ids => "[#{campaign_id}]",
110
+ :time_ranges => date_param,
111
+ :include_deleted => include_deleted
112
+ })
113
+ Thread.exclusive do
114
+ #Rails.logger.warn(result.inspect)
115
+ result.first['stats'].each do |id, stats|
116
+ stats.each do |metric, value|
117
+ next if metric == 'id'
118
+ metrics_data[call[:date]][metric] = metrics_data[call[:date]][metric].to_f + value.to_f
119
+ end
120
+ end
121
+ end
122
+ end
123
+ end.each(&:join)
124
+ end
125
+
126
+ metrics_data
127
+ end
128
+
129
+ def ad_groups(args = {})
130
+ params = {:account_id => args[:account_id], :include_deleted => args[:include_deleted] || false}
131
+ params[:campaign_ids] = args[:campaign_ids] if args[:campaign_ids]
132
+ params[:campaign_ids] = "[#{args[:campaign_id]}]" if args[:campaign_id]
133
+ rest_api_parse('ads.getAdGroups', :params => params, :log_call_url => true)
134
+ end
135
+
136
+ def initialize
137
+ load_tokens
138
+ end
139
+
140
+ def load_tokens
141
+ tokens = YAML.load(File.open(File.join(Rails.root, 'config', 'facebook.yml')))
142
+ self.app_secret = tokens[:APP_SECRET]
143
+ self.app_id = tokens[:APP_ID]
144
+ end
145
+
146
+ def login_url(current_url, permissions=[:read_insights,:ads_management,:offline_access])
147
+ "https://www.facebook.com/dialog/oauth?client_id=#{self.app_id}&scope=#{permissions.join(',')}&redirect_uri=#{URI.escape(current_url, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]"))}"
148
+ end
149
+
150
+ def logout_url(current_url)
151
+ "https://www.facebook.com/logout.php?next=#{URI.escape(current_url, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]"))}&access_token=#{URI.escape(self.access_token, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]"))}"
152
+ end
153
+
154
+ def authenticate(args)
155
+ load_tokens
156
+ response = graph_api_fetch(
157
+ "oauth/access_token",
158
+ :params => {
159
+ :client_id => app_id,
160
+ :client_secret => app_secret,
161
+ :code => args[:code],
162
+ :redirect_uri => args[:url]
163
+ },
164
+ :no_access_token => true
165
+ )
166
+
167
+ self.access_token = CGI.parse(response.body)['access_token'].first
168
+ end
169
+
170
+ def logged_in?
171
+ check_auth
172
+ !self.access_token.nil?
173
+ end
174
+
175
+ def check_auth
176
+ if self.access_token
177
+ response = graph_api_fetch('me')
178
+ if response.code != '200'
179
+ self.access_token = nil
180
+ end
181
+ end
182
+ end
183
+
184
+ def graph_api_parse(method_name, args = {})
185
+ ActiveSupport::JSON.decode(graph_api_fetch(method_name, args).body)
186
+ end
187
+
188
+ def graph_api_fetch(method_name, args = {})
189
+ api_params = args[:params] || {}
190
+ use_access_token = !args[:no_access_token]
191
+ log_call_url = args[:log_call_url]
192
+
193
+ api_fetch('graph.facebook.com', method_name, api_params, use_access_token, log_call_url)
194
+ end
195
+
196
+ def rest_api_parse(method_name, args = {})
197
+ results = []
198
+ result = [:dummy]
199
+ previous_result = []
200
+
201
+ page = 0
202
+ per_page = 10
203
+
204
+ until result.empty? or result.is_a?(Hash) or result == previous_result
205
+ if method_name =~ /^ads./
206
+ args[:params] = {} unless args[:params]
207
+ args[:params][:limit] = per_page
208
+ args[:params][:offset] = per_page * page
209
+ #args[:params][:include_count] = 1
210
+ end
211
+
212
+ previous_result = result
213
+ result = ActiveSupport::JSON.decode(rest_api_fetch(method_name, args).body)
214
+
215
+ page += 1
216
+ results << result unless result == previous_result
217
+
218
+ result = [] unless method_name =~ /^ads\./
219
+ end
220
+ results.flatten
221
+ end
222
+
223
+ def rest_api_fetch(method_name, args = {})
224
+ api_params = args[:params] || {}
225
+ use_access_token = !args[:no_access_token]
226
+ log_call_url = args[:log_call_url]
227
+ multipart_post = args[:mp_post]
228
+
229
+ api_params["format"] = 'json-strings'
230
+
231
+ api_fetch('api.facebook.com/method', method_name, api_params, use_access_token, log_call_url, :mp_post => multipart_post)
232
+
233
+ end
234
+
235
+ def api_fetch(api_base_url, method_name, api_params, use_access_token, log_call_url, args = {})
236
+
237
+ api_params["access_token"] = self.access_token if use_access_token
238
+
239
+ params_fragment = api_params.map{|k,v|"#{k}=#{URI.escape("#{v}", Regexp.new("[^#{URI::PATTERN::UNRESERVED}]"))}"}.join('&')
240
+
241
+ call_url = ['https:/', api_base_url, method_name].join('/')
242
+ call_url << "?#{params_fragment}" unless params_fragment.blank? or args[:mp_post]
243
+
244
+ Rails.logger.warn("About to fetch: #{call_url}") if log_call_url
245
+ Rails.logger.warn("Parameters: #{api_params.inspect}") if log_call_url
246
+
247
+ uri = URI.parse(call_url)
248
+ http = Net::HTTP.new(uri.host, uri.port)
249
+ http.use_ssl = true
250
+ if args[:mp_post]
251
+ mp_post = args[:mp_post]
252
+ api_params[mp_post[:name]] = UploadIO.new(mp_post[:file], mp_post[:mime], mp_post[:name])
253
+ post = Net::HTTP::Post::Multipart.new(
254
+ uri.request_uri,
255
+ api_params
256
+ )
257
+ response = http.request(post)
258
+ else
259
+ response = http.request(Net::HTTP::Get.new(uri.request_uri))
260
+ end
261
+
262
+ Rails.logger.warn("And returned #{response.inspect}: #{response.body}") if log_call_url
263
+
264
+ response
265
+ end
266
+
267
+ def self.format_targeting(targeting)
268
+ Rails.logger.warn '-0-0-0-0-0-0-0-0-0-0-'
269
+ Rails.logger.warn 'ABOUT TO FORMAT TARGETING'
270
+ Rails.logger.warn targeting.inspect
271
+ Rails.logger.warn '-0-0-0-0-0-0-0-0-0-0-'
272
+
273
+ begin
274
+
275
+ formatted_targeting = []
276
+ targeting = targeting.dup
277
+ Rails.logger.warn(targeting.inspect)
278
+ adgroup_id = targeting.delete('adgroup_id')
279
+
280
+ genders = targeting.delete('genders')
281
+ if genders.nil? or genders.length == 2
282
+ gender = 'People'
283
+ elsif genders == ['1']
284
+ gender = 'Men'
285
+ else
286
+ gender = 'Women'
287
+ end
288
+
289
+ #education_statuses =
290
+
291
+ age_min = targeting.delete('age_min')
292
+ age_max = targeting.delete('age_max')
293
+ if age_min and age_max
294
+ formatted_targeting << "#{gender} between #{age_min} and #{age_max} years of age"
295
+ elsif age_min
296
+ formatted_targeting << "#{gender} #{age_min} years of age and older"
297
+ elsif age_max
298
+ formatted_targeting << "#{gender} #{age_max} years of age and younger"
299
+ elsif gender != 'People'
300
+ formatted_targeting << "#{gender} only"
301
+ end
302
+
303
+ relationship_statuses = targeting.delete('relationship_statuses')
304
+ if relationship_statuses and !relationship_statuses.include?('0') #0 indicates ALL
305
+ ref = {'1' => 'single', '2' => 'in a relationship', '3' => 'married', '4' => 'engaged'}
306
+ formatted_targeting << "Are #{relationship_statuses.map{|s|ref[s]}.join(' or ')}"
307
+ end
308
+
309
+ education_statuses = targeting.delete('education_statuses')
310
+ if education_statuses and !education_statuses.include?('0') #0 indicates ALL
311
+ ref = {'1' => 'in high school', '2' => 'in college', '3' => 'college graduates'}
312
+ formatted_targeting << "Are #{education_statuses.map{|s|ref[s]}.join(' or ')}"
313
+ end
314
+
315
+ #puts "remaining keys: #{targeting.keys.inspect}"
316
+ targeting.each do |target_name, target_data|
317
+ target_string = "#{target_name}: "
318
+ target_data = target_data.map{|t|t['name']} if target_data.first.is_a?(Hash)
319
+ target_string << [target_data].flatten.join(', ')
320
+ formatted_targeting << target_string
321
+ end
322
+
323
+ return formatted_targeting
324
+ rescue => ex
325
+
326
+ Rails.logger.warn "ERROR FORMATTING TARGETING"
327
+ Rails.logger.warn ex.backtrace
328
+ return ["There was an error formatting the following raw targeting", targeting.inspect]
329
+ end
330
+
331
+ end
332
+
333
+ end
334
+
335
+ end
metadata ADDED
@@ -0,0 +1,87 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rb_facebook
3
+ version: !ruby/object:Gem::Version
4
+ hash: 23
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 4
10
+ version: 0.0.4
11
+ platform: ruby
12
+ authors:
13
+ - Joshua Levinson
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-07-28 00:00:00 +00:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: rails
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 7
30
+ segments:
31
+ - 3
32
+ - 0
33
+ - 0
34
+ version: 3.0.0
35
+ type: :runtime
36
+ version_requirements: *id001
37
+ description: |
38
+ Provides a simple way to access all methods of the facebook REST and Graph APIs.
39
+
40
+ (c)2011 Raybeam, Inc. (www.raybeam.com)
41
+
42
+ email:
43
+ - pianojosh@gmail.com
44
+ executables: []
45
+
46
+ extensions: []
47
+
48
+ extra_rdoc_files: []
49
+
50
+ files:
51
+ - lib/rb_facebook.rb
52
+ has_rdoc: true
53
+ homepage: http://www.raybeam.com
54
+ licenses: []
55
+
56
+ post_install_message:
57
+ rdoc_options: []
58
+
59
+ require_paths:
60
+ - lib
61
+ required_ruby_version: !ruby/object:Gem::Requirement
62
+ none: false
63
+ requirements:
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ hash: 3
67
+ segments:
68
+ - 0
69
+ version: "0"
70
+ required_rubygems_version: !ruby/object:Gem::Requirement
71
+ none: false
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ hash: 3
76
+ segments:
77
+ - 0
78
+ version: "0"
79
+ requirements: []
80
+
81
+ rubyforge_project: rb_facebook
82
+ rubygems_version: 1.6.2
83
+ signing_key:
84
+ specification_version: 3
85
+ summary: Lightweight wrapper around the facebook REST and Graph API
86
+ test_files: []
87
+