jet-facebooker 1.0.64

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 (156) hide show
  1. data/.autotest +15 -0
  2. data/CHANGELOG.rdoc +24 -0
  3. data/COPYING.rdoc +19 -0
  4. data/Manifest.txt +152 -0
  5. data/README.rdoc +119 -0
  6. data/Rakefile +94 -0
  7. data/TODO.rdoc +4 -0
  8. data/examples/desktop_login.rb +14 -0
  9. data/facebooker.gemspec +42 -0
  10. data/generators/facebook/facebook_generator.rb +14 -0
  11. data/generators/facebook/templates/config/facebooker.yml +49 -0
  12. data/generators/facebook/templates/public/javascripts/facebooker.js +332 -0
  13. data/generators/facebook_controller/USAGE +33 -0
  14. data/generators/facebook_controller/facebook_controller_generator.rb +40 -0
  15. data/generators/facebook_controller/templates/controller.rb +7 -0
  16. data/generators/facebook_controller/templates/functional_test.rb +11 -0
  17. data/generators/facebook_controller/templates/helper.rb +2 -0
  18. data/generators/facebook_controller/templates/view.fbml.erb +2 -0
  19. data/generators/facebook_controller/templates/view.html.erb +2 -0
  20. data/generators/facebook_publisher/facebook_publisher_generator.rb +14 -0
  21. data/generators/facebook_publisher/templates/create_facebook_templates.rb +15 -0
  22. data/generators/facebook_publisher/templates/publisher.rb +3 -0
  23. data/generators/facebook_scaffold/USAGE +27 -0
  24. data/generators/facebook_scaffold/facebook_scaffold_generator.rb +118 -0
  25. data/generators/facebook_scaffold/templates/controller.rb +93 -0
  26. data/generators/facebook_scaffold/templates/facebook_style.css +2579 -0
  27. data/generators/facebook_scaffold/templates/functional_test.rb +89 -0
  28. data/generators/facebook_scaffold/templates/helper.rb +2 -0
  29. data/generators/facebook_scaffold/templates/layout.fbml.erb +6 -0
  30. data/generators/facebook_scaffold/templates/layout.html.erb +17 -0
  31. data/generators/facebook_scaffold/templates/style.css +74 -0
  32. data/generators/facebook_scaffold/templates/view_edit.fbml.erb +13 -0
  33. data/generators/facebook_scaffold/templates/view_edit.html.erb +18 -0
  34. data/generators/facebook_scaffold/templates/view_index.fbml.erb +24 -0
  35. data/generators/facebook_scaffold/templates/view_index.html.erb +24 -0
  36. data/generators/facebook_scaffold/templates/view_new.fbml.erb +12 -0
  37. data/generators/facebook_scaffold/templates/view_new.html.erb +17 -0
  38. data/generators/facebook_scaffold/templates/view_show.fbml.erb +10 -0
  39. data/generators/facebook_scaffold/templates/view_show.html.erb +10 -0
  40. data/generators/publisher/publisher_generator.rb +14 -0
  41. data/generators/xd_receiver/templates/xd_receiver.html +10 -0
  42. data/generators/xd_receiver/templates/xd_receiver_ssl.html +10 -0
  43. data/generators/xd_receiver/xd_receiver_generator.rb +10 -0
  44. data/init.rb +26 -0
  45. data/install.rb +12 -0
  46. data/lib/facebooker.rb +261 -0
  47. data/lib/facebooker/adapters/adapter_base.rb +91 -0
  48. data/lib/facebooker/adapters/bebo_adapter.rb +77 -0
  49. data/lib/facebooker/adapters/facebook_adapter.rb +60 -0
  50. data/lib/facebooker/admin.rb +42 -0
  51. data/lib/facebooker/application.rb +37 -0
  52. data/lib/facebooker/attachment.rb +51 -0
  53. data/lib/facebooker/batch_request.rb +45 -0
  54. data/lib/facebooker/data.rb +57 -0
  55. data/lib/facebooker/feed.rb +78 -0
  56. data/lib/facebooker/logging.rb +44 -0
  57. data/lib/facebooker/mobile.rb +20 -0
  58. data/lib/facebooker/mock/service.rb +50 -0
  59. data/lib/facebooker/mock/session.rb +18 -0
  60. data/lib/facebooker/model.rb +139 -0
  61. data/lib/facebooker/models/affiliation.rb +10 -0
  62. data/lib/facebooker/models/album.rb +11 -0
  63. data/lib/facebooker/models/applicationproperties.rb +39 -0
  64. data/lib/facebooker/models/applicationrestrictions.rb +10 -0
  65. data/lib/facebooker/models/comment.rb +9 -0
  66. data/lib/facebooker/models/cookie.rb +10 -0
  67. data/lib/facebooker/models/education_info.rb +11 -0
  68. data/lib/facebooker/models/event.rb +28 -0
  69. data/lib/facebooker/models/family_relative_info.rb +7 -0
  70. data/lib/facebooker/models/friend_list.rb +16 -0
  71. data/lib/facebooker/models/group.rb +36 -0
  72. data/lib/facebooker/models/info_item.rb +10 -0
  73. data/lib/facebooker/models/info_section.rb +10 -0
  74. data/lib/facebooker/models/location.rb +8 -0
  75. data/lib/facebooker/models/message_thread.rb +89 -0
  76. data/lib/facebooker/models/notifications.rb +17 -0
  77. data/lib/facebooker/models/page.rb +46 -0
  78. data/lib/facebooker/models/photo.rb +19 -0
  79. data/lib/facebooker/models/tag.rb +12 -0
  80. data/lib/facebooker/models/user.rb +722 -0
  81. data/lib/facebooker/models/video.rb +9 -0
  82. data/lib/facebooker/models/work_info.rb +10 -0
  83. data/lib/facebooker/parser.rb +951 -0
  84. data/lib/facebooker/rails/backwards_compatible_param_checks.rb +31 -0
  85. data/lib/facebooker/rails/controller.rb +353 -0
  86. data/lib/facebooker/rails/cucumber.rb +28 -0
  87. data/lib/facebooker/rails/cucumber/world.rb +40 -0
  88. data/lib/facebooker/rails/extensions/action_controller.rb +48 -0
  89. data/lib/facebooker/rails/extensions/rack_setup.rb +16 -0
  90. data/lib/facebooker/rails/extensions/routing.rb +15 -0
  91. data/lib/facebooker/rails/facebook_form_builder.rb +141 -0
  92. data/lib/facebooker/rails/facebook_pretty_errors.rb +22 -0
  93. data/lib/facebooker/rails/facebook_request_fix.rb +28 -0
  94. data/lib/facebooker/rails/facebook_request_fix_2-3.rb +31 -0
  95. data/lib/facebooker/rails/facebook_session_handling.rb +68 -0
  96. data/lib/facebooker/rails/facebook_url_helper.rb +192 -0
  97. data/lib/facebooker/rails/facebook_url_rewriting.rb +61 -0
  98. data/lib/facebooker/rails/helpers.rb +835 -0
  99. data/lib/facebooker/rails/helpers/fb_connect.rb +161 -0
  100. data/lib/facebooker/rails/helpers/stream_publish.rb +22 -0
  101. data/lib/facebooker/rails/integration_session.rb +38 -0
  102. data/lib/facebooker/rails/profile_publisher_extensions.rb +42 -0
  103. data/lib/facebooker/rails/publisher.rb +600 -0
  104. data/lib/facebooker/rails/routing.rb +49 -0
  105. data/lib/facebooker/rails/test_helpers.rb +68 -0
  106. data/lib/facebooker/rails/utilities.rb +22 -0
  107. data/lib/facebooker/server_cache.rb +24 -0
  108. data/lib/facebooker/service.rb +103 -0
  109. data/lib/facebooker/service/base_service.rb +19 -0
  110. data/lib/facebooker/service/curl_service.rb +44 -0
  111. data/lib/facebooker/service/net_http_service.rb +12 -0
  112. data/lib/facebooker/service/typhoeus_multi_service.rb +27 -0
  113. data/lib/facebooker/service/typhoeus_service.rb +17 -0
  114. data/lib/facebooker/session.rb +771 -0
  115. data/lib/facebooker/stream_post.rb +19 -0
  116. data/lib/facebooker/version.rb +9 -0
  117. data/lib/net/http_multipart_post.rb +123 -0
  118. data/lib/rack/facebook.rb +89 -0
  119. data/lib/rack/facebook_session.rb +21 -0
  120. data/lib/tasks/facebooker.rake +19 -0
  121. data/lib/tasks/facebooker.rb +2 -0
  122. data/lib/tasks/tunnel.rake +46 -0
  123. data/rails/init.rb +1 -0
  124. data/setup.rb +1585 -0
  125. data/templates/layout.erb +24 -0
  126. data/test/facebooker/adapters_test.rb +191 -0
  127. data/test/facebooker/admin_test.rb +102 -0
  128. data/test/facebooker/application_test.rb +110 -0
  129. data/test/facebooker/attachment_test.rb +72 -0
  130. data/test/facebooker/batch_request_test.rb +83 -0
  131. data/test/facebooker/data_test.rb +86 -0
  132. data/test/facebooker/logging_test.rb +43 -0
  133. data/test/facebooker/mobile_test.rb +45 -0
  134. data/test/facebooker/model_test.rb +133 -0
  135. data/test/facebooker/models/event_test.rb +15 -0
  136. data/test/facebooker/models/page_test.rb +56 -0
  137. data/test/facebooker/models/photo_test.rb +16 -0
  138. data/test/facebooker/models/user_test.rb +1074 -0
  139. data/test/facebooker/rails/facebook_request_fix_2-3_test.rb +25 -0
  140. data/test/facebooker/rails/facebook_url_rewriting_test.rb +76 -0
  141. data/test/facebooker/rails/integration_session_test.rb +13 -0
  142. data/test/facebooker/rails/publisher_test.rb +532 -0
  143. data/test/facebooker/rails_integration_test.rb +1543 -0
  144. data/test/facebooker/server_cache_test.rb +44 -0
  145. data/test/facebooker/service_test.rb +58 -0
  146. data/test/facebooker/session_test.rb +883 -0
  147. data/test/facebooker_test.rb +1175 -0
  148. data/test/fixtures/multipart_post_body_with_only_parameters.txt +33 -0
  149. data/test/fixtures/multipart_post_body_with_single_file.txt +38 -0
  150. data/test/fixtures/multipart_post_body_with_single_file_that_has_nil_key.txt +38 -0
  151. data/test/net/http_multipart_post_test.rb +52 -0
  152. data/test/rack/facebook_session_test.rb +34 -0
  153. data/test/rack/facebook_test.rb +73 -0
  154. data/test/rails_test_helper.rb +36 -0
  155. data/test/test_helper.rb +74 -0
  156. metadata +289 -0
