Browse Source

Fixes #4483 - Custom payload for webhooks.

Co-authored-by: Dominik Klein <dk@zammad.com>
Co-authored-by: Tobias Schäfer <ts@zammad.com>
Co-authored-by: Florian Liebe <fl@zammad.com>
Florian Liebe 1 year ago
parent
commit
16ae0ea5d1

+ 0 - 1
.rubocop/todo.rspec.yml

@@ -45,7 +45,6 @@ RSpec/ContextWording:
     - 'spec/lib/ldap/user_spec.rb'
     - 'spec/lib/ldap_spec.rb'
     - 'spec/lib/notification_factory/mailer_spec.rb'
-    - 'spec/lib/notification_factory/slack_spec.rb'
     - 'spec/lib/notification_factory/template_spec.rb'
     - 'spec/lib/notification_factory_spec.rb'
     - 'spec/lib/password_hash_spec.rb'

+ 0 - 1
.rubocop/todo.yml

@@ -287,7 +287,6 @@ Metrics/AbcSize:
     - 'lib/models.rb'
     - 'lib/notification_factory/mailer.rb'
     - 'lib/notification_factory/renderer.rb'
-    - 'lib/notification_factory/slack.rb'
     - 'lib/push_messages.rb'
     - 'lib/report/article_by_type_sender.rb'
     - 'lib/report/base.rb'

+ 17 - 15
app/assets/javascripts/app/controllers/_application_controller/_generic_index.coffee

@@ -169,26 +169,28 @@ class App.ControllerGenericIndex extends App.Controller
       return
 
     new App.ControllerGenericEdit(
-      id:            item.id
-      pageData:      @pageData
-      genericObject: @genericObject
-      container:     @container
-      small:         @small
-      large:         @large
-      veryLarge:     @veryLarge
-      handlers:      @handlers
+      id:               item.id
+      pageData:         @pageData
+      genericObject:    @genericObject
+      container:        @container
+      small:            @small
+      large:            @large
+      veryLarge:        @veryLarge
+      handlers:         @handlers
+      validateOnSubmit: @validateOnSubmit
     )
 
   new: (e) ->
     e.preventDefault()
     new App.ControllerGenericNew(
-      pageData:      @pageData
-      genericObject: @genericObject
-      container:     @container
-      small:         @small
-      large:         @large
-      veryLarge:     @veryLarge
-      handlers:      @handlers
+      pageData:         @pageData
+      genericObject:    @genericObject
+      container:        @container
+      small:            @small
+      large:            @large
+      veryLarge:        @veryLarge
+      handlers:         @handlers
+      validateOnSubmit: @validateOnSubmit
     )
 
   payload: (e) ->

+ 5 - 1
app/assets/javascripts/app/controllers/_application_controller/_modal_generic_edit.coffee

@@ -30,7 +30,11 @@ class App.ControllerGenericEdit extends App.ControllerModal
     errors = @item.validate(
       controllerForm: @controller
     )
-    if errors
+
+    if @validateOnSubmit
+      errors = Object.assign({}, errors, @validateOnSubmit(params))
+
+    if !_.isEmpty(errors)
       @log 'error', errors
       @formValidate( form: e.target, errors: errors )
       return false

+ 5 - 1
app/assets/javascripts/app/controllers/_application_controller/_modal_generic_new.coffee

@@ -31,7 +31,11 @@ class App.ControllerGenericNew extends App.ControllerModal
     errors = object.validate(
       controllerForm: @controller
     )
-    if errors
+
+    if @validateOnSubmit
+      errors = Object.assign({}, errors, @validateOnSubmit(params))
+
+    if !_.isEmpty(errors)
       @log 'error', errors
       @formValidate( form: e.target, errors: errors )
       return false

+ 9 - 2
app/assets/javascripts/app/controllers/_ui_element/textarea.coffee

@@ -6,10 +6,17 @@ class App.UiElement.textarea
     if attribute.rows is undefined
       attribute.rows = 4
 
-    fileUploaderId = 'file-uploader-' + new Date().getTime() + '-' + Math.floor( Math.random() * 99999 )
-    item = $( App.view('generic/textarea')( attribute: attribute ) + '<div class="file-uploader ' + attribute.class + '" id="' + fileUploaderId + '"></div>' )
+    item = $( App.view('generic/textarea')( attribute: attribute ) )
+
+    if attribute.collapsible
+      collapseClasses= 'panel-collapse collapse'
+      if !_.isEmpty(attribute.value)
+        collapseClasses += ' in'
+      item = $('<div id="collapse-' + attribute.id + '" class="' + collapseClasses + '">').append(item)
 
     if attribute.upload
+      fileUploaderId = 'file-uploader-' + new Date().getTime() + '-' + Math.floor( Math.random() * 99999 )
+      item.append('<div class="file-uploader ' + attribute.class + '" id="' + fileUploaderId + '"></div>')
 
       # add file uploader
       u = ->

+ 18 - 0
app/assets/javascripts/app/controllers/webhook.coffee

