diff --git a/app/assets/javascripts/app/controllers/monitoring.coffee b/app/assets/javascripts/app/controllers/monitoring.coffee
new file mode 100644
index 000000000..5850e8102
--- /dev/null
+++ b/app/assets/javascripts/app/controllers/monitoring.coffee
@@ -0,0 +1,47 @@
+class Index extends App.ControllerSubContent
+ requiredPermission: 'admin.monitoring'
+ header: 'Monitoring'
+ events:
+ 'click .js-resetToken': 'resetToken'
+ 'click .js-select': 'selectAll'
+
+ constructor: ->
+ super
+ @load()
+ @interval(
+ =>
+ @load()
+ 35000
+ )
+
+ # fetch data, render view
+ load: ->
+ @startLoading()
+ @ajax(
+ id: 'health_check'
+ type: 'GET'
+ url: "#{@apiPath}/monitoring/health_check"
+ success: (data) =>
+ @stopLoading()
+ console.log('111', data, @data)
+ return if @data && data.token is @data.token && data.healthy is @data.healthy && data.message is @data.message
+ console.log('222')
+ @data = data
+ @render()
+ )
+
+ render: =>
+ @html App.view('monitoring')(data: @data)
+
+ resetToken: (e) =>
+ e.preventDefault()
+ @formDisable(e)
+ @ajax(
+ id: 'health_check_token'
+ type: 'POST'
+ url: "#{@apiPath}/monitoring/token"
+ success: (data) =>
+ @load()
+ )
+
+App.Config.set('Monitoring', { prio: 3600, name: 'Monitoring', parent: '#system', target: '#system/monitoring', controller: Index, permission: ['admin.monitoring'] }, 'NavBarAdmin')
diff --git a/app/assets/javascripts/app/controllers/package.coffee b/app/assets/javascripts/app/controllers/package.coffee
index 00d9702a0..8f7bb7af0 100644
--- a/app/assets/javascripts/app/controllers/package.coffee
+++ b/app/assets/javascripts/app/controllers/package.coffee
@@ -54,4 +54,4 @@ class Index extends App.ControllerSubContent
@load()
)
-App.Config.set('Packages', { prio: 3600, name: 'Packages', parent: '#system', target: '#system/package', controller: Index, permission: ['admin.package'] }, 'NavBarAdmin')
+App.Config.set('Packages', { prio: 3700, name: 'Packages', parent: '#system', target: '#system/package', controller: Index, permission: ['admin.package'] }, 'NavBarAdmin')
diff --git a/app/assets/javascripts/app/views/monitoring.jst.eco b/app/assets/javascripts/app/views/monitoring.jst.eco
new file mode 100644
index 000000000..053c128ed
--- /dev/null
+++ b/app/assets/javascripts/app/views/monitoring.jst.eco
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+
+
+
+
+
+
<%- @T('Health information can be retrieved as JSON using') %>:
+
+
+
+
+
+
+ <% if _.isEmpty(@data.issues): %>
+ - <%- @T('no issues') %>
+ <% else: %>
+ <% for issue in @data.issues: %>
+
- <%= issue %>
+ <% end %>
+ <% end %>
+
+
+
+
\ No newline at end of file
diff --git a/app/controllers/monitoring_controller.rb b/app/controllers/monitoring_controller.rb
new file mode 100644
index 000000000..1fa9c3bdc
--- /dev/null
+++ b/app/controllers/monitoring_controller.rb
@@ -0,0 +1,182 @@
+# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
+
+class MonitoringController < ApplicationController
+ before_action -> { authentication_check(permission: 'admin.monitoring') }, except: [:health_check, :status]
+
+=begin
+
+Resource:
+GET /api/v1/monitoring/health_check?token=XXX
+
+Response:
+{
+ "healthy": true,
+ "message": "success",
+}
+
+{
+ "healthy": false,
+ "message": "authentication of XXX failed; issue #2",
+ "issues": ["authentication of XXX failed", "issue #2"],
+}
+
+Test:
+curl http://localhost/api/v1/monitoring/health_check?token=XXX
+
+=end
+
+ def health_check
+ token_or_permission_check
+
+ issues = []
+
+ # channel check
+ Channel.where(active: true).each { |channel|
+ next if (channel.status_in.empty? || channel.status_in == 'ok') && (channel.status_out.empty? || channel.status_out == 'ok')
+ if channel.status_in == 'error'
+ message = "Channel: #{channel.area} in "
+ %w(host user uid).each { |key|
+ next if !channel.options[key] || channel.options[key].empty?
+ message += "key:#{channel.options[key]};"
+ }
+ issues.push "#{message} #{channel.last_log_in}"
+ end
+ next if channel.status_out != 'error'
+ message = "Channel: #{channel.area} out "
+ %w(host user uid).each { |key|
+ next if !channel.options[key] || channel.options[key].empty?
+ message += "key:#{channel.options[key]};"
+ }
+ issues.push "#{message} #{channel.last_log_out}"
+ }
+
+ # unprocessable mail check
+ directory = "#{Rails.root}/tmp/unprocessable_mail"
+ if File.exist?(directory)
+ count = 0
+ Dir.glob("#{directory}/*.eml") { |_entry|
+ count += 1
+ }
+ if count.nonzero?
+ issues.push "unprocessable mails: #{count}"
+ end
+ end
+
+ # scheduler check
+ Scheduler.where(active: true).where.not(last_run: nil).each { |scheduler|
+ next if scheduler.period <= 300
+ next if scheduler.last_run + scheduler.period.seconds > Time.zone.now - 5.minutes
+ issues.push 'scheduler not running'
+ break
+ }
+ if Scheduler.where(active: true, last_run: nil).count == Scheduler.where(active: true).count
+ issues.push 'scheduler not running'
+ end
+
+ token = Setting.get('monitoring_token')
+
+ if issues.empty?
+ result = {
+ healthy: true,
+ message: 'success',
+ token: token,
+ }
+ render json: result
+ return
+ end
+
+ result = {
+ healthy: false,
+ message: issues.join(';'),
+ issues: issues,
+ token: token,
+ }
+ render json: result
+ end
+
+=begin
+
+Resource:
+GET /api/v1/monitoring/status?token=XXX
+
+Response:
+{
+ "agents": 8123,
+ "last_login": "2016-11-21T14:14:14Z",
+ "counts": {
+ "users": 12313,
+ "tickets": 23123,
+ "ticket_articles": 131451,
+ },
+ "last_created_at": {
+ "users": "2016-11-21T14:14:14Z",
+ "tickets": "2016-11-21T14:14:14Z",
+ "ticket_articles": "2016-11-21T14:14:14Z",
+ },
+}
+
+Test:
+curl http://localhost/api/v1/monitoring/status?token=XXX
+
+=end
+
+ def status
+ token_or_permission_check
+
+ last_login = nil
+ last_login_user = User.where('last_login IS NOT NULL').order(last_login: :desc).limit(1).first
+ if last_login_user
+ last_login = last_login_user.last_login
+ end
+
+ status = {
+ counts: {},
+ last_created_at: {},
+ last_login: last_login,
+ agents: User.with_permissions('ticket.agent').count,
+ }
+
+ map = {
+ users: User,
+ groups: Group,
+ overviews: Overview,
+ tickets: Ticket,
+ ticket_articles: Ticket::Article,
+ }
+ map.each { |key, class_name|
+ status[:counts][key] = class_name.count
+ last = class_name.last
+ status[:last_created_at][key] = if last
+ last.created_at
+ end
+ }
+
+ render json: status
+ end
+
+ def token
+ access_check
+ token = SecureRandom.urlsafe_base64(40)
+ Setting.set('monitoring_token', token)
+
+ result = {
+ token: token,
+ }
+ render json: result, status: :created
+ end
+
+ private
+
+ def token_or_permission_check
+ user = authentication_check_only(permission: 'admin.monitoring')
+ return if user
+ return if Setting.get('monitoring_token') == params[:token]
+ raise Exceptions::NotAuthorized
+ end
+
+ def access_check
+ return if Permission.find_by(name: 'admin.monitoring', active: true)
+ raise Exceptions::NotAuthorized
+ end
+
+end
diff --git a/app/models/channel/email_build.rb b/app/models/channel/email_build.rb
index 540ae4763..31eb5f60d 100644
--- a/app/models/channel/email_build.rb
+++ b/app/models/channel/email_build.rb
@@ -32,8 +32,8 @@ module Channel::EmailBuild
attr['X-Auto-Response-Suppress'] = 'All'
end
- #attr['X-Powered-BY'] = 'Zammad - Support/Helpdesk (http://www.zammad.org/)'
- attr['X-Mailer'] = 'Zammad Mail Service (1.x)'
+ attr['X-Powered-By'] = 'Zammad - Helpdesk/Support (https://zammad.org/)'
+ attr['X-Mailer'] = 'Zammad Mail Service'
# set headers
attr.each do |key, value|
diff --git a/app/models/channel/filter/auto_response_check.rb b/app/models/channel/filter/auto_response_check.rb
index c6481beca..588094802 100644
--- a/app/models/channel/filter/auto_response_check.rb
+++ b/app/models/channel/filter/auto_response_check.rb
@@ -14,11 +14,20 @@ module Channel::Filter::AutoResponseCheck
mail[ 'x-zammad-article-preferences'.to_sym ]['send-auto-response'] = false
mail[ 'x-zammad-article-preferences'.to_sym ]['is-auto-response'] = true
+ # do not send an auto respondse if one of the following headers exists
+ return if mail[ 'list-unsubscribe'.to_sym ] && mail[ 'list-unsubscribe'.to_sym ] =~ /.../
return if mail[ 'x-loop'.to_sym ] && mail[ 'x-loop'.to_sym ] =~ /(yes|true)/i
return if mail[ 'precedence'.to_sym ] && mail[ 'precedence'.to_sym ] =~ /(bulk|list|junk)/i
return if mail[ 'auto-submitted'.to_sym ] && mail[ 'auto-submitted'.to_sym ] =~ /auto-(generated|replied)/i
return if mail[ 'x-auto-response-suppress'.to_sym ] && mail[ 'x-auto-response-suppress'.to_sym ] =~ /all/i
+ # do not send an auto respondse if sender is system it self
+ message_id = mail[ 'message_id'.to_sym ]
+ if message_id
+ fqdn = Setting.get('fqdn')
+ return if message_id =~ /@#{Regexp.quote(fqdn)}/i
+ end
+
mail[ 'x-zammad-send-auto-response'.to_sym ] = true
mail[ 'x-zammad-is-auto-response'.to_sym ] = false
diff --git a/config/routes/monitoring.rb b/config/routes/monitoring.rb
new file mode 100644
index 000000000..18f2e6c93
--- /dev/null
+++ b/config/routes/monitoring.rb
@@ -0,0 +1,8 @@
+Zammad::Application.routes.draw do
+ api_path = Rails.configuration.api_path
+
+ match api_path + '/monitoring/health_check', to: 'monitoring#health_check', via: :get
+ match api_path + '/monitoring/status', to: 'monitoring#status', via: :get
+ match api_path + '/monitoring/token', to: 'monitoring#token', via: :post
+
+end
diff --git a/db/migrate/20161122000001_monitoring_issue_453.rb b/db/migrate/20161122000001_monitoring_issue_453.rb
new file mode 100644
index 000000000..769ea181f
--- /dev/null
+++ b/db/migrate/20161122000001_monitoring_issue_453.rb
@@ -0,0 +1,37 @@
+class MonitoringIssue453 < ActiveRecord::Migration
+ def up
+ # return if it's a new setup
+ return if !Setting.find_by(name: 'system_init_done')
+
+ Setting.create_if_not_exists(
+ title: 'Monitoring Token',
+ name: 'monitoring_token',
+ area: 'HealthCheck::Base',
+ description: 'Token for Monitoring.',
+ options: {
+ form: [
+ {
+ display: '',
+ null: false,
+ name: 'monitoring_token',
+ tag: 'input',
+ },
+ ],
+ },
+ state: SecureRandom.urlsafe_base64(40),
+ preferences: {
+ permission: ['admin.monitoring'],
+ },
+ frontend: false,
+ )
+
+ Permission.create_if_not_exists(
+ name: 'admin.monitoring',
+ note: 'Manage %s',
+ preferences: {
+ translations: ['Monitoring']
+ },
+ )
+
+ end
+end
diff --git a/db/seeds.rb b/db/seeds.rb
index b584368de..5762b971d 100644
--- a/db/seeds.rb
+++ b/db/seeds.rb
@@ -1575,7 +1575,7 @@ Setting.create_if_not_exists(
frontend: false
)
-Setting.create_or_update(
+Setting.create_if_not_exists(
title: 'API Token Access',
name: 'api_token_access',
area: 'API::Base',
@@ -1600,7 +1600,7 @@ Setting.create_or_update(
},
frontend: false
)
-Setting.create_or_update(
+Setting.create_if_not_exists(
title: 'API Password Access',
name: 'api_password_access',
area: 'API::Base',
@@ -1626,6 +1626,28 @@ Setting.create_or_update(
frontend: false
)
+Setting.create_if_not_exists(
+ title: 'Monitoring Token',
+ name: 'monitoring_token',
+ area: 'HealthCheck::Base',
+ description: 'Token for Monitoring.',
+ options: {
+ form: [
+ {
+ display: '',
+ null: false,
+ name: 'monitoring_token',
+ tag: 'input',
+ },
+ ],
+ },
+ state: SecureRandom.urlsafe_base64(40),
+ preferences: {
+ permission: ['admin.monitoring'],
+ },
+ frontend: false
+)
+
Setting.create_if_not_exists(
title: 'Enable Chat',
name: 'chat',
@@ -2765,6 +2787,13 @@ Permission.create_if_not_exists(
translations: ['Translations']
},
)
+Permission.create_if_not_exists(
+ name: 'admin.monitoring',
+ note: 'Manage %s',
+ preferences: {
+ translations: ['Monitoring']
+ },
+)
Permission.create_if_not_exists(
name: 'admin.maintenance',
note: 'Manage %s',
diff --git a/script/build/test_slice_tests.sh b/script/build/test_slice_tests.sh
index 5020c3220..6d5c0e79d 100755
--- a/script/build/test_slice_tests.sh
+++ b/script/build/test_slice_tests.sh
@@ -47,6 +47,8 @@ if [ "$LEVEL" == '1' ]; then
# test/browser/maintenance_login_message_test.rb
# test/browser/maintenance_mode_test.rb
# test/browser/maintenance_session_message_test.rb
+ # test/browser/manage_test.rb
+ # test/browser/monitoring_test.rb
rm test/browser/preferences_language_test.rb
rm test/browser/preferences_permission_check_test.rb
rm test/browser/preferences_token_access_test.rb
@@ -101,6 +103,7 @@ elif [ "$LEVEL" == '2' ]; then
rm test/browser/maintenance_mode_test.rb
rm test/browser/maintenance_session_message_test.rb
rm test/browser/manage_test.rb
+ rm test/browser/monitoring_test.rb
rm test/browser/preferences_language_test.rb
rm test/browser/preferences_permission_check_test.rb
rm test/browser/preferences_token_access_test.rb
@@ -155,6 +158,7 @@ elif [ "$LEVEL" == '3' ]; then
rm test/browser/maintenance_mode_test.rb
rm test/browser/maintenance_session_message_test.rb
rm test/browser/manage_test.rb
+ rm test/browser/monitoring_test.rb
rm test/browser/preferences_language_test.rb
rm test/browser/preferences_permission_check_test.rb
rm test/browser/preferences_token_access_test.rb
@@ -209,6 +213,7 @@ elif [ "$LEVEL" == '4' ]; then
rm test/browser/maintenance_mode_test.rb
rm test/browser/maintenance_session_message_test.rb
rm test/browser/manage_test.rb
+ rm test/browser/monitoring_test.rb
rm test/browser/preferences_language_test.rb
rm test/browser/preferences_permission_check_test.rb
rm test/browser/preferences_token_access_test.rb
@@ -262,6 +267,7 @@ elif [ "$LEVEL" == '5' ]; then
rm test/browser/maintenance_mode_test.rb
rm test/browser/maintenance_session_message_test.rb
rm test/browser/manage_test.rb
+ rm test/browser/monitoring_test.rb
rm test/browser/preferences_language_test.rb
rm test/browser/preferences_permission_check_test.rb
rm test/browser/preferences_token_access_test.rb
@@ -318,6 +324,7 @@ elif [ "$LEVEL" == '6' ]; then
rm test/browser/maintenance_mode_test.rb
rm test/browser/maintenance_session_message_test.rb
rm test/browser/manage_test.rb
+ rm test/browser/monitoring_test.rb
# test/browser/preferences_language_test.rb
# test/browser/preferences_permission_check_test.rb
# test/browser/preferences_token_access_test.rb
diff --git a/test/browser/monitoring_test.rb b/test/browser/monitoring_test.rb
new file mode 100644
index 000000000..d4e79b4db
--- /dev/null
+++ b/test/browser/monitoring_test.rb
@@ -0,0 +1,43 @@
+# encoding: utf-8
+require 'browser_test_helper'
+
+class MonitoringTest < TestCase
+
+ def test_mode
+ browser1 = browser_instance
+ login(
+ browser: browser1,
+ username: 'master@example.com',
+ password: 'test',
+ url: browser_url,
+ )
+ click(
+ browser: browser1,
+ css: 'a[href="#manage"]',
+ )
+ click(
+ browser: browser1,
+ css: 'a[href="#system/monitoring"]',
+ )
+
+ token = browser1.find_elements(css: '.active.content .js-token')[0].attribute('value')
+ url = browser1.find_elements(css: '.active.content .js-url')[0].attribute('value')
+
+ assert_match(token.to_s, url)
+
+ click(
+ browser: browser1,
+ css: '.active.content .js-resetToken',
+ )
+ sleep 3
+
+ token_new = browser1.find_elements(css: '.active.content .js-token')[0].attribute('value')
+ url_new = browser1.find_elements(css: '.active.content .js-url')[0].attribute('value')
+
+ assert_not_equal(token, token_new)
+ assert_not_equal(url, url_new)
+ assert_match(token_new.to_s, url_new)
+
+ end
+
+end
diff --git a/test/controllers/monitoring_controller_test.rb b/test/controllers/monitoring_controller_test.rb
new file mode 100644
index 000000000..e1ac7fe63
--- /dev/null
+++ b/test/controllers/monitoring_controller_test.rb
@@ -0,0 +1,393 @@
+# encoding: utf-8
+require 'test_helper'
+
+class MonitoringControllerTest < ActionDispatch::IntegrationTest
+ setup do
+
+ # set accept header
+ @headers = { 'ACCEPT' => 'application/json', 'CONTENT_TYPE' => 'application/json' }
+
+ # set token
+ @token = SecureRandom.urlsafe_base64(64)
+ Setting.set('monitoring_token', @token)
+
+ # create agent
+ roles = Role.where(name: %w(Admin Agent))
+ groups = Group.all
+
+ # channel cleanup
+ Channel.where.not(area: 'Email::Notification').destroy_all
+ Channel.all.each { |channel|
+ channel.status_in = 'ok'
+ channel.status_out = 'ok'
+ channel.last_log_in = nil
+ channel.last_log_out = nil
+ channel.save!
+ }
+ dir = "#{Rails.root}/tmp/unprocessable_mail"
+ Dir.glob("#{dir}/*.eml") do |entry|
+ File.delete(entry)
+ end
+
+ Scheduler.where(active: true).each { |scheduler|
+ scheduler.last_run = Time.zone.now
+ scheduler.save!
+ }
+
+ permission = Permission.find_by(name: 'admin.monitoring')
+ permission.active = true
+ permission.save!
+
+ UserInfo.current_user_id = 1
+ @admin = User.create_or_update(
+ login: 'monitoring-admin',
+ firstname: 'Monitoring',
+ lastname: 'Admin',
+ email: 'monitoring-admin@example.com',
+ password: 'adminpw',
+ active: true,
+ roles: roles,
+ groups: groups,
+ )
+
+ # create agent
+ roles = Role.where(name: 'Agent')
+ @agent = User.create_or_update(
+ login: 'monitoring-agent@example.com',
+ firstname: 'Monitoring',
+ lastname: 'Agent',
+ email: 'monitoring-agent@example.com',
+ password: 'agentpw',
+ active: true,
+ roles: roles,
+ groups: groups,
+ )
+
+ # create customer without org
+ roles = Role.where(name: 'Customer')
+ @customer_without_org = User.create_or_update(
+ login: 'monitoring-customer1@example.com',
+ firstname: 'Monitoring',
+ lastname: 'Customer1',
+ email: 'monitoring-customer1@example.com',
+ password: 'customer1pw',
+ active: true,
+ roles: roles,
+ )
+
+ end
+
+ test '01 monitoring without token' do
+
+ # health_check
+ get '/api/v1/monitoring/health_check', {}, @headers
+ assert_response(401)
+
+ result = JSON.parse(@response.body)
+ assert_equal(Hash, result.class)
+ assert_not(result['healthy'])
+ assert_equal('Not authorized', result['error'])
+
+ # status
+ get '/api/v1/monitoring/status', {}, @headers
+ assert_response(401)
+
+ result = JSON.parse(@response.body)
+ assert_equal(Hash, result.class)
+ assert_not(result['agents'])
+ assert_not(result['last_login'])
+ assert_not(result['counts'])
+ assert_not(result['last_created_at'])
+ assert_equal('Not authorized', result['error'])
+
+ # token
+ post '/api/v1/monitoring/token', {}, @headers
+ assert_response(401)
+
+ result = JSON.parse(@response.body)
+ assert_equal(Hash, result.class)
+ assert_not(result['token'])
+ assert_equal('authentication failed', result['error'])
+
+ end
+
+ test '02 monitoring with wrong token' do
+
+ # health_check
+ get '/api/v1/monitoring/health_check?token=abc', {}, @headers
+ assert_response(401)
+
+ result = JSON.parse(@response.body)
+ assert_equal(Hash, result.class)
+ assert_not(result['healthy'])
+ assert_equal('Not authorized', result['error'])
+
+ # status
+ get '/api/v1/monitoring/status?token=abc', {}, @headers
+ assert_response(401)
+
+ result = JSON.parse(@response.body)
+ assert_equal(Hash, result.class)
+ assert_not(result['agents'])
+ assert_not(result['last_login'])
+ assert_not(result['counts'])
+ assert_not(result['last_created_at'])
+ assert_equal('Not authorized', result['error'])
+
+ # token
+ post '/api/v1/monitoring/token', { token: 'abc' }.to_json, @headers
+ assert_response(401)
+
+ result = JSON.parse(@response.body)
+ assert_equal(Hash, result.class)
+ assert_not(result['token'])
+ assert_equal('authentication failed', result['error'])
+
+ end
+
+ test '03 monitoring with correct token' do
+
+ # health_check
+ get "/api/v1/monitoring/health_check?token=#{@token}", {}, @headers
+ assert_response(200)
+
+ result = JSON.parse(@response.body)
+ assert_equal(Hash, result.class)
+ assert_not(result['error'])
+ assert_equal(true, result['healthy'])
+ assert_equal('success', result['message'])
+
+ # status
+ get "/api/v1/monitoring/status?token=#{@token}", {}, @headers
+ assert_response(200)
+
+ result = JSON.parse(@response.body)
+ assert_equal(Hash, result.class)
+ assert_not(result['error'])
+ assert(result.key?('agents'))
+ assert(result.key?('last_login'))
+ assert(result.key?('counts'))
+ assert(result.key?('last_created_at'))
+
+ # token
+ post '/api/v1/monitoring/token', { token: @token }.to_json, @headers
+ assert_response(401)
+
+ result = JSON.parse(@response.body)
+ assert_equal(Hash, result.class)
+ assert_not(result['token'])
+ assert_equal('authentication failed', result['error'])
+
+ end
+
+ test '04 monitoring with admin user' do
+
+ credentials = ActionController::HttpAuthentication::Basic.encode_credentials('monitoring-admin@example.com', 'adminpw')
+
+ # health_check
+ get '/api/v1/monitoring/health_check', {}, @headers.merge('Authorization' => credentials)
+ assert_response(200)
+
+ result = JSON.parse(@response.body)
+ assert_equal(Hash, result.class)
+ assert_not(result['error'])
+ assert_equal(true, result['healthy'])
+ assert_equal('success', result['message'])
+
+ # status
+ get '/api/v1/monitoring/status', {}, @headers.merge('Authorization' => credentials)
+ assert_response(200)
+
+ result = JSON.parse(@response.body)
+ assert_equal(Hash, result.class)
+ assert_not(result['error'])
+ assert(result.key?('agents'))
+ assert(result.key?('last_login'))
+ assert(result.key?('counts'))
+ assert(result.key?('last_created_at'))
+
+ # token
+ post '/api/v1/monitoring/token', { token: @token }.to_json, @headers.merge('Authorization' => credentials)
+ assert_response(201)
+
+ result = JSON.parse(@response.body)
+ assert_equal(Hash, result.class)
+ assert(result['token'])
+ @token = result['token']
+ assert_not(result['error'])
+
+ end
+
+ test '05 monitoring with agent user' do
+
+ credentials = ActionController::HttpAuthentication::Basic.encode_credentials('monitoring-agent@example.com', 'agentpw')
+
+ # health_check
+ get '/api/v1/monitoring/health_check', {}, @headers.merge('Authorization' => credentials)
+ assert_response(401)
+
+ result = JSON.parse(@response.body)
+ assert_equal(Hash, result.class)
+ assert_not(result['healthy'])
+ assert_equal('Not authorized (user)!', result['error'])
+
+ # status
+ get '/api/v1/monitoring/status', {}, @headers.merge('Authorization' => credentials)
+ assert_response(401)
+
+ result = JSON.parse(@response.body)
+ assert_equal(Hash, result.class)
+ assert_not(result['agents'])
+ assert_not(result['last_login'])
+ assert_not(result['counts'])
+ assert_not(result['last_created_at'])
+ assert_equal('Not authorized (user)!', result['error'])
+
+ # token
+ post '/api/v1/monitoring/token', { token: @token }.to_json, @headers.merge('Authorization' => credentials)
+ assert_response(401)
+
+ result = JSON.parse(@response.body)
+ assert_equal(Hash, result.class)
+ assert_not(result['token'])
+ assert_equal('Not authorized (user)!', result['error'])
+
+ end
+
+ test '06 monitoring with admin user and invalid permission' do
+
+ permission = Permission.find_by(name: 'admin.monitoring')
+ permission.active = false
+ permission.save!
+
+ credentials = ActionController::HttpAuthentication::Basic.encode_credentials('monitoring-admin@example.com', 'adminpw')
+
+ # health_check
+ get '/api/v1/monitoring/health_check', {}, @headers.merge('Authorization' => credentials)
+ assert_response(401)
+
+ result = JSON.parse(@response.body)
+ assert_equal(Hash, result.class)
+ assert_not(result['healthy'])
+ assert_equal('Not authorized (user)!', result['error'])
+
+ # status
+ get '/api/v1/monitoring/status', {}, @headers.merge('Authorization' => credentials)
+ assert_response(401)
+
+ result = JSON.parse(@response.body)
+ assert_equal(Hash, result.class)
+ assert_not(result['agents'])
+ assert_not(result['last_login'])
+ assert_not(result['counts'])
+ assert_not(result['last_created_at'])
+ assert_equal('Not authorized (user)!', result['error'])
+
+ # token
+ post '/api/v1/monitoring/token', { token: @token }.to_json, @headers.merge('Authorization' => credentials)
+ assert_response(401)
+
+ result = JSON.parse(@response.body)
+ assert_equal(Hash, result.class)
+ assert_not(result['token'])
+ assert_equal('Not authorized (user)!', result['error'])
+
+ permission.active = true
+ permission.save!
+ end
+
+ test '07 monitoring with correct token and invalid permission' do
+
+ permission = Permission.find_by(name: 'admin.monitoring')
+ permission.active = false
+ permission.save!
+
+ # health_check
+ get "/api/v1/monitoring/health_check?token=#{@token}", {}, @headers
+ assert_response(200)
+
+ result = JSON.parse(@response.body)
+ assert_equal(Hash, result.class)
+ assert_not(result['error'])
+ assert_equal(true, result['healthy'])
+ assert_equal('success', result['message'])
+
+ # status
+ get "/api/v1/monitoring/status?token=#{@token}", {}, @headers
+ assert_response(200)
+
+ result = JSON.parse(@response.body)
+ assert_equal(Hash, result.class)
+ assert_not(result['error'])
+ assert(result.key?('agents'))
+ assert(result.key?('last_login'))
+ assert(result.key?('counts'))
+ assert(result.key?('last_created_at'))
+
+ # token
+ post '/api/v1/monitoring/token', { token: @token }.to_json, @headers
+ assert_response(401)
+
+ result = JSON.parse(@response.body)
+ assert_equal(Hash, result.class)
+ assert_not(result['token'])
+ assert_equal('authentication failed', result['error'])
+
+ permission.active = true
+ permission.save!
+
+ end
+
+ test '08 check health false' do
+
+ channel = Channel.find_by(active: true)
+ channel.status_in = 'ok'
+ channel.status_out = 'error'
+ channel.last_log_in = nil
+ channel.last_log_out = nil
+ channel.save!
+
+ # health_check
+ get "/api/v1/monitoring/health_check?token=#{@token}", {}, @headers
+ assert_response(200)
+
+ result = JSON.parse(@response.body)
+ assert_equal(Hash, result.class)
+ assert(result['message'])
+ assert(result['issues'])
+ assert_equal(false, result['healthy'])
+ assert_equal('Channel: Email::Notification out ', result['message'])
+
+ scheduler = Scheduler.where(active: true).last
+ scheduler.last_run = Time.zone.now - 1.day
+ scheduler.period = 600
+ scheduler.save!
+
+ # health_check
+ get "/api/v1/monitoring/health_check?token=#{@token}", {}, @headers
+ assert_response(200)
+
+ result = JSON.parse(@response.body)
+ assert_equal(Hash, result.class)
+ assert(result['message'])
+ assert(result['issues'])
+ assert_equal(false, result['healthy'])
+ assert_equal('Channel: Email::Notification out ;scheduler not running', result['message'])
+
+ dir = "#{Rails.root}/tmp/unprocessable_mail"
+ FileUtils.touch("#{dir}/test.eml")
+
+ # health_check
+ get "/api/v1/monitoring/health_check?token=#{@token}", {}, @headers
+ assert_response(200)
+
+ result = JSON.parse(@response.body)
+ assert_equal(Hash, result.class)
+ assert(result['message'])
+ assert(result['issues'])
+ assert_equal(false, result['healthy'])
+ assert_equal('Channel: Email::Notification out ;unprocessable mails: 1;scheduler not running', result['message'])
+
+ end
+
+end
diff --git a/test/unit/email_process_auto_response_test.rb b/test/unit/email_process_auto_response_test.rb
index a0b37e928..1d81118f6 100644
--- a/test/unit/email_process_auto_response_test.rb
+++ b/test/unit/email_process_auto_response_test.rb
@@ -105,6 +105,39 @@ Some Text"
Scheduler.worker(true)
assert_equal(1, article_p.ticket.articles.count)
+ email_raw_string = "From: me@example.com
+To: customer@example.com
+Subject: some new subject
+List-Unsubscribe:
+
+Some Text"
+
+ fqdn = Setting.get('fqdn')
+ email_raw_string = "From: me@example.com
+To: customer@example.com
+Subject: some new subject
+Message-ID: <1234@#{fqdn}>
+
+Some Text"
+
+ ticket_p, article_p, user_p, mail = Channel::EmailParser.new.process({}, email_raw_string)
+ assert_equal(false, mail['x-zammad-send-auto-response'.to_sym])
+ Scheduler.worker(true)
+ assert_equal(1, article_p.ticket.articles.count)
+
+ fqdn = Setting.get('fqdn')
+ email_raw_string = "From: me@example.com
+To: customer@example.com
+Subject: some new subject
+Message-ID: <1234@not_matching.#{fqdn}>
+
+Some Text"
+
+ ticket_p, article_p, user_p, mail = Channel::EmailParser.new.process({}, email_raw_string)
+ assert_equal(true, mail['x-zammad-send-auto-response'.to_sym])
+ Scheduler.worker(true)
+ assert_equal(2, article_p.ticket.articles.count)
+
email_raw_string = "Return-Path:
X-Original-To: sales@znuny.com
Received: from mail-qk0-f170.example.com (mail-qk0-f170.example.com [209.1.1.1])