@@ -0,0 +1,11 @@
1
+ module Facebooker
2
+ class EducationInfo
3
+ class HighschoolInfo
4
+ include Model
5
+ attr_accessor :hs1_id, :hs2_id, :grad_year, :hs1_name, :hs2_name
6
+ end
7
+
8
+ include Model
9
+ attr_accessor :concentrations, :name, :year, :degree
10
+ end
11
+ end
@@ -0,0 +1,28 @@
1
+ require 'facebooker/model'
2
+ module Facebooker
3
+ class Event
4
+
5
+ ##
6
+ # The relationship between a Facebook user and an Event to which he or she has been
7
+ # invited and may or may not be attending (based on #rsvp_status)
8
+ class Attendance
9
+ include Model
10
+ attr_accessor :eid, :uid, :rsvp_status
11
+
12
+ ##
13
+ # Get the full, populated Event object which this Attendance is associated with.
14
+ # First access will query the Facebook API (facebook.events.get). Subsequent
15
+ # calls are retrieved from in-memory cache.
16
+ def event
17
+ @event ||= Event.from_hash(session.post('facebook.events.get', :eids => [eid]).first)
18
+ end
19
+
20
+ #TODO: implement user() method
21
+ end
22
+
23
+ include Model
24
+ attr_accessor :pic, :pic_small, :pic_big, :name, :creator, :update_time, :description, :tagline, :venue, :host, :event_type, :nid, :location, :end_time, :start_time, :event_subtype
25
+
26
+ id_is :eid
27
+ end
28
+ end
@@ -0,0 +1,7 @@
1
+ require 'facebooker/model'
2
+ module Facebooker
3
+ class FamilyRelativeInfo
4
+ include Model
5
+ attr_accessor :relationship, :uid, :name, :birthday
6
+ end
7
+ end
@@ -0,0 +1,16 @@
1
+ require 'facebooker/model'
2
+ module Facebooker
3
+ ##
4
+ # A simple representation of a friend list.
5
+ class FriendList
6
+ include Model
7
+ attr_accessor :name
8
+
9
+ id_is :flid
10
+
11
+ # We need this to be an integer, so do the conversion
12
+ def flid=(f)
13
+ @flid= ( f.nil? ? nil : f.to_i)
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,36 @@
1
+ require 'facebooker/model'
2
+ module Facebooker
3
+ class Group
4
+ ##
5
+ # The model of a user's relationship to a group. Users can occupy different positions within a group (e.g. 'owner')
6
+ class Membership
7
+ include Model
8
+ attr_accessor :position, :gid, :uid
9
+ end
10
+ include Model
11
+ attr_accessor :pic, :pic_small, :pic_big, :name, :creator, :recent_news, :update_time, :group_subtype, :group_type, :website, :office, :description, :venue, :nid, :privacy
12
+
13
+ id_is :gid
14
+
15
+ ##
16
+ # Get the full list of members as populated User objects. First time fetches group members via Facebook API call.
17
+ # Subsequent calls return cached values.
18
+ # This is a convenience method for getting all of the Membership instances and instantiating User instances for each Membership.
19
+ def members
20
+ @members ||= memberships.map do |membership|
21
+ User.new(membership.uid, session)
22
+ end
23
+ end
24
+
25
+ ##
26
+ # Get a list of Membership instances associated with this Group. First call retrieves the Membership instances via a Facebook
27
+ # API call. Subsequent calls are retrieved from in-memory cache.
28
+ def memberships
29
+ @memberships ||= session.post('facebook.groups.getMembers', :gid => gid).map do |hash|
30
+ Membership.from_hash(hash) do |membership|
31
+ membership.gid = gid
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,10 @@
1
+ module Facebooker
2
+ class InfoItem
3
+ include Model
4
+ attr_accessor :label, :image, :description, :link, :sublabel
5
+
6
+ def to_json
7
+ {:label => label, :image => image, :description => description, :link => link, :sublabel => sublabel}.to_json
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,10 @@
1
+ module Facebooker
2
+ class InfoSection
3
+ include Model
4
+ attr_accessor :field, :items
5
+
6
+ def to_json
7
+ {:field => field, :items => items}.to_json
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,8 @@
1
+ module Facebooker
2
+ ##
3
+ # Representation of Location used in all places where a Location is specified.
4
+ class Location
5
+ include Model
6
+ attr_accessor :city, :zip, :country, :state
7
+ end
8
+ end
@@ -0,0 +1,89 @@
1
+ require 'facebooker/model'
2
+ module Facebooker
3
+ class MessageThread
4
+ include Model
5
+
6
+ id_is :thread_id
7
+ attr_accessor :subject, :updated_time, :recipients
8
+ attr_accessor :parent_message_id, :parent_thread_id, :message_count
9
+ attr_accessor :snippet, :snippet_author, :object_id, :unread
10
+
11
+ class Message
12
+ include Model
13
+
14
+ attr_accessor :message_id, :author_id, :body, :created_time, :attachment, :thread_id
15
+
16
+ # An attachment can be a photo, a video, or a link
17
+ class Attachment
18
+ include Model
19
+
20
+ attr_accessor :name, :href, :icon, :caption, :description
21
+
22
+ # The Facebook messages API is in beta, this helper method is supposed to fail anytime soon
23
+ def video?
24
+ self.href =~ /\Ahttp:\/\/www\.facebook\.com\/video\/video\.php.*/
25
+ end
26
+
27
+ # The Facebook messages API is in beta, this helper method is supposed to fail anytime soon
28
+ def photo?
29
+ self.href =~ /\Ahttp:\/\/www\.facebook\.com\/photo\.php.*/
30
+ end
31
+
32
+ # The Facebook messages API is in beta, this helper method is supposed to fail anytime soon
33
+ def link?
34
+ !video? && !photo?
35
+ end
36
+ end
37
+ hash_settable_accessor :attachment, Facebooker::MessageThread::Message::Attachment
38
+ end
39
+ hash_settable_list_accessor :messages, Facebooker::MessageThread::Message
40
+
41
+ end
42
+ end
43
+
44
+ # Example of attachments
45
+
46
+ # -- Photo --
47
+
48
+ # <attachment>
49
+ # <media list="true"/>
50
+ # <href>http://www.facebook.com/photo.php?pid=12345&amp;id=54321</href>
51
+ # <properties list="true"/>
52
+ # <icon>http://b.static.ak.fbcdn.net/rsrc.php/zB010/hash/9yvl71tw.gif</icon>
53
+ # <fb_object_type/>
54
+ # <fb_object_id/>
55
+ # <tagged_ids list="true"/>
56
+ # </attachment>
57
+
58
+ # -- Webcam video --
59
+
60
+ # <attachment>
61
+ # <media list="true"/>
62
+ # <name>Feb 10, 2010 1:26pm</name>
63
+ # <href>http://www.facebook.com/video/video.php?v=12345</href>
64
+ # <properties list="true"/>
65
+ # <icon>http://static.ak.fbcdn.net/rsrc.php/zB010/hash/9yvl71tw.gif</icon>
66
+ # <fb_object_type/>
67
+ # <fb_object_id/>
68
+ # <tagged_ids list="true"/>
69
+ # </attachment>
70
+
71
+ # -- Link --
72
+
73
+ # <attachment>
74
+ # <media list="true">
75
+ # <stream_media>
76
+ # <href>http://www.facebook.com/l.php?u=http%253A%252F%252Fwww.google.fr%252F&amp;h=e46dd63cdbfadb74958fbe44e98f339c</href>
77
+ # <type>link</type>
78
+ # <src>http://external.ak.fbcdn.net/safe_image.php?d=dd54bba6b6e6479a89bb8084573c02c8&amp;w=90&amp;h=90&amp;url=http%3A%2F%2Fwww.google.fr%2Fintl%2Ffr_fr%2Fimages%2Flogo.gif</src>
79
+ # </stream_media>
80
+ # </media>
81
+ # <name>Google</name>
82
+ # <href>http://www.facebook.com/l.php?u=http%253A%252F%252Fwww.google.fr%252F&amp;h=e46dd63cdbfadb74958fbe44e98f339c</href>
83
+ # <caption>www.google.fr</caption>
84
+ # <properties list="true"/>
85
+ # <icon>http://b.static.ak.fbcdn.net/rsrc.php/zB010/hash/9yvl71tw.gif</icon>
86
+ # <fb_object_type/>
87
+ # <fb_object_id/>
88
+ # <tagged_ids list="true"/>
89
+ # </attachment>
@@ -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,722 @@
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 :message, :time, :status_id
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
+ def create_album(params)
301
+ @album = session.post('facebook.photos.createAlbum', params) {|response| Album.from_hash(response)}
302
+ end
303
+
304
+ def profile_photos
305
+ session.get_photos(nil, nil, profile_pic_album_id)
306
+ end
307
+
308
+ # Upload a photo to the user's profile.
309
+ #
310
+ # In your view, create a multipart form that posts directly to your application (not through canvas):
311
+ #
312
+ # <% form_tag photos_url(:canvas => false), :html => {:multipart => true, :promptpermission => 'photo_upload'} do %>
313
+ # Photo: <%= file_field_tag 'photo' %>
314
+ # Caption: <%= text_area_tag 'caption' %>
315
+ # <%= submit_tag 'Upload Photo', :class => 'inputsubmit' %>
316
+ # <% end %>
317
+ #
318
+ # And in your controller:
319
+ #
320
+ # class PhotosController < ApplicationController
321
+ # def create
322
+ # file = Net::HTTP::MultipartPostFile.new(
323
+ # params[:photo].original_filename,
324
+ # params[:photo].content_type,
325
+ # params[:photo].read
326
+ # )
327
+ #
328
+ # @photo = facebook_session.user.upload_photo(file, :caption => params[:caption])
329
+ # redirect_to photos_url(:canvas => true)
330
+ # end
331
+ # end
332
+ #
333
+ # Options correspond to http://wiki.developers.facebook.com/index.php/Photos.upload
334
+ def upload_photo(multipart_post_file, options = {})
335
+ Photo.from_hash(session.post_file('facebook.photos.upload',
336
+ options.merge(nil => multipart_post_file)))
337
+ end
338
+
339
+ # Upload a video to the user's profile.
340
+ #
341
+ # In your view, create a multipart form that posts directly to your application (not through canvas):
342
+ #
343
+ # <% form_tag videos_url(:canvas => false), :html => {:multipart => true, :promptpermission => 'video_upload'} do %>
344
+ # Video: <%= file_field_tag 'video' %>
345
+ # Title: <%= text_area_tag 'title' %>
346
+ # Description: <%= text_area_tag 'description' %>
347
+ # <%= submit_tag 'Upload Video', :class => 'inputsubmit' %>
348
+ # <% end %>
349
+ #
350
+ # And in your controller:
351
+ #
352
+ # class VideosController < ApplicationController
353
+ # def create
354
+ # file = Net::HTTP::MultipartPostFile.new(
355
+ # params[:photo].original_filename,
356
+ # params[:photo].content_type,
357
+ # params[:photo].read
358
+ # )
359
+ #
360
+ # @video = facebook_session.user.upload_video(file, :description => params[:description])
361
+ # redirect_to videos_url(:canvas => true)
362
+ # end
363
+ # end
364
+ #
365
+ # Options correspond to http://wiki.developers.facebook.com/index.php/Video.upload
366
+ def upload_video(multipart_post_file, options = {})
367
+ Video.from_hash(session.post_file('facebook.video.upload',
368
+ options.merge(nil => multipart_post_file, :base => Facebooker.video_server_base)))
369
+ end
370
+
371
+ def profile_fbml
372
+ session.post('facebook.profile.getFBML', :uid => id)
373
+ end
374
+
375
+ ##
376
+ # Set the profile FBML for this user
377
+ #
378
+ # This does not set profile actions, that should be done with profile_action=
379
+ def profile_fbml=(markup)
380
+ set_profile_fbml(markup, nil, nil, nil)
381
+ end
382
+
383
+ ##
384
+ # Set the mobile profile FBML
385
+ def mobile_fbml=(markup)
386
+ set_profile_fbml(nil, markup, nil,nil)
387
+ end
388
+
389
+ def profile_action=(markup)
390
+ set_profile_fbml(nil, nil, markup,nil)
391
+ end
392
+
393
+ def profile_main=(markup)
394
+ set_profile_fbml(nil,nil,nil,markup)
395
+ end
396
+
397
+ def set_profile_fbml(profile_fbml, mobile_fbml, profile_action_fbml, profile_main = nil)
398
+ parameters = {:uid => id}
399
+ parameters[:profile] = profile_fbml if profile_fbml
400
+ parameters[:profile_action] = profile_action_fbml if profile_action_fbml
401
+ parameters[:mobile_profile] = mobile_fbml if mobile_fbml
402
+ parameters[:profile_main] = profile_main if profile_main
403
+ session.post('facebook.profile.setFBML', parameters,false)
404
+ end
405
+
406
+ ## ** NEW PROFILE DESIGN ***
407
+ # Set a info section for this user
408
+ #
409
+ # Note: using set_profile_info as I feel using user.set_info could be confused with the user.getInfo facebook method.
410
+ # Also, I feel it fits in line with user.set_profile_fbml.
411
+ def set_profile_info(title, info_fields, format = :text)
412
+ session.post('facebook.profile.setInfo', :title => title, :uid => id,
413
+ :type => format.to_s == "text" ? 1 : 5, :info_fields => info_fields.to_json)
414
+ end
415
+
416
+ def get_profile_info
417
+ session.post('facebook.profile.getInfo', :uid => id)
418
+ end
419
+
420
+ ##
421
+ # This DOES NOT set the status of a user on Facebook
422
+ # Use the set_status method instead
423
+ def status=(message)
424
+ case message
425
+ when String,Status
426
+ @status = message
427
+ when Hash
428
+ @status = Status.from_hash(message)
429
+ end
430
+ end
431
+
432
+
433
+ ##
434
+ # Return +limit+ statuses from the user
435
+ def statuses( limit = 50 )
436
+ session.post('facebook.status.get', {:uid => uid, :limit => limit}).collect { |ret| Status.from_hash(ret) }
437
+ end
438
+
439
+ ##
440
+ # Set the status for a user
441
+ # DOES NOT prepend "is" to the message
442
+ #
443
+ # requires extended permission.
444
+ def set_status(message)
445
+ self.status=message
446
+ session.post('facebook.users.setStatus',{:status=>message,:status_includes_verb=>1,:uid => uid}, false) do |ret|
447
+ ret
448
+ end
449
+ end
450
+
451
+ ##
452
+ # Checks to see if the user has enabled the given extended permission
453
+ def has_permission?(ext_perm) # ext_perm = email, offline_access, status_update, photo_upload, create_listing, create_event, rsvp_event, sms
454
+ session.post('facebook.users.hasAppPermission', {:ext_perm=>ext_perm, :uid => uid}, false) == "1"
455
+ end
456
+
457
+ ##
458
+ # Returns whether the user (either the session user or user specified by uid) has authorized the calling application
459
+ def app_user?
460
+ session.post('facebook.users.isAppUser', {:uid => self.id}, use_session_key = true)
461
+ end
462
+
463
+ ##
464
+ # Convenience method to check multiple permissions at once
465
+ def has_permissions?(ext_perms)
466
+ ext_perms.all?{|p| has_permission?(p)}
467
+ end
468
+
469
+ ##
470
+ # Convenience method to send email to the current user
471
+ def send_email(subject, text=nil, fbml=nil)
472
+ session.send_email([id], subject, text, fbml)
473
+ end
474
+
475
+ ##
476
+ # Convenience method to set cookie for the current user
477
+ def set_cookie(name, value, expires=nil, path=nil)
478
+ session.data.set_cookie(id, name, value, expires, path)
479
+ end
480
+
481
+ ##
482
+ # Convenience method to get cookies for the current user
483
+ def get_cookies(name=nil)
484
+ session.data.get_cookies(id, name)
485
+ end
486
+
487
+ ##
488
+ # Returns the user's id as an integer
489
+ def to_i
490
+ id
491
+ end
492
+
493
+ def to_s
494
+ id.to_s
495
+ end
496
+
497
+
498
+ ### NEW DASHBOARD API STUFF
499
+
500
+ # facebook_session.user.dashboard_count
501
+ def dashboard_count
502
+ session.post('facebook.dashboard.getCount', :uid => uid)
503
+ end
504
+
505
+ # facebook_session.user.dashboard_count = 5
506
+ def dashboard_count=(new_count)
507
+ session.post('facebook.dashboard.setCount', :uid => uid, :count => new_count)
508
+ end
509
+
510
+ # facebook_session.user.dashboard_increment_count
511
+ def dashboard_increment_count
512
+ session.post('facebook.dashboard.incrementCount', :uid => uid)
513
+ end
514
+
515
+ # facebook_session.user.dashboard_decrement_count
516
+ def dashboard_decrement_count
517
+ session.post('facebook.dashboard.decrementCount', :uid => uid)
518
+ end
519
+
520
+ # The following methods are not bound to a specific user but do relate to Users in general,
521
+ # so I've made them into class methods.
522
+
523
+ # Facebooker::User.dashboard_multi_get_count ['1234', '5678']
524
+ def self.dashboard_multi_get_count(*uids)
525
+ Facebooker::Session.create.post("facebook.dashboard.multiGetCount", :uids => uids.flatten)
526
+ end
527
+
528
+ # Facebooker::User.dashboard_multi_set_count({ '1234' => '11', '5678' => '22' })
529
+ def self.dashboard_multi_set_count(ids)
530
+ Facebooker::Session.create.post("facebook.dashboard.multiSetCount", :ids => ids.to_json)
531
+ end
532
+
533
+ # Facebooker::User.dashboard_multi_increment_count ['1234', '5678']
534
+ def self.dashboard_multi_increment_count(*uids)
535
+ Facebooker::Session.create.post("facebook.dashboard.multiIncrementCount", :uids => uids.flatten.collect{ |uid| uid.to_s }.to_json)
536
+ end
537
+
538
+ # Facebooker::User.dashboard_multi_decrement_count ['1234', '5678']
539
+ def self.dashboard_multi_decrement_count(*uids)
540
+ Facebooker::Session.create.post("facebook.dashboard.multiDecrementCount", :uids => uids.flatten.collect{ |uid| uid.to_s }.to_json)
541
+ end
542
+
543
+
544
+
545
+
546
+ def get_news(*news_ids)
547
+ params = { :uid => uid }
548
+ params[:news_ids] = news_ids.flatten if news_ids
549
+
550
+ session.post('facebook.dashboard.getNews', params)
551
+ end
552
+
553
+ # 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'
554
+ def add_news(news, image=nil)
555
+ params = { :uid => uid }
556
+ params[:news] = news
557
+ params[:image] = image if image
558
+
559
+ session.post('facebook.dashboard.addNews', params)
560
+ end
561
+
562
+ # facebook_session.user.clear_news ['111111']
563
+ def clear_news(*news_ids)
564
+ params = { :uid => uid }
565
+ params[:news_ids] = news_ids.flatten if news_ids
566
+
567
+ session.post('facebook.dashboard.clearNews', params)
568
+ end
569
+
570
+ # 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')
571
+ def self.multi_add_news(uids, news, image=nil)
572
+ params = { :uids => uids, :news => news }
573
+ params[:image] = image if image
574
+
575
+ Facebooker::Session.create.post("facebook.dashboard.multiAddNews", params)
576
+ end
577
+
578
+ # Facebooker::User.multi_clear_news({"1234"=>["319103117527"], "4321"=>["313954287803"]})
579
+ def self.multi_clear_news(ids)
580
+ Facebooker::Session.create.post("facebook.dashboard.multiClearNews", :ids => ids.to_json)
581
+ end
582
+
583
+ # Facebooker::User.multi_get_news({"1234"=>["319103117527"], "4321"=>["313954287803"]})
584
+ def self.multi_get_news(ids)
585
+ Facebooker::Session.create.post('facebook.dashboard.multiGetNews', :ids => ids.to_json)
586
+ end
587
+
588
+ # facebook_session.user.get_activity '123'
589
+ def get_activity(*activity_ids)
590
+ params = {}
591
+ params[:activity_ids] = activity_ids.flatten if activity_ids
592
+
593
+ session.post('facebook.dashboard.getActivity', params)
594
+ end
595
+
596
+ # facebook_session.user.publish_activity({ :message => '{*actor*} rolled around', :action_link => { :text => 'Roll around too', :href => 'http://facebook.er/' }})
597
+ def publish_activity(activity)
598
+ session.post('facebook.dashboard.publishActivity', { :activity => activity.to_json })
599
+ end
600
+
601
+ # facebook_session.user.remove_activity ['123']
602
+ def remove_activity(*activity_ids)
603
+ session.post('facebook.dashboard.removeActivity', { :activity_ids => activity_ids.flatten })
604
+ end
605
+
606
+
607
+ ##
608
+ # Two Facebooker::User objects should be considered equal if their Facebook ids are equal
609
+ def ==(other_user)
610
+ other_user.is_a?(User) && id == other_user.id
611
+ end
612
+
613
+
614
+ # register a user with Facebook
615
+ # users should be a hast with at least an :email field
616
+ # you can optionally provide an :account_id field as well
617
+
618
+ def self.register(users)
619
+ user_map={}
620
+ users=users.map do |h|
621
+ returning h.dup do |d|
622
+ if email=d.delete(:email)
623
+ hash = hash_email(email)
624
+ user_map[hash]=h
625
+ d[:email_hash]=hash
626
+ end
627
+ end
628
+ end
629
+ Facebooker::Session.create.post("facebook.connect.registerUsers",:accounts=>users.to_json) do |ret|
630
+ ret.each do |hash|
631
+ user_map.delete(hash)
632
+ end
633
+ unless user_map.empty?
634
+ e=Facebooker::Session::UserRegistrationFailed.new
635
+ e.failed_users = user_map.values
636
+ raise e
637
+ end
638
+ ret
639
+ end
640
+ end
641
+
642
+ # Get a count of unconnected friends
643
+ def getUnconnectedFriendsCount
644
+ session.post("facebook.connect.getUnconnectedFriendsCount")
645
+ end
646
+
647
+
648
+ # Unregister an array of email hashes
649
+ def self.unregister(email_hashes)
650
+ Facebooker::Session.create.post("facebook.connect.unregisterUsers",:email_hashes=>email_hashes.to_json) do |ret|
651
+ ret.each do |hash|
652
+ email_hashes.delete(hash)
653
+ end
654
+ unless email_hashes.empty?
655
+ e=Facebooker::Session::UserUnRegistrationFailed.new
656
+ e.failed_users = email_hashes
657
+ raise e
658
+ end
659
+ ret
660
+ end
661
+ end
662
+
663
+ # unregister an array of email addresses
664
+ def self.unregister_emails(emails)
665
+ emails_hash = {}
666
+ emails.each {|e| emails_hash[hash_email(e)] = e}
667
+ begin
668
+ unregister(emails_hash.keys).collect {|r| emails_hash[r]}
669
+ rescue
670
+ # re-raise with emails instead of hashes.
671
+ e = Facebooker::Session::UserUnRegistrationFailed.new
672
+ e.failed_users = $!.failed_users.collect { |f| emails_hash[f] }
673
+ raise e
674
+ end
675
+ end
676
+
677
+ def self.hash_email(email)
678
+ email = email.downcase.strip
679
+ crc=Zlib.crc32(email)
680
+ md5=Digest::MD5.hexdigest(email)
681
+ "#{crc}_#{md5}"
682
+ end
683
+
684
+ def self.cast_to_facebook_id(object)
685
+ if object.respond_to?(:facebook_id)
686
+ object.facebook_id
687
+ else
688
+ object
689
+ end
690
+ end
691
+
692
+ def self.user_fields(fields = [])
693
+ valid_fields(fields)
694
+ end
695
+
696
+ def self.standard_fields(fields = [])
697
+ valid_fields(fields,STANDARD_FIELDS)
698
+ end
699
+
700
+ private
701
+ def publish(feed_story_or_action)
702
+ session.post(Facebooker::Feed::METHODS[feed_story_or_action.class.name.split(/::/).last], feed_story_or_action.to_params) == "1" ? true : false
703
+ end
704
+
705
+ def self.valid_fields(fields, allowable=FIELDS)
706
+ allowable.reject{|field_name| !fields.empty? && !fields.include?(field_name)}.join(',')
707
+ end
708
+
709
+ def collect(fields, allowable=FIELDS)
710
+ allowable.reject{|field_name| !fields.empty? && !fields.include?(field_name)}.join(',')
711
+ end
712
+
713
+ def profile_pic_album_id
714
+ merge_aid(-3, id)
715
+ end
716
+
717
+ def merge_aid(aid, uid)
718
+ (uid << 32) + (aid & 0xFFFFFFFF)
719
+ end
720
+
721
+ end
722
+ end