tenderlove-facebooker 1.0.16.20090319151701

Sign up to get free protection for your applications and to get access to all the features.
Files changed (124) hide show
  1. data/CHANGELOG.rdoc +17 -0
  2. data/COPYING.rdoc +19 -0
  3. data/Manifest.txt +123 -0
  4. data/README.rdoc +103 -0
  5. data/Rakefile +86 -0
  6. data/TODO.rdoc +4 -0
  7. data/examples/desktop_login.rb +14 -0
  8. data/facebooker.gemspec +38 -0
  9. data/generators/facebook/facebook_generator.rb +14 -0
  10. data/generators/facebook/templates/config/facebooker.yml +46 -0
  11. data/generators/facebook/templates/public/javascripts/facebooker.js +99 -0
  12. data/generators/facebook_controller/USAGE +33 -0
  13. data/generators/facebook_controller/facebook_controller_generator.rb +40 -0
  14. data/generators/facebook_controller/templates/controller.rb +7 -0
  15. data/generators/facebook_controller/templates/functional_test.rb +11 -0
  16. data/generators/facebook_controller/templates/helper.rb +2 -0
  17. data/generators/facebook_controller/templates/view.fbml.erb +2 -0
  18. data/generators/facebook_controller/templates/view.html.erb +2 -0
  19. data/generators/facebook_publisher/facebook_publisher_generator.rb +14 -0
  20. data/generators/facebook_publisher/templates/create_facebook_templates.rb +15 -0
  21. data/generators/facebook_publisher/templates/publisher.rb +3 -0
  22. data/generators/facebook_scaffold/USAGE +27 -0
  23. data/generators/facebook_scaffold/facebook_scaffold_generator.rb +118 -0
  24. data/generators/facebook_scaffold/templates/controller.rb +93 -0
  25. data/generators/facebook_scaffold/templates/facebook_style.css +2579 -0
  26. data/generators/facebook_scaffold/templates/functional_test.rb +89 -0
  27. data/generators/facebook_scaffold/templates/helper.rb +2 -0
  28. data/generators/facebook_scaffold/templates/layout.fbml.erb +6 -0
  29. data/generators/facebook_scaffold/templates/layout.html.erb +17 -0
  30. data/generators/facebook_scaffold/templates/style.css +74 -0
  31. data/generators/facebook_scaffold/templates/view_edit.fbml.erb +13 -0
  32. data/generators/facebook_scaffold/templates/view_edit.html.erb +18 -0
  33. data/generators/facebook_scaffold/templates/view_index.fbml.erb +24 -0
  34. data/generators/facebook_scaffold/templates/view_index.html.erb +24 -0
  35. data/generators/facebook_scaffold/templates/view_new.fbml.erb +12 -0
  36. data/generators/facebook_scaffold/templates/view_new.html.erb +17 -0
  37. data/generators/facebook_scaffold/templates/view_show.fbml.erb +10 -0
  38. data/generators/facebook_scaffold/templates/view_show.html.erb +10 -0
  39. data/generators/publisher/publisher_generator.rb +14 -0
  40. data/generators/xd_receiver/templates/xd_receiver.html +10 -0
  41. data/generators/xd_receiver/xd_receiver_generator.rb +9 -0
  42. data/init.rb +72 -0
  43. data/install.rb +12 -0
  44. data/lib/facebooker/adapters/adapter_base.rb +87 -0
  45. data/lib/facebooker/adapters/bebo_adapter.rb +75 -0
  46. data/lib/facebooker/adapters/facebook_adapter.rb +52 -0
  47. data/lib/facebooker/admin.rb +42 -0
  48. data/lib/facebooker/batch_request.rb +44 -0
  49. data/lib/facebooker/data.rb +57 -0
  50. data/lib/facebooker/feed.rb +78 -0
  51. data/lib/facebooker/logging.rb +51 -0
  52. data/lib/facebooker/mobile.rb +20 -0
  53. data/lib/facebooker/mock/service.rb +50 -0
  54. data/lib/facebooker/mock/session.rb +18 -0
  55. data/lib/facebooker/model.rb +135 -0
  56. data/lib/facebooker/models/affiliation.rb +10 -0
  57. data/lib/facebooker/models/album.rb +11 -0
  58. data/lib/facebooker/models/applicationproperties.rb +39 -0
  59. data/lib/facebooker/models/applicationrestrictions.rb +10 -0
  60. data/lib/facebooker/models/cookie.rb +10 -0
  61. data/lib/facebooker/models/education_info.rb +11 -0
  62. data/lib/facebooker/models/event.rb +28 -0
  63. data/lib/facebooker/models/friend_list.rb +16 -0
  64. data/lib/facebooker/models/group.rb +36 -0
  65. data/lib/facebooker/models/info_item.rb +10 -0
  66. data/lib/facebooker/models/info_section.rb +10 -0
  67. data/lib/facebooker/models/location.rb +8 -0
  68. data/lib/facebooker/models/notifications.rb +17 -0
  69. data/lib/facebooker/models/page.rb +27 -0
  70. data/lib/facebooker/models/photo.rb +12 -0
  71. data/lib/facebooker/models/tag.rb +12 -0
  72. data/lib/facebooker/models/user.rb +426 -0
  73. data/lib/facebooker/models/video.rb +9 -0
  74. data/lib/facebooker/models/work_info.rb +9 -0
  75. data/lib/facebooker/parser.rb +589 -0
  76. data/lib/facebooker/rails/controller.rb +304 -0
  77. data/lib/facebooker/rails/cucumber/world.rb +46 -0
  78. data/lib/facebooker/rails/cucumber.rb +28 -0
  79. data/lib/facebooker/rails/facebook_form_builder.rb +112 -0
  80. data/lib/facebooker/rails/facebook_pretty_errors.rb +22 -0
  81. data/lib/facebooker/rails/facebook_request_fix.rb +24 -0
  82. data/lib/facebooker/rails/facebook_session_handling.rb +69 -0
  83. data/lib/facebooker/rails/facebook_url_helper.rb +192 -0
  84. data/lib/facebooker/rails/facebook_url_rewriting.rb +39 -0
  85. data/lib/facebooker/rails/helpers/fb_connect.rb +89 -0
  86. data/lib/facebooker/rails/helpers.rb +762 -0
  87. data/lib/facebooker/rails/integration_session.rb +38 -0
  88. data/lib/facebooker/rails/profile_publisher_extensions.rb +42 -0
  89. data/lib/facebooker/rails/publisher.rb +526 -0
  90. data/lib/facebooker/rails/routing.rb +49 -0
  91. data/lib/facebooker/rails/test_helpers.rb +68 -0
  92. data/lib/facebooker/rails/utilities.rb +22 -0
  93. data/lib/facebooker/server_cache.rb +24 -0
  94. data/lib/facebooker/service.rb +94 -0
  95. data/lib/facebooker/session.rb +584 -0
  96. data/lib/facebooker/version.rb +9 -0
  97. data/lib/facebooker.rb +174 -0
  98. data/lib/net/http_multipart_post.rb +123 -0
  99. data/lib/tasks/facebooker.rake +18 -0
  100. data/lib/tasks/tunnel.rake +46 -0
  101. data/rails/init.rb +1 -0
  102. data/setup.rb +1585 -0
  103. data/templates/layout.erb +24 -0
  104. data/test/facebooker/adapters_test.rb +96 -0
  105. data/test/facebooker/admin_test.rb +102 -0
  106. data/test/facebooker/batch_request_test.rb +83 -0
  107. data/test/facebooker/data_test.rb +86 -0
  108. data/test/facebooker/logging_test.rb +43 -0
  109. data/test/facebooker/mobile_test.rb +45 -0
  110. data/test/facebooker/model_test.rb +123 -0
  111. data/test/facebooker/models/event_test.rb +15 -0
  112. data/test/facebooker/models/user_test.rb +295 -0
  113. data/test/facebooker/rails/publisher_test.rb +452 -0
  114. data/test/facebooker/rails_integration_test.rb +1312 -0
  115. data/test/facebooker/server_cache_test.rb +44 -0
  116. data/test/facebooker/session_test.rb +614 -0
  117. data/test/facebooker_test.rb +925 -0
  118. data/test/fixtures/multipart_post_body_with_only_parameters.txt +33 -0
  119. data/test/fixtures/multipart_post_body_with_single_file.txt +38 -0
  120. data/test/fixtures/multipart_post_body_with_single_file_that_has_nil_key.txt +38 -0
  121. data/test/net/http_multipart_post_test.rb +52 -0
  122. data/test/rails_test_helper.rb +11 -0
  123. data/test/test_helper.rb +66 -0
  124. metadata +217 -0
