mjfreshyfresh-mini_fb 0.1.11

Sign up to get free protection for your applications and to get access to all the features.
Files changed (4) hide show
  1. data/README.markdown +49 -0
  2. data/lib/mini_fb.rb +279 -0
  3. data/test/test_mini_fb.rb +29 -0
  4. metadata +57 -0
@@ -0,0 +1,49 @@
1
+ MiniFB - the simple miniature facebook library
2
+ ==============================================
3
+
4
+ MiniFB is a small, lightweight Ruby library for interacting with the [Facebook API](http://wiki.developers.facebook.com/index.php/API).
5
+
6
+ Installation
7
+ -------------
8
+
9
+ We're using gemcutter so be sure to have gemcutter as a source, then:
10
+
11
+ gem install mini_fb
12
+
13
+ General Usage
14
+ -------------
15
+
16
+ The most general case is to use MiniFB.call method:
17
+
18
+ user_hash = MiniFB.call(FB_API_KEY, FB_SECRET, "Users.getInfo", "session_key"=>@session_key, "uids"=>@uid, "fields"=>User.all_fields)
19
+
20
+ Which simply returns the parsed json response from Facebook.
21
+
22
+ Some Higher Level Objects for Common Uses
23
+ ----------------------
24
+
25
+ Get a MiniFB::Session:
26
+
27
+ @fb = MiniFB::Session.new(FB_API_KEY, FB_SECRET, @fb_session, @fb_uid)
28
+
29
+ With the session, you can then get the user information for the session/uid.
30
+
31
+ user = @fb.user
32
+
33
+ Then get info from the user:
34
+
35
+ first_name = user["first_name"]
36
+
37
+ Or profile photos:
38
+
39
+ photos = user.profile_photos
40
+
41
+ Or if you want other photos, try:
42
+
43
+ photos = @fb.photos("pids"=>[12343243,920382343,9208348])
44
+
45
+ Support
46
+ --------
47
+
48
+ Join our Discussion Group at: http://groups.google.com/group/mini_fb
49
+
@@ -0,0 +1,279 @@
1
+ require 'digest/md5'
2
+ require 'erb'
3
+ require 'json' unless defined? JSON
4
+
5
+ module MiniFB
6
+
7
+ # Global constants
8
+ FB_URL = "http://api.facebook.com/restserver.php"
9
+ FB_API_VERSION = "1.0"
10
+
11
+ @@logging = false
12
+
13
+ def enable_logging
14
+ @@logging = true
15
+ end
16
+
17
+ def disable_logging
18
+ @@logging = false
19
+ end
20
+
21
+ class FaceBookError < StandardError
22
+ # Error that happens during a facebook call.
23
+ def initialize( error_code, error_msg )
24
+ super("Facebook error #{error_code}: #{error_msg}" )
25
+ end
26
+ end
27
+
28
+ class Session
29
+ attr_accessor :api_key, :secret_key, :session_key, :uid
30
+
31
+
32
+ def initialize(api_key, secret_key, session_key, uid)
33
+ @api_key = api_key
34
+ @secret_key = FaceBookSecret.new secret_key
35
+ @session_key = session_key
36
+ @uid = uid
37
+ end
38
+
39
+ # returns current user
40
+ def user
41
+ return @user unless @user.nil?
42
+ @user = User.new(MiniFB.call(@api_key, @secret_key, "Users.getInfo", "session_key"=>@session_key, "uids"=>@uid, "fields"=>User.all_fields)[0], self)
43
+ @user
44
+ end
45
+
46
+ def photos
47
+ Photos.new(self)
48
+ end
49
+
50
+
51
+ def call(method, params={})
52
+ return MiniFB.call(api_key, secret_key, method, params.update("session_key"=>session_key))
53
+ end
54
+
55
+
56
+ end
57
+ class User
58
+ FIELDS = [:uid, :status, :political, :pic_small, :name, :quotes, :is_app_user, :tv, :profile_update_time, :meeting_sex, :hs_info, :timezone, :relationship_status, :hometown_location, :about_me, :wall_count, :significant_other_id, :pic_big, :music, :work_history, :sex, :religion, :notes_count, :activities, :pic_square, :movies, :has_added_app, :education_history, :birthday, :birthday_date, :first_name, :meeting_for, :last_name, :interests, :current_location, :pic, :books, :affiliations, :locale, :profile_url, :proxied_email, :email_hashes, :allowed_restrictions, :pic_with_logo, :pic_big_with_logo, :pic_small_with_logo, :pic_square_with_logo]
59
+ STANDARD_FIELDS = [:uid, :first_name, :last_name, :name, :timezone, :birthday, :sex, :affiliations, :locale, :profile_url, :proxied_email]
60
+
61
+ def self.all_fields
62
+ FIELDS.join(",")
63
+ end
64
+
65
+ def self.standard_fields
66
+ STANDARD_FIELDS.join(",")
67
+ end
68
+
69
+ def initialize(fb_hash, session)
70
+ @fb_hash = fb_hash
71
+ @session = session
72
+ end
73
+
74
+ def [](key)
75
+ @fb_hash[key]
76
+ end
77
+
78
+ def uid
79
+ return self["uid"]
80
+ end
81
+
82
+ def profile_photos
83
+ @session.photos.get("uid"=>uid, "aid"=>profile_pic_album_id)
84
+ end
85
+
86
+ def profile_pic_album_id
87
+ merge_aid(-3, uid)
88
+ end
89
+
90
+ def merge_aid(aid, uid)
91
+ uid = uid.to_i
92
+ ret = (uid << 32) + (aid & 0xFFFFFFFF)
93
+ # puts 'merge_aid=' + ret.inspect
94
+ return ret
95
+ end
96
+ end
97
+
98
+ class Photos
99
+
100
+ def initialize(session)
101
+ @session = session
102
+ end
103
+
104
+ def get(params)
105
+ pids = params["pids"]
106
+ if !pids.nil? && pids.is_a?(Array)
107
+ pids = pids.join(",")
108
+ params["pids"] = pids
109
+ end
110
+ @session.call("photos.get", params)
111
+ end
112
+ end
113
+
114
+ BAD_JSON_METHODS = ["users.getLoggedInUser","auth.promoteSession"]
115
+
116
+ # Call facebook server with a method request. Most keyword arguments
117
+ # are passed directly to the server with a few exceptions.
118
+ # The 'sig' value will always be computed automatically.
119
+ # The 'v' version will be supplied automatically if needed.
120
+ # The 'call_id' defaults to True, which will generate a valid
121
+ # number. Otherwise it should be a valid number or False to disable.
122
+
123
+ # The default return is a parsed json object.
124
+ # Unless the 'format' and/or 'callback' arguments are given,
125
+ # in which case the raw text of the reply is returned. The string
126
+ # will always be returned, even during errors.
127
+
128
+ # If an error occurs, a FacebookError exception will be raised
129
+ # with the proper code and message.
130
+
131
+ # The secret argument should be an instance of FacebookSecret
132
+ # to hide value from simple introspection.
133
+ def MiniFB.call( api_key, secret, method, kwargs )
134
+
135
+ puts 'kwargs=' + kwargs.inspect
136
+
137
+ if secret.is_a? String
138
+ secret = FaceBookSecret.new(secret)
139
+ end
140
+
141
+ # Prepare arguments for call
142
+ call_id = kwargs.fetch("call_id", true)
143
+ if call_id == true then
144
+ kwargs["call_id"] = Time.now.tv_sec.to_s
145
+ else
146
+ kwargs.delete("call_id")
147
+ end
148
+
149
+ custom_format = kwargs.include?("format") or kwargs.include?("callback")
150
+ kwargs["format"] ||= "JSON"
151
+ kwargs["v"] ||= FB_API_VERSION
152
+ kwargs["api_key"]||= api_key
153
+ kwargs["method"] ||= method
154
+
155
+ # Hash with secret
156
+ arg_string = String.new
157
+ # todo: convert symbols to strings, symbols break the next line
158
+ kwargs.sort.each { |kv| arg_string << kv[0] << "=" << kv[1].to_s }
159
+ kwargs["sig"] = Digest::MD5.hexdigest( arg_string + secret.value.call )
160
+
161
+ # Call website with POST request
162
+ begin
163
+ response = Net::HTTP.post_form( URI.parse(FB_URL), kwargs )
164
+ rescue SocketError => err
165
+ raise IOError.new( "Cannot connect to the facebook server: " + err )
166
+ end
167
+
168
+ # Handle response
169
+ return response.body if custom_format
170
+
171
+ fb_method = kwargs["method"]
172
+ body = response.body
173
+
174
+ begin
175
+ data = JSON.parse( body )
176
+ puts 'response=' + data.inspect if @@logging
177
+ if data.include?( "error_msg" ) then
178
+ raise FaceBookError.new( data["error_code"] || 1, data["error_msg"] )
179
+ end
180
+
181
+ rescue JSON::ParserError => ex
182
+ if BAD_JSON_METHODS.include?(fb_method) # Little hack because this response isn't valid JSON
183
+ return body
184
+ else
185
+ raise ex
186
+ end
187
+ end
188
+ return data
189
+ end
190
+
191
+ # Returns true is signature is valid, false otherwise.
192
+ def MiniFB.verify_signature( secret, arguments )
193
+ signature = arguments.delete( "fb_sig" )
194
+ return false if signature.nil?
195
+
196
+ unsigned = Hash.new
197
+ signed = Hash.new
198
+
199
+ arguments.each do |k, v|
200
+ if k =~ /^fb_sig_(.*)/ then
201
+ signed[$1] = v
202
+ else
203
+ unsigned[k] = v
204
+ end
205
+ end
206
+
207
+ arg_string = String.new
208
+ signed.sort.each { |kv| arg_string << kv[0] << "=" << kv[1] }
209
+ if Digest::MD5.hexdigest( arg_string + secret ) == signature
210
+ return true
211
+ end
212
+ return false
213
+ end
214
+
215
+ # Returns the login/add app url for your application.
216
+ #
217
+ # options:
218
+ # - :next => a relative next page to go to. relative to your facebook connect url or if :canvas is true, then relative to facebook app url
219
+ # - :canvas => true/false - to say whether this is a canvas app or not
220
+ def self.login_url(api_key, options={})
221
+ login_url = "http://api.facebook.com/login.php?api_key=#{api_key}"
222
+ login_url << "&next=#{options[:next]}" if options[:next]
223
+ login_url << "&canvas" if options[:canvas]
224
+ login_url
225
+ end
226
+
227
+ # This function expects arguments as a hash, so
228
+ # it is agnostic to different POST handling variants in ruby.
229
+ #
230
+ # Validate the arguments received from facebook. This is usually
231
+ # sent for the iframe in Facebook's canvas. It is not necessary
232
+ # to use this on the auth_token and uid passed to callbacks like
233
+ # post-add and post-remove.
234
+ #
235
+ # The arguments must be a mapping of to string keys and values
236
+ # or a string of http request data.
237
+ #
238
+ # If the data is invalid or not signed properly, an empty
239
+ # dictionary is returned.
240
+ #
241
+ # The secret argument should be an instance of FacebookSecret
242
+ # to hide value from simple introspection.
243
+ #
244
+ # DEPRECATED, use verify_signature instead
245
+ def MiniFB.validate( secret, arguments )
246
+
247
+ signature = arguments.delete( "fb_sig" )
248
+ return arguments if signature.nil?
249
+
250
+ unsigned = Hash.new
251
+ signed = Hash.new
252
+
253
+ arguments.each do |k, v|
254
+ if k =~ /^fb_sig_(.*)/ then
255
+ signed[$1] = v
256
+ else
257
+ unsigned[k] = v
258
+ end
259
+ end
260
+
261
+ arg_string = String.new
262
+ signed.sort.each { |kv| arg_string << kv[0] << "=" << kv[1] }
263
+ if Digest::MD5.hexdigest( arg_string + secret ) != signature
264
+ unsigned # Hash is incorrect, return only unsigned fields.
265
+ else
266
+ unsigned.merge signed
267
+ end
268
+ end
269
+
270
+ class FaceBookSecret
271
+ # Simple container that stores a secret value.
272
+ # Proc cannot be dumped or introspected by normal tools.
273
+ attr_reader :value
274
+
275
+ def initialize( value )
276
+ @value = Proc.new { value }
277
+ end
278
+ end
279
+ end
@@ -0,0 +1,29 @@
1
+ require 'test/unit'
2
+ class MiniFBTests < Test::Unit::TestCase
3
+
4
+
5
+ def setup
6
+ end
7
+
8
+ def teardown
9
+
10
+ end
11
+
12
+ # Test signature verification.
13
+ def test_signature
14
+
15
+ end
16
+
17
+ def test_basic_calls
18
+
19
+ end
20
+
21
+ def test_session
22
+
23
+ end
24
+
25
+ def test_photos
26
+
27
+ end
28
+
29
+ end
metadata ADDED
@@ -0,0 +1,57 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mjfreshyfresh-mini_fb
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.11
5
+ platform: ruby
6
+ authors:
7
+ - Travis Reeder
8
+ - Aaron Hurley
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2010-01-20 00:00:00 -08:00
14
+ default_executable:
15
+ dependencies: []
16
+
17
+ description: Tiny facebook library
18
+ email: michael@stepchangegroup.com
19
+ executables: []
20
+
21
+ extensions: []
22
+
23
+ extra_rdoc_files:
24
+ - README.markdown
25
+ files:
26
+ - lib/mini_fb.rb
27
+ - README.markdown
28
+ has_rdoc: true
29
+ homepage: http://github.com/mjfreshyfresh/mini_fb
30
+ licenses: []
31
+
32
+ post_install_message:
33
+ rdoc_options:
34
+ - --charset=UTF-8
35
+ require_paths:
36
+ - lib
37
+ required_ruby_version: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ version: "0"
42
+ version:
43
+ required_rubygems_version: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: "0"
48
+ version:
49
+ requirements: []
50
+
51
+ rubyforge_project:
52
+ rubygems_version: 1.3.5
53
+ signing_key:
54
+ specification_version: 3
55
+ summary: Tiny facebook library
56
+ test_files:
57
+ - test/test_mini_fb.rb