facebooker 1.0.13 → 1.0.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Manifest.txt +29 -16
- data/Rakefile +9 -2
- data/generators/facebook/templates/public/javascripts/facebooker.js +1 -8
- data/init.rb +3 -1
- data/lib/facebooker.rb +4 -2
- data/lib/facebooker/adapters/facebook_adapter.rb +4 -0
- data/lib/facebooker/admin.rb +2 -2
- data/lib/facebooker/mobile.rb +20 -0
- data/lib/facebooker/mock/service.rb +50 -0
- data/lib/facebooker/mock/session.rb +18 -0
- data/lib/facebooker/model.rb +3 -3
- data/lib/facebooker/models/applicationrestrictions.rb +10 -0
- data/lib/facebooker/models/user.rb +35 -3
- data/lib/facebooker/models/user.rb.orig +396 -0
- data/lib/facebooker/models/user.rb.rej +17 -0
- data/lib/facebooker/models/video.rb +9 -0
- data/lib/facebooker/parser.rb +22 -1
- data/lib/facebooker/rails/controller.rb +34 -12
- data/lib/facebooker/rails/cucumber.rb +28 -0
- data/lib/facebooker/rails/cucumber/world.rb +46 -0
- data/lib/facebooker/rails/facebook_pretty_errors.rb +19 -11
- data/lib/facebooker/rails/helpers.rb +203 -122
- data/lib/facebooker/rails/helpers/fb_connect.rb +56 -5
- data/lib/facebooker/rails/integration_session.rb +38 -0
- data/lib/facebooker/rails/publisher.rb +15 -2
- data/lib/facebooker/rails/test_helpers.rb +11 -26
- data/lib/facebooker/service.rb +6 -3
- data/lib/facebooker/session.rb +24 -2
- data/lib/facebooker/session.rb.orig +564 -0
- data/lib/facebooker/session.rb.rej +29 -0
- data/lib/facebooker/version.rb +1 -1
- data/lib/tasks/tunnel.rake +2 -2
- data/test/{adapters_test.rb → facebooker/adapters_test.rb} +2 -4
- data/test/{facebook_admin_test.rb → facebooker/admin_test.rb} +2 -2
- data/test/{batch_request_test.rb → facebooker/batch_request_test.rb} +3 -2
- data/test/{facebook_data_test.rb → facebooker/data_test.rb} +2 -2
- data/test/{logging_test.rb → facebooker/logging_test.rb} +3 -3
- data/test/facebooker/mobile_test.rb +45 -0
- data/test/{model_test.rb → facebooker/model_test.rb} +36 -4
- data/test/{event_test.rb → facebooker/models/event_test.rb} +2 -2
- data/test/{user_test.rb → facebooker/models/user_test.rb} +10 -5
- data/test/{publisher_test.rb → facebooker/rails/publisher_test.rb} +12 -18
- data/test/{rails_integration_test.rb → facebooker/rails_integration_test.rb} +347 -272
- data/test/{facebook_cache_test.rb → facebooker/server_cache_test.rb} +1 -1
- data/test/{session_test.rb → facebooker/session_test.rb} +3 -2
- data/test/facebooker_test.rb +19 -1
- data/test/{http_multipart_post_test.rb → net/http_multipart_post_test.rb} +2 -4
- data/test/rails_test_helper.rb +11 -0
- data/test/test_helper.rb +8 -2
- metadata +45 -32
- data/lib/facebooker/rails/facebook_asset_path.rb +0 -18
data/Manifest.txt
CHANGED
@@ -41,7 +41,6 @@ generators/xd_receiver/xd_receiver_generator.rb
|
|
41
41
|
generators/xd_receiver/templates/xd_receiver.html
|
42
42
|
init.rb
|
43
43
|
install.rb
|
44
|
-
lib/facebooker.rb
|
45
44
|
lib/facebooker/adapters/adapter_base.rb
|
46
45
|
lib/facebooker/adapters/bebo_adapter.rb
|
47
46
|
lib/facebooker/adapters/facebook_adapter.rb
|
@@ -50,10 +49,14 @@ lib/facebooker/batch_request.rb
|
|
50
49
|
lib/facebooker/data.rb
|
51
50
|
lib/facebooker/feed.rb
|
52
51
|
lib/facebooker/logging.rb
|
52
|
+
lib/facebooker/mock/service.rb
|
53
|
+
lib/facebooker/mock/session.rb
|
54
|
+
lib/facebooker/mobile.rb
|
53
55
|
lib/facebooker/model.rb
|
54
56
|
lib/facebooker/models/affiliation.rb
|
55
57
|
lib/facebooker/models/album.rb
|
56
58
|
lib/facebooker/models/applicationproperties.rb
|
59
|
+
lib/facebooker/models/applicationrestrictions.rb
|
57
60
|
lib/facebooker/models/cookie.rb
|
58
61
|
lib/facebooker/models/education_info.rb
|
59
62
|
lib/facebooker/models/event.rb
|
@@ -67,18 +70,23 @@ lib/facebooker/models/page.rb
|
|
67
70
|
lib/facebooker/models/photo.rb
|
68
71
|
lib/facebooker/models/tag.rb
|
69
72
|
lib/facebooker/models/user.rb
|
73
|
+
lib/facebooker/models/user.rb.orig
|
74
|
+
lib/facebooker/models/user.rb.rej
|
75
|
+
lib/facebooker/models/video.rb
|
70
76
|
lib/facebooker/models/work_info.rb
|
71
77
|
lib/facebooker/parser.rb
|
72
78
|
lib/facebooker/rails/controller.rb
|
73
|
-
lib/facebooker/rails/
|
79
|
+
lib/facebooker/rails/cucumber/world.rb
|
80
|
+
lib/facebooker/rails/cucumber.rb
|
74
81
|
lib/facebooker/rails/facebook_form_builder.rb
|
75
82
|
lib/facebooker/rails/facebook_pretty_errors.rb
|
76
83
|
lib/facebooker/rails/facebook_request_fix.rb
|
77
84
|
lib/facebooker/rails/facebook_session_handling.rb
|
78
85
|
lib/facebooker/rails/facebook_url_helper.rb
|
79
86
|
lib/facebooker/rails/facebook_url_rewriting.rb
|
80
|
-
lib/facebooker/rails/helpers.rb
|
81
87
|
lib/facebooker/rails/helpers/fb_connect.rb
|
88
|
+
lib/facebooker/rails/helpers.rb
|
89
|
+
lib/facebooker/rails/integration_session.rb
|
82
90
|
lib/facebooker/rails/profile_publisher_extensions.rb
|
83
91
|
lib/facebooker/rails/publisher.rb
|
84
92
|
lib/facebooker/rails/routing.rb
|
@@ -87,28 +95,33 @@ lib/facebooker/rails/utilities.rb
|
|
87
95
|
lib/facebooker/server_cache.rb
|
88
96
|
lib/facebooker/service.rb
|
89
97
|
lib/facebooker/session.rb
|
98
|
+
lib/facebooker/session.rb.orig
|
99
|
+
lib/facebooker/session.rb.rej
|
90
100
|
lib/facebooker/version.rb
|
101
|
+
lib/facebooker.rb
|
91
102
|
lib/net/http_multipart_post.rb
|
92
103
|
lib/tasks/facebooker.rake
|
93
104
|
lib/tasks/tunnel.rake
|
94
105
|
rails/init.rb
|
95
106
|
setup.rb
|
96
107
|
templates/layout.erb
|
97
|
-
test/adapters_test.rb
|
98
|
-
test/
|
99
|
-
test/
|
100
|
-
test/
|
101
|
-
test/
|
102
|
-
test/
|
108
|
+
test/facebooker/adapters_test.rb
|
109
|
+
test/facebooker/admin_test.rb
|
110
|
+
test/facebooker/batch_request_test.rb
|
111
|
+
test/facebooker/data_test.rb
|
112
|
+
test/facebooker/logging_test.rb
|
113
|
+
test/facebooker/model_test.rb
|
114
|
+
test/facebooker/models/event_test.rb
|
115
|
+
test/facebooker/models/user_test.rb
|
116
|
+
test/facebooker/rails/publisher_test.rb
|
117
|
+
test/facebooker/rails_integration_test.rb
|
118
|
+
test/facebooker/server_cache_test.rb
|
119
|
+
test/facebooker/session_test.rb
|
103
120
|
test/facebooker_test.rb
|
104
121
|
test/fixtures/multipart_post_body_with_only_parameters.txt
|
105
122
|
test/fixtures/multipart_post_body_with_single_file.txt
|
106
123
|
test/fixtures/multipart_post_body_with_single_file_that_has_nil_key.txt
|
107
|
-
test/http_multipart_post_test.rb
|
108
|
-
test/
|
109
|
-
test/model_test.rb
|
110
|
-
test/publisher_test.rb
|
111
|
-
test/rails_integration_test.rb
|
112
|
-
test/session_test.rb
|
124
|
+
test/net/http_multipart_post_test.rb
|
125
|
+
test/rails_test_helper.rb
|
113
126
|
test/test_helper.rb
|
114
|
-
test/
|
127
|
+
test/facebooker/mobile_test.rb
|
data/Rakefile
CHANGED
@@ -3,6 +3,12 @@
|
|
3
3
|
require 'rubygems'
|
4
4
|
ENV['RUBY_FLAGS']="-I#{%w(lib ext bin test).join(File::PATH_SEPARATOR)}"
|
5
5
|
require 'hoe'
|
6
|
+
begin
|
7
|
+
require 'load_multi_rails_rake_tasks'
|
8
|
+
rescue LoadError
|
9
|
+
$stderr.puts "Install the multi_rails gem to run tests against multiple versions of Rails"
|
10
|
+
end
|
11
|
+
|
6
12
|
$: << File.dirname(__FILE__) + '/lib'
|
7
13
|
require './lib/facebooker.rb'
|
8
14
|
|
@@ -15,7 +21,7 @@ Hoe.new('facebooker', Facebooker::VERSION::STRING) do |p|
|
|
15
21
|
p.url = p.paragraphs_of('README.txt', 0).first.split(/\n/)[1..-1]
|
16
22
|
p.changes = p.paragraphs_of('History.txt', 0..1).join("\n\n")
|
17
23
|
p.remote_rdoc_dir = '' # Release to root
|
18
|
-
p.test_globs = 'test
|
24
|
+
p.test_globs = 'test/**/*_test.rb'
|
19
25
|
p.extra_deps << ['json', '>= 1.0.0']
|
20
26
|
end
|
21
27
|
|
@@ -29,9 +35,10 @@ namespace :test do
|
|
29
35
|
desc 'Aggregate code coverage for unit, functional and integration tests'
|
30
36
|
Rcov::RcovTask.new(:coverage) do |t|
|
31
37
|
t.libs << "test"
|
32
|
-
t.test_files = FileList["test
|
38
|
+
t.test_files = FileList["test/**/*_test.rb"]
|
33
39
|
t.output_dir = "coverage/"
|
34
40
|
t.verbose = true
|
41
|
+
t.rcov_opts = ['--exclude', 'test,/usr/lib/ruby,/Library/Ruby,/System/Library', '--sort', 'coverage']
|
35
42
|
end
|
36
43
|
end
|
37
44
|
|
@@ -48,14 +48,7 @@ function encodeURIComponent(str) {
|
|
48
48
|
|
49
49
|
var Form = {};
|
50
50
|
Form.serialize = function(form_element) {
|
51
|
-
|
52
|
-
param_string="";
|
53
|
-
for (var name in elements) {
|
54
|
-
if (param_string)
|
55
|
-
param_string += "&";
|
56
|
-
param_string += encodeURIComponent(name)+"="+encodeURIComponent(elements[name]);
|
57
|
-
}
|
58
|
-
return param_string;
|
51
|
+
return $(form_element).serialize();
|
59
52
|
};
|
60
53
|
|
61
54
|
Ajax.Updater = function (container,url,options) {
|
data/init.rb
CHANGED
@@ -12,7 +12,6 @@ require 'net/http_multipart_post'
|
|
12
12
|
require 'facebooker/rails/controller'
|
13
13
|
require 'facebooker/rails/facebook_url_rewriting'
|
14
14
|
require 'facebooker/rails/facebook_session_handling'
|
15
|
-
require 'facebooker/rails/facebook_asset_path'
|
16
15
|
require 'facebooker/rails/facebook_request_fix'
|
17
16
|
require 'facebooker/rails/routing'
|
18
17
|
require 'facebooker/rails/facebook_pretty_errors' rescue nil
|
@@ -68,3 +67,6 @@ end
|
|
68
67
|
# pull :canvas=> into env in routing to allow for conditions
|
69
68
|
ActionController::Routing::RouteSet.send :include, Facebooker::Rails::Routing::RouteSetExtensions
|
70
69
|
ActionController::Routing::RouteSet::Mapper.send :include, Facebooker::Rails::Routing::MapperExtensions
|
70
|
+
|
71
|
+
Mime::Type.register_alias "text/html", :fbml
|
72
|
+
Mime::Type.register_alias "text/javascript", :fbjs
|
data/lib/facebooker.rb
CHANGED
@@ -100,7 +100,7 @@ module Facebooker
|
|
100
100
|
@timeout
|
101
101
|
end
|
102
102
|
|
103
|
-
[:api_key,:secret_key, :www_server_base_url,:login_url_base,:install_url_base,:api_rest_path,:api_server_base,:api_server_base_url,:canvas_server_base].each do |delegated_method|
|
103
|
+
[:api_key,:secret_key, :www_server_base_url,:login_url_base,:install_url_base,:api_rest_path,:api_server_base,:api_server_base_url,:canvas_server_base, :video_server_base].each do |delegated_method|
|
104
104
|
define_method(delegated_method){ return current_adapter.send(delegated_method)}
|
105
105
|
end
|
106
106
|
|
@@ -147,6 +147,7 @@ require 'facebooker/service'
|
|
147
147
|
require 'facebooker/server_cache'
|
148
148
|
require 'facebooker/data'
|
149
149
|
require 'facebooker/admin'
|
150
|
+
require 'facebooker/mobile'
|
150
151
|
require 'facebooker/session'
|
151
152
|
require 'facebooker/version'
|
152
153
|
require 'facebooker/models/location'
|
@@ -166,7 +167,8 @@ require 'facebooker/models/tag'
|
|
166
167
|
require 'facebooker/models/user'
|
167
168
|
require 'facebooker/models/info_item'
|
168
169
|
require 'facebooker/models/info_section'
|
170
|
+
require 'facebooker/models/friend_list'
|
171
|
+
require 'facebooker/models/video'
|
169
172
|
require 'facebooker/adapters/adapter_base'
|
170
173
|
require 'facebooker/adapters/facebook_adapter'
|
171
174
|
require 'facebooker/adapters/bebo_adapter'
|
172
|
-
require 'facebooker/models/friend_list'
|
data/lib/facebooker/admin.rb
CHANGED
@@ -15,7 +15,7 @@ module Facebooker
|
|
15
15
|
# +properties+: Hash of properties you want to view.
|
16
16
|
def get_app_properties(*properties)
|
17
17
|
json = @session.post('facebook.admin.getAppProperties', :properties => properties.to_json)
|
18
|
-
hash =
|
18
|
+
hash = Facebooker.json_decode(CGI.unescapeHTML(json))
|
19
19
|
@properties = ApplicationProperties.from_hash(hash)
|
20
20
|
end
|
21
21
|
|
@@ -29,7 +29,7 @@ module Facebooker
|
|
29
29
|
# ** BETA ***
|
30
30
|
def get_restriction_info(*restrictions)
|
31
31
|
json = @session.post('facebook.admin.getRestrictionInfo')
|
32
|
-
hash =
|
32
|
+
hash = Facebooker.json_decode(CGI.unescapeHTML(json))
|
33
33
|
@restrictions = ApplicationRestrictions.from_hash(hash)
|
34
34
|
end
|
35
35
|
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Facebooker
|
2
|
+
class Mobile
|
3
|
+
def initialize(session)
|
4
|
+
@session = session
|
5
|
+
end
|
6
|
+
|
7
|
+
# Used to determine whether the user identified by "uid" has enabled SMS for this application.
|
8
|
+
def can_send(user)
|
9
|
+
@session.post('facebook.sms.canSend', :uid => User.cast_to_facebook_id(user))
|
10
|
+
end
|
11
|
+
|
12
|
+
# Send the given message to the user.
|
13
|
+
# See http://wiki.developers.facebook.com/index.php/Mobile
|
14
|
+
def send(user, message)
|
15
|
+
@session.post('facebook.sms.send',
|
16
|
+
{:uid => User.cast_to_facebook_id(user),
|
17
|
+
:message => message}, false)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'digest/md5'
|
2
|
+
require 'facebooker/service'
|
3
|
+
|
4
|
+
module Facebooker
|
5
|
+
# A mock service that reads the Facebook response from fixtures
|
6
|
+
# Adapted from http://gist.github.com/44344
|
7
|
+
#
|
8
|
+
# Facebooker::MockService.fixture_path = 'path/to/dir'
|
9
|
+
# Facebooker::Session.current = Facebooker::MockSession.create
|
10
|
+
#
|
11
|
+
class MockService < Service
|
12
|
+
class << self
|
13
|
+
attr_accessor :fixture_path
|
14
|
+
end
|
15
|
+
|
16
|
+
def read_fixture(method, filename, original = nil)
|
17
|
+
path = fixture_path(method, filename)
|
18
|
+
File.read path
|
19
|
+
rescue Errno::ENAMETOOLONG
|
20
|
+
read_fixture(method, hash_fixture_name(filename), filename)
|
21
|
+
rescue Errno::ENOENT => e
|
22
|
+
if File.exists?(fixture_path(method, 'default'))
|
23
|
+
File.read fixture_path(method, 'default')
|
24
|
+
else
|
25
|
+
e.message << "\n(Non-hashed path is #{original})" if original
|
26
|
+
e.message << "\nFacebook API Reference: http://wiki.developers.facebook.com/index.php/#{method.sub(/^facebook\./, '')}#Example_Return_XML"
|
27
|
+
raise e
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def post(params)
|
32
|
+
method = params.delete(:method)
|
33
|
+
params.delete_if {|k,_| [:v, :api_key, :call_id, :sig].include?(k) }
|
34
|
+
Parser.parse(method, read_fixture(method, fixture_name(params)))
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
def fixture_path(method, filename)
|
39
|
+
File.join(self.class.fixture_path, method, "#{filename}.xml")
|
40
|
+
end
|
41
|
+
|
42
|
+
def hash_fixture_name(filename)
|
43
|
+
Digest::MD5.hexdigest(filename)
|
44
|
+
end
|
45
|
+
|
46
|
+
def fixture_name(params)
|
47
|
+
params.map {|*args| args.join('=') }.sort.join('&')
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'facebooker/session'
|
2
|
+
|
3
|
+
module Facebooker
|
4
|
+
class MockSession < Session
|
5
|
+
def secured?
|
6
|
+
true
|
7
|
+
end
|
8
|
+
|
9
|
+
def secure!
|
10
|
+
@uid = 1
|
11
|
+
true
|
12
|
+
end
|
13
|
+
|
14
|
+
def service
|
15
|
+
@service ||= MockService.new(Facebooker.api_server_base, Facebooker.api_rest_path, @api_key)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
data/lib/facebooker/model.rb
CHANGED
@@ -119,10 +119,10 @@ module Facebooker
|
|
119
119
|
##
|
120
120
|
# Set model's attributes via Hash. Keys should map directly to the model's attribute names.
|
121
121
|
def populate_from_hash!(hash)
|
122
|
-
unless hash.empty?
|
122
|
+
unless hash.nil? || hash.empty?
|
123
123
|
hash.each do |key, value|
|
124
124
|
set_attr_method = "#{key}="
|
125
|
-
if respond_to?(set_attr_method)
|
125
|
+
if !value.nil? && respond_to?(set_attr_method)
|
126
126
|
self.__send__(set_attr_method, value)
|
127
127
|
else
|
128
128
|
Facebooker::Logging.log_info("**Warning**, Attempt to set non-attribute: #{key}",hash)
|
@@ -132,4 +132,4 @@ module Facebooker
|
|
132
132
|
end
|
133
133
|
end
|
134
134
|
end
|
135
|
-
end
|
135
|
+
end
|
@@ -10,8 +10,8 @@ module Facebooker
|
|
10
10
|
include Model
|
11
11
|
attr_accessor :message, :time, :status_id
|
12
12
|
end
|
13
|
-
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, :uid, :work_history, :sex, :religion, :notes_count, :activities, :pic_square, :movies, :has_added_app, :education_history, :birthday, :first_name, :meeting_for, :last_name, :interests, :current_location, :pic, :books, :affiliations, :locale, :profile_url, :proxied_email
|
14
|
-
STANDARD_FIELDS = [:uid, :first_name, :last_name, :name, :timezone, :birthday, :sex, :affiliations, :locale, :profile_url]
|
13
|
+
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, :uid, :work_history, :sex, :religion, :notes_count, :activities, :pic_square, :movies, :has_added_app, :education_history, :birthday, :first_name, :meeting_for, :last_name, :interests, :current_location, :pic, :books, :affiliations, :locale, :profile_url, :proxied_email, :email_hashes, :allowed_restrictions]
|
14
|
+
STANDARD_FIELDS = [:uid, :first_name, :last_name, :name, :timezone, :birthday, :sex, :affiliations, :locale, :profile_url, :pic_square]
|
15
15
|
populating_attr_accessor *FIELDS
|
16
16
|
attr_reader :affiliations
|
17
17
|
populating_hash_settable_accessor :current_location, Location
|
@@ -204,6 +204,38 @@ module Facebooker
|
|
204
204
|
options.merge(nil => multipart_post_file)))
|
205
205
|
end
|
206
206
|
|
207
|
+
# Upload a video to the user's profile.
|
208
|
+
#
|
209
|
+
# In your view, create a multipart form that posts directly to your application (not through canvas):
|
210
|
+
#
|
211
|
+
# <% form_tag videos_url(:canvas => false), :html => {:multipart => true, :promptpermission => 'video_upload'} do %>
|
212
|
+
# Video: <%= file_field_tag 'video' %>
|
213
|
+
# Title: <%= text_area_tag 'title' %>
|
214
|
+
# Description: <%= text_area_tag 'description' %>
|
215
|
+
# <%= submit_tag 'Upload Video', :class => 'inputsubmit' %>
|
216
|
+
# <% end %>
|
217
|
+
#
|
218
|
+
# And in your controller:
|
219
|
+
#
|
220
|
+
# class VideosController < ApplicationController
|
221
|
+
# def create
|
222
|
+
# file = Net::HTTP::MultipartPostFile.new(
|
223
|
+
# params[:photo].original_filename,
|
224
|
+
# params[:photo].content_type,
|
225
|
+
# params[:photo].read
|
226
|
+
# )
|
227
|
+
#
|
228
|
+
# @video = facebook_session.user.upload_video(file, :description => params[:description])
|
229
|
+
# redirect_to videos_url(:canvas => true)
|
230
|
+
# end
|
231
|
+
# end
|
232
|
+
#
|
233
|
+
# Options correspond to http://wiki.developers.facebook.com/index.php/Video.upload
|
234
|
+
def upload_video(multipart_post_file, options = {})
|
235
|
+
Video.from_hash(session.post_file('facebook.video.upload',
|
236
|
+
options.merge(nil => multipart_post_file, :base => Facebooker.video_server_base)))
|
237
|
+
end
|
238
|
+
|
207
239
|
def profile_fbml
|
208
240
|
session.post('facebook.profile.getFBML', :uid => id)
|
209
241
|
end
|
@@ -314,7 +346,7 @@ module Facebooker
|
|
314
346
|
##
|
315
347
|
# Two Facebooker::User objects should be considered equal if their Facebook ids are equal
|
316
348
|
def ==(other_user)
|
317
|
-
id == other_user.id
|
349
|
+
other_user.is_a?(User) && id == other_user.id
|
318
350
|
end
|
319
351
|
|
320
352
|
|
@@ -0,0 +1,396 @@
|
|
1
|
+
require 'facebooker/model'
|
2
|
+
require 'facebooker/models/affiliation'
|
3
|
+
require 'facebooker/models/work_info'
|
4
|
+
module Facebooker
|
5
|
+
#
|
6
|
+
# Holds attributes and behavior for a Facebook User
|
7
|
+
class User
|
8
|
+
include Model
|
9
|
+
class Status
|
10
|
+
include Model
|
11
|
+
attr_accessor :message, :time, :status_id
|
12
|
+
end
|
13
|
+
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, :uid, :work_history, :sex, :religion, :notes_count, :activities, :pic_square, :movies, :has_added_app, :education_history, :birthday, :first_name, :meeting_for, :last_name, :interests, :current_location, :pic, :books, :affiliations, :locale, :profile_url, :proxied_email]
|
14
|
+
STANDARD_FIELDS = [:uid, :first_name, :last_name, :name, :timezone, :birthday, :sex, :affiliations, :locale, :profile_url]
|
15
|
+
attr_accessor :id, :session
|
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_accessor :status, Status
|
22
|
+
populating_hash_settable_list_accessor :affiliations, Affiliation
|
23
|
+
populating_hash_settable_list_accessor :education_history, EducationInfo
|
24
|
+
populating_hash_settable_list_accessor :work_history, WorkInfo
|
25
|
+
|
26
|
+
# Can pass in these two forms:
|
27
|
+
# id, session, (optional) attribute_hash
|
28
|
+
# attribute_hash
|
29
|
+
def initialize(*args)
|
30
|
+
if (args.first.kind_of?(String) || args.first.kind_of?(Integer)) && args.size==1
|
31
|
+
@id=Integer(args.shift)
|
32
|
+
@session = Session.current
|
33
|
+
elsif (args.first.kind_of?(String) || args.first.kind_of?(Integer)) && args[1].kind_of?(Session)
|
34
|
+
@id = Integer(args.shift)
|
35
|
+
@session = args.shift
|
36
|
+
end
|
37
|
+
if args.last.kind_of?(Hash)
|
38
|
+
populate_from_hash!(args.pop)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# Returns a user's events, params correspond to API call parameters (except UID):
|
43
|
+
# http://wiki.developers.facebook.com/index.php/Events.get
|
44
|
+
# E.g:
|
45
|
+
# @user.events(:start_time => Time.now, :end_time => 1.month.from_now)
|
46
|
+
# # => Returns events betwen now and a month from now
|
47
|
+
def events(params={})
|
48
|
+
@events ||= {}
|
49
|
+
[:start_time,:end_time].compact.each do |key|
|
50
|
+
params[key] = params[key].to_i
|
51
|
+
end
|
52
|
+
# puts @events[params.to_s].nil?
|
53
|
+
@events[params.to_s] ||= @session.post('facebook.events.get', {:uid => self.id}.merge(params)).map do |event|
|
54
|
+
Event.from_hash(event)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
#
|
59
|
+
# Set the list of friends, given an array of User objects. If the list has been retrieved previously, will not set
|
60
|
+
def friends=(list_of_friends,flid=nil)
|
61
|
+
@friends_hash ||= {}
|
62
|
+
flid=cast_to_friend_list_id(flid)
|
63
|
+
#use __blank instead of nil so that this is cached
|
64
|
+
cache_key = flid||"__blank"
|
65
|
+
|
66
|
+
@friends_hash[cache_key] ||= list_of_friends
|
67
|
+
end
|
68
|
+
|
69
|
+
def cast_to_friend_list_id(flid)
|
70
|
+
case flid
|
71
|
+
when String
|
72
|
+
list=friend_lists.detect {|f| f.name==flid}
|
73
|
+
raise Facebooker::Session::InvalidFriendList unless list
|
74
|
+
list.flid
|
75
|
+
when FriendList
|
76
|
+
flid.flid
|
77
|
+
else
|
78
|
+
flid
|
79
|
+
end
|
80
|
+
end
|
81
|
+
##
|
82
|
+
# Retrieve friends
|
83
|
+
def friends(flid = nil)
|
84
|
+
@friends_hash ||= {}
|
85
|
+
flid=cast_to_friend_list_id(flid)
|
86
|
+
|
87
|
+
#use __blank instead of nil so that this is cached
|
88
|
+
cache_key = flid||"__blank"
|
89
|
+
options = {:uid=>@id}
|
90
|
+
options[:flid] = flid unless flid.nil?
|
91
|
+
@friends_hash[cache_key] ||= @session.post('facebook.friends.get', options,false).map do |uid|
|
92
|
+
User.new(uid, @session)
|
93
|
+
end
|
94
|
+
@friends_hash[cache_key]
|
95
|
+
end
|
96
|
+
|
97
|
+
def friend_lists
|
98
|
+
@friend_lists ||= @session.post('facebook.friends.getLists').map do |hash|
|
99
|
+
friend_list = FriendList.from_hash(hash)
|
100
|
+
friend_list.session = session
|
101
|
+
friend_list
|
102
|
+
end
|
103
|
+
end
|
104
|
+
###
|
105
|
+
# Retrieve friends with user info populated
|
106
|
+
# Subsequent calls will be retrieved from memory.
|
107
|
+
# Optional: list of fields to retrieve as symbols
|
108
|
+
def friends!(*fields)
|
109
|
+
@friends ||= session.post('facebook.users.getInfo', :fields => collect(fields), :uids => friends.map{|f| f.id}.join(',')).map do |hash|
|
110
|
+
User.new(hash['uid'], session, hash)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
###
|
115
|
+
# Retrieve profile data for logged in user
|
116
|
+
# Optional: list of fields to retrieve as symbols
|
117
|
+
def populate(*fields)
|
118
|
+
session.post('facebook.users.getInfo', :fields => collect(fields), :uids => id) do |response|
|
119
|
+
populate_from_hash!(response.first)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def friends_with?(user_or_id)
|
124
|
+
friends.map{|f| f.to_i}.include?(user_or_id.to_i)
|
125
|
+
end
|
126
|
+
|
127
|
+
def friends_with_this_app
|
128
|
+
@friends_with_this_app ||= session.post('facebook.friends.getAppUsers').map do |uid|
|
129
|
+
User.new(uid, session)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
def groups(gids = [])
|
134
|
+
args = gids.empty? ? {} : {:gids => gids}
|
135
|
+
@groups ||= session.post('facebook.groups.get', args).map do |hash|
|
136
|
+
group = Group.from_hash(hash)
|
137
|
+
group.session = session
|
138
|
+
group
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
def notifications
|
143
|
+
@notifications ||= Notifications.from_hash(session.post('facebook.notifications.get'))
|
144
|
+
end
|
145
|
+
|
146
|
+
def publish_story(story)
|
147
|
+
publish(story)
|
148
|
+
end
|
149
|
+
|
150
|
+
def publish_action(action)
|
151
|
+
publish(action)
|
152
|
+
end
|
153
|
+
|
154
|
+
def publish_templatized_action(action)
|
155
|
+
publish(action)
|
156
|
+
end
|
157
|
+
|
158
|
+
def albums
|
159
|
+
@albums ||= session.post('facebook.photos.getAlbums', :uid => self.id) do |response|
|
160
|
+
response.map do |hash|
|
161
|
+
Album.from_hash(hash)
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
def create_album(params)
|
167
|
+
@album = session.post('facebook.photos.createAlbum', params) {|response| Album.from_hash(response)}
|
168
|
+
end
|
169
|
+
|
170
|
+
def profile_photos
|
171
|
+
session.get_photos(nil, nil, profile_pic_album_id)
|
172
|
+
end
|
173
|
+
|
174
|
+
# Upload a photo to the user's profile.
|
175
|
+
#
|
176
|
+
# In your view, create a multipart form that posts directly to your application (not through canvas):
|
177
|
+
#
|
178
|
+
# <% form_tag photos_url(:canvas => false), :html => {:multipart => true, :promptpermission => 'photo_upload'} do %>
|
179
|
+
# Photo: <%= file_field_tag 'photo' %>
|
180
|
+
# Caption: <%= text_area_tag 'caption' %>
|
181
|
+
# <%= submit_tag 'Upload Photo', :class => 'inputsubmit' %>
|
182
|
+
# <% end %>
|
183
|
+
#
|
184
|
+
# And in your controller:
|
185
|
+
#
|
186
|
+
# class PhotosController < ApplicationController
|
187
|
+
# def create
|
188
|
+
# file = Net::HTTP::MultipartPostFile.new(
|
189
|
+
# params[:photo].original_filename,
|
190
|
+
# params[:photo].content_type,
|
191
|
+
# params[:photo].read
|
192
|
+
# )
|
193
|
+
#
|
194
|
+
# @photo = facebook_session.user.upload_photo(file, :caption => params[:caption])
|
195
|
+
# redirect_to photos_url(:canvas => true)
|
196
|
+
# end
|
197
|
+
# end
|
198
|
+
#
|
199
|
+
# Options correspond to http://wiki.developers.facebook.com/index.php/Photos.upload
|
200
|
+
def upload_photo(multipart_post_file, options = {})
|
201
|
+
Photo.from_hash(session.post_file('facebook.photos.upload',
|
202
|
+
options.merge(nil => multipart_post_file)))
|
203
|
+
end
|
204
|
+
|
205
|
+
def profile_fbml
|
206
|
+
session.post('facebook.profile.getFBML', :uid => @id)
|
207
|
+
end
|
208
|
+
|
209
|
+
##
|
210
|
+
# Set the profile FBML for this user
|
211
|
+
#
|
212
|
+
# This does not set profile actions, that should be done with profile_action=
|
213
|
+
def profile_fbml=(markup)
|
214
|
+
set_profile_fbml(markup, nil, nil)
|
215
|
+
end
|
216
|
+
|
217
|
+
##
|
218
|
+
# Set the mobile profile FBML
|
219
|
+
def mobile_fbml=(markup)
|
220
|
+
set_profile_fbml(nil, markup, nil)
|
221
|
+
end
|
222
|
+
|
223
|
+
def profile_action=(markup)
|
224
|
+
set_profile_fbml(nil, nil, markup)
|
225
|
+
end
|
226
|
+
|
227
|
+
def profile_main=(markup)
|
228
|
+
set_profile_fbml(nil,nil,nil,markup)
|
229
|
+
end
|
230
|
+
|
231
|
+
def set_profile_fbml(profile_fbml, mobile_fbml, profile_action_fbml, profile_main = nil)
|
232
|
+
parameters = {:uid => @id}
|
233
|
+
parameters[:profile] = profile_fbml if profile_fbml
|
234
|
+
parameters[:profile_action] = profile_action_fbml if profile_action_fbml
|
235
|
+
parameters[:mobile_profile] = mobile_fbml if mobile_fbml
|
236
|
+
parameters[:profile_main] = profile_main if profile_main
|
237
|
+
session.post('facebook.profile.setFBML', parameters,false)
|
238
|
+
end
|
239
|
+
|
240
|
+
## ** NEW PROFILE DESIGN ***
|
241
|
+
# Set a info section for this user
|
242
|
+
#
|
243
|
+
# Note: using set_profile_info as I feel using user.set_info could be confused with the user.getInfo facebook method.
|
244
|
+
# Also, I feel it fits in line with user.set_profile_fbml.
|
245
|
+
def set_profile_info(title, info_fields, format = :text)
|
246
|
+
session.post('facebook.profile.setInfo', :title => title, :uid => @id,
|
247
|
+
:type => format.to_s == "text" ? 1 : 5, :info_fields => info_fields.to_json)
|
248
|
+
end
|
249
|
+
|
250
|
+
def get_profile_info
|
251
|
+
session.post('facebook.profile.getInfo', :uid => @id)
|
252
|
+
end
|
253
|
+
|
254
|
+
##
|
255
|
+
# This DOES NOT set the status of a user on Facebook
|
256
|
+
# Use the set_status method instead
|
257
|
+
def status=(message)
|
258
|
+
case message
|
259
|
+
when String,Status
|
260
|
+
@status = message
|
261
|
+
when Hash
|
262
|
+
@status = Status.from_hash(message)
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
##
|
267
|
+
# Set the status for a user
|
268
|
+
# DOES NOT prepend "is" to the message
|
269
|
+
#
|
270
|
+
# requires extended permission.
|
271
|
+
def set_status(message)
|
272
|
+
self.status=message
|
273
|
+
session.post('facebook.users.setStatus',:status=>message,:status_includes_verb=>1) do |ret|
|
274
|
+
ret
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
278
|
+
##
|
279
|
+
# Checks to see if the user has enabled the given extended permission
|
280
|
+
def has_permission?(ext_perm) # ext_perm = email, offline_access, status_update, photo_upload, create_listing, create_event, rsvp_event, sms
|
281
|
+
session.post('facebook.users.hasAppPermission',:ext_perm=>ext_perm) == "1"
|
282
|
+
end
|
283
|
+
|
284
|
+
##
|
285
|
+
# Convenience method to send email to the current user
|
286
|
+
def send_email(subject, text=nil, fbml=nil)
|
287
|
+
session.send_email([@id], subject, text, fbml)
|
288
|
+
end
|
289
|
+
|
290
|
+
##
|
291
|
+
# Convenience method to set cookie for the current user
|
292
|
+
def set_cookie(name, value, expires=nil, path=nil)
|
293
|
+
session.data.set_cookie(@id, name, value, expires, path)
|
294
|
+
end
|
295
|
+
|
296
|
+
##
|
297
|
+
# Convenience method to get cookies for the current user
|
298
|
+
def get_cookies(name=nil)
|
299
|
+
session.data.get_cookies(@id, name)
|
300
|
+
end
|
301
|
+
|
302
|
+
##
|
303
|
+
# Returns the user's id as an integer
|
304
|
+
def to_i
|
305
|
+
id
|
306
|
+
end
|
307
|
+
|
308
|
+
def to_s
|
309
|
+
id.to_s
|
310
|
+
end
|
311
|
+
|
312
|
+
##
|
313
|
+
# Two Facebooker::User objects should be considered equal if their Facebook ids are equal
|
314
|
+
def ==(other_user)
|
315
|
+
id == other_user.id
|
316
|
+
end
|
317
|
+
|
318
|
+
|
319
|
+
# register a user with Facebook
|
320
|
+
# users should be a hast with at least an :email field
|
321
|
+
# you can optionally provide an :account_id field as well
|
322
|
+
|
323
|
+
def self.register(users)
|
324
|
+
user_map={}
|
325
|
+
users=users.map do |h|
|
326
|
+
returning h.dup do |d|
|
327
|
+
if email=d.delete(:email)
|
328
|
+
hash = hash_email(email)
|
329
|
+
user_map[hash]=h
|
330
|
+
d[:email_hash]=hash
|
331
|
+
end
|
332
|
+
end
|
333
|
+
end
|
334
|
+
Facebooker::Session.create.post("facebook.connect.registerUsers",:accounts=>users.to_json) do |ret|
|
335
|
+
ret.each do |hash|
|
336
|
+
user_map.delete(hash)
|
337
|
+
end
|
338
|
+
unless user_map.empty?
|
339
|
+
e=Facebooker::Session::UserRegistrationFailed.new
|
340
|
+
e.failed_users = user_map.values
|
341
|
+
raise e
|
342
|
+
end
|
343
|
+
ret
|
344
|
+
end
|
345
|
+
end
|
346
|
+
|
347
|
+
def self.hash_email(email)
|
348
|
+
email = email.downcase.strip
|
349
|
+
crc=Zlib.crc32(email)
|
350
|
+
md5=Digest::MD5.hexdigest(email)
|
351
|
+
"#{crc}_#{md5}"
|
352
|
+
end
|
353
|
+
|
354
|
+
def self.cast_to_facebook_id(object)
|
355
|
+
if object.respond_to?(:facebook_id)
|
356
|
+
object.facebook_id
|
357
|
+
else
|
358
|
+
object
|
359
|
+
end
|
360
|
+
end
|
361
|
+
|
362
|
+
def facebook_id
|
363
|
+
@id
|
364
|
+
end
|
365
|
+
|
366
|
+
def self.user_fields(fields = [])
|
367
|
+
valid_fields(fields)
|
368
|
+
end
|
369
|
+
|
370
|
+
def self.standard_fields(fields = [])
|
371
|
+
valid_fields(fields,STANDARD_FIELDS)
|
372
|
+
end
|
373
|
+
|
374
|
+
private
|
375
|
+
def publish(feed_story_or_action)
|
376
|
+
session.post(Facebooker::Feed::METHODS[feed_story_or_action.class.name.split(/::/).last], feed_story_or_action.to_params) == "1" ? true : false
|
377
|
+
end
|
378
|
+
|
379
|
+
def self.valid_fields(fields, allowable=FIELDS)
|
380
|
+
allowable.reject{|field_name| !fields.empty? && !fields.include?(field_name)}.join(',')
|
381
|
+
end
|
382
|
+
|
383
|
+
def collect(fields, allowable=FIELDS)
|
384
|
+
allowable.reject{|field_name| !fields.empty? && !fields.include?(field_name)}.join(',')
|
385
|
+
end
|
386
|
+
|
387
|
+
def profile_pic_album_id
|
388
|
+
merge_aid(-3, @id)
|
389
|
+
end
|
390
|
+
|
391
|
+
def merge_aid(aid, uid)
|
392
|
+
(uid << 32) + (aid & 0xFFFFFFFF)
|
393
|
+
end
|
394
|
+
|
395
|
+
end
|
396
|
+
end
|