data/lib/facebooker.rb ADDED
@@ -0,0 +1,174 @@
1
+ begin
2
+ unless Object.const_defined?("ActiveSupport") and ActiveSupport.const_defined?("JSON")
3
+ require 'json'
4
+ module Facebooker
5
+ def self.json_decode(str)
6
+ JSON.parse(str)
7
+ end
8
+ end
9
+ else
10
+ module Facebooker
11
+ def self.json_decode(str)
12
+ ActiveSupport::JSON.decode(str)
13
+ end
14
+ end
15
+ end
16
+ rescue
17
+ require 'json'
18
+ end
19
+ require 'zlib'
20
+ require 'digest/md5'
21
+
22
+
23
+
24
+ module Facebooker
25
+
26
+ class << self
27
+
28
+ def load_configuration(facebooker_yaml_file)
29
+ if File.exist?(facebooker_yaml_file)
30
+ if defined? RAILS_ENV
31
+ facebooker = YAML.load_file(facebooker_yaml_file)[RAILS_ENV]
32
+ else
33
+ facebooker = YAML.load_file(facebooker_yaml_file)
34
+ end
35
+ ENV['FACEBOOK_API_KEY'] = facebooker['api_key']
36
+ ENV['FACEBOOK_SECRET_KEY'] = facebooker['secret_key']
37
+ ENV['FACEBOOKER_RELATIVE_URL_ROOT'] = facebooker['canvas_page_name']
38
+ ENV['FACEBOOKER_API'] = facebooker['api']
39
+ if facebooker.has_key?('set_asset_host_to_callback_url')
40
+ Facebooker.set_asset_host_to_callback_url = facebooker['set_asset_host_to_callback_url']
41
+ end
42
+ Facebooker.timeout = facebooker['timeout']
43
+ if Object.const_defined?("ActionController")
44
+ ActionController::Base.asset_host = facebooker['callback_url'] if(ActionController::Base.asset_host.blank?) && Facebooker.set_asset_host_to_callback_url
45
+ end
46
+ @facebooker_configuration = facebooker
47
+ end
48
+ end
49
+
50
+ def facebooker_config
51
+ @facebooker_configuration
52
+ end
53
+
54
+ def current_adapter=(adapter_class)
55
+ @current_adapter = adapter_class
56
+ end
57
+
58
+ def current_adapter
59
+ @current_adapter || Facebooker::AdapterBase.default_adapter
60
+ end
61
+
62
+ def load_adapter(params)
63
+ self.current_adapter = Facebooker::AdapterBase.load_adapter(params)
64
+ end
65
+
66
+ def facebook_path_prefix=(path)
67
+ current_adapter.facebook_path_prefix = path
68
+ end
69
+
70
+ # Default is canvas_page_name in yml file
71
+ def facebook_path_prefix
72
+ current_adapter.facebook_path_prefix
73
+ end
74
+
75
+ def is_for?(application_container)
76
+ current_adapter.is_for?(application_container)
77
+ end
78
+
79
+ def set_asset_host_to_callback_url=(val)
80
+ @set_asset_host_to_callback_url=val
81
+ end
82
+
83
+ def set_asset_host_to_callback_url
84
+ @set_asset_host_to_callback_url.nil? ? true : @set_asset_host_to_callback_url
85
+ end
86
+
87
+ def use_curl=(val)
88
+ @use_curl=val
89
+ end
90
+
91
+ def use_curl?
92
+ @use_curl
93
+ end
94
+
95
+ def timeout=(val)
96
+ @timeout = val.to_i
97
+ end
98
+
99
+ def timeout
100
+ @timeout
101
+ end
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, :video_server_base].each do |delegated_method|
104
+ define_method(delegated_method){ return current_adapter.send(delegated_method)}
105
+ end
106
+
107
+
108
+ def path_prefix
109
+ @path_prefix
110
+ end
111
+
112
+
113
+ # Set the asset path to the canvas path for just this one request
114
+ # by definition, we will make this a canvas request
115
+ def with_asset_path_for_canvas
116
+ original_asset_host = ActionController::Base.asset_host
117
+ begin
118
+ ActionController::Base.asset_host = Facebooker.api_server_base_url
119
+ request_for_canvas(true) do
120
+ yield
121
+ end
122
+ ensure
123
+ ActionController::Base.asset_host = original_asset_host
124
+ end
125
+ end
126
+
127
+ # If this request is_canvas_request
128
+ # then use the application name as the url root
129
+ def request_for_canvas(is_canvas_request)
130
+ original_path_prefix = @path_prefix
131
+ begin
132
+ @path_prefix = facebook_path_prefix if is_canvas_request
133
+ yield
134
+ ensure
135
+ @path_prefix = original_path_prefix
136
+ end
137
+ end
138
+ end
139
+ end
140
+
141
+ require 'facebooker/batch_request'
142
+ require 'facebooker/feed'
143
+ require 'facebooker/logging'
144
+ require 'facebooker/model'
145
+ require 'facebooker/parser'
146
+ require 'facebooker/service'
147
+ require 'facebooker/server_cache'
148
+ require 'facebooker/data'
149
+ require 'facebooker/admin'
150
+ require 'facebooker/mobile'
151
+ require 'facebooker/session'
152
+ require 'facebooker/version'
153
+ require 'facebooker/models/location'
154
+ require 'facebooker/models/affiliation'
155
+ require 'facebooker/models/album'
156
+ require 'facebooker/models/education_info'
157
+ require 'facebooker/models/work_info'
158
+ require 'facebooker/models/event'
159
+ require 'facebooker/models/group'
160
+ require 'facebooker/models/notifications'
161
+ require 'facebooker/models/page'
162
+ require 'facebooker/models/photo'
163
+ require 'facebooker/models/cookie'
164
+ require 'facebooker/models/applicationproperties'
165
+ require 'facebooker/models/applicationrestrictions'
166
+ require 'facebooker/models/tag'
167
+ require 'facebooker/models/user'
168
+ require 'facebooker/models/info_item'
169
+ require 'facebooker/models/info_section'
170
+ require 'facebooker/models/friend_list'
171
+ require 'facebooker/models/video'
172
+ require 'facebooker/adapters/adapter_base'
173
+ require 'facebooker/adapters/facebook_adapter'
174
+ require 'facebooker/adapters/bebo_adapter'
@@ -0,0 +1,123 @@
1
+ require 'net/http'
2
+
3
+ module Net
4
+ class HTTP
5
+ class << self
6
+ def post_multipart_form(url, params)
7
+ MultipartPost.new(url, params).post
8
+ end
9
+ end
10
+
11
+ class MultipartPostFile
12
+ def initialize(filename=nil, content_type=nil, data=nil)
13
+ @filename = filename
14
+ @content_type = content_type
15
+ @data = data
16
+ end
17
+
18
+ attr_accessor :filename
19
+ attr_accessor :content_type
20
+ attr_accessor :data
21
+ end
22
+
23
+ class MultipartPost
24
+ def initialize(url, params)
25
+ @url = url
26
+ @multipart_post_files = extract_file_parameters_from(params)
27
+ @params = extract_non_file_parameters_from(params)
28
+ end
29
+
30
+ def post
31
+ req = Post.new(url.path)
32
+ req.body = body
33
+ req.content_type = content_type
34
+ req.basic_auth url.user, url.password if url.user
35
+ Net::HTTP.new(url.host, url.port).start {|http|
36
+ http.request(req)
37
+ }
38
+ end
39
+
40
+ BOUNDARY = "MichaelNiessnerIsSuperDuperAwesome"
41
+
42
+ protected
43
+ attr_reader :url, :params, :multipart_post_files
44
+
45
+ def extract_file_parameters_from(hash)
46
+ hash.reject{|key, value| !multipart_post_file?(value)}
47
+ end
48
+
49
+ def extract_non_file_parameters_from(hash)
50
+ hash.reject{|key, value| multipart_post_file?(value)}
51
+ end
52
+
53
+ def multipart_post_file?(object)
54
+ object.respond_to?(:content_type) &&
55
+ object.respond_to?(:data) &&
56
+ object.respond_to?(:filename)
57
+ end
58
+
59
+ def content_type
60
+ "multipart/form-data; boundary=#{BOUNDARY}"
61
+ end
62
+
63
+ def body
64
+ encode_parameters + encode_multipart_post_files + final_boundary
65
+ end
66
+
67
+ def encode_multipart_post_files
68
+ return "" if multipart_post_files.empty?
69
+ if multipart_post_files.size == 1
70
+ name = multipart_post_files.keys.first
71
+ file = multipart_post_files.values.first
72
+ encode_multipart_post_file(name, file)
73
+ else
74
+ raise "Currently more than 1 file upload is not supported."
75
+ end
76
+ end
77
+
78
+ def encode_multipart_post_file(name, multipart_post_file)
79
+ parameter_boundary +
80
+ disposition_with_filename(name, multipart_post_file.filename) +
81
+ file_content_type(multipart_post_file.content_type) +
82
+ multipart_post_file.data +
83
+ "\r\n"
84
+ end
85
+
86
+ def encode_parameters
87
+ params.sort_by{|key, value| key.to_s}.map{|key, value| encode_parameter(key, value)}.join
88
+ end
89
+
90
+ def encode_parameter(key, value)
91
+ parameter_boundary + disposition_with_name(key) + value.to_s + "\r\n"
92
+ end
93
+
94
+ def file_content_type(string)
95
+ "Content-Type: #{string}\r\n\r\n"
96
+ end
97
+
98
+ def disposition_with_filename(name, filename)
99
+ if name.nil?
100
+ disposition("filename=\"#{filename}\"")
101
+ else
102
+ disposition("name=\"#{name}\"; filename=\"#{filename}\"")
103
+ end
104
+ end
105
+
106
+ def disposition_with_name(name)
107
+ disposition("name=\"#{name}\"\r\n")
108
+ end
109
+
110
+ def disposition(attribute)
111
+ "Content-Disposition: form-data; #{attribute}\r\n"
112
+ end
113
+
114
+ def parameter_boundary
115
+ "--#{BOUNDARY}\r\n"
116
+ end
117
+
118
+ def final_boundary
119
+ "--#{BOUNDARY}--\r\n"
120
+ end
121
+ end
122
+ end
123
+ end
@@ -0,0 +1,18 @@
1
+ require 'fileutils'
2
+
3
+ namespace :facebooker do
4
+
5
+ desc "Create a basic facebooker.yml configuration file"
6
+ task :setup => :environment do
7
+ facebook_config = File.join(RAILS_ROOT,"config","facebooker.yml")
8
+ unless File.exist?(facebook_config)
9
+ FileUtils.cp File.join(RAILS_ROOT,"vendor", "plugins", "facebooker", "facebooker.yml.tpl"), facebook_config
10
+ puts "Ensure 'GatewayPorts yes' is enabled in the remote development server's sshd config when using any of the facebooker:tunnel:*' rake tasks"
11
+ puts "Configuration created in #{RAILS_ROOT}/config/facebooker.yml"
12
+ else
13
+ puts "#{RAILS_ROOT}/config/facebooker.yml already exists"
14
+ end
15
+ end
16
+
17
+ end
18
+
@@ -0,0 +1,46 @@
1
+ namespace :facebooker do
2
+
3
+ tunnel_ns = namespace :tunnel do
4
+ # Courtesy of Christopher Haupt
5
+ # http://www.BuildingWebApps.com
6
+ # http://www.LearningRails.com
7
+ desc "Create a reverse ssh tunnel from a public server to a private development server."
8
+ task :start => [ :environment, :config ] do
9
+ puts @notification
10
+ system @ssh_command
11
+ end
12
+
13
+ desc "Create a reverse ssh tunnel in the background. Requires ssh keys to be setup."
14
+ task :background_start => [ :environment, :config ] do
15
+ puts @notification
16
+ system "#{@ssh_command} > /dev/null 2>&1 &"
17
+ end
18
+
19
+ # Adapted from Evan Weaver: http://blog.evanweaver.com/articles/2007/07/13/developing-a-facebook-app-locally/
20
+ desc "Check if reverse tunnel is running"
21
+ task :status => [ :environment, :config ] do
22
+ if `ssh #{@public_host} -l #{@public_host_username} netstat -an |
23
+ egrep "tcp.*:#{@public_port}.*LISTEN" | wc`.to_i > 0
24
+ puts "Seems ok"
25
+ else
26
+ puts "Down"
27
+ end
28
+ end
29
+
30
+ task :config => :environment do
31
+ facebook_config = File.dirname(__FILE__) + '/../../../../../config/facebooker.yml'
32
+ FACEBOOKER = YAML.load_file(facebook_config)[RAILS_ENV]
33
+ @public_host_username = FACEBOOKER['tunnel']['public_host_username']
34
+ @public_host = FACEBOOKER['tunnel']['public_host']
35
+ @public_port = FACEBOOKER['tunnel']['public_port']
36
+ @local_port = FACEBOOKER['tunnel']['local_port']
37
+ @ssh_port = FACEBOOKER['tunnel']['ssh_port'] || 22
38
+ @notification = "Starting tunnel #{@public_host}:#{@public_port} to 0.0.0.0:#{@local_port}"
39
+ @notification << " using SSH port #{@ssh_port}" unless @ssh_port == 22
40
+ # "GatewayPorts yes" needs to be enabled in the remote's sshd config
41
+ @ssh_command = "ssh -v -p #{@ssh_port} -nNT4 -R *:#{@public_port}:localhost:#{@local_port} #{@public_host_username}@#{@public_host}"
42
+ end
43
+ end
44
+ desc "Create a reverse ssh tunnel from a public server to a private development server."
45
+ task :tunnel => tunnel_ns[:start]
46
+ end
data/rails/init.rb ADDED
@@ -0,0 +1 @@
1
+ require File.join(File.dirname(__FILE__),'../init.rb')