djanowski-facebooker 1.0.1

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 (111) hide show
  1. data/CHANGELOG.txt +0 -0
  2. data/COPYING +19 -0
  3. data/History.txt +16 -0
  4. data/Manifest.txt +110 -0
  5. data/README +46 -0
  6. data/README.txt +81 -0
  7. data/Rakefile +76 -0
  8. data/TODO.txt +10 -0
  9. data/generators/facebook/facebook_generator.rb +14 -0
  10. data/generators/facebook/templates/config/facebooker.yml +41 -0
  11. data/generators/facebook/templates/public/javascripts/facebooker.js +106 -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/init.rb +54 -0
  41. data/install.rb +12 -0
  42. data/lib/facebooker/adapters/adapter_base.rb +87 -0
  43. data/lib/facebooker/adapters/bebo_adapter.rb +73 -0
  44. data/lib/facebooker/adapters/facebook_adapter.rb +48 -0
  45. data/lib/facebooker/admin.rb +28 -0
  46. data/lib/facebooker/batch_request.rb +44 -0
  47. data/lib/facebooker/data.rb +57 -0
  48. data/lib/facebooker/feed.rb +78 -0
  49. data/lib/facebooker/logging.rb +51 -0
  50. data/lib/facebooker/model.rb +123 -0
  51. data/lib/facebooker/models/affiliation.rb +10 -0
  52. data/lib/facebooker/models/album.rb +11 -0
  53. data/lib/facebooker/models/applicationproperties.rb +39 -0
  54. data/lib/facebooker/models/cookie.rb +10 -0
  55. data/lib/facebooker/models/education_info.rb +11 -0
  56. data/lib/facebooker/models/event.rb +26 -0
  57. data/lib/facebooker/models/friend_list.rb +14 -0
  58. data/lib/facebooker/models/group.rb +35 -0
  59. data/lib/facebooker/models/info_item.rb +10 -0
  60. data/lib/facebooker/models/info_section.rb +10 -0
  61. data/lib/facebooker/models/location.rb +8 -0
  62. data/lib/facebooker/models/notifications.rb +17 -0
  63. data/lib/facebooker/models/page.rb +27 -0
  64. data/lib/facebooker/models/photo.rb +10 -0
  65. data/lib/facebooker/models/tag.rb +12 -0
  66. data/lib/facebooker/models/user.rb +352 -0
  67. data/lib/facebooker/models/work_info.rb +9 -0
  68. data/lib/facebooker/parser.rb +540 -0
  69. data/lib/facebooker/rails/controller.rb +246 -0
  70. data/lib/facebooker/rails/facebook_asset_path.rb +18 -0
  71. data/lib/facebooker/rails/facebook_form_builder.rb +112 -0
  72. data/lib/facebooker/rails/facebook_pretty_errors.rb +14 -0
  73. data/lib/facebooker/rails/facebook_request_fix.rb +24 -0
  74. data/lib/facebooker/rails/facebook_session_handling.rb +69 -0
  75. data/lib/facebooker/rails/facebook_url_rewriting.rb +39 -0
  76. data/lib/facebooker/rails/helpers.rb +615 -0
  77. data/lib/facebooker/rails/profile_publisher_extensions.rb +42 -0
  78. data/lib/facebooker/rails/publisher.rb +492 -0
  79. data/lib/facebooker/rails/routing.rb +49 -0
  80. data/lib/facebooker/rails/test_helpers.rb +88 -0
  81. data/lib/facebooker/rails/utilities.rb +22 -0
  82. data/lib/facebooker/server_cache.rb +24 -0
  83. data/lib/facebooker/service.rb +31 -0
  84. data/lib/facebooker/session.rb +564 -0
  85. data/lib/facebooker/version.rb +9 -0
  86. data/lib/facebooker.rb +143 -0
  87. data/lib/net/http_multipart_post.rb +123 -0
  88. data/lib/tasks/facebooker.rake +18 -0
  89. data/lib/tasks/tunnel.rake +46 -0
  90. data/rails/init.rb +1 -0
  91. data/setup.rb +1585 -0
  92. data/templates/layout.erb +24 -0
  93. data/test/adapters_test.rb +98 -0
  94. data/test/batch_request_test.rb +82 -0
  95. data/test/event_test.rb +15 -0
  96. data/test/facebook_admin_test.rb +75 -0
  97. data/test/facebook_cache_test.rb +43 -0
  98. data/test/facebook_data_test.rb +84 -0
  99. data/test/facebooker_test.rb +855 -0
  100. data/test/fixtures/multipart_post_body_with_only_parameters.txt +33 -0
  101. data/test/fixtures/multipart_post_body_with_single_file.txt +38 -0
  102. data/test/fixtures/multipart_post_body_with_single_file_that_has_nil_key.txt +38 -0
  103. data/test/http_multipart_post_test.rb +54 -0
  104. data/test/logging_test.rb +43 -0
  105. data/test/model_test.rb +91 -0
  106. data/test/publisher_test.rb +436 -0
  107. data/test/rails_integration_test.rb +1126 -0
  108. data/test/session_test.rb +587 -0
  109. data/test/test_helper.rb +60 -0
  110. data/test/user_test.rb +229 -0
  111. metadata +181 -0
