Feature #29664 » Add-configuration-option-to-enable-or-disable-webhooks.patch
| app/controllers/webhooks_controller.rb | ||
|---|---|---|
| 4 | 4 |
self.main_menu = false |
| 5 | 5 | |
| 6 | 6 |
before_action :require_login |
| 7 |
before_action :check_enabled |
|
| 7 | 8 |
before_action :authorize |
| 8 | 9 | |
| 9 | 10 |
before_action :find_webhook, only: [:edit, :update, :destroy] |
| ... | ... | |
| 62 | 63 |
def authorize |
| 63 | 64 |
deny_access unless User.current.allowed_to?(:use_webhooks, nil, global: true) |
| 64 | 65 |
end |
| 66 | ||
| 67 |
def check_enabled |
|
| 68 |
render_404 unless Webhook.enabled? |
|
| 69 |
end |
|
| 65 | 70 |
end |
| app/models/webhook.rb | ||
|---|---|---|
| 42 | 42 | |
| 43 | 43 |
before_validation ->(hook){ hook.projects = hook.projects.to_a & hook.setable_projects }
|
| 44 | 44 | |
| 45 |
def self.enabled? |
|
| 46 |
Redmine::Configuration['webhooks'] |
|
| 47 |
end |
|
| 48 | ||
| 45 | 49 |
# Triggers the given event for the given object, scheduling qualifying hooks |
| 46 | 50 |
# to be called. |
| 47 | 51 |
def self.trigger(event, object) |
| 52 |
return unless enabled? |
|
| 53 | ||
| 48 | 54 |
hooks_for(event, object).each do |hook| |
| 49 | 55 |
payload = hook.payload(event, object) |
| 50 | 56 |
WebhookJob.perform_later(hook.id, payload.to_json) |
| app/views/my/account.html.erb | ||
|---|---|---|
| 1 | 1 |
<div class="contextual"> |
| 2 | 2 |
<%= additional_emails_link(@user) %> |
| 3 | 3 |
<%= link_to(sprite_icon('key', l(:button_change_password)), { :action => 'password'}, :class => 'icon icon-passwd') if @user.change_password_allowed? %>
|
| 4 |
<%= link_to sprite_icon('webhook', l(:label_webhook_plural)), webhooks_path, class: 'icon icon-webhook' if @user.allowed_to?(:use_webhooks, nil, global: true) %>
|
|
| 4 |
<%= link_to sprite_icon('webhook', l(:label_webhook_plural)), webhooks_path, class: 'icon icon-webhook' if Webhook.enabled? && @user.allowed_to?(:use_webhooks, nil, global: true) %>
|
|
| 5 | 5 |
<%= link_to(sprite_icon('apps', l('label_oauth_authorized_application_plural')), oauth_authorized_applications_path, :class => 'icon icon-applications') if Setting.rest_api_enabled? %>
|
| 6 | 6 |
<%= call_hook(:view_my_account_contextual, :user => @user)%> |
| 7 | 7 |
</div> |
| config/configuration.yml.example | ||
|---|---|---|
| 226 | 226 | |
| 227 | 227 |
# Webhooks |
| 228 | 228 |
# |
| 229 |
# Enables or disables the Webhooks feature (enabled by default). |
|
| 230 |
# When disabled, all related UI will be hidden, and no webhooks will be triggered, |
|
| 231 |
# but existing webhook data will be retained. |
|
| 232 |
# webhooks: true |
|
| 233 |
# |
|
| 229 | 234 |
# An optional list of hosts and/or IP addresses and/or IP networks which |
| 230 | 235 |
# should NOT be valid as webhook targets. You can add your internal IPs and |
| 231 | 236 |
# hostnames here to avoid possible SSRF attacks. |
| lib/redmine/configuration.rb | ||
|---|---|---|
| 27 | 27 |
'email_delivery' => nil, |
| 28 | 28 |
'max_concurrent_ajax_uploads' => 2, |
| 29 | 29 |
'common_mark_enable_hardbreaks' => true, |
| 30 |
'thumbnails_generation_timeout' => 10 |
|
| 30 |
'thumbnails_generation_timeout' => 10, |
|
| 31 |
'webhooks' => true |
|
| 31 | 32 |
} |
| 32 | 33 | |
| 33 | 34 |
@config = nil |
| lib/redmine/preparation.rb | ||
|---|---|---|
| 50 | 50 |
map.permission :save_queries, {:queries => [:new, :create, :edit, :update, :destroy]}, :require => :loggedin
|
| 51 | 51 | |
| 52 | 52 |
# Webhooks |
| 53 |
map.permission :use_webhooks, {}, :require => :member
|
|
| 53 |
map.permission :use_webhooks, {}, :require => :member if Redmine::Configuration['webhooks']
|
|
| 54 | 54 | |
| 55 | 55 |
map.project_module :issue_tracking do |map| |
| 56 | 56 |
# Issues |
| test/functional/my_controller_test.rb | ||
|---|---|---|
| 398 | 398 |
assert_select 'select[name=?]', 'user[language]' |
| 399 | 399 |
end |
| 400 | 400 | |
| 401 |
def test_my_account_should_toggle_webhook_link_with_configuration |
|
| 402 |
User.find(2).roles.first.add_permission!(:use_webhooks) |
|
| 403 | ||
| 404 |
get :account |
|
| 405 |
assert_response :success |
|
| 406 |
assert_select 'a.icon-webhook', 1 |
|
| 407 | ||
| 408 |
Redmine::Configuration.with 'webhooks' => false do |
|
| 409 |
get :account |
|
| 410 |
assert_response :success |
|
| 411 |
assert_select 'a.icon-webhook', 0 |
|
| 412 |
end |
|
| 413 |
end |
|
| 414 | ||
| 401 | 415 |
def test_my_account_with_avatar_enabled_should_link_to_edit_avatar |
| 402 | 416 |
with_settings :gravatar_enabled => '1' do |
| 403 | 417 |
Redmine::Configuration.with 'avatar_server_url' => 'https://gravatar.com' do |
| test/functional/webhooks_controller_test.rb | ||
|---|---|---|
| 27 | 27 |
assert_select 'td', text: @other_hook.url, count: 0 |
| 28 | 28 |
end |
| 29 | 29 | |
| 30 |
test "should return not found when disabled" do |
|
| 31 |
Redmine::Configuration.with 'webhooks' => false do |
|
| 32 |
get :index |
|
| 33 |
assert_response :not_found |
|
| 34 | ||
| 35 |
get :new |
|
| 36 |
assert_response :not_found |
|
| 37 |
end |
|
| 38 |
end |
|
| 39 | ||
| 30 | 40 |
test "should get new" do |
| 31 | 41 |
get :new |
| 32 | 42 |
assert_response :success |
| test/unit/webhook_test.rb | ||
|---|---|---|
| 168 | 168 |
end |
| 169 | 169 |
end |
| 170 | 170 | |
| 171 |
test "enabled? should follow configuration flag" do |
|
| 172 |
assert Webhook.enabled? |
|
| 173 | ||
| 174 |
Redmine::Configuration.with 'webhooks' => false do |
|
| 175 |
assert_not Webhook.enabled? |
|
| 176 |
end |
|
| 177 | ||
| 178 |
Redmine::Configuration.with 'webhooks' => true do |
|
| 179 |
assert Webhook.enabled? |
|
| 180 |
end |
|
| 181 |
end |
|
| 182 | ||
| 183 |
test "trigger should not enqueue jobs when disabled" do |
|
| 184 |
create_hook |
|
| 185 | ||
| 186 |
Redmine::Configuration.with 'webhooks' => false do |
|
| 187 |
assert_no_enqueued_jobs do |
|
| 188 |
Webhook.trigger('issue.created', @issue)
|
|
| 189 |
end |
|
| 190 |
end |
|
| 191 |
end |
|
| 192 | ||
| 171 | 193 |
test "should compute payload" do |
| 172 | 194 |
hook = create_hook |
| 173 | 195 |
payload = hook.payload('issue.created', @issue)
|