Merge branch 'develop' of github.com:martini/zammad into develop
Conflicts: app/assets/javascripts/app/controllers/layout_ref.js.coffee
This commit is contained in:
commit
afe4181247
11 changed files with 263 additions and 89 deletions
|
@ -1289,6 +1289,7 @@ class slaRef extends App.ControllerContent
|
|||
'click .js-activateColumn': 'activateColumn'
|
||||
'click .js-activateRow': 'activateRow'
|
||||
'click [data-type=new]': 'createNew'
|
||||
'click .js-toggle': 'toggleSla'
|
||||
|
||||
constructor: ->
|
||||
super
|
||||
|
@ -1297,6 +1298,13 @@ class slaRef extends App.ControllerContent
|
|||
render: ->
|
||||
@html App.view('layout_ref/sla')()
|
||||
|
||||
toggleSla: (e) =>
|
||||
sla = $(e.currentTarget).closest('.sla')
|
||||
isInactive = sla.hasClass('is-inactive')
|
||||
sla.toggleClass('is-inactive')
|
||||
isInactive = !isInactive
|
||||
sla.find('.js-toggle').text(if isInactive then 'Enable' else 'Disable')
|
||||
|
||||
activateColumn: (event) =>
|
||||
checkbox = @$(event.currentTarget)
|
||||
columnName = checkbox.attr('data-target')
|
||||
|
|
|
@ -76,15 +76,93 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="table-overview">
|
||||
<p>
|
||||
<strong>Service-Level-Agreements</strong>, abgekürzt <b>SLAs</b>, unterstützen Sie gegenüber Kunden gewisse zeitliche Reaktionen einzuhalten. Somit können Sie z. B. sagen Kunden sollen immer nach spätestens 8 Stunden eine Reaktion von Ihnen bekommen. Falls es zu einer drohenden Unterschreitung oder einer Unterschreitung kommt, weißt Zammad Sie auf solche Ereignisse hin.
|
||||
</p>
|
||||
<p>
|
||||
Es können <strong>Reaktionszeit</strong> (Zeit zwischen Erstellung eines Tickets und erster Reaktion eines Agenten), <strong>Aktualisierungszeit</strong> (Zeit zwischen Nachfrage eines Kunden und Reaktion eines Agenten) und <strong>Lösungszeit</strong> (Zeit zwischen Erstellung und schließen eines Tickets) definiert werden.
|
||||
</p>
|
||||
<p>
|
||||
Drohenden Unterschreitungen oder Unterschreitungen werden in einer eigenen Ansicht in den Übersichten angezeigt. Zudem können <strong>E-Mail Benachrichtigungen</strong> konfiguriert werden.
|
||||
</p>
|
||||
<div class="sla">
|
||||
<div class="sla-filters">
|
||||
<h3>Filters</h3>
|
||||
Where <b>Organization</b> equals to <b>Deutsche Bank</b>.<br>
|
||||
Where <b>Priority</b> is <b>high</b>.
|
||||
</div>
|
||||
<div class="arrow">
|
||||
<svg class="icon"><use xlink:href="#icon-arrow-right" /></svg>
|
||||
</div>
|
||||
<div class="sla-times">
|
||||
<h3>Repsonse Times</h3>
|
||||
<div class="response-times">
|
||||
<div class="response-times-entry">
|
||||
<div class="response-time">00:30 Stunden</div>
|
||||
<div class="response-name">
|
||||
<svg class="icon icon-reply"><use xlink:href="#icon-reply" /></svg>
|
||||
First Response Time
|
||||
</div>
|
||||
</div>
|
||||
<div class="response-times-entry">
|
||||
<div class="response-time">01:00 Stunden</div>
|
||||
<div class="response-name">
|
||||
<svg class="icon icon-reply-all"><use xlink:href="#icon-reply-all" /></svg>
|
||||
Update Time
|
||||
</div>
|
||||
</div>
|
||||
<div class="response-times-entry">
|
||||
<div class="response-time">48:00 Stunden</div>
|
||||
<div class="response-name">
|
||||
<svg class="icon icon-checkmark"><use xlink:href="#icon-checkmark" /></svg>
|
||||
Solution Time
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sla-businessHours">
|
||||
<h3>Business Hours <span class="subtitle">in European Central Time</span></h3>
|
||||
Mo-Tu 7am - 5pm, Fr 7am - 1pm
|
||||
</div>
|
||||
<div class="sla-controls">
|
||||
<div class="sla-toggle btn js-toggle">Disable</div>
|
||||
<div class="sla-edit btn js-edit">Edit</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="sla is-inactive">
|
||||
<div class="sla-filters">
|
||||
<h3>Filters</h3>
|
||||
Where <b>Organization</b> equals to <b>Deutsche Bank</b>.<br>
|
||||
Where <b>Priority</b> is <b>high</b>.
|
||||
</div>
|
||||
<div class="arrow">
|
||||
<svg class="icon"><use xlink:href="#icon-arrow-right" /></svg>
|
||||
</div>
|
||||
<div class="sla-times">
|
||||
<h3>Repsonse Times</h3>
|
||||
<div class="response-times">
|
||||
<div class="response-times-entry">
|
||||
<div class="response-time">00:30 Stunden</div>
|
||||
<div class="response-name">
|
||||
<svg class="icon icon-reply"><use xlink:href="#icon-reply" /></svg>
|
||||
First Response Time
|
||||
</div>
|
||||
</div>
|
||||
<div class="response-times-entry">
|
||||
<div class="response-time">01:00 Stunden</div>
|
||||
<div class="response-name">
|
||||
<svg class="icon icon-reply-all"><use xlink:href="#icon-reply-all" /></svg>
|
||||
Update Time
|
||||
</div>
|
||||
</div>
|
||||
<div class="response-times-entry">
|
||||
<div class="response-time">48:00 Stunden</div>
|
||||
<div class="response-name">
|
||||
<svg class="icon icon-checkmark"><use xlink:href="#icon-checkmark" /></svg>
|
||||
Solution Time
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sla-businessHours">
|
||||
<h3>Business Hours <span class="subtitle">in European Central Time</span></h3>
|
||||
Mo-Tu 7am - 5pm, Fr 7am - 1pm
|
||||
</div>
|
||||
<div class="sla-controls">
|
||||
<div class="sla-toggle btn js-toggle">Enable</div>
|
||||
<div class="sla-edit btn js-edit">Edit</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -16,7 +16,7 @@ body {
|
|||
font-family: "Fira Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
line-height: 1.45;
|
||||
font-weight: normal;
|
||||
background: hsl(210,17%,98%);
|
||||
background: hsl(210,14%,97%);
|
||||
height: 100%;
|
||||
color: hsl(198,19%,72%);
|
||||
word-wrap: break-word;
|
||||
|
@ -5508,6 +5508,81 @@ output {
|
|||
}
|
||||
}
|
||||
|
||||
.sla {
|
||||
background: white;
|
||||
border: 1px solid hsl(199,44%,93%);
|
||||
color: hsl(206,7%,28%);
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
padding: 20px;
|
||||
box-shadow: 0 2px hsl(210,7%,94%);
|
||||
|
||||
& + .sla {
|
||||
margin-top: 17px;
|
||||
}
|
||||
|
||||
&.is-inactive {
|
||||
box-shadow: none;
|
||||
position: relative;
|
||||
top: 2px;
|
||||
|
||||
& > *:not(.sla-controls) {
|
||||
opacity: 0.33;
|
||||
}
|
||||
}
|
||||
|
||||
h3 {
|
||||
color: hsl(0,0%,60%);
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.arrow {
|
||||
align-self: center;
|
||||
margin: 25px 50px 0;
|
||||
|
||||
.icon {
|
||||
width: 15px;
|
||||
height: 24px;
|
||||
fill: hsl(198,17%,89%);
|
||||
}
|
||||
}
|
||||
|
||||
.response-times-entry {
|
||||
display: flex;
|
||||
|
||||
.icon {
|
||||
display: none;
|
||||
vertical-align: middle;
|
||||
margin-right: 3px;
|
||||
|
||||
&:not(.icon-checkmark) {
|
||||
}
|
||||
}
|
||||
|
||||
.response-time {
|
||||
margin-right: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.response-times-entry:not(:last-child) {
|
||||
margin: 0 0 2px;
|
||||
}
|
||||
|
||||
.sla-businessHours {
|
||||
flex-basis: 100%;
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
.sla-controls {
|
||||
flex-basis: 100%;
|
||||
display: flex;
|
||||
|
||||
.sla-edit {
|
||||
margin-left: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
----------------
|
||||
|
|
|
@ -98,122 +98,98 @@ class ApplicationController < ActionController::Base
|
|||
def authentication_check_only(auth_param)
|
||||
|
||||
logger.debug 'authentication_check'
|
||||
session[:request_type] = 1
|
||||
#logger.debug params.inspect
|
||||
#logger.debug session.inspect
|
||||
#logger.debug cookies.inspect
|
||||
|
||||
# check http basic auth
|
||||
authenticate_with_http_basic do |username, password|
|
||||
logger.debug 'http basic auth check'
|
||||
session[:request_type] = 2
|
||||
# already logged in, early exit
|
||||
if session.id && session[:user_id]
|
||||
userdata = User.find( session[:user_id] )
|
||||
current_user_set(userdata)
|
||||
|
||||
userdata = User.authenticate( username, password )
|
||||
message = ''
|
||||
if !userdata
|
||||
message = 'authentication failed'
|
||||
end
|
||||
return {
|
||||
auth: true
|
||||
}
|
||||
end
|
||||
|
||||
# return auth ok
|
||||
if message == ''
|
||||
error_message = 'authentication failed'
|
||||
|
||||
# remember user
|
||||
session[:user_id] = userdata.id
|
||||
# check logon session
|
||||
if params['logon_session']
|
||||
logon_session = ActiveRecord::SessionStore::Session.where( session_id: params['logon_session'] ).first
|
||||
|
||||
# set basic auth user to current user
|
||||
# set logon session user to current user
|
||||
if logon_session
|
||||
userdata = User.find( logon_session.data[:user_id] )
|
||||
current_user_set(userdata)
|
||||
|
||||
session[:persistent] = true
|
||||
|
||||
return {
|
||||
auth: true
|
||||
}
|
||||
end
|
||||
|
||||
# return auth not ok
|
||||
error_message = 'no valid session, user_id'
|
||||
end
|
||||
|
||||
# check sso
|
||||
sso_userdata = User.sso(params)
|
||||
if sso_userdata
|
||||
|
||||
current_user_set(sso_userdata)
|
||||
|
||||
session[:persistent] = true
|
||||
|
||||
return {
|
||||
auth: false,
|
||||
message: message,
|
||||
auth: true
|
||||
}
|
||||
end
|
||||
|
||||
# check logon session
|
||||
if params['logon_session']
|
||||
logon_session = ActiveRecord::SessionStore::Session.where( session_id: params['logon_session'] ).first
|
||||
if logon_session
|
||||
userdata = User.find( logon_session.data[:user_id] )
|
||||
end
|
||||
# check http basic auth
|
||||
authenticate_with_http_basic do |username, password|
|
||||
logger.debug "http basic auth check '#{username}'"
|
||||
|
||||
session[:request_type] = 3
|
||||
userdata = User.authenticate( username, password )
|
||||
|
||||
# set logon session user to current user
|
||||
next if !userdata
|
||||
|
||||
# set basic auth user to current user
|
||||
current_user_set(userdata)
|
||||
return {
|
||||
auth: true
|
||||
}
|
||||
end
|
||||
|
||||
# check sso
|
||||
if !session[:user_id]
|
||||
|
||||
user = User.sso(params)
|
||||
|
||||
# Log the authorizing user in.
|
||||
if user
|
||||
session[:user_id] = user.id
|
||||
end
|
||||
end
|
||||
|
||||
# check token
|
||||
if auth_param[:token_action]
|
||||
authenticate_with_http_token do |token, options|
|
||||
logger.debug 'token auth check'
|
||||
session[:request_type] = 4
|
||||
authenticate_with_http_token do |token, _options|
|
||||
logger.debug "token auth check #{token}"
|
||||
|
||||
userdata = Token.check(
|
||||
action: auth_param[:token_action],
|
||||
name: token,
|
||||
)
|
||||
|
||||
message = ''
|
||||
if !userdata
|
||||
message = 'authentication failed'
|
||||
end
|
||||
next if !userdata
|
||||
|
||||
# return auth ok
|
||||
if message == ''
|
||||
# set token user to current user
|
||||
current_user_set(userdata)
|
||||
|
||||
# remember user
|
||||
session[:user_id] = userdata.id
|
||||
|
||||
# set token user to current user
|
||||
current_user_set(userdata)
|
||||
return {
|
||||
auth: true
|
||||
}
|
||||
end
|
||||
|
||||
# return auth not ok
|
||||
return {
|
||||
auth: false,
|
||||
message: message,
|
||||
auth: true
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
# return auth not ok (no session exists)
|
||||
if !session[:user_id]
|
||||
logger.debug 'no valid session, user_id'
|
||||
message = 'no valid session, user_id'
|
||||
return {
|
||||
auth: false,
|
||||
message: message,
|
||||
}
|
||||
end
|
||||
|
||||
logger.debug error_message
|
||||
{
|
||||
auth: true
|
||||
auth: false,
|
||||
message: error_message,
|
||||
}
|
||||
end
|
||||
|
||||
def authentication_check( auth_param = { basic_auth_promt: false } )
|
||||
def authentication_check( auth_param = {} )
|
||||
result = authentication_check_only(auth_param)
|
||||
|
||||
# check if basic_auth fallback is possible
|
||||
|
@ -233,6 +209,9 @@ class ApplicationController < ActionController::Base
|
|||
return false
|
||||
end
|
||||
|
||||
# store current user id into the session
|
||||
session[:user_id] = current_user.id
|
||||
|
||||
# return auth ok
|
||||
true
|
||||
end
|
||||
|
|
|
@ -54,6 +54,10 @@ class SessionsController < ApplicationController
|
|||
# )
|
||||
end
|
||||
|
||||
# sessions created via this
|
||||
# controller are persistent
|
||||
session[:persistent] = true
|
||||
|
||||
# return new session data
|
||||
render status: :created,
|
||||
json: {
|
||||
|
|
|
@ -13,15 +13,17 @@ class Observer::Session < ActiveRecord::Observer
|
|||
check(record)
|
||||
end
|
||||
|
||||
# move the persistent attribute from the sub structure
|
||||
# to the first level so it gets stored in the database
|
||||
# column to make the cleanup lookup more performant
|
||||
def check(record)
|
||||
return if !record.data
|
||||
return if record[:request_type]
|
||||
return if record[:persistent]
|
||||
|
||||
# remember request type
|
||||
return if !record.data['request_type']
|
||||
return if !record.data['persistent']
|
||||
|
||||
record[:request_type] = record.data['request_type']
|
||||
record.data.delete('request_type')
|
||||
record[:persistent] = record.data['persistent']
|
||||
record.data.delete('persistent')
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -21,7 +21,7 @@ class Token < ActiveRecord::Base
|
|||
return
|
||||
end
|
||||
|
||||
# return token if valid
|
||||
# return token user
|
||||
token.user
|
||||
end
|
||||
|
||||
|
|
Binary file not shown.
24
db/migrate/20150623145511_session_changes.rb
Normal file
24
db/migrate/20150623145511_session_changes.rb
Normal file
|
@ -0,0 +1,24 @@
|
|||
class SessionChanges < ActiveRecord::Migration
|
||||
def up
|
||||
|
||||
ActiveRecord::SessionStore::Session.delete_all
|
||||
|
||||
remove_index :sessions, :request_type
|
||||
remove_column :sessions, :request_type
|
||||
|
||||
add_column :sessions, :persistent, :boolean, null: true
|
||||
add_index :sessions, :persistent
|
||||
end
|
||||
|
||||
def down
|
||||
|
||||
ActiveRecord::SessionStore::Session.delete_all
|
||||
|
||||
remove_index :sessions, :persistent
|
||||
remove_column :sessions, :persistent
|
||||
|
||||
add_column :sessions, :request_type, :integer, null: true
|
||||
add_index :sessions, :request_type
|
||||
end
|
||||
|
||||
end
|
|
@ -56,6 +56,8 @@ module ICal::Ticket
|
|||
events_data = []
|
||||
tickets.each do |ticket|
|
||||
|
||||
next if !ticket.pending_time
|
||||
|
||||
event_data = {}
|
||||
|
||||
# rubocop:disable Rails/TimeZone
|
||||
|
@ -86,6 +88,8 @@ module ICal::Ticket
|
|||
events_data = []
|
||||
tickets.each do |ticket|
|
||||
|
||||
next if !ticket.escalation_time
|
||||
|
||||
event_data = {}
|
||||
|
||||
# rubocop:disable Rails/TimeZone
|
||||
|
|
|
@ -29,7 +29,7 @@ module SessionHelper
|
|||
def self.cleanup_expired
|
||||
|
||||
# delete temp. sessions
|
||||
ActiveRecord::SessionStore::Session.where('request_type IS NULL AND updated_at < ?', Time.zone.now - 1.days ).delete_all
|
||||
ActiveRecord::SessionStore::Session.where('persistent IS NULL AND updated_at < ?', Time.zone.now - 1.days ).delete_all
|
||||
|
||||
# web sessions older the x days
|
||||
ActiveRecord::SessionStore::Session.where('updated_at < ?', Time.zone.now - 90.days ).delete_all
|
||||
|
|
Loading…
Reference in a new issue