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.
- data/CHANGELOG.rdoc +17 -0
- data/COPYING.rdoc +19 -0
- data/Manifest.txt +123 -0
- data/README.rdoc +103 -0
- data/Rakefile +86 -0
- data/TODO.rdoc +4 -0
- data/examples/desktop_login.rb +14 -0
- data/facebooker.gemspec +38 -0
- data/generators/facebook/facebook_generator.rb +14 -0
- data/generators/facebook/templates/config/facebooker.yml +46 -0
- data/generators/facebook/templates/public/javascripts/facebooker.js +99 -0
- data/generators/facebook_controller/USAGE +33 -0
- data/generators/facebook_controller/facebook_controller_generator.rb +40 -0
- data/generators/facebook_controller/templates/controller.rb +7 -0
- data/generators/facebook_controller/templates/functional_test.rb +11 -0
- data/generators/facebook_controller/templates/helper.rb +2 -0
- data/generators/facebook_controller/templates/view.fbml.erb +2 -0
- data/generators/facebook_controller/templates/view.html.erb +2 -0
- data/generators/facebook_publisher/facebook_publisher_generator.rb +14 -0
- data/generators/facebook_publisher/templates/create_facebook_templates.rb +15 -0
- data/generators/facebook_publisher/templates/publisher.rb +3 -0
- data/generators/facebook_scaffold/USAGE +27 -0
- data/generators/facebook_scaffold/facebook_scaffold_generator.rb +118 -0
- data/generators/facebook_scaffold/templates/controller.rb +93 -0
- data/generators/facebook_scaffold/templates/facebook_style.css +2579 -0
- data/generators/facebook_scaffold/templates/functional_test.rb +89 -0
- data/generators/facebook_scaffold/templates/helper.rb +2 -0
- data/generators/facebook_scaffold/templates/layout.fbml.erb +6 -0
- data/generators/facebook_scaffold/templates/layout.html.erb +17 -0
- data/generators/facebook_scaffold/templates/style.css +74 -0
- data/generators/facebook_scaffold/templates/view_edit.fbml.erb +13 -0
- data/generators/facebook_scaffold/templates/view_edit.html.erb +18 -0
- data/generators/facebook_scaffold/templates/view_index.fbml.erb +24 -0
- data/generators/facebook_scaffold/templates/view_index.html.erb +24 -0
- data/generators/facebook_scaffold/templates/view_new.fbml.erb +12 -0
- data/generators/facebook_scaffold/templates/view_new.html.erb +17 -0
- data/generators/facebook_scaffold/templates/view_show.fbml.erb +10 -0
- data/generators/facebook_scaffold/templates/view_show.html.erb +10 -0
- data/generators/publisher/publisher_generator.rb +14 -0
- data/generators/xd_receiver/templates/xd_receiver.html +10 -0
- data/generators/xd_receiver/xd_receiver_generator.rb +9 -0
- data/init.rb +72 -0
- data/install.rb +12 -0
- data/lib/facebooker/adapters/adapter_base.rb +87 -0
- data/lib/facebooker/adapters/bebo_adapter.rb +75 -0
- data/lib/facebooker/adapters/facebook_adapter.rb +52 -0
- data/lib/facebooker/admin.rb +42 -0
- data/lib/facebooker/batch_request.rb +44 -0
- data/lib/facebooker/data.rb +57 -0
- data/lib/facebooker/feed.rb +78 -0
- data/lib/facebooker/logging.rb +51 -0
- 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 +135 -0
- data/lib/facebooker/models/affiliation.rb +10 -0
- data/lib/facebooker/models/album.rb +11 -0
- data/lib/facebooker/models/applicationproperties.rb +39 -0
- data/lib/facebooker/models/applicationrestrictions.rb +10 -0
- data/lib/facebooker/models/cookie.rb +10 -0
- data/lib/facebooker/models/education_info.rb +11 -0
- data/lib/facebooker/models/event.rb +28 -0
- data/lib/facebooker/models/friend_list.rb +16 -0
- data/lib/facebooker/models/group.rb +36 -0
- data/lib/facebooker/models/info_item.rb +10 -0
- data/lib/facebooker/models/info_section.rb +10 -0
- data/lib/facebooker/models/location.rb +8 -0
- data/lib/facebooker/models/notifications.rb +17 -0
- data/lib/facebooker/models/page.rb +27 -0
- data/lib/facebooker/models/photo.rb +12 -0
- data/lib/facebooker/models/tag.rb +12 -0
- data/lib/facebooker/models/user.rb +426 -0
- data/lib/facebooker/models/video.rb +9 -0
- data/lib/facebooker/models/work_info.rb +9 -0
- data/lib/facebooker/parser.rb +589 -0
- data/lib/facebooker/rails/controller.rb +304 -0
- data/lib/facebooker/rails/cucumber/world.rb +46 -0
- data/lib/facebooker/rails/cucumber.rb +28 -0
- data/lib/facebooker/rails/facebook_form_builder.rb +112 -0
- data/lib/facebooker/rails/facebook_pretty_errors.rb +22 -0
- data/lib/facebooker/rails/facebook_request_fix.rb +24 -0
- data/lib/facebooker/rails/facebook_session_handling.rb +69 -0
- data/lib/facebooker/rails/facebook_url_helper.rb +192 -0
- data/lib/facebooker/rails/facebook_url_rewriting.rb +39 -0
- data/lib/facebooker/rails/helpers/fb_connect.rb +89 -0
- data/lib/facebooker/rails/helpers.rb +762 -0
- data/lib/facebooker/rails/integration_session.rb +38 -0
- data/lib/facebooker/rails/profile_publisher_extensions.rb +42 -0
- data/lib/facebooker/rails/publisher.rb +526 -0
- data/lib/facebooker/rails/routing.rb +49 -0
- data/lib/facebooker/rails/test_helpers.rb +68 -0
- data/lib/facebooker/rails/utilities.rb +22 -0
- data/lib/facebooker/server_cache.rb +24 -0
- data/lib/facebooker/service.rb +94 -0
- data/lib/facebooker/session.rb +584 -0
- data/lib/facebooker/version.rb +9 -0
- data/lib/facebooker.rb +174 -0
- data/lib/net/http_multipart_post.rb +123 -0
- data/lib/tasks/facebooker.rake +18 -0
- data/lib/tasks/tunnel.rake +46 -0
- data/rails/init.rb +1 -0
- data/setup.rb +1585 -0
- data/templates/layout.erb +24 -0
- data/test/facebooker/adapters_test.rb +96 -0
- data/test/facebooker/admin_test.rb +102 -0
- data/test/facebooker/batch_request_test.rb +83 -0
- data/test/facebooker/data_test.rb +86 -0
- data/test/facebooker/logging_test.rb +43 -0
- data/test/facebooker/mobile_test.rb +45 -0
- data/test/facebooker/model_test.rb +123 -0
- data/test/facebooker/models/event_test.rb +15 -0
- data/test/facebooker/models/user_test.rb +295 -0
- data/test/facebooker/rails/publisher_test.rb +452 -0
- data/test/facebooker/rails_integration_test.rb +1312 -0
- data/test/facebooker/server_cache_test.rb +44 -0
- data/test/facebooker/session_test.rb +614 -0
- data/test/facebooker_test.rb +925 -0
- data/test/fixtures/multipart_post_body_with_only_parameters.txt +33 -0
- data/test/fixtures/multipart_post_body_with_single_file.txt +38 -0
- data/test/fixtures/multipart_post_body_with_single_file_that_has_nil_key.txt +38 -0
- data/test/net/http_multipart_post_test.rb +52 -0
- data/test/rails_test_helper.rb +11 -0
- data/test/test_helper.rb +66 -0
- metadata +217 -0
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'action_controller/integration'
|
2
|
+
|
3
|
+
class Facebooker::Rails::IntegrationSession < ActionController::Integration::Session
|
4
|
+
include Facebooker::Rails::TestHelpers
|
5
|
+
attr_accessor :default_request_params, :canvas
|
6
|
+
|
7
|
+
def process(method, path, parameters = nil, headers = nil)
|
8
|
+
if canvas
|
9
|
+
parameters = facebook_params(@default_request_params.merge(parameters || {}))
|
10
|
+
end
|
11
|
+
super method, path, parameters, headers
|
12
|
+
end
|
13
|
+
|
14
|
+
def reset!
|
15
|
+
self.default_request_params = {:fb_sig_in_canvas => '1'}.with_indifferent_access
|
16
|
+
self.canvas = true
|
17
|
+
super
|
18
|
+
end
|
19
|
+
|
20
|
+
def get(path, parameters = nil, headers = nil)
|
21
|
+
if canvas
|
22
|
+
post path, (parameters || {}).merge('fb_sig_request_method' => 'GET'), headers
|
23
|
+
else
|
24
|
+
super path, parameters, headers
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
%w(put delete).each do |method|
|
29
|
+
define_method method do |*args|
|
30
|
+
if canvas
|
31
|
+
path, parameters, headers = *args
|
32
|
+
post path, (parameters || {}).merge('_method' => method.upcase), headers
|
33
|
+
else
|
34
|
+
super *args
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Facebooker
|
2
|
+
module Rails
|
3
|
+
module ProfilePublisherExtensions
|
4
|
+
|
5
|
+
##
|
6
|
+
# returns true if Facebook is requesting the interface for a profile publisher
|
7
|
+
def wants_interface?
|
8
|
+
params[:method] == "publisher_getInterface"
|
9
|
+
end
|
10
|
+
|
11
|
+
##
|
12
|
+
# render the interface for a publisher.
|
13
|
+
# fbml is the content in string form. Use render_to_string to get the content from a template
|
14
|
+
# publish_enabled controlls whether the post form is active by default. If it isn't, you'll need to use fbjs to activate it
|
15
|
+
# comment_enabled controls whether to include a comment box
|
16
|
+
def render_publisher_interface(fbml,publish_enabled=true,comment_enabled=false)
|
17
|
+
render :json=>{:content=>{:fbml=>fbml,:publishEnabled=>publish_enabled,:commentEnabled=>comment_enabled},
|
18
|
+
:method=>"publisher_getInterface"}
|
19
|
+
end
|
20
|
+
|
21
|
+
# render an error while publishing the template
|
22
|
+
# This can be used for validation errors
|
23
|
+
def render_publisher_error(title,body)
|
24
|
+
render :json=>{:errorCode=>1,:errorTitle=>title,:errorMessage=>body}.to_json
|
25
|
+
end
|
26
|
+
|
27
|
+
# render the response for a feed. This takes a user_action object like those returned from the Rails Publisher
|
28
|
+
# For instance, AttackPublisher.create_attack(@attack)
|
29
|
+
# The template must have been registered previously
|
30
|
+
def render_publisher_response(user_action)
|
31
|
+
render :json=>{:content=> {
|
32
|
+
:feed=>{
|
33
|
+
:template_id=>user_action.template_id,
|
34
|
+
:template_data=>user_action.data
|
35
|
+
}
|
36
|
+
},
|
37
|
+
:method=>"publisher_getFeedStory"
|
38
|
+
}
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,526 @@
|
|
1
|
+
module Facebooker
|
2
|
+
module Rails
|
3
|
+
# ActionMailer like module for publishing Facbook messages
|
4
|
+
#
|
5
|
+
# To use, create a subclass and define methods
|
6
|
+
# Each method should start by calling send_as to specify the type of message
|
7
|
+
# Valid options are :email and :notification, :user_action, :profile, :ref
|
8
|
+
#
|
9
|
+
#
|
10
|
+
# Below is an example of each type
|
11
|
+
#
|
12
|
+
# class TestPublisher < Facebooker::Rails::Publisher
|
13
|
+
# # The new message templates are supported as well
|
14
|
+
# # First, create a method that contains your templates:
|
15
|
+
# # You may include multiple one line story templates and short story templates
|
16
|
+
# # but only one full story template
|
17
|
+
# # Your most specific template should be first
|
18
|
+
# #
|
19
|
+
# # Before using, you must register your template by calling register. For this example
|
20
|
+
# # You would call TestPublisher.register_publish_action
|
21
|
+
# # Registering the template will store the template id returned from Facebook in the
|
22
|
+
# # facebook_templates table that is created when you create your first publisher
|
23
|
+
# def publish_action_template
|
24
|
+
# one_line_story_template "{*actor*} did stuff with {*friend*}"
|
25
|
+
# one_line_story_template "{*actor*} did stuff"
|
26
|
+
# short_story_template "{*actor*} has a title {*friend*}", render(:partial=>"short_body")
|
27
|
+
# short_story_template "{*actor*} has a title", render(:partial=>"short_body")
|
28
|
+
# full_story_template "{*actor*} has a title {*friend*}", render(:partial=>"full_body")
|
29
|
+
# action_links action_link("My text {*template_var*}","{*link_url*}")
|
30
|
+
# end
|
31
|
+
#
|
32
|
+
# # To send a registered template, you need to create a method to set the data
|
33
|
+
# # The publisher will look up the template id from the facebook_templates table
|
34
|
+
# def publish_action(f)
|
35
|
+
# send_as :user_action
|
36
|
+
# from f
|
37
|
+
# story_size SHORT # or ONE_LINE or FULL
|
38
|
+
# data :friend=>"Mike"
|
39
|
+
# end
|
40
|
+
#
|
41
|
+
#
|
42
|
+
# # Provide a from user to send a general notification
|
43
|
+
# # if from is nil, this will send an announcement
|
44
|
+
# def notification(to,f)
|
45
|
+
# send_as :notification
|
46
|
+
# recipients to
|
47
|
+
# from f
|
48
|
+
# fbml "Not"
|
49
|
+
# end
|
50
|
+
#
|
51
|
+
# def email(to,f)
|
52
|
+
# send_as :email
|
53
|
+
# recipients to
|
54
|
+
# from f
|
55
|
+
# title "Email"
|
56
|
+
# fbml 'text'
|
57
|
+
# text fbml
|
58
|
+
# end
|
59
|
+
# # This will render the profile in /users/profile.erb
|
60
|
+
# # it will set @user to user_to_update in the template
|
61
|
+
# # The mobile profile will be rendered from the app/views/test_publisher/_mobile.erb
|
62
|
+
# # template
|
63
|
+
# def profile_update(user_to_update,user_with_session_to_use)
|
64
|
+
# send_as :profile
|
65
|
+
# from user_with_session_to_use
|
66
|
+
# to user_to_update
|
67
|
+
# profile render(:action=>"/users/profile",:assigns=>{:user=>user_to_update})
|
68
|
+
# profile_action "A string"
|
69
|
+
# mobile_profile render(:partial=>"mobile",:assigns=>{:user=>user_to_update})
|
70
|
+
# end
|
71
|
+
#
|
72
|
+
# # Update the given handle ref with the content from a
|
73
|
+
# # template
|
74
|
+
# def ref_update(user)
|
75
|
+
# send_as :ref
|
76
|
+
# from user
|
77
|
+
# fbml render(:action=>"/users/profile",:assigns=>{:user=>user_to_update})
|
78
|
+
# handle "a_ref_handle"
|
79
|
+
# end
|
80
|
+
#
|
81
|
+
#
|
82
|
+
# To send a message, use ActionMailer like semantics
|
83
|
+
# TestPublisher.deliver_action(@user)
|
84
|
+
#
|
85
|
+
# For testing, you may want to create an instance of the underlying message without sending it
|
86
|
+
# TestPublisher.create_action(@user)
|
87
|
+
# will create and return an instance of Facebooker::Feeds::Action
|
88
|
+
#
|
89
|
+
# Publisher makes many helpers available, including the linking and asset helpers
|
90
|
+
class Publisher
|
91
|
+
|
92
|
+
#story sizes from the Facebooker API
|
93
|
+
ONE_LINE=1
|
94
|
+
SHORT=2
|
95
|
+
FULL=4
|
96
|
+
|
97
|
+
def initialize
|
98
|
+
@controller = PublisherController.new
|
99
|
+
end
|
100
|
+
|
101
|
+
# use facebook options everywhere
|
102
|
+
def request_comes_from_facebook?
|
103
|
+
true
|
104
|
+
end
|
105
|
+
|
106
|
+
class FacebookTemplate < ::ActiveRecord::Base
|
107
|
+
|
108
|
+
|
109
|
+
cattr_accessor :template_cache
|
110
|
+
self.template_cache = {}
|
111
|
+
|
112
|
+
def self.inspect(*args)
|
113
|
+
"FacebookTemplate"
|
114
|
+
end
|
115
|
+
|
116
|
+
def template_changed?(hash)
|
117
|
+
if respond_to?(:content_hash)
|
118
|
+
content_hash != hash
|
119
|
+
else
|
120
|
+
false
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
class << self
|
125
|
+
|
126
|
+
def register(klass,method)
|
127
|
+
publisher = setup_publisher(klass,method)
|
128
|
+
template_id = Facebooker::Session.create.register_template_bundle(publisher.one_line_story_templates,publisher.short_story_templates,publisher.full_story_template,publisher.action_links)
|
129
|
+
template = find_or_initialize_by_template_name(template_name(klass,method))
|
130
|
+
template.bundle_id = template_id
|
131
|
+
template.content_hash = hashed_content(klass,method) if template.respond_to?(:content_hash)
|
132
|
+
template.save!
|
133
|
+
cache(klass,method,template)
|
134
|
+
template
|
135
|
+
end
|
136
|
+
|
137
|
+
def for_class_and_method(klass,method)
|
138
|
+
find_cached(klass,method)
|
139
|
+
end
|
140
|
+
def bundle_id_for_class_and_method(klass,method)
|
141
|
+
for_class_and_method(klass,method).bundle_id
|
142
|
+
end
|
143
|
+
|
144
|
+
def cache(klass,method,template)
|
145
|
+
template_cache[template_name(klass,method)] = template
|
146
|
+
end
|
147
|
+
|
148
|
+
def clear_cache!
|
149
|
+
self.template_cache = {}
|
150
|
+
end
|
151
|
+
|
152
|
+
def find_cached(klass,method)
|
153
|
+
template_cache[template_name(klass,method)] || find_in_db(klass,method)
|
154
|
+
end
|
155
|
+
|
156
|
+
def find_in_db(klass,method)
|
157
|
+
template = find_by_template_name(template_name(klass,method))
|
158
|
+
if template and template.template_changed?(hashed_content(klass,method))
|
159
|
+
template.destroy
|
160
|
+
template = nil
|
161
|
+
end
|
162
|
+
|
163
|
+
if template.nil?
|
164
|
+
template = register(klass,method)
|
165
|
+
end
|
166
|
+
template
|
167
|
+
end
|
168
|
+
|
169
|
+
def setup_publisher(klass,method)
|
170
|
+
publisher = klass.new
|
171
|
+
publisher.send method + '_template'
|
172
|
+
publisher
|
173
|
+
end
|
174
|
+
|
175
|
+
def hashed_content(klass, method)
|
176
|
+
publisher = setup_publisher(klass,method)
|
177
|
+
# sort the Hash elements (in the short_story and full_story) before generating MD5
|
178
|
+
Digest::MD5.hexdigest [publisher.one_line_story_templates,
|
179
|
+
(publisher.short_story_templates and publisher.short_story_templates.collect{|ss| ss.to_a.sort_by{|e| e[0].to_s}}),
|
180
|
+
(publisher.full_story_template and publisher.full_story_template.to_a.sort_by{|e| e[0].to_s})
|
181
|
+
].to_json
|
182
|
+
end
|
183
|
+
|
184
|
+
def template_name(klass,method)
|
185
|
+
"#{klass.name}::#{method}"
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
class_inheritable_accessor :master_helper_module
|
191
|
+
attr_accessor :one_line_story_templates, :short_story_templates, :action_links
|
192
|
+
|
193
|
+
cattr_accessor :skip_registry
|
194
|
+
self.skip_registry = false
|
195
|
+
|
196
|
+
|
197
|
+
class InvalidSender < StandardError; end
|
198
|
+
class UnknownBodyType < StandardError; end
|
199
|
+
class UnspecifiedBodyType < StandardError; end
|
200
|
+
class Email
|
201
|
+
attr_accessor :title
|
202
|
+
attr_accessor :text
|
203
|
+
attr_accessor :fbml
|
204
|
+
end
|
205
|
+
|
206
|
+
class Notification
|
207
|
+
attr_accessor :fbml
|
208
|
+
end
|
209
|
+
|
210
|
+
class Profile
|
211
|
+
attr_accessor :profile
|
212
|
+
attr_accessor :profile_action
|
213
|
+
attr_accessor :mobile_profile
|
214
|
+
attr_accessor :profile_main
|
215
|
+
end
|
216
|
+
class Ref
|
217
|
+
attr_accessor :handle
|
218
|
+
attr_accessor :fbml
|
219
|
+
end
|
220
|
+
class UserAction
|
221
|
+
attr_accessor :data
|
222
|
+
attr_accessor :target_ids
|
223
|
+
attr_accessor :body_general
|
224
|
+
attr_accessor :template_id
|
225
|
+
attr_accessor :template_name
|
226
|
+
attr_accessor :story_size
|
227
|
+
def target_ids=(val)
|
228
|
+
@target_ids = val.is_a?(Array) ? val.join(",") : val
|
229
|
+
end
|
230
|
+
def data_hash
|
231
|
+
default_data = story_size.nil? ? {} : {:story_size=>story_size}
|
232
|
+
default_data.merge(data||{})
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
cattr_accessor :ignore_errors
|
237
|
+
attr_accessor :_body
|
238
|
+
|
239
|
+
def recipients(*args)
|
240
|
+
if args.size==0
|
241
|
+
@recipients
|
242
|
+
else
|
243
|
+
@recipients=args.first
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
def from(*args)
|
248
|
+
if args.size==0
|
249
|
+
@from
|
250
|
+
else
|
251
|
+
@from=args.first
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
|
256
|
+
def send_as(option)
|
257
|
+
self._body=case option
|
258
|
+
when :action
|
259
|
+
Facebooker::Feed::Action.new
|
260
|
+
when :story
|
261
|
+
Facebooker::Feed::Story.new
|
262
|
+
when :templatized_action
|
263
|
+
Facebooker::Feed::TemplatizedAction.new
|
264
|
+
when :notification
|
265
|
+
Notification.new
|
266
|
+
when :email
|
267
|
+
Email.new
|
268
|
+
when :profile
|
269
|
+
Profile.new
|
270
|
+
when :ref
|
271
|
+
Ref.new
|
272
|
+
when :user_action
|
273
|
+
UserAction.new
|
274
|
+
else
|
275
|
+
raise UnknownBodyType.new("Unknown type to publish")
|
276
|
+
end
|
277
|
+
end
|
278
|
+
|
279
|
+
def full_story_template(title=nil,body=nil,params={})
|
280
|
+
if title.nil?
|
281
|
+
@full_story_template
|
282
|
+
else
|
283
|
+
@full_story_template=params.merge(:template_title=>title, :template_body=>body)
|
284
|
+
end
|
285
|
+
end
|
286
|
+
|
287
|
+
def one_line_story_template(str)
|
288
|
+
@one_line_story_templates ||= []
|
289
|
+
@one_line_story_templates << str
|
290
|
+
end
|
291
|
+
|
292
|
+
def short_story_template(title,body,params={})
|
293
|
+
@short_story_templates ||= []
|
294
|
+
@short_story_templates << params.merge(:template_title=>title, :template_body=>body)
|
295
|
+
end
|
296
|
+
|
297
|
+
def action_links(*links)
|
298
|
+
if links.blank?
|
299
|
+
@action_links
|
300
|
+
else
|
301
|
+
@action_links = links
|
302
|
+
end
|
303
|
+
end
|
304
|
+
|
305
|
+
def method_missing(name,*args)
|
306
|
+
if args.size==1 and self._body.respond_to?("#{name}=")
|
307
|
+
self._body.send("#{name}=",*args)
|
308
|
+
elsif self._body.respond_to?(name)
|
309
|
+
self._body.send(name,*args)
|
310
|
+
else
|
311
|
+
super
|
312
|
+
end
|
313
|
+
end
|
314
|
+
|
315
|
+
# work around the fact that facebook cares about the order of the keys in the hash
|
316
|
+
class ImageHolder
|
317
|
+
attr_accessor :src,:href
|
318
|
+
def initialize(src,href)
|
319
|
+
self.src=src
|
320
|
+
self.href=href
|
321
|
+
end
|
322
|
+
|
323
|
+
def to_json
|
324
|
+
"{\"src\":#{src.to_json}, \"href\":#{href.to_json}}"
|
325
|
+
end
|
326
|
+
end
|
327
|
+
|
328
|
+
def image(src,target)
|
329
|
+
ImageHolder.new(image_path(src),target.respond_to?(:to_str) ? target : url_for(target))
|
330
|
+
end
|
331
|
+
|
332
|
+
def action_link(text,target)
|
333
|
+
{:text=>text, :href=>target}
|
334
|
+
end
|
335
|
+
|
336
|
+
def requires_from_user?(from,body)
|
337
|
+
! (announcement_notification?(from,body) or ref_update?(body) or profile_update?(body))
|
338
|
+
end
|
339
|
+
|
340
|
+
def profile_update?(body)
|
341
|
+
body.is_a?(Profile)
|
342
|
+
end
|
343
|
+
|
344
|
+
def ref_update?(body)
|
345
|
+
body.is_a?(Ref)
|
346
|
+
end
|
347
|
+
|
348
|
+
def announcement_notification?(from,body)
|
349
|
+
from.nil? and body.is_a?(Notification)
|
350
|
+
end
|
351
|
+
|
352
|
+
def send_message(method)
|
353
|
+
@recipients = @recipients.is_a?(Array) ? @recipients : [@recipients]
|
354
|
+
if from.nil? and @recipients.size==1 and requires_from_user?(from,_body)
|
355
|
+
@from = @recipients.first
|
356
|
+
end
|
357
|
+
# notifications can
|
358
|
+
# omit the from address
|
359
|
+
raise InvalidSender.new("Sender must be a Facebooker::User") unless from.is_a?(Facebooker::User) || !requires_from_user?(from,_body)
|
360
|
+
case _body
|
361
|
+
when Facebooker::Feed::TemplatizedAction,Facebooker::Feed::Action
|
362
|
+
from.publish_action(_body)
|
363
|
+
when Facebooker::Feed::Story
|
364
|
+
@recipients.each {|r| r.publish_story(_body)}
|
365
|
+
when Notification
|
366
|
+
(from.nil? ? Facebooker::Session.create : from.session).send_notification(@recipients,_body.fbml)
|
367
|
+
when Email
|
368
|
+
from.session.send_email(@recipients,
|
369
|
+
_body.title,
|
370
|
+
_body.text,
|
371
|
+
_body.fbml)
|
372
|
+
when Profile
|
373
|
+
# If recipient and from aren't the same person, create a new user object using the
|
374
|
+
# userid from recipient and the session from from
|
375
|
+
@from = Facebooker::User.new(Facebooker::User.cast_to_facebook_id(@recipients.first),Facebooker::Session.create)
|
376
|
+
@from.set_profile_fbml(_body.profile, _body.mobile_profile, _body.profile_action, _body.profile_main)
|
377
|
+
when Ref
|
378
|
+
Facebooker::Session.create.server_cache.set_ref_handle(_body.handle,_body.fbml)
|
379
|
+
when UserAction
|
380
|
+
@from.session.publish_user_action(_body.template_id,_body.data_hash,_body.target_ids,_body.body_general)
|
381
|
+
else
|
382
|
+
raise UnspecifiedBodyType.new("You must specify a valid send_as")
|
383
|
+
end
|
384
|
+
end
|
385
|
+
|
386
|
+
# nodoc
|
387
|
+
# needed for actionview
|
388
|
+
def logger
|
389
|
+
RAILS_DEFAULT_LOGGER
|
390
|
+
end
|
391
|
+
|
392
|
+
# nodoc
|
393
|
+
# delegate to action view. Set up assigns and render
|
394
|
+
def render(opts)
|
395
|
+
opts = opts.dup
|
396
|
+
body = opts.delete(:assigns) || {}
|
397
|
+
initialize_template_class(body.dup.merge(:controller=>self)).render(opts)
|
398
|
+
end
|
399
|
+
|
400
|
+
|
401
|
+
def initialize_template_class(assigns)
|
402
|
+
template_root = "#{RAILS_ROOT}/app/views"
|
403
|
+
controller_root = File.join(template_root,self.class.controller_path)
|
404
|
+
#only do this on Rails 2.1
|
405
|
+
if ActionController::Base.respond_to?(:append_view_path)
|
406
|
+
# only add the view path once
|
407
|
+
ActionController::Base.append_view_path(controller_root) unless ActionController::Base.view_paths.include?(controller_root)
|
408
|
+
end
|
409
|
+
returning ActionView::Base.new([template_root,controller_root], assigns, self) do |template|
|
410
|
+
template.controller=self
|
411
|
+
template.extend(self.class.master_helper_module)
|
412
|
+
def template.request_comes_from_facebook?
|
413
|
+
true
|
414
|
+
end
|
415
|
+
end
|
416
|
+
end
|
417
|
+
|
418
|
+
|
419
|
+
self.master_helper_module = Module.new
|
420
|
+
self.master_helper_module.module_eval do
|
421
|
+
# url_helper delegates to @controller,
|
422
|
+
# so we need to define that in the template
|
423
|
+
# we make it point to the publisher
|
424
|
+
include ActionView::Helpers::UrlHelper
|
425
|
+
include ActionView::Helpers::TextHelper
|
426
|
+
include ActionView::Helpers::TagHelper
|
427
|
+
include ActionView::Helpers::FormHelper
|
428
|
+
include ActionView::Helpers::FormTagHelper
|
429
|
+
include ActionView::Helpers::AssetTagHelper
|
430
|
+
include Facebooker::Rails::Helpers
|
431
|
+
|
432
|
+
#define this for the publisher views
|
433
|
+
def protect_against_forgery?
|
434
|
+
@paf ||= ActionController::Base.new.send(:protect_against_forgery?)
|
435
|
+
end
|
436
|
+
|
437
|
+
# url_for calls in publishers tend to want full paths
|
438
|
+
def url_for(options = {})
|
439
|
+
super(options.kind_of?(Hash) ? {:only_path => false}.update(options) : options)
|
440
|
+
end
|
441
|
+
end
|
442
|
+
ActionController::Routing::Routes.named_routes.install(self.master_helper_module)
|
443
|
+
include self.master_helper_module
|
444
|
+
class <<self
|
445
|
+
|
446
|
+
def register_all_templates
|
447
|
+
all_templates = instance_methods.grep(/_template$/) - %w(short_story_template full_story_template one_line_story_template)
|
448
|
+
all_templates.each do |template|
|
449
|
+
template_name=template.sub(/_template$/,"")
|
450
|
+
puts "Registering #{template_name}"
|
451
|
+
send("register_"+template_name)
|
452
|
+
end
|
453
|
+
end
|
454
|
+
|
455
|
+
def method_missing(name,*args)
|
456
|
+
should_send = false
|
457
|
+
method = ''
|
458
|
+
if md = /^create_(.*)$/.match(name.to_s)
|
459
|
+
method = md[1]
|
460
|
+
elsif md = /^deliver_(.*)$/.match(name.to_s)
|
461
|
+
method = md[1]
|
462
|
+
should_send = true
|
463
|
+
elsif md = /^register_(.*)$/.match(name.to_s)
|
464
|
+
return FacebookTemplate.register(self, md[1])
|
465
|
+
else
|
466
|
+
super
|
467
|
+
end
|
468
|
+
|
469
|
+
#now create the item
|
470
|
+
(publisher=new).send(method,*args)
|
471
|
+
case publisher._body
|
472
|
+
when UserAction
|
473
|
+
publisher._body.template_name = method
|
474
|
+
publisher._body.template_id = FacebookTemplate.bundle_id_for_class_and_method(self,method)
|
475
|
+
end
|
476
|
+
|
477
|
+
should_send ? publisher.send_message(method) : publisher._body
|
478
|
+
end
|
479
|
+
|
480
|
+
def default_url_options
|
481
|
+
{:host => Facebooker.canvas_server_base + Facebooker.facebook_path_prefix}
|
482
|
+
end
|
483
|
+
|
484
|
+
def controller_path
|
485
|
+
self.to_s.underscore
|
486
|
+
end
|
487
|
+
|
488
|
+
def helper(*args)
|
489
|
+
args.each do |arg|
|
490
|
+
case arg
|
491
|
+
when Symbol,String
|
492
|
+
add_template_helper("#{arg.to_s.classify}Helper".constantize)
|
493
|
+
when Module
|
494
|
+
add_template_helper(arg)
|
495
|
+
end
|
496
|
+
end
|
497
|
+
end
|
498
|
+
|
499
|
+
def add_template_helper(helper_module) #:nodoc:
|
500
|
+
master_helper_module.send :include,helper_module
|
501
|
+
include master_helper_module
|
502
|
+
end
|
503
|
+
|
504
|
+
|
505
|
+
def inherited(child)
|
506
|
+
super
|
507
|
+
child.master_helper_module=Module.new
|
508
|
+
child.master_helper_module.__send__(:include,self.master_helper_module)
|
509
|
+
child.send(:include, child.master_helper_module)
|
510
|
+
FacebookTemplate.clear_cache!
|
511
|
+
end
|
512
|
+
|
513
|
+
end
|
514
|
+
class PublisherController
|
515
|
+
include Facebooker::Rails::Publisher.master_helper_module
|
516
|
+
include ActionController::UrlWriter
|
517
|
+
|
518
|
+
def self.default_url_options(*args)
|
519
|
+
Facebooker::Rails::Publisher.default_url_options(*args)
|
520
|
+
end
|
521
|
+
|
522
|
+
end
|
523
|
+
|
524
|
+
end
|
525
|
+
end
|
526
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module Facebooker
|
2
|
+
module Rails
|
3
|
+
module Routing
|
4
|
+
module RouteSetExtensions
|
5
|
+
def self.included(base)
|
6
|
+
base.alias_method_chain :extract_request_environment, :facebooker
|
7
|
+
end
|
8
|
+
|
9
|
+
def extract_request_environment_with_facebooker(request)
|
10
|
+
env = extract_request_environment_without_facebooker(request)
|
11
|
+
env.merge :canvas => (request.parameters[:fb_sig_in_canvas]=="1")
|
12
|
+
end
|
13
|
+
end
|
14
|
+
module MapperExtensions
|
15
|
+
|
16
|
+
# Generates pseudo-resource routes. Since everything is a POST, routes can't be identified
|
17
|
+
# using HTTP verbs. Therefore, the action is appended to the beginning of each named route,
|
18
|
+
# except for index.
|
19
|
+
#
|
20
|
+
# Example:
|
21
|
+
# map.facebook_resources :profiles
|
22
|
+
#
|
23
|
+
# Generates the following routes:
|
24
|
+
#
|
25
|
+
# new_profile POST /profiles/new {:controller=>"profiles", :action=>"new"}
|
26
|
+
# profiles POST /profiles/index {:controller=>"profiles", :action=>"index"}
|
27
|
+
# show_profile POST /profiles/:id/show {:controller=>"profiles", :action=>"show"}
|
28
|
+
# create_profile POST /profiles/create {:controller=>"profiles", :action=>"create"}
|
29
|
+
# edit_profile POST /profiles/:id/edit {:controller=>"profiles", :action=>"edit"}
|
30
|
+
# update_profile POST /profiles/:id/update {:controller=>"profiles", :action=>"update"}
|
31
|
+
# destroy_profile POST /profiles/:id/destroy {:controller=>"profiles", :action=>"destroy"}
|
32
|
+
#
|
33
|
+
def facebook_resources(name_sym)
|
34
|
+
name = name_sym.to_s
|
35
|
+
|
36
|
+
with_options :controller => name, :conditions => { :method => :post } do |map|
|
37
|
+
map.named_route("new_#{name.singularize}", "#{name}/new", :action => 'new')
|
38
|
+
map.named_route(name, "#{name}/index", :action => 'index')
|
39
|
+
map.named_route("show_#{name.singularize}", "#{name}/:id/show", :action => 'show', :id => /\d+/)
|
40
|
+
map.named_route("create_#{name.singularize}", "#{name}/create", :action => 'create')
|
41
|
+
map.named_route("edit_#{name.singularize}", "#{name}/:id/edit", :action => 'edit', :id => /\d+/)
|
42
|
+
map.named_route("update_#{name.singularize}", "#{name}/:id/update", :action => 'update', :id => /\d+/)
|
43
|
+
map.named_route("destroy_#{name.singularize}", "#{name}/:id/destroy", :action => 'destroy', :id => /\d+/)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|