facebooker-lite 1.0.67

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.
Files changed (118) hide show
  1. data/.autotest +15 -0
  2. data/CHANGELOG.rdoc +24 -0
  3. data/COPYING.rdoc +19 -0
  4. data/Manifest.txt +114 -0
  5. data/README.rdoc +120 -0
  6. data/Rakefile +94 -0
  7. data/TODO.rdoc +4 -0
  8. data/facebooker.gemspec +42 -0
  9. data/generators/xd_receiver/templates/xd_receiver.html +10 -0
  10. data/generators/xd_receiver/templates/xd_receiver_ssl.html +10 -0
  11. data/generators/xd_receiver/xd_receiver_generator.rb +10 -0
  12. data/init.rb +25 -0
  13. data/install.rb +12 -0
  14. data/lib/facebooker.rb +261 -0
  15. data/lib/facebooker/adapters/adapter_base.rb +91 -0
  16. data/lib/facebooker/adapters/bebo_adapter.rb +77 -0
  17. data/lib/facebooker/adapters/facebook_adapter.rb +60 -0
  18. data/lib/facebooker/admin.rb +42 -0
  19. data/lib/facebooker/application.rb +37 -0
  20. data/lib/facebooker/attachment.rb +51 -0
  21. data/lib/facebooker/batch_request.rb +45 -0
  22. data/lib/facebooker/data.rb +57 -0
  23. data/lib/facebooker/feed.rb +78 -0
  24. data/lib/facebooker/logging.rb +44 -0
  25. data/lib/facebooker/mobile.rb +20 -0
  26. data/lib/facebooker/mock/service.rb +50 -0
  27. data/lib/facebooker/mock/session.rb +18 -0
  28. data/lib/facebooker/model.rb +139 -0
  29. data/lib/facebooker/models/affiliation.rb +10 -0
  30. data/lib/facebooker/models/album.rb +11 -0
  31. data/lib/facebooker/models/applicationproperties.rb +39 -0
  32. data/lib/facebooker/models/applicationrestrictions.rb +10 -0
  33. data/lib/facebooker/models/comment.rb +9 -0
  34. data/lib/facebooker/models/cookie.rb +10 -0
  35. data/lib/facebooker/models/education_info.rb +11 -0
  36. data/lib/facebooker/models/event.rb +28 -0
  37. data/lib/facebooker/models/family_relative_info.rb +7 -0
  38. data/lib/facebooker/models/friend_list.rb +16 -0
  39. data/lib/facebooker/models/group.rb +36 -0
  40. data/lib/facebooker/models/info_item.rb +10 -0
  41. data/lib/facebooker/models/info_section.rb +10 -0
  42. data/lib/facebooker/models/location.rb +8 -0
  43. data/lib/facebooker/models/message_thread.rb +89 -0
  44. data/lib/facebooker/models/notifications.rb +17 -0
  45. data/lib/facebooker/models/page.rb +46 -0
  46. data/lib/facebooker/models/photo.rb +19 -0
  47. data/lib/facebooker/models/tag.rb +12 -0
  48. data/lib/facebooker/models/user.rb +751 -0
  49. data/lib/facebooker/models/video.rb +9 -0
  50. data/lib/facebooker/models/work_info.rb +10 -0
  51. data/lib/facebooker/parser.rb +970 -0
  52. data/lib/facebooker/rails/backwards_compatible_param_checks.rb +31 -0
  53. data/lib/facebooker/rails/controller.rb +353 -0
  54. data/lib/facebooker/rails/extensions/action_controller.rb +47 -0
  55. data/lib/facebooker/rails/extensions/rack_setup.rb +16 -0
  56. data/lib/facebooker/rails/extensions/routing.rb +15 -0
  57. data/lib/facebooker/rails/facebook_pretty_errors.rb +22 -0
  58. data/lib/facebooker/rails/facebook_request_fix.rb +28 -0
  59. data/lib/facebooker/rails/facebook_request_fix_2-3.rb +31 -0
  60. data/lib/facebooker/rails/facebook_session_handling.rb +68 -0
  61. data/lib/facebooker/rails/facebook_url_rewriting.rb +60 -0
  62. data/lib/facebooker/rails/helpers/fb_connect.rb +75 -0
  63. data/lib/facebooker/rails/integration_session.rb +38 -0
  64. data/lib/facebooker/rails/profile_publisher_extensions.rb +42 -0
  65. data/lib/facebooker/rails/publisher.rb +608 -0
  66. data/lib/facebooker/rails/routing.rb +49 -0
  67. data/lib/facebooker/rails/test_helpers.rb +68 -0
  68. data/lib/facebooker/rails/utilities.rb +22 -0
  69. data/lib/facebooker/server_cache.rb +24 -0
  70. data/lib/facebooker/service.rb +103 -0
  71. data/lib/facebooker/service/base_service.rb +19 -0
  72. data/lib/facebooker/service/curl_service.rb +44 -0
  73. data/lib/facebooker/service/net_http_service.rb +12 -0
  74. data/lib/facebooker/service/typhoeus_multi_service.rb +27 -0
  75. data/lib/facebooker/service/typhoeus_service.rb +17 -0
  76. data/lib/facebooker/session.rb +786 -0
  77. data/lib/facebooker/stream_post.rb +19 -0
  78. data/lib/facebooker/version.rb +9 -0
  79. data/lib/net/http_multipart_post.rb +123 -0
  80. data/lib/rack/facebook.rb +89 -0
  81. data/lib/rack/facebook_session.rb +21 -0
  82. data/lib/tasks/facebooker.rake +19 -0
  83. data/lib/tasks/facebooker.rb +2 -0
  84. data/lib/tasks/tunnel.rake +46 -0
  85. data/rails/init.rb +1 -0
  86. data/setup.rb +1585 -0
  87. data/templates/layout.erb +24 -0
  88. data/test/facebooker/adapters_test.rb +191 -0
  89. data/test/facebooker/admin_test.rb +102 -0
  90. data/test/facebooker/application_test.rb +110 -0
  91. data/test/facebooker/attachment_test.rb +72 -0
  92. data/test/facebooker/batch_request_test.rb +83 -0
  93. data/test/facebooker/data_test.rb +86 -0
  94. data/test/facebooker/logging_test.rb +43 -0
  95. data/test/facebooker/mobile_test.rb +45 -0
  96. data/test/facebooker/model_test.rb +133 -0
  97. data/test/facebooker/models/event_test.rb +15 -0
  98. data/test/facebooker/models/page_test.rb +56 -0
  99. data/test/facebooker/models/photo_test.rb +16 -0
  100. data/test/facebooker/models/user_test.rb +1074 -0
  101. data/test/facebooker/rails/facebook_request_fix_2-3_test.rb +25 -0
  102. data/test/facebooker/rails/facebook_url_rewriting_test.rb +76 -0
  103. data/test/facebooker/rails/integration_session_test.rb +13 -0
  104. data/test/facebooker/rails/publisher_test.rb +538 -0
  105. data/test/facebooker/rails_integration_test.rb +1543 -0
  106. data/test/facebooker/server_cache_test.rb +44 -0
  107. data/test/facebooker/service_test.rb +58 -0
  108. data/test/facebooker/session_test.rb +883 -0
  109. data/test/facebooker_test.rb +1263 -0
  110. data/test/fixtures/multipart_post_body_with_only_parameters.txt +33 -0
  111. data/test/fixtures/multipart_post_body_with_single_file.txt +38 -0
  112. data/test/fixtures/multipart_post_body_with_single_file_that_has_nil_key.txt +38 -0
  113. data/test/net/http_multipart_post_test.rb +52 -0
  114. data/test/rack/facebook_session_test.rb +34 -0
  115. data/test/rack/facebook_test.rb +73 -0
  116. data/test/rails_test_helper.rb +36 -0
  117. data/test/test_helper.rb +74 -0
  118. metadata +278 -0
