##// END OF EJS Templates
Added request and controller objects to the hooks by default....
Eric Davis -
r2368:5b7a5c39a7da
parent child
Show More
@@ -17,6 +17,8
17
17
18 module Redmine
18 module Redmine
19 module Hook
19 module Hook
20 include ActionController::UrlWriter
21
20 @@listener_classes = []
22 @@listener_classes = []
21 @@listeners = nil
23 @@listeners = nil
22 @@hook_listeners = {}
24 @@hook_listeners = {}
@@ -55,11 +57,22 module Redmine
55 # Calls a hook.
57 # Calls a hook.
56 # Returns the listeners response.
58 # Returns the listeners response.
57 def call_hook(hook, context={})
59 def call_hook(hook, context={})
58 response = ''
60 returning [] do |response|
59 hook_listeners(hook).each do |listener|
61 hls = hook_listeners(hook)
60 response << listener.send(hook, context).to_s
62 if hls.any?
63 request = context[:request]
64 if request
65 default_url_options[:host] ||= request.env["SERVER_NAME"]
66 # Only set port if it's requested and isn't port 80. Otherwise a url
67 # like: +http://example.com:/url+ may be generated
68 if request.env["SERVER_PORT"] && request.env["SERVER_PORT"] != 80
69 default_url_options[:port] ||= request.env["SERVER_PORT"]
70 end
71 default_url_options[:protocol] ||= request.protocol
72 end
73 hls.each {|listener| response << listener.send(hook, context)}
74 end
61 end
75 end
62 response
63 end
76 end
64 end
77 end
65
78
@@ -91,17 +104,48 module Redmine
91 include ActionView::Helpers::TextHelper
104 include ActionView::Helpers::TextHelper
92 include ActionController::UrlWriter
105 include ActionController::UrlWriter
93 include ApplicationHelper
106 include ApplicationHelper
107
108 # Helper method to directly render a partial using the context:
109 #
110 # class MyHook < Redmine::Hook::ViewListener
111 # render_on :view_issues_show_details_bottom, :partial => "show_more_data"
112 # end
113 #
114 def self.render_on(hook, options={})
115 define_method hook do |context|
116 context[:controller].send(:render_to_string, {:locals => context}.merge(options))
117 end
118 end
94 end
119 end
95
120
96 # Helper module included in ApplicationHelper so that hooks can be called
121 # Helper module included in ApplicationHelper and ActionControllerso that
97 # in views like this:
122 # hooks can be called in views like this:
123 #
98 # <%= call_hook(:some_hook) %>
124 # <%= call_hook(:some_hook) %>
99 # <%= call_hook(:another_hook, :foo => 'bar' %>
125 # <%= call_hook(:another_hook, :foo => 'bar' %>
100 #
126 #
101 # Current project is automatically added to the call context.
127 # Or in controllers like:
128 # call_hook(:some_hook)
129 # call_hook(:another_hook, :foo => 'bar'
130 #
131 # Hooks added to views will be concatenated into a string. Hooks added to
132 # controllers will return an array of results.
133 #
134 # Several objects are automatically added to the call context:
135 #
136 # * project => current project
137 # * request => Request instance
138 # * controller => current Controller instance
139 #
102 module Helper
140 module Helper
103 def call_hook(hook, context={})
141 def call_hook(hook, context={})
104 Redmine::Hook.call_hook(hook, {:project => @project}.merge(context))
142 if is_a?(ActionController::Base)
143 ctx = {:controller => self, :project => @project, :request => request}
144 Redmine::Hook.call_hook(hook, ctx.merge(context))
145 else
146 ctx = {:controller => controller, :project => @project, :request => request}
147 Redmine::Hook.call_hook(hook, ctx.merge(context)).join(' ')
148 end
105 end
149 end
106 end
150 end
107 end
151 end
@@ -20,7 +20,7 require File.dirname(__FILE__) + '/../../../test_helper'
20 class Redmine::Hook::ManagerTest < Test::Unit::TestCase
20 class Redmine::Hook::ManagerTest < Test::Unit::TestCase
21
21
22 # Some hooks that are manually registered in these tests
22 # Some hooks that are manually registered in these tests
23 class TestHook < Redmine::Hook::Listener; end
23 class TestHook < Redmine::Hook::ViewListener; end
24
24
25 class TestHook1 < TestHook
25 class TestHook1 < TestHook
26 def view_layouts_base_html_head(context)
26 def view_layouts_base_html_head(context)
@@ -39,6 +39,13 class Redmine::Hook::ManagerTest < Test::Unit::TestCase
39 "Context keys: #{context.keys.collect(&:to_s).sort.join(', ')}."
39 "Context keys: #{context.keys.collect(&:to_s).sort.join(', ')}."
40 end
40 end
41 end
41 end
42
43 class TestLinkToHook < TestHook
44 def view_layouts_base_html_head(context)
45 link_to('Issues', :controller => 'issues')
46 end
47 end
48
42 Redmine::Hook.clear_listeners
49 Redmine::Hook.clear_listeners
43
50
44 def setup
51 def setup
@@ -47,6 +54,7 class Redmine::Hook::ManagerTest < Test::Unit::TestCase
47
54
48 def teardown
55 def teardown
49 @hook_module.clear_listeners
56 @hook_module.clear_listeners
57 @hook_module.default_url_options = { }
50 end
58 end
51
59
52 def test_clear_listeners
60 def test_clear_listeners
@@ -67,17 +75,84 class Redmine::Hook::ManagerTest < Test::Unit::TestCase
67
75
68 def test_call_hook
76 def test_call_hook
69 @hook_module.add_listener(TestHook1)
77 @hook_module.add_listener(TestHook1)
70 assert_equal 'Test hook 1 listener.', @hook_module.call_hook(:view_layouts_base_html_head)
78 assert_equal ['Test hook 1 listener.'], @hook_module.call_hook(:view_layouts_base_html_head)
71 end
79 end
72
80
73 def test_call_hook_with_context
81 def test_call_hook_with_context
74 @hook_module.add_listener(TestHook3)
82 @hook_module.add_listener(TestHook3)
75 assert_equal 'Context keys: bar, foo.', @hook_module.call_hook(:view_layouts_base_html_head, :foo => 1, :bar => 'a')
83 assert_equal ['Context keys: bar, foo.'], @hook_module.call_hook(:view_layouts_base_html_head, :foo => 1, :bar => 'a')
76 end
84 end
77
85
78 def test_call_hook_with_multiple_listeners
86 def test_call_hook_with_multiple_listeners
79 @hook_module.add_listener(TestHook1)
87 @hook_module.add_listener(TestHook1)
80 @hook_module.add_listener(TestHook2)
88 @hook_module.add_listener(TestHook2)
81 assert_equal 'Test hook 1 listener.Test hook 2 listener.', @hook_module.call_hook(:view_layouts_base_html_head)
89 assert_equal ['Test hook 1 listener.', 'Test hook 2 listener.'], @hook_module.call_hook(:view_layouts_base_html_head)
90 end
91
92 # Context: Redmine::Hook::call_hook
93 def test_call_hook_default_url_options_set
94 request = ActionController::TestRequest.new
95 request.env = { "SERVER_NAME" => 'example.com'}
96 @hook_module.add_listener(TestLinkToHook)
97
98 assert_equal ['<a href="http://example.com/issues">Issues</a>'],
99 @hook_module.call_hook(:view_layouts_base_html_head, :request => request)
100 end
101
102 def test_call_hook_default_url_options_set_with_no_standard_request_port
103 request = ActionController::TestRequest.new
104 request.env = { "SERVER_NAME" => 'example.com', "SERVER_PORT" => 3000}
105 @hook_module.add_listener(TestLinkToHook)
106
107 assert_equal ['<a href="http://example.com:3000/issues">Issues</a>'],
108 @hook_module.call_hook(:view_layouts_base_html_head, :request => request)
109 end
110
111 def test_call_hook_default_url_options_set_with_ssl
112 request = ActionController::TestRequest.new
113 request.env = { "SERVER_NAME" => 'example.com', "HTTPS" => 'on'}
114 @hook_module.add_listener(TestLinkToHook)
115
116 assert_equal ['<a href="https://example.com/issues">Issues</a>'],
117 @hook_module.call_hook(:view_layouts_base_html_head, :request => request)
118 end
119
120 def test_call_hook_default_url_options_set_with_forwarded_ssl
121 request = ActionController::TestRequest.new
122 request.env = { "SERVER_NAME" => 'example.com', "HTTP_X_FORWARDED_PROTO" => "https"}
123 @hook_module.add_listener(TestLinkToHook)
124
125 assert_equal ['<a href="https://example.com/issues">Issues</a>'],
126 @hook_module.call_hook(:view_layouts_base_html_head, :request => request)
127 end
128
129 # Context: Redmine::Hook::Helper.call_hook
130 def test_call_hook_with_project_added_to_context
131 # TODO: Implement test
132 end
133
134 def test_call_hook_from_controller_with_controller_added_to_context
135 # TODO: Implement test
136 end
137
138 def test_call_hook_from_controller_with_request_added_to_context
139 # TODO: Implement test
140 end
141
142 def test_call_hook_from_view_with_project_added_to_context
143 # TODO: Implement test
144 end
145
146 def test_call_hook_from_view_with_controller_added_to_context
147 # TODO: Implement test
148 end
149
150 def test_call_hook_from_view_with_request_added_to_context
151 # TODO: Implement test
152 end
153
154 def test_call_hook_from_view_should_join_responses_with_a_space
155 # TODO: Implement test
82 end
156 end
83 end
157 end
158
General Comments 0
You need to be logged in to leave comments. Login now