tenderlove-facebooker 1.0.16.20090319151701

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 (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')