foreman_webhooks 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +619 -0
- data/README.md +30 -0
- data/Rakefile +49 -0
- data/app/controllers/api/v2/webhook_templates_controller.rb +110 -0
- data/app/controllers/api/v2/webhooks_controller.rb +61 -0
- data/app/controllers/concerns/foreman_webhooks/controller/parameters/webhook.rb +34 -0
- data/app/controllers/concerns/foreman_webhooks/controller/parameters/webhook_template.rb +34 -0
- data/app/controllers/webhook_templates_controller.rb +5 -0
- data/app/controllers/webhooks_controller.rb +39 -0
- data/app/jobs/foreman_webhooks/deliver_webhook_job.rb +27 -0
- data/app/lib/foreman_webhooks/renderer/scope/webhook_template.rb +36 -0
- data/app/models/webhook.rb +141 -0
- data/app/models/webhook_template.rb +59 -0
- data/app/services/foreman_webhooks/webhook_service.rb +111 -0
- data/app/subscribers/foreman_webhooks/event_subscriber.rb +9 -0
- data/app/views/api/v2/webhook_templates/base.json.rabl +5 -0
- data/app/views/api/v2/webhook_templates/create.json.rabl +5 -0
- data/app/views/api/v2/webhook_templates/index.json.rabl +5 -0
- data/app/views/api/v2/webhook_templates/main.json.rabl +7 -0
- data/app/views/api/v2/webhook_templates/show.json.rabl +11 -0
- data/app/views/api/v2/webhook_templates/update.json.rabl +5 -0
- data/app/views/api/v2/webhooks/base.json.rabl +5 -0
- data/app/views/api/v2/webhooks/create.json.rabl +5 -0
- data/app/views/api/v2/webhooks/index.json.rabl +5 -0
- data/app/views/api/v2/webhooks/main.json.rabl +8 -0
- data/app/views/api/v2/webhooks/show.json.rabl +17 -0
- data/app/views/api/v2/webhooks/update.json.rabl +5 -0
- data/app/views/foreman_webhooks/webhook_templates/ansible_tower_-_host_in_inventory.erb +20 -0
- data/app/views/foreman_webhooks/webhook_templates/empty_payload.erb +6 -0
- data/app/views/foreman_webhooks/webhook_templates/webhook_template_-_payload_default.erb +11 -0
- data/app/views/webhook_templates/_alerts.html.erb +3 -0
- data/app/views/webhook_templates/_custom_tab_headers.html.erb +1 -0
- data/app/views/webhook_templates/_custom_tabs.html.erb +5 -0
- data/app/views/webhook_templates/edit.html.erb +3 -0
- data/app/views/webhook_templates/index.html.erb +29 -0
- data/app/views/webhook_templates/new.html.erb +3 -0
- data/app/views/webhooks/_form.html.erb +37 -0
- data/app/views/webhooks/_templates.html.erb +5 -0
- data/app/views/webhooks/edit.html.erb +3 -0
- data/app/views/webhooks/new.html.erb +3 -0
- data/config/routes.rb +45 -0
- data/db/migrate/20191016100128_create_webhook_targets.rb +13 -0
- data/db/migrate/20200831194208_rename_webhook_targets_to_webhooks.rb +7 -0
- data/db/migrate/20200831194514_add_template_to_webhooks.rb +7 -0
- data/db/migrate/20200907232758_rename_webhook_permissions.rb +22 -0
- data/db/migrate/20200908004234_add_columns_to_webhooks.rb +13 -0
- data/db/migrate/20201014115147_rename_ca_file_column.rb +7 -0
- data/db/migrate/20201109135301_add_http_headers.rb +8 -0
- data/db/seeds.d/95_webhook_templates.rb +7 -0
- data/lib/foreman_webhooks.rb +6 -0
- data/lib/foreman_webhooks/engine.rb +80 -0
- data/lib/foreman_webhooks/version.rb +5 -0
- data/lib/tasks/foreman_webhooks_tasks.rake +47 -0
- data/package.json +45 -0
- data/test/controllers/api/v2/webhook_templates_controller_test.rb +200 -0
- data/test/controllers/api/v2/webhooks_controller_test.rb +108 -0
- data/test/factories/webhook.rb +20 -0
- data/test/factories/webhook_target.rb +9 -0
- data/test/factories/webhook_template.rb +16 -0
- data/test/jobs/foreman_webhooks/deliver_webhook_job_test.rb +17 -0
- data/test/models/webhook_test.rb +38 -0
- data/test/test_plugin_helper.rb +8 -0
- data/test/unit/foreman_webhooks/webhook_service_test.rb +53 -0
- data/webpack/ForemanWebhooks/Routes/ForemanWebhooksRoutes.js +12 -0
- data/webpack/ForemanWebhooks/Routes/Webhooks/WebhooksIndexPage/Components/EmptyWebhooksTable/index.js +29 -0
- data/webpack/ForemanWebhooks/Routes/Webhooks/WebhooksIndexPage/Components/WebhookDeleteModal.js +43 -0
- data/webpack/ForemanWebhooks/Routes/Webhooks/WebhooksIndexPage/Components/WebhooksTable/Components/EnabledCell.js +16 -0
- data/webpack/ForemanWebhooks/Routes/Webhooks/WebhooksIndexPage/Components/WebhooksTable/Components/Formatters/__tests__/__snapshots__/enabledCellFormatter.test.js.snap +7 -0
- data/webpack/ForemanWebhooks/Routes/Webhooks/WebhooksIndexPage/Components/WebhooksTable/Components/Formatters/__tests__/enabledCellFormatter.test.js +7 -0
- data/webpack/ForemanWebhooks/Routes/Webhooks/WebhooksIndexPage/Components/WebhooksTable/Components/Formatters/enabledCellFormatter.js +6 -0
- data/webpack/ForemanWebhooks/Routes/Webhooks/WebhooksIndexPage/Components/WebhooksTable/Components/Formatters/index.js +1 -0
- data/webpack/ForemanWebhooks/Routes/Webhooks/WebhooksIndexPage/Components/WebhooksTable/Components/__tests__/EnabledCell.test.js +14 -0
- data/webpack/ForemanWebhooks/Routes/Webhooks/WebhooksIndexPage/Components/WebhooksTable/Components/__tests__/__snapshots__/EnabledCell.test.js.snap +17 -0
- data/webpack/ForemanWebhooks/Routes/Webhooks/WebhooksIndexPage/Components/WebhooksTable/WebhooksTable.js +75 -0
- data/webpack/ForemanWebhooks/Routes/Webhooks/WebhooksIndexPage/Components/WebhooksTable/WebhooksTableSchema.js +41 -0
- data/webpack/ForemanWebhooks/Routes/Webhooks/WebhooksIndexPage/Components/WebhooksTable/__tests__/WebhooksTable.test.js +57 -0
- data/webpack/ForemanWebhooks/Routes/Webhooks/WebhooksIndexPage/Components/WebhooksTable/__tests__/__snapshots__/WebhooksTable.test.js.snap +115 -0
- data/webpack/ForemanWebhooks/Routes/Webhooks/WebhooksIndexPage/Components/WebhooksTable/index.js +25 -0
- data/webpack/ForemanWebhooks/Routes/Webhooks/WebhooksIndexPage/WebhooksIndexPage.js +87 -0
- data/webpack/ForemanWebhooks/Routes/Webhooks/WebhooksIndexPage/__tests__/WebhooksIndexPage.fixtures.js +74 -0
- data/webpack/ForemanWebhooks/Routes/Webhooks/WebhooksIndexPage/__tests__/WebhooksIndexPage.test.js +21 -0
- data/webpack/ForemanWebhooks/Routes/Webhooks/WebhooksIndexPage/__tests__/__snapshots__/WebhooksIndexPage.test.js.snap +68 -0
- data/webpack/ForemanWebhooks/Routes/Webhooks/WebhooksIndexPage/index.js +51 -0
- data/webpack/ForemanWebhooks/Routes/Webhooks/WebhooksPageActions.js +51 -0
- data/webpack/ForemanWebhooks/Routes/Webhooks/WebhooksPageHelpers.js +29 -0
- data/webpack/ForemanWebhooks/Routes/Webhooks/WebhooksPageSelectors.js +85 -0
- data/webpack/ForemanWebhooks/Routes/Webhooks/__tests__/WebhooksPageHelpers.test.js +20 -0
- data/webpack/ForemanWebhooks/Routes/Webhooks/__tests__/WebhooksPageSelectors.test.js +45 -0
- data/webpack/ForemanWebhooks/Routes/Webhooks/__tests__/__snapshots__/WebhooksPageSelectors.test.js.snap +50 -0
- data/webpack/ForemanWebhooks/Routes/Webhooks/constants.js +13 -0
- data/webpack/__mocks__/foremanReact/common/HOC.js +2 -0
- data/webpack/__mocks__/foremanReact/common/I18n.js +7 -0
- data/webpack/__mocks__/foremanReact/common/helpers.js +7 -0
- data/webpack/__mocks__/foremanReact/common/urlHelpers.js +1 -0
- data/webpack/__mocks__/foremanReact/components/ForemanModal/ForemanModalActions.js +2 -0
- data/webpack/__mocks__/foremanReact/components/ForemanModal/ForemanModalHooks.js +10 -0
- data/webpack/__mocks__/foremanReact/components/ForemanModal/index.js +18 -0
- data/webpack/__mocks__/foremanReact/components/Layout/LayoutActions.js +2 -0
- data/webpack/__mocks__/foremanReact/components/Pagination/PaginationWrapper.js +2 -0
- data/webpack/__mocks__/foremanReact/components/common/EmptyState.js +5 -0
- data/webpack/__mocks__/foremanReact/components/common/table.js +5 -0
- data/webpack/__mocks__/foremanReact/constants.js +24 -0
- data/webpack/__mocks__/foremanReact/redux/API/APISelectors.js +6 -0
- data/webpack/__mocks__/foremanReact/redux/API/index.js +10 -0
- data/webpack/__mocks__/foremanReact/redux/actions/toasts.js +8 -0
- data/webpack/__mocks__/foremanReact/routes/common/PageLayout/PageLayout.js +10 -0
- data/webpack/index.js +0 -0
- data/webpack/routes_index.js +4 -0
- metadata +195 -0
@@ -0,0 +1,59 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class WebhookTemplate < Template
|
4
|
+
audited
|
5
|
+
|
6
|
+
include Authorizable
|
7
|
+
extend FriendlyId
|
8
|
+
friendly_id :name
|
9
|
+
include Parameterizable::ByIdName
|
10
|
+
|
11
|
+
class << self
|
12
|
+
# we have to override the base_class because polymorphic associations does not detect it correctly, more details at
|
13
|
+
# http://apidock.com/rails/ActiveRecord/Associations/ClassMethods/has_many#1010-Polymorphic-has-many-within-inherited-class-gotcha
|
14
|
+
def base_class
|
15
|
+
self
|
16
|
+
end
|
17
|
+
end
|
18
|
+
self.table_name = 'templates'
|
19
|
+
|
20
|
+
before_destroy EnsureNotUsedBy.new(:webhooks)
|
21
|
+
has_many :webhooks, foreign_key: :webhook_template_id
|
22
|
+
|
23
|
+
validates :name, uniqueness: true
|
24
|
+
|
25
|
+
include Taxonomix
|
26
|
+
scoped_search on: :name, complete_value: true, default_order: true
|
27
|
+
scoped_search on: :locked, complete_value: { true: true, false: false }
|
28
|
+
scoped_search on: :snippet, complete_value: { true: true, false: false }
|
29
|
+
scoped_search on: :template
|
30
|
+
scoped_search on: :default, only_explicit: true, complete_value: { true: true, false: false }
|
31
|
+
|
32
|
+
# with proc support, default_scope can no longer be chained
|
33
|
+
# include all default scoping here
|
34
|
+
default_scope lambda {
|
35
|
+
with_taxonomy_scope do
|
36
|
+
order("#{Template.table_name}.name")
|
37
|
+
end
|
38
|
+
}
|
39
|
+
|
40
|
+
def self.default_render_scope_class
|
41
|
+
ForemanWebhooks::Renderer::Scope::WebhookTemplate
|
42
|
+
end
|
43
|
+
|
44
|
+
def taxonomy_foreign_conditions
|
45
|
+
{ webhook_template_id: id }
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.acceptable_template_input_types
|
49
|
+
[:user]
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.log_render_results?
|
53
|
+
true
|
54
|
+
end
|
55
|
+
|
56
|
+
def support_single_host_render?
|
57
|
+
false
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ForemanWebhooks
|
4
|
+
class WebhookService
|
5
|
+
attr_accessor :webhook, :event_name, :payload, :rendered_headers, :rendered_url
|
6
|
+
|
7
|
+
delegate :logger, to: Rails
|
8
|
+
|
9
|
+
def initialize(webhook:, event_name:, payload:, headers:, url:)
|
10
|
+
@webhook = webhook
|
11
|
+
@event_name = event_name
|
12
|
+
@payload = payload
|
13
|
+
@rendered_headers = headers
|
14
|
+
@rendered_url = url
|
15
|
+
end
|
16
|
+
|
17
|
+
def execute
|
18
|
+
logger.info("Performing '#{webhook.name}' webhook request for event '#{event_name}'")
|
19
|
+
Foreman::Logging.blob("Payload for '#{event_name}'", payload)
|
20
|
+
headers = {}
|
21
|
+
begin
|
22
|
+
headers = JSON.parse(rendered_headers)
|
23
|
+
rescue StandardError => e
|
24
|
+
logger.warn("Could not parse HTTP headers JSON, ignoring: #{e}")
|
25
|
+
logger.debug("Headers: #{rendered_headers}")
|
26
|
+
end
|
27
|
+
|
28
|
+
response = self.class.request(url: webhook.target_url,
|
29
|
+
payload: payload,
|
30
|
+
http_method: webhook.http_method,
|
31
|
+
user: webhook.user,
|
32
|
+
password: webhook.password,
|
33
|
+
content_type: webhook.http_content_type,
|
34
|
+
headers: headers,
|
35
|
+
ca_verify: webhook.verify_ssl?,
|
36
|
+
ca_string: webhook.ca_certs_store,
|
37
|
+
follow_redirects: true)
|
38
|
+
|
39
|
+
status = case response.code.to_i
|
40
|
+
when 400..599
|
41
|
+
logger.error("#{webhook.http_method.to_s.upcase} response was #{response.code}")
|
42
|
+
:error
|
43
|
+
else
|
44
|
+
logger.info("#{webhook.http_method.to_s.upcase} response was #{response.code}")
|
45
|
+
:success
|
46
|
+
end
|
47
|
+
|
48
|
+
{
|
49
|
+
status: status,
|
50
|
+
message: response.message,
|
51
|
+
http_status: response.code.to_i
|
52
|
+
}
|
53
|
+
rescue SocketError, OpenSSL::SSL::SSLError, Errno::ECONNREFUSED, Errno::ECONNRESET, Errno::EHOSTUNREACH, Net::OpenTimeout, Net::ReadTimeout => e
|
54
|
+
Foreman::Logging.exception("Failed to execute the webhook #{webhook.name} -> #{event_name}", e)
|
55
|
+
{
|
56
|
+
status: :error,
|
57
|
+
message: e.to_s
|
58
|
+
}
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.request(url:, payload: '', http_method: :GET, user: nil, password: nil, content_type: 'application/json', headers: {}, ca_string: nil, ca_verify: false, follow_redirects: true, redirect_limit: 3)
|
62
|
+
uri = URI.parse(url)
|
63
|
+
|
64
|
+
request = Object.const_get("Net::HTTP::#{http_method.to_s.capitalize}").new(uri.request_uri)
|
65
|
+
request.basic_auth(user, password) if user && password
|
66
|
+
request['Content-Type'] = content_type
|
67
|
+
request['X-Request-Id'] = ::Logging.mdc['request'] || SecureRandom.uuid
|
68
|
+
request['X-Session-Id'] = ::Logging.mdc['session'] || SecureRandom.uuid
|
69
|
+
headers.each_pair do |key, value|
|
70
|
+
request[key.to_s] = value.to_s
|
71
|
+
end
|
72
|
+
request.body = payload
|
73
|
+
|
74
|
+
Rails.logger.debug("Webhook #{http_method.to_s.upcase} request: #{uri}")
|
75
|
+
Rails.logger.debug("Headers: #{request.to_hash.inspect}")
|
76
|
+
Rails.logger.debug("Body: #{request.body.inspect}")
|
77
|
+
|
78
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
79
|
+
http.open_timeout = Setting[:proxy_request_timeout]
|
80
|
+
http.read_timeout = Setting[:proxy_request_timeout]
|
81
|
+
http.ssl_timeout = Setting[:proxy_request_timeout]
|
82
|
+
if uri.scheme == 'https'
|
83
|
+
http.use_ssl = true
|
84
|
+
http.verify_mode = ca_verify ? OpenSSL::SSL::VERIFY_PEER : OpenSSL::SSL::VERIFY_NONE
|
85
|
+
http.cert_store = ca_string if ca_string
|
86
|
+
end
|
87
|
+
http.request(request) do |response|
|
88
|
+
case response
|
89
|
+
when Net::HTTPRedirection then
|
90
|
+
new_location = response['location']
|
91
|
+
Rails.logger.debug "Redirected to #{new_location} (redirects left: #{redirect_limit})"
|
92
|
+
raise(::Foreman::Exception, N_(format('Too many HTTP redirects when calling %{uri}', uri: uri, code: response.code))) if redirect_limit <= 0
|
93
|
+
|
94
|
+
self.request(url: new_location,
|
95
|
+
payload: payload,
|
96
|
+
http_method: http_method,
|
97
|
+
user: user,
|
98
|
+
password: password,
|
99
|
+
content_type: content_type,
|
100
|
+
ca_string: ca_string,
|
101
|
+
ca_verify: ca_verify,
|
102
|
+
headers: headers,
|
103
|
+
follow_redirects: follow_redirects,
|
104
|
+
redirect_limit: redirect_limit - 1)
|
105
|
+
else
|
106
|
+
response
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
object @webhook_template
|
4
|
+
|
5
|
+
extends 'api/v2/webhook_templates/main'
|
6
|
+
|
7
|
+
attributes :template, :default, :snippet, :locked
|
8
|
+
|
9
|
+
node do |webhook_template|
|
10
|
+
partial('api/v2/taxonomies/children_nodes', object: webhook_template)
|
11
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
object @webhook
|
4
|
+
|
5
|
+
extends 'api/v2/webhooks/main'
|
6
|
+
|
7
|
+
attributes :target_url,
|
8
|
+
:event,
|
9
|
+
:http_method,
|
10
|
+
:http_content_type,
|
11
|
+
:enabled,
|
12
|
+
:verify_ssl,
|
13
|
+
:http_headers
|
14
|
+
|
15
|
+
child :webhook_template do
|
16
|
+
extends 'api/v2/webhook_templates/base'
|
17
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
<%#
|
2
|
+
name: Ansible Tower - Host in Inventory
|
3
|
+
description: Create/update a host with associated inventory in Ansible Tower.
|
4
|
+
snippet: false
|
5
|
+
model: WebhookTemplate
|
6
|
+
-%>
|
7
|
+
<%#
|
8
|
+
Create URL: https://tower/api/v2/hosts
|
9
|
+
Update/Delete URL: https://tower/api/v2/hosts/$HOST_ID
|
10
|
+
-%>
|
11
|
+
<%=
|
12
|
+
payload({
|
13
|
+
"name": @object.name,
|
14
|
+
"description": "Created via Foreman Webhook",
|
15
|
+
"inventory": @object.host_param('ansible_tower_inventory_id') || 1,
|
16
|
+
"enabled": true,
|
17
|
+
"instance_id": "",
|
18
|
+
"variables": ""
|
19
|
+
}, with_defaults: false)
|
20
|
+
-%>
|
@@ -0,0 +1 @@
|
|
1
|
+
<li><a href='#template_type' data-toggle='tab'><%= _('Type') %></a></li>
|
@@ -0,0 +1,29 @@
|
|
1
|
+
<% title _('Webhook Templates') %>
|
2
|
+
|
3
|
+
<% title_actions new_link(_('Create Template')) %>
|
4
|
+
|
5
|
+
<table class="<%= table_css_classes 'table-fixed' %>">
|
6
|
+
<thead>
|
7
|
+
<tr>
|
8
|
+
<th class="col-md-3"><%= sort :name, as: s_('WebhookTemplate|Name') %></th>
|
9
|
+
<th class="col-md-1"><%= sort :snippet, as: s_('WebhookTemplate|Snippet') %></th>
|
10
|
+
<th class="col-md-1"><%= sort :locked, as: s_('WebhookTemplate|Locked'), default: 'DESC' %></th>
|
11
|
+
<th class="col-md-1"><%= _('Actions') %></th>
|
12
|
+
</tr>
|
13
|
+
</thead>
|
14
|
+
<tbody>
|
15
|
+
<% for webhook_template in @templates %>
|
16
|
+
<tr>
|
17
|
+
<td class="ellipsis"><%= link_to_if_authorized webhook_template,
|
18
|
+
hash_for_edit_webhook_template_path(id: webhook_template.to_param).
|
19
|
+
merge(auth_object: webhook_template, authorizer: authorizer, permission: 'edit_webhook_templates') %>
|
20
|
+
</td>
|
21
|
+
<td align='center'><%= checked_icon webhook_template.snippet %></td>
|
22
|
+
<td align='center'><%= locked_icon webhook_template.locked?, _('This template is locked for editing.') %>
|
23
|
+
</td>
|
24
|
+
<td><%= action_buttons(*permitted_actions(webhook_template)) %></td>
|
25
|
+
</tr>
|
26
|
+
<% end %>
|
27
|
+
</tbody>
|
28
|
+
</table>
|
29
|
+
<%= will_paginate_with_info @templates %>
|
@@ -0,0 +1,37 @@
|
|
1
|
+
<%= form_for @webhook, url: (@webhook.new_record? ? webhooks_path : webhook_path(id: @webhook)) do |f| %>
|
2
|
+
<%= base_errors_for @webhook %>
|
3
|
+
<%= text_f f, :name %>
|
4
|
+
<%= text_f f, :target_url, help_inline: _('Target URL that should be called by Foreman') %>
|
5
|
+
|
6
|
+
<%= text_f f, :user, help_block: _('Authentication credentials') %>
|
7
|
+
<%= password_f f, :password, keep_value: true %>
|
8
|
+
|
9
|
+
<%= selectable_f f, :http_method, Webhook::ALLOWED_HTTP_METHODS,
|
10
|
+
{ include_blank: false,
|
11
|
+
selected: @webhook.http_method },
|
12
|
+
{ label: _('HTTP Method'),
|
13
|
+
label_help: _(f.object.try(:description)),
|
14
|
+
required: true } %>
|
15
|
+
<%= text_f f, :http_content_type %>
|
16
|
+
|
17
|
+
<%= render('templates', f: f) %>
|
18
|
+
|
19
|
+
<%= selectable_f f, :event, Webhook.available_events.sort.map { |e| e.delete_suffix(Webhook::EVENT_POSTFIX) },
|
20
|
+
{ include_blank: false,
|
21
|
+
selected: @webhook.event&.delete_suffix(Webhook::EVENT_POSTFIX) },
|
22
|
+
{ label: _('Subscribe to'),
|
23
|
+
label_help: _(f.object.try(:description)),
|
24
|
+
required: true } %>
|
25
|
+
|
26
|
+
<%= checkbox_f f, :enabled, help_inline: _('If unchecked, the webhook will be inactive') %>
|
27
|
+
<%= checkbox_f f, :verify_ssl, help_inline: _("Uncheck this option to disable validation of the receiver's SSL certificate") %>
|
28
|
+
<%= textarea_f f, :ssl_ca_certs, label: _('X509 Certification Authorities'),
|
29
|
+
size: 'col-md-8', rows: 10,
|
30
|
+
placeholder: _("Optional CAs in PEM format concatenated to verify the receiver's SSL certificate.") %>
|
31
|
+
|
32
|
+
<%= textarea_f f, :http_headers, label: _('Optional HTTP headers as JSON (ERB allowed)'),
|
33
|
+
size: 'col-md-8', rows: 6,
|
34
|
+
placeholder: "{\n\"X-Shellhook-Arg-1\": \"value\"\n}" %>
|
35
|
+
|
36
|
+
<%= submit_or_cancel(f, false, { react_cancel_button: true, cancel_path: '/webhooks' }) %>
|
37
|
+
<% end %>
|
data/config/routes.rb
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
Rails.application.routes.draw do
|
4
|
+
resources :webhooks, except: %i[index show] do
|
5
|
+
collection do
|
6
|
+
get 'auto_complete_search'
|
7
|
+
end
|
8
|
+
end
|
9
|
+
match '/webhooks' => 'react#index', via: :get
|
10
|
+
|
11
|
+
namespace :api, defaults: { format: 'json' } do
|
12
|
+
scope '(:apiv)',
|
13
|
+
module: :v2,
|
14
|
+
defaults: { apiv: 'v2' },
|
15
|
+
apiv: /v1|v2/,
|
16
|
+
constraints: ApiConstraints.new(version: 2, default: true) do
|
17
|
+
resources :webhooks, only: %i[index show create update destroy]
|
18
|
+
resources :webhook_templates, except: %i[new edit] do
|
19
|
+
member do
|
20
|
+
post :clone
|
21
|
+
get :export
|
22
|
+
end
|
23
|
+
collection do
|
24
|
+
post :import
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
scope 'templates' do
|
31
|
+
resources :webhook_templates, except: :show do
|
32
|
+
member do
|
33
|
+
get 'clone_template'
|
34
|
+
get 'lock'
|
35
|
+
get 'unlock'
|
36
|
+
get 'export'
|
37
|
+
post 'preview'
|
38
|
+
end
|
39
|
+
collection do
|
40
|
+
post 'preview'
|
41
|
+
get 'auto_complete_search'
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|