@@ -0,0 +1,17 @@
1
+ module Facebooker
2
+ class Notifications
3
+ include Model
4
+ attr_accessor :messages, :group_invites, :pokes, :friend_requests, :event_invites, :shares
5
+
6
+ [:Messages, :Pokes, :Shares].each do |notification_type|
7
+ const_set(notification_type, Class.new do
8
+ include Model
9
+ attr_accessor :unread, :most_recent
10
+ end)
11
+ attribute_name = "#{notification_type.to_s.downcase}"
12
+ define_method("#{attribute_name}=") do |value|
13
+ instance_variable_set("@#{attribute_name}", value.kind_of?(Hash) ? Notifications.const_get(notification_type).from_hash(value) : value)
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,46 @@
1
+ require 'facebooker/model'
2
+ module Facebooker
3
+ class Page
4
+
5
+ def initialize(*args)
6
+ if args.size == 1 and (args.first.is_a?(Integer) or args.first.is_a?(String))
7
+ self.page_id=args.first
8
+ else
9
+ super
10
+ end
11
+ end
12
+
13
+ class Genre
14
+ include Model
15
+ FIELDS = [ :dance, :party, :relax, :talk, :think, :workout, :sing, :intimate, :raunchy, :headphones ]
16
+ attr_accessor(*FIELDS)
17
+
18
+ def initialize(*args)
19
+ super
20
+
21
+ # convert '1'/'0' to true/false
22
+ FIELDS.each do |field|
23
+ self.send("#{field}=", self.send(field) == '1')
24
+ end
25
+ end
26
+ end
27
+
28
+ include Model
29
+ attr_accessor :page_id,:name,:pic_small,:pic_big,:pic_square,:pic,:pic_large,:type,:website,:has_added_app,:founded,:company_overview,:mission,:products,:location,:parking,:public_transit,:hours,:attire,:payment_options,:culinary_team,:general_manager,:price_range,:restaurant_services,:restaurant_specialties,:release_date,:genre,:starring,:screenplay_by,:directed_by,:produced_by,:studio,:awards,:plot_outline,:network,:season,:schedule,:written_by,:band_members,:hometown,:current_location,:record_label,:booking_agent,:artists_we_like,:influences,:band_interests,:bio,:affiliation,:birthday,:personal_info,:personal_interests,:members,:built,:features,:mpg,:general_info,:fan_count,:page_url
30
+ attr_reader :genre
31
+
32
+ alias_method :id, :page_id
33
+
34
+ def genre=(value)
35
+ @genre = value.kind_of?(Hash) ? Genre.from_hash(value) : value
36
+ end
37
+
38
+ def user_is_admin?(user)
39
+ Session.current.post('facebook.pages.isAdmin', :page_id=>self.page_id, :uid=>Facebooker::User.cast_to_facebook_id(user))
40
+ end
41
+
42
+ def user_is_fan?(user)
43
+ Session.current.post('facebook.pages.isFan', :page_id=>self.page_id, :uid=>Facebooker::User.cast_to_facebook_id(user))
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,19 @@
1
+ require 'facebooker/model'
2
+ module Facebooker
3
+ class Photo
4
+ include Model
5
+ attr_accessor :aid, :owner, :title,
6
+ :link, :caption, :created,
7
+ :src, :src_big, :src_small,
8
+ :story_fbid
9
+
10
+ id_is :pid
11
+
12
+ #override the generated method for id_is to use a string
13
+ def pid=(val)
14
+ @pid = val
15
+ end
16
+
17
+ alias :id= :pid=
18
+ end
19
+ end
@@ -0,0 +1,12 @@
1
+ require 'facebooker/model'
2
+ module Facebooker
3
+ class Tag
4
+ include Model
5
+ attr_accessor :pid, :subject, :xcoord, :ycoord, :text, :created
6
+
7
+ def coordinates
8
+ [xcoord, ycoord]
9
+ end
10
+
11
+ end
12
+ end
@@ -0,0 +1,751 @@
1
+ require 'facebooker/model'
2
+ require 'facebooker/models/affiliation'
3
+ require 'facebooker/models/work_info'
4
+ require 'facebooker/models/family_relative_info'
5
+ module Facebooker
6
+ #
7
+ # Holds attributes and behavior for a Facebook User
8
+ class User
9
+ include Model
10
+ class Status
11
+ include Model
12
+ attr_accessor :uid, :message, :time, :status_id, :source
13
+ end
14
+ FIELDS = [: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, :online_presence, :verified, :profile_blurb, :username, :website, :is_blocked, :family, :email]
15
+ STANDARD_FIELDS = [:uid, :first_name, :last_name, :name, :timezone, :birthday, :sex, :affiliations, :locale, :profile_url, :proxied_email, :email]
16
+ populating_attr_accessor(*FIELDS)
17
+ attr_reader :affiliations
18
+ populating_hash_settable_accessor :current_location, Location
19
+ populating_hash_settable_accessor :hometown_location, Location
20
+ populating_hash_settable_accessor :hs_info, EducationInfo::HighschoolInfo
21
+ populating_hash_settable_list_accessor :affiliations, Affiliation
22
+ populating_hash_settable_list_accessor :education_history, EducationInfo
23
+ populating_hash_settable_list_accessor :work_history, WorkInfo
24
+ populating_hash_settable_list_accessor :family, FamilyRelativeInfo
25
+
26
+ populating_attr_reader :status
27
+
28
+ attr_accessor :request_locale
29
+
30
+ # Can pass in these two forms:
31
+ # id, session, (optional) attribute_hash
32
+ # attribute_hash
33
+ def initialize(*args)
34
+ @friends = nil
35
+ @current_location = nil
36
+ @pic = nil
37
+ @hometown_location = nil
38
+ @populated = false
39
+ @session = nil
40
+ @id = nil
41
+ if (args.first.kind_of?(String) || args.first.kind_of?(Integer)) && args.size==1
42
+ self.uid = args.shift
43
+ @session = Session.current
44
+ elsif (args.first.kind_of?(String) || args.first.kind_of?(Integer)) && args[1].kind_of?(Session)
45
+ self.uid = args.shift
46
+ @session = args.shift
47
+ end
48
+ if args.last.kind_of?(Hash)
49
+ populate_from_hash!(args.pop)
50
+ end
51
+ end
52
+
53
+ id_is :uid
54
+ alias :facebook_id :id
55
+
56
+ # Returns a user's events, params correspond to API call parameters (except UID):
57
+ # http://wiki.developers.facebook.com/index.php/Events.get
58
+ # E.g:
59
+ # @user.events(:start_time => Time.now, :end_time => 1.month.from_now)
60
+ # # => Returns events betwen now and a month from now
61
+ def events(params={})
62
+ @events ||= {}
63
+ [:start_time,:end_time].compact.each do |key|
64
+ params[key] = params[key].to_i
65
+ end
66
+ # puts @events[params.to_s].nil?
67
+ @events[params.to_s] ||= @session.post('facebook.events.get', {:uid => self.id}.merge(params)).map do |event|
68
+ Event.from_hash(event)
69
+ end
70
+ end
71
+
72
+ # Rsvp to an event with the eid and rsvp_status which can be 'attending', 'unsure', or 'declined'.
73
+ # http://wiki.developers.facebook.com/index.php/Events.rsvp
74
+ # E.g:
75
+ # @user.rsvp_event('100321123', 'attending')
76
+ # # => Returns true if all went well
77
+ def rsvp_event(eid, rsvp_status, options = {})
78
+ result = @session.post('facebook.events.rsvp', options.merge(:eid => eid, :rsvp_status => rsvp_status))
79
+ result == '1' ? true : false
80
+ end
81
+
82
+ #
83
+ # Set the list of friends, given an array of User objects. If the list has been retrieved previously, will not set
84
+ def friends=(list_of_friends,flid=nil)
85
+ @friends_hash ||= {}
86
+ flid=cast_to_friend_list_id(flid)
87
+ #use __blank instead of nil so that this is cached
88
+ cache_key = flid||"__blank"
89
+
90
+ @friends_hash[cache_key] ||= list_of_friends
91
+ end
92
+
93
+ def cast_to_friend_list_id(flid)
94
+ case flid
95
+ when String
96
+ list=friend_lists.detect {|f| f.name==flid}
97
+ raise Facebooker::Session::InvalidFriendList unless list
98
+ list.flid
99
+ when FriendList
100
+ flid.flid
101
+ else
102
+ flid
103
+ end
104
+ end
105
+ ##
106
+ # Retrieve friends
107
+ def friends(flid = nil)
108
+ @friends_hash ||= {}
109
+ flid=cast_to_friend_list_id(flid)
110
+
111
+ #use __blank instead of nil so that this is cached
112
+ cache_key = flid||"__blank"
113
+ options = {:uid=>self.id}
114
+ options[:flid] = flid unless flid.nil?
115
+ @friends_hash[cache_key] ||= @session.post('facebook.friends.get', options,false).map do |uid|
116
+ User.new(uid, @session)
117
+ end
118
+ @friends_hash[cache_key]
119
+ end
120
+
121
+ def friend_ids
122
+ options = {:uid => self.id}
123
+ @session.post('facebook.friends.get', options, false)
124
+ end
125
+
126
+ ###
127
+ # Publish a post into the stream on the user's Wall and News Feed. This
128
+ # post also appears in the user's friend's streams. The +publish_stream+
129
+ # extended permission must be granted in order to use this method.
130
+ #
131
+ # See: http://wiki.developers.facebook.com/index.php/Stream.publish
132
+ #
133
+ # +target+ can be the current user or some other user.
134
+ #
135
+ # To publish to a Page on the Page's behave, specify the page id as
136
+ # :uid and set :post_as_page to 'true', use the current user as target
137
+ #
138
+ # Example:
139
+ # # Publish a message to my own wall:
140
+ # me.publish_to(me, :message => 'hello world')
141
+ #
142
+ # # Publish to a friend's wall with an action link:
143
+ # me.publish_to(my_friend, :message => 'how are you?', :action_links => [
144
+ # :text => 'my website',
145
+ # :href => 'http://tenderlovemaking.com/'
146
+ # ])
147
+ def publish_to(target, options = {})
148
+ @session.post('facebook.stream.publish', prepare_publish_to_options(target, options), false)
149
+ end
150
+
151
+ # Prepares options for the stream.publish
152
+ def prepare_publish_to_options(target, options)
153
+ opts = {:uid => self.id,
154
+ :target_id => target.id,
155
+ :message => options[:message]}
156
+
157
+ if a = options[:attachment]
158
+ opts[:attachment] = convert_attachment_to_json(a)
159
+ end
160
+ if (links = options[:action_links] && Facebooker.json_encode(options[:action_links]))
161
+ opts[:action_links] = links
162
+ end
163
+ unless options[:uid].nil?
164
+ opts[:uid] = options[:uid]
165
+ end
166
+ if options[:post_as_page]
167
+ opts.delete(:target_id)
168
+ end
169
+ opts
170
+ end
171
+
172
+ def convert_attachment_to_json(attachment)
173
+ a = attachment.respond_to?(:to_hash) ? attachment.to_hash : attachment
174
+ Facebooker.json_encode(a)
175
+ end
176
+
177
+ ###
178
+ # Publish a comment on a post
179
+ #
180
+ # See: http://wiki.developers.facebook.com/index.php/Stream.addComment
181
+ #
182
+ # +post_id+ the post_id for the post that is being commented on
183
+ # +comment+ the text of the comment
184
+ def comment_on(post_id, comment)
185
+ @session.post('facebook.stream.addComment', {:post_id=>post_id, :comment=>comment})
186
+ end
187
+
188
+
189
+ ###
190
+ # Publish a comment to a specific comment set by xid
191
+ #
192
+ # See: http://wiki.developers.facebook.com/index.php/Comments.add
193
+ #
194
+ # +xid+ the xid for the set of comments
195
+ # +text+ the text of the comment
196
+ def add_comment(xid, text,title=nil,url=nil,publish_to_stream=false)
197
+ @session.post('facebook.comments.add',{:xid=>xid,:text=>text,:title=>title,:url=>url,:publish_to_stream=>publish_to_stream})
198
+ end
199
+
200
+ ###
201
+ # Add a like on a post
202
+ #
203
+ # See: http://wiki.developers.facebook.com/index.php/Stream.addLike
204
+ #
205
+ # +post_id+ the post_id for the post that is being commented on
206
+ def add_like_on(post_id)
207
+ @session.post('facebook.stream.addLike', {:post_id=>post_id})
208
+ end
209
+
210
+ def friend_lists
211
+ @friend_lists ||= @session.post('facebook.friends.getLists').map do |hash|
212
+ friend_list = FriendList.from_hash(hash)
213
+ friend_list.session = session
214
+ friend_list
215
+ end
216
+ end
217
+ ###
218
+ # Retrieve friends with user info populated
219
+ # Subsequent calls will be retrieved from memory.
220
+ # Optional: list of fields to retrieve as symbols
221
+ def friends!(*fields)
222
+ @friends ||= session.post('facebook.users.getInfo', :fields => collect(fields), :uids => friends.map{|f| f.id}.join(',')).map do |hash|
223
+ User.new(hash['uid'], session, hash)
224
+ end
225
+ end
226
+
227
+ ###
228
+ # Retrieve profile data for logged in user
229
+ # Optional: list of fields to retrieve as symbols
230
+ def populate(*fields)
231
+ arguments = {:fields => collect(fields), :uids => id}
232
+ arguments[:locale]=request_locale unless request_locale.nil?
233
+ session.post('facebook.users.getInfo', arguments) do |response|
234
+ populate_from_hash!(response.first)
235
+ end
236
+ end
237
+
238
+ def friends_with?(user_or_id)
239
+ friends.map{|f| f.to_i}.include?(user_or_id.to_i)
240
+ end
241
+
242
+ def friends_with_this_app
243
+ @friends_with_this_app ||= friend_ids_with_this_app.map do |uid|
244
+ User.new(uid, session)
245
+ end
246
+ end
247
+
248
+ def friend_ids_with_this_app
249
+ @friend_ids_with_this_app ||= session.post('facebook.friends.getAppUsers')
250
+ end
251
+
252
+ def groups(gids = [])
253
+ args = gids.empty? ? {} : {:gids => gids}
254
+ @groups ||= session.post('facebook.groups.get', args).map do |hash|
255
+ group = Group.from_hash(hash)
256
+ group.session = session
257
+ group
258
+ end
259
+ end
260
+
261
+ ###
262
+ # Get threads in a folder
263
+ #
264
+ # See: http://wiki.developers.facebook.com/index.php/Message.getThreadsInFolder
265
+ #
266
+ # +options+ possible options are :folder_id, :limit and :offset
267
+ def threads(options = {})
268
+ options ||= {}
269
+ @threads = session.post('facebook.message.getThreadsInFolder', options) do |response|
270
+ response.map do |hash|
271
+ MessageThread.from_hash(hash)
272
+ end
273
+ end
274
+ end
275
+
276
+ def notifications
277
+ @notifications ||= Notifications.from_hash(session.post('facebook.notifications.get'))
278
+ end
279
+
280
+ def publish_story(story)
281
+ publish(story)
282
+ end
283
+
284
+ def publish_action(action)
285
+ publish(action)
286
+ end
287
+
288
+ def publish_templatized_action(action)
289
+ publish(action)
290
+ end
291
+
292
+ def albums
293
+ @albums ||= session.post('facebook.photos.getAlbums', :uid => self.id) do |response|
294
+ response.map do |hash|
295
+ Album.from_hash(hash)
296
+ end
297
+ end
298
+ end
299
+
300
+ ###
301
+ # Retrieve user's facebook stream
302
+ # See http://wiki.developers.facebook.com/index.php/Stream.get for options
303
+ #
304
+
305
+ def stream(options = {})
306
+ @stream = session.post('facebook.stream.get', prepare_get_stream_options(options)) do |response|
307
+ response
308
+ end
309
+ end
310
+
311
+ def create_album(params)
312
+ @album = session.post('facebook.photos.createAlbum', params) {|response| Album.from_hash(response)}
313
+ end
314
+
315
+ def profile_photos
316
+ session.get_photos(nil, nil, profile_pic_album_id)
317
+ end
318
+
319
+ # Upload a photo to the user's profile.
320
+ #
321
+ # In your view, create a multipart form that posts directly to your application (not through canvas):
322
+ #
323
+ # <% form_tag photos_url(:canvas => false), :html => {:multipart => true, :promptpermission => 'photo_upload'} do %>
324
+ # Photo: <%= file_field_tag 'photo' %>
325
+ # Caption: <%= text_area_tag 'caption' %>
326
+ # <%= submit_tag 'Upload Photo', :class => 'inputsubmit' %>
327
+ # <% end %>
328
+ #
329
+ # And in your controller:
330
+ #
331
+ # class PhotosController < ApplicationController
332
+ # def create
333
+ # file = Net::HTTP::MultipartPostFile.new(
334
+ # params[:photo].original_filename,
335
+ # params[:photo].content_type,
336
+ # params[:photo].read
337
+ # )
338
+ #
339
+ # @photo = facebook_session.user.upload_photo(file, :caption => params[:caption])
340
+ # redirect_to photos_url(:canvas => true)
341
+ # end
342
+ # end
343
+ #
344
+ # Options correspond to http://wiki.developers.facebook.com/index.php/Photos.upload
345
+ def upload_photo(multipart_post_file, options = {})
346
+ Photo.from_hash(session.post_file('facebook.photos.upload',
347
+ options.merge(nil => multipart_post_file)))
348
+ end
349
+
350
+ # Upload a video to the user's profile.
351
+ #
352
+ # In your view, create a multipart form that posts directly to your application (not through canvas):
353
+ #
354
+ # <% form_tag videos_url(:canvas => false), :html => {:multipart => true, :promptpermission => 'video_upload'} do %>
355
+ # Video: <%= file_field_tag 'video' %>
356
+ # Title: <%= text_area_tag 'title' %>
357
+ # Description: <%= text_area_tag 'description' %>
358
+ # <%= submit_tag 'Upload Video', :class => 'inputsubmit' %>
359
+ # <% end %>
360
+ #
361
+ # And in your controller:
362
+ #
363
+ # class VideosController < ApplicationController
364
+ # def create
365
+ # file = Net::HTTP::MultipartPostFile.new(
366
+ # params[:photo].original_filename,
367
+ # params[:photo].content_type,
368
+ # params[:photo].read
369
+ # )
370
+ #
371
+ # @video = facebook_session.user.upload_video(file, :description => params[:description])
372
+ # redirect_to videos_url(:canvas => true)
373
+ # end
374
+ # end
375
+ #
376
+ # Options correspond to http://wiki.developers.facebook.com/index.php/Video.upload
377
+ def upload_video(multipart_post_file, options = {})
378
+ Video.from_hash(session.post_file('facebook.video.upload',
379
+ options.merge(nil => multipart_post_file, :base => Facebooker.video_server_base)))
380
+ end
381
+
382
+ def profile_fbml
383
+ session.post('facebook.profile.getFBML', :uid => id)
384
+ end
385
+
386
+ ##
387
+ # Set the profile FBML for this user
388
+ #
389
+ # This does not set profile actions, that should be done with profile_action=
390
+ def profile_fbml=(markup)
391
+ set_profile_fbml(markup, nil, nil, nil)
392
+ end
393
+
394
+ ##
395
+ # Set the mobile profile FBML
396
+ def mobile_fbml=(markup)
397
+ set_profile_fbml(nil, markup, nil,nil)
398
+ end
399
+
400
+ def profile_action=(markup)
401
+ set_profile_fbml(nil, nil, markup,nil)
402
+ end
403
+
404
+ def profile_main=(markup)
405
+ set_profile_fbml(nil,nil,nil,markup)
406
+ end
407
+
408
+ def set_profile_fbml(profile_fbml, mobile_fbml, profile_action_fbml, profile_main = nil)
409
+ parameters = {:uid => id}
410
+ parameters[:profile] = profile_fbml if profile_fbml
411
+ parameters[:profile_action] = profile_action_fbml if profile_action_fbml
412
+ parameters[:mobile_profile] = mobile_fbml if mobile_fbml
413
+ parameters[:profile_main] = profile_main if profile_main
414
+ session.post('facebook.profile.setFBML', parameters,false)
415
+ end
416
+
417
+ ## ** NEW PROFILE DESIGN ***
418
+ # Set a info section for this user
419
+ #
420
+ # Note: using set_profile_info as I feel using user.set_info could be confused with the user.getInfo facebook method.
421
+ # Also, I feel it fits in line with user.set_profile_fbml.
422
+ def set_profile_info(title, info_fields, format = :text)
423
+ session.post('facebook.profile.setInfo', :title => title, :uid => id,
424
+ :type => format.to_s == "text" ? 1 : 5, :info_fields => info_fields.to_json)
425
+ end
426
+
427
+ def get_profile_info
428
+ session.post('facebook.profile.getInfo', :uid => id)
429
+ end
430
+
431
+ ##
432
+ # This DOES NOT set the status of a user on Facebook
433
+ # Use the set_status method instead
434
+ def status=(message)
435
+ case message
436
+ when String,Status
437
+ @status = message
438
+ when Hash
439
+ @status = Status.from_hash(message)
440
+ end
441
+ end
442
+
443
+
444
+ ##
445
+ # Return +limit+ statuses from the user
446
+ def statuses( limit = 50 )
447
+ session.post('facebook.status.get', {:uid => uid, :limit => limit}).collect { |ret| Status.from_hash(ret) }
448
+ end
449
+
450
+ ##
451
+ # Set the status for a user
452
+ # DOES NOT prepend "is" to the message
453
+ #
454
+ # requires extended permission.
455
+ def set_status(message)
456
+ self.status=message
457
+ session.post('facebook.users.setStatus',{:status=>message,:status_includes_verb=>1,:uid => uid}, false) do |ret|
458
+ ret
459
+ end
460
+ end
461
+
462
+ ##
463
+ # Checks to see if the user has enabled the given extended permission
464
+ def has_permission?(ext_perm) # ext_perm = email, offline_access, status_update, photo_upload, create_listing, create_event, rsvp_event, sms
465
+ session.post('facebook.users.hasAppPermission', {:ext_perm=>ext_perm, :uid => uid}, false) == "1"
466
+ end
467
+
468
+ ##
469
+ # Returns whether the user (either the session user or user specified by uid) has authorized the calling application
470
+ def app_user?
471
+ session.post('facebook.users.isAppUser', {:uid => self.id}, use_session_key = true)
472
+ end
473
+
474
+ ##
475
+ # Convenience method to check multiple permissions at once
476
+ def has_permissions?(ext_perms)
477
+ ext_perms.all?{|p| has_permission?(p)}
478
+ end
479
+
480
+ ##
481
+ ## Revoke any extended permission given by a user
482
+ def revoke_permission(ext_perm)
483
+ session.post('facebook.auth.revokeExtendedPermission', { :perm => ext_perm, :uid => uid }, false)
484
+ end
485
+
486
+ ##
487
+ # Convenience method to send email to the current user
488
+ def send_email(subject, text=nil, fbml=nil)
489
+ session.send_email([id], subject, text, fbml)
490
+ end
491
+
492
+ ##
493
+ # Convenience method to set cookie for the current user
494
+ def set_cookie(name, value, expires=nil, path=nil)
495
+ session.data.set_cookie(id, name, value, expires, path)
496
+ end
497
+
498
+ ##
499
+ # Convenience method to get cookies for the current user
500
+ def get_cookies(name=nil)
501
+ session.data.get_cookies(id, name)
502
+ end
503
+
504
+ ##
505
+ # Returns the user's id as an integer
506
+ def to_i
507
+ id
508
+ end
509
+
510
+ def to_s
511
+ id.to_s
512
+ end
513
+
514
+
515
+ ### NEW DASHBOARD API STUFF
516
+
517
+ # facebook_session.user.dashboard_count
518
+ def dashboard_count
519
+ session.post('facebook.dashboard.getCount', :uid => uid)
520
+ end
521
+
522
+ # facebook_session.user.dashboard_count = 5
523
+ def dashboard_count=(new_count)
524
+ session.post('facebook.dashboard.setCount', :uid => uid, :count => new_count)
525
+ end
526
+
527
+ # facebook_session.user.dashboard_increment_count
528
+ def dashboard_increment_count
529
+ session.post('facebook.dashboard.incrementCount', :uid => uid)
530
+ end
531
+
532
+ # facebook_session.user.dashboard_decrement_count
533
+ def dashboard_decrement_count
534
+ session.post('facebook.dashboard.decrementCount', :uid => uid)
535
+ end
536
+
537
+ # The following methods are not bound to a specific user but do relate to Users in general,
538
+ # so I've made them into class methods.
539
+
540
+ # Facebooker::User.dashboard_multi_get_count ['1234', '5678']
541
+ def self.dashboard_multi_get_count(*uids)
542
+ Facebooker::Session.create.post("facebook.dashboard.multiGetCount", :uids => uids.flatten)
543
+ end
544
+
545
+ # Facebooker::User.dashboard_multi_set_count({ '1234' => '11', '5678' => '22' })
546
+ def self.dashboard_multi_set_count(ids)
547
+ Facebooker::Session.create.post("facebook.dashboard.multiSetCount", :ids => ids.to_json)
548
+ end
549
+
550
+ # Facebooker::User.dashboard_multi_increment_count ['1234', '5678']
551
+ def self.dashboard_multi_increment_count(*uids)
552
+ Facebooker::Session.create.post("facebook.dashboard.multiIncrementCount", :uids => uids.flatten.collect{ |uid| uid.to_s }.to_json)
553
+ end
554
+
555
+ # Facebooker::User.dashboard_multi_decrement_count ['1234', '5678']
556
+ def self.dashboard_multi_decrement_count(*uids)
557
+ Facebooker::Session.create.post("facebook.dashboard.multiDecrementCount", :uids => uids.flatten.collect{ |uid| uid.to_s }.to_json)
558
+ end
559
+
560
+
561
+
562
+
563
+ def get_news(*news_ids)
564
+ params = { :uid => uid }
565
+ params[:news_ids] = news_ids.flatten if news_ids
566
+
567
+ session.post('facebook.dashboard.getNews', params)
568
+ end
569
+
570
+ # facebook_session.user.add_news [{ :message => 'Hey, who are you?', :action_link => { :text => "I-I'm a test user", :href => 'http://facebook.er/' }}], 'http://facebook.er/icon.png'
571
+ def add_news(news, image=nil)
572
+ params = { :uid => uid }
573
+ params[:news] = news
574
+ params[:image] = image if image
575
+
576
+ session.post('facebook.dashboard.addNews', params)
577
+ end
578
+
579
+ # facebook_session.user.clear_news ['111111']
580
+ def clear_news(*news_ids)
581
+ params = { :uid => uid }
582
+ params[:news_ids] = news_ids.flatten if news_ids
583
+
584
+ session.post('facebook.dashboard.clearNews', params)
585
+ end
586
+
587
+ # Facebooker::User.multi_add_news(['1234', '4321'], [{ :message => 'Hi users', :action_link => { :text => "Uh hey there app", :href => 'http://facebook.er/' }}], 'http://facebook.er/icon.png')
588
+ def self.multi_add_news(uids, news, image=nil)
589
+ params = { :uids => uids, :news => news }
590
+ params[:image] = image if image
591
+
592
+ Facebooker::Session.create.post("facebook.dashboard.multiAddNews", params)
593
+ end
594
+
595
+ # Facebooker::User.multi_clear_news({"1234"=>["319103117527"], "4321"=>["313954287803"]})
596
+ def self.multi_clear_news(ids)
597
+ Facebooker::Session.create.post("facebook.dashboard.multiClearNews", :ids => ids.to_json)
598
+ end
599
+
600
+ # Facebooker::User.multi_get_news({"1234"=>["319103117527"], "4321"=>["313954287803"]})
601
+ def self.multi_get_news(ids)
602
+ Facebooker::Session.create.post('facebook.dashboard.multiGetNews', :ids => ids.to_json)
603
+ end
604
+
605
+ # facebook_session.user.get_activity '123'
606
+ def get_activity(*activity_ids)
607
+ params = {}
608
+ params[:activity_ids] = activity_ids.flatten if activity_ids
609
+
610
+ session.post('facebook.dashboard.getActivity', params)
611
+ end
612
+
613
+ # facebook_session.user.publish_activity({ :message => '{*actor*} rolled around', :action_link => { :text => 'Roll around too', :href => 'http://facebook.er/' }})
614
+ def publish_activity(activity)
615
+ session.post('facebook.dashboard.publishActivity', { :activity => activity.to_json })
616
+ end
617
+
618
+ # facebook_session.user.remove_activity ['123']
619
+ def remove_activity(*activity_ids)
620
+ session.post('facebook.dashboard.removeActivity', { :activity_ids => activity_ids.flatten })
621
+ end
622
+
623
+
624
+ ##
625
+ # Two Facebooker::User objects should be considered equal if their Facebook ids are equal
626
+ def ==(other_user)
627
+ other_user.is_a?(User) && id == other_user.id
628
+ end
629
+
630
+
631
+ # register a user with Facebook
632
+ # users should be a hast with at least an :email field
633
+ # you can optionally provide an :account_id field as well
634
+
635
+ def self.register(users)
636
+ user_map={}
637
+ users=users.map do |h|
638
+ returning h.dup do |d|
639
+ if email=d.delete(:email)
640
+ hash = hash_email(email)
641
+ user_map[hash]=h
642
+ d[:email_hash]=hash
643
+ end
644
+ end
645
+ end
646
+ Facebooker::Session.create.post("facebook.connect.registerUsers",:accounts=>users.to_json) do |ret|
647
+ ret.each do |hash|
648
+ user_map.delete(hash)
649
+ end
650
+ unless user_map.empty?
651
+ e=Facebooker::Session::UserRegistrationFailed.new
652
+ e.failed_users = user_map.values
653
+ raise e
654
+ end
655
+ ret
656
+ end
657
+ end
658
+
659
+ # Get a count of unconnected friends
660
+ def getUnconnectedFriendsCount
661
+ session.post("facebook.connect.getUnconnectedFriendsCount")
662
+ end
663
+
664
+
665
+ # Unregister an array of email hashes
666
+ def self.unregister(email_hashes)
667
+ Facebooker::Session.create.post("facebook.connect.unregisterUsers",:email_hashes=>email_hashes.to_json) do |ret|
668
+ ret.each do |hash|
669
+ email_hashes.delete(hash)
670
+ end
671
+ unless email_hashes.empty?
672
+ e=Facebooker::Session::UserUnRegistrationFailed.new
673
+ e.failed_users = email_hashes
674
+ raise e
675
+ end
676
+ ret
677
+ end
678
+ end
679
+
680
+ # unregister an array of email addresses
681
+ def self.unregister_emails(emails)
682
+ emails_hash = {}
683
+ emails.each {|e| emails_hash[hash_email(e)] = e}
684
+ begin
685
+ unregister(emails_hash.keys).collect {|r| emails_hash[r]}
686
+ rescue
687
+ # re-raise with emails instead of hashes.
688
+ e = Facebooker::Session::UserUnRegistrationFailed.new
689
+ e.failed_users = $!.failed_users.collect { |f| emails_hash[f] }
690
+ raise e
691
+ end
692
+ end
693
+
694
+ def self.hash_email(email)
695
+ email = email.downcase.strip
696
+ crc=Zlib.crc32(email)
697
+ md5=Digest::MD5.hexdigest(email)
698
+ "#{crc}_#{md5}"
699
+ end
700
+
701
+ def self.cast_to_facebook_id(object)
702
+ if object.respond_to?(:facebook_id)
703
+ object.facebook_id
704
+ else
705
+ object
706
+ end
707
+ end
708
+
709
+ def self.user_fields(fields = [])
710
+ valid_fields(fields)
711
+ end
712
+
713
+ def self.standard_fields(fields = [])
714
+ valid_fields(fields,STANDARD_FIELDS)
715
+ end
716
+
717
+ private
718
+ def publish(feed_story_or_action)
719
+ session.post(Facebooker::Feed::METHODS[feed_story_or_action.class.name.split(/::/).last], feed_story_or_action.to_params) == "1" ? true : false
720
+ end
721
+
722
+ def self.valid_fields(fields, allowable=FIELDS)
723
+ allowable.reject{|field_name| !fields.empty? && !fields.include?(field_name)}.join(',')
724
+ end
725
+
726
+ def collect(fields, allowable=FIELDS)
727
+ allowable.reject{|field_name| !fields.empty? && !fields.include?(field_name)}.join(',')
728
+ end
729
+
730
+ def profile_pic_album_id
731
+ merge_aid(-3, id)
732
+ end
733
+
734
+ def merge_aid(aid, uid)
735
+ (uid << 32) + (aid & 0xFFFFFFFF)
736
+ end
737
+
738
+ def prepare_get_stream_options(options)
739
+ opts = {}
740
+
741
+ opts[:viewer_id] = self.id
742
+ opts[:source_ids] = options[:source_ids] if options[:source_ids]
743
+ opts[:start_time] = options[:start_time].to_i if options[:start_time]
744
+ opts[:end_time] = options[:end_time].to_i if options[:end_time]
745
+ opts[:limit] = options[:limit] if options[:limit].is_a?(Integer)
746
+ opts[:metadata] = Facebooker.json_encode(options[:metadata]) if options[:metadata]
747
+ opts
748
+ end
749
+
750
+ end
751
+ end