data/lib/facebooker.rb ADDED
@@ -0,0 +1,143 @@
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
+ require 'facebooker/batch_request'
23
+ require 'facebooker/feed'
24
+ require 'facebooker/logging'
25
+ require 'facebooker/model'
26
+ require 'facebooker/parser'
27
+ require 'facebooker/service'
28
+ require 'facebooker/server_cache'
29
+ require 'facebooker/data'
30
+ require 'facebooker/admin'
31
+ require 'facebooker/session'
32
+ require 'facebooker/version'
33
+ require 'facebooker/models/location'
34
+ require 'facebooker/models/affiliation'
35
+ require 'facebooker/models/album'
36
+ require 'facebooker/models/education_info'
37
+ require 'facebooker/models/work_info'
38
+ require 'facebooker/models/event'
39
+ require 'facebooker/models/group'
40
+ require 'facebooker/models/notifications'
41
+ require 'facebooker/models/page'
42
+ require 'facebooker/models/photo'
43
+ require 'facebooker/models/cookie'
44
+ require 'facebooker/models/applicationproperties'
45
+ require 'facebooker/models/tag'
46
+ require 'facebooker/models/user'
47
+ require 'facebooker/models/info_item'
48
+ require 'facebooker/models/info_section'
49
+ require 'facebooker/adapters/adapter_base'
50
+ require 'facebooker/adapters/facebook_adapter'
51
+ require 'facebooker/adapters/bebo_adapter'
52
+ require 'facebooker/models/friend_list'
53
+
54
+ module Facebooker
55
+
56
+ class << self
57
+
58
+ def load_configuration(facebooker_yaml_file)
59
+ if File.exist?(facebooker_yaml_file)
60
+ if defined? RAILS_ENV
61
+ facebooker = YAML.load_file(facebooker_yaml_file)[RAILS_ENV]
62
+ else
63
+ facebooker = YAML.load_file(facebooker_yaml_file)
64
+ end
65
+ ENV['FACEBOOK_API_KEY'] = facebooker['api_key']
66
+ ENV['FACEBOOK_SECRET_KEY'] = facebooker['secret_key']
67
+ ENV['FACEBOOKER_RELATIVE_URL_ROOT'] = facebooker['canvas_page_name']
68
+ ENV['FACEBOOKER_API'] = facebooker['api']
69
+ if Object.const_defined?("ActionController")
70
+ ActionController::Base.asset_host = facebooker['callback_url'] if(ActionController::Base.asset_host.blank?)
71
+ end
72
+ @facebooker_configuration = facebooker
73
+ end
74
+ end
75
+
76
+ def facebooker_config
77
+ @facebooker_configuration
78
+ end
79
+
80
+ def current_adapter=(adapter_class)
81
+ @current_adapter = adapter_class
82
+ end
83
+
84
+ def current_adapter
85
+ @current_adapter || Facebooker::AdapterBase.default_adapter
86
+ end
87
+
88
+ def load_adapter(params)
89
+ self.current_adapter = Facebooker::AdapterBase.load_adapter(params)
90
+ end
91
+
92
+ def facebook_path_prefix=(path)
93
+ current_adapter.facebook_path_prefix = path
94
+ end
95
+
96
+ # Default is canvas_page_name in yml file
97
+ def facebook_path_prefix
98
+ current_adapter.facebook_path_prefix
99
+ end
100
+
101
+ def is_for?(application_container)
102
+ current_adapter.is_for?(application_container)
103
+ end
104
+
105
+
106
+
107
+ [: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|
108
+ define_method(delegated_method){ return current_adapter.send(delegated_method)}
109
+ end
110
+
111
+
112
+ def path_prefix
113
+ @path_prefix
114
+ end
115
+
116
+
117
+ # Set the asset path to the canvas path for just this one request
118
+ # by definition, we will make this a canvas request
119
+ def with_asset_path_for_canvas
120
+ original_asset_host = ActionController::Base.asset_host
121
+ begin
122
+ ActionController::Base.asset_host = Facebooker.api_server_base_url
123
+ request_for_canvas(true) do
124
+ yield
125
+ end
126
+ ensure
127
+ ActionController::Base.asset_host = original_asset_host
128
+ end
129
+ end
130
+
131
+ # If this request is_canvas_request
132
+ # then use the application name as the url root
133
+ def request_for_canvas(is_canvas_request)
134
+ original_path_prefix = @path_prefix
135
+ begin
136
+ @path_prefix = facebook_path_prefix if is_canvas_request
137
+ yield
138
+ ensure
139
+ @path_prefix = original_path_prefix
140
+ end
141
+ end
142
+ end
143
+ end
@@ -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
+ exec @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
+ exec "#{@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')