@@ -29,6 +29,7 @@ class Index extends App.ControllerSubContent
       payloadExampleUrl: '/api/v1/webhooks/preview'
       container: @el.closest('.content')
       veryLarge: true
+      validateOnSubmit: @validateOnSubmit
     )
 
   show: (params) =>
@@ -38,4 +39,21 @@ class Index extends App.ControllerSubContent
 
     @genericController.paginate( @page || 1 )
 
+  validateOnSubmit: (params) ->
+    return if params['custom_payload'] is undefined
+
+    errors = {}
+
+    isError = false
+    try
+      if(!_.isObject(JSON.parse(params['custom_payload'])))
+        isError = true
+    catch e
+      isError = true
+
+    if isError
+      errors['custom_payload'] = __('Please enter a valid JSON string.')
+
+    errors
+
 App.Config.set('Webhook', { prio: 3350, name: __('Webhook'), parent: '#manage', target: '#manage/webhook', controller: Index, permission: ['admin.webhook'] }, 'NavBarAdmin')

+ 2 - 1
app/assets/javascripts/app/models/webhook.coffee

@@ -1,5 +1,5 @@
 class App.Webhook extends App.Model
-  @configure 'Webhook', 'name', 'endpoint', 'signature_token', 'ssl_verify', 'basic_auth_username', 'basic_auth_password', 'note', 'active'
+  @configure 'Webhook', 'name', 'endpoint', 'signature_token', 'ssl_verify', 'basic_auth_username', 'basic_auth_password', 'custom_payload', 'note', 'active'
   @extend Spine.Model.Ajax
   @url: @apiPath + '/webhooks'
   @configure_attributes = [
@@ -9,6 +9,7 @@ class App.Webhook extends App.Model
     { name: 'ssl_verify',       display: __('SSL Verify'),                tag: 'boolean',   null: true, translate: true, options: { true: 'yes', false: 'no'  }, default: true },
     { name: 'basic_auth_username', display: __('HTTP Basic Authentication Username'), tag: 'input', type: 'text', limit: 250, null: true, item_class: 'formGroup--halfSize' },
     { name: 'basic_auth_password', display: __('HTTP Basic Authentication Password'), tag: 'input', type: 'text', limit: 250, null: true, item_class: 'formGroup--halfSize' },
+    { name: 'custom_payload',   display: __('Custom Payload'),            tag: 'textarea', rows: 6, null: true, collapsible: true },
     { name: 'note',             display: __('Note'),                      tag: 'textarea', note: '', limit: 250, null: true },
     { name: 'active',           display: __('Active'),                    tag: 'active',    default: true },
     { name: 'updated_at',       display: __('Updated'),                   tag: 'datetime',  readonly: 1 },

+ 12 - 1
app/assets/javascripts/app/views/generic/attribute.jst.eco

@@ -3,7 +3,18 @@
   <h2>
   <% end %>
   <div class="formGroup-label">
-    <label for="<%= @attribute.id %>"<% if @attribute.label_class: %> class="<%= @attribute.label_class %>"<% end %>><%- @T(@attribute.display) %> <span><% if !@attribute.null: %>*<% end %></span></label>
+    <% if @attribute.collapsible: %>
+      <a data-toggle="collapse" href="#collapse-<%= @attribute.id %>"<% if _.isEmpty(@attribute.value): %> class="collapsed"<% end %>>
+    <% end %>
+    <label for="<%= @attribute.id %>"<% if @attribute.label_class: %> class="<%= @attribute.label_class %>"<% end %>>
+      <% if @attribute.collapsible: %>
+      <%- @Icon('arrow-right') %>
+      <%- @Icon('arrow-down') %>
+      <% end %>
+      <%- @T(@attribute.display) %>
+      <span><% if !@attribute.null: %>*<% end %></span>
+    </label>
+    <% if @attribute.collapsible: %></a><% end %>
     <%- @item %>
     <% if @bookmarkable: %>
     <div class="align-right js-bookmark formGroup-bookmark">

+ 36 - 0
app/assets/stylesheets/zammad.scss

@@ -2127,6 +2127,42 @@ fieldset > .form-group {
     margin: 0;
   }
 
+  a[data-toggle='collapse'] > label {
+    cursor: pointer;
+    color: var(--text-link);
+  }
+
+  a[data-toggle='collapse'] {
+    &:focus,
+    &:active {
+      text-decoration: underline;
+    }
+
+    &.collapsed {
+      & svg {
+        &.icon-arrow-right {
+          display: inline;
+        }
+
+        &.icon-arrow-down {
+          display: none;
+        }
+      }
+    }
+
+    &:not(.collapsed) {
+      & svg {
+        &.icon-arrow-right {
+          display: none;
+        }
+
+        &.icon-arrow-down {
+          display: inline;
+        }
+      }
+    }
+  }
+
   .bookmark.icon {
     margin-bottom: -1px;
   }

Some files were not shown because too many files changed in this diff