diff --git a/Gemfile b/Gemfile
index 59fc6ba5a..307af7e9b 100644
--- a/Gemfile
+++ b/Gemfile
@@ -28,6 +28,7 @@ end
gem 'autoprefixer-rails'
+gem 'doorkeeper'
gem 'oauth2'
gem 'omniauth'
diff --git a/Gemfile.lock b/Gemfile.lock
index 66593bad4..81962222b 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -82,6 +82,8 @@ GEM
docile (1.1.5)
domain_name (0.5.20160826)
unf (>= 0.0.5, < 1.0.0)
+ doorkeeper (4.2.0)
+ railties (>= 4.2)
eco (1.0.0)
coffee-script
eco-source
@@ -366,6 +368,7 @@ DEPENDENCIES
daemons
delayed_job_active_record
diffy
+ doorkeeper
eco
em-websocket
email_verifier
diff --git a/app/assets/javascripts/app/controllers/_application_controller_table.coffee b/app/assets/javascripts/app/controllers/_application_controller_table.coffee
index c35ae9507..60c1511d0 100644
--- a/app/assets/javascripts/app/controllers/_application_controller_table.coffee
+++ b/app/assets/javascripts/app/controllers/_application_controller_table.coffee
@@ -78,14 +78,15 @@ class App.ControllerTable extends App.Controller
e.preventDefault()
console.log('checkboxClick', e.target)
- callbackHeader = (header) ->
- console.log('current header is', header)
+ callbackHeader = (headers) ->
+ console.log('current header is', headers)
# add new header item
attribute =
name: 'some name'
display: 'Some Name'
- header.push attribute
- console.log('new header is', header)
+ headers.push attribute
+ console.log('new header is', headers)
+ headers
callbackAttributes = (value, object, attribute, header, refObject) ->
console.log('data of item col', value, object, attribute, header, refObject)
diff --git a/app/assets/javascripts/app/controllers/api.coffee b/app/assets/javascripts/app/controllers/api.coffee
index 9b301bbf5..89fdbd0a0 100644
--- a/app/assets/javascripts/app/controllers/api.coffee
+++ b/app/assets/javascripts/app/controllers/api.coffee
@@ -34,20 +34,47 @@ class Index extends App.ControllerSubContent
App.Setting.unsubscribe(@subscribeApplicationId)
table = =>
+
+ callbackHeader = (headers) ->
+ attribute =
+ name: 'view'
+ display: 'View'
+ headers.splice(3, 0, attribute)
+ attribute =
+ name: 'token'
+ display: 'Token'
+ headers.splice(4, 0, attribute)
+ headers
+
+ callbackViewAttributes = (value, object, attribute, header, refObject) ->
+ value = 'X'
+ value
+
+ callbackTokenAttributes = (value, object, attribute, header, refObject) ->
+ value = 'X'
+ value
+
new App.ControllerTable(
- el: @$('.js-appList')
- model: App.Application
- tableId: 'applications'
- objects: App.Application.all()
+ el: @$('.js-appList')
+ model: App.Application
+ tableId: 'applications'
+ objects: App.Application.all()
bindRow:
events:
'click': @appEdit
+ bindCol:
+ view:
+ events:
+ 'click': @appView
+ token:
+ events:
+ 'click': @appToken
+ callbackHeader: [callbackHeader]
+ callbackAttributes:
+ view: [callbackViewAttributes]
+ token: [callbackTokenAttributes]
)
table()
- #App.Application.fetchFull(
- # table
- # clear: true
- #)
@subscribeApplicationId = App.Application.subscribe(table, initFetch: true, clear: true)
@@ -82,6 +109,18 @@ class Index extends App.ControllerSubContent
value = @PasswordAccess.prop('checked')
App.Setting.set('api_password_access', value)
+ appToken: (id, e) ->
+ e.preventDefault()
+ new ViewAppTokenModal(
+ app: App.Application.find(id)
+ )
+
+ appView: (id, e) ->
+ e.preventDefault()
+ new ViewAppModal(
+ app: App.Application.find(id)
+ )
+
appNew: (e) ->
e.preventDefault()
new App.ControllerGenericNew(
@@ -107,4 +146,51 @@ class Index extends App.ControllerSubContent
container: @el.closest('.content')
)
+class ViewAppModal extends App.ControllerModal
+ headPrefix: 'App'
+ buttonSubmit: false
+ buttonCancel: true
+ shown: true
+ small: true
+ events:
+ 'click .js-select': 'selectAll'
+
+ constructor: (params) ->
+ @head = params.app.name
+ super
+
+ content: ->
+ "AppID:
+
+ Secret: "
+
+class ViewAppTokenModal extends App.ControllerModal
+ headPrefix: 'Generate Token'
+ buttonSubmit: 'Generate Token'
+ buttonCancel: true
+ shown: true
+ small: true
+ events:
+ 'click .js-select': 'selectAll'
+
+ constructor: (params) ->
+ @head = params.app.name
+ super
+
+ content: ->
+ "#{App.i18n.translateContent('Generate Access Token for |%s|', App.Session.get().displayNameLong())}"
+
+ onSubmit: =>
+ @ajax(
+ id: 'application_token'
+ type: 'POST'
+ url: "#{@apiPath}/applications/token"
+ processData: true
+ data: JSON.stringify(id: @app.id)
+ success: (data, status, xhr) =>
+ @contentInline = "#{App.i18n.translateContent('New Access Token is')}: "
+ @update()
+ @$('.js-submit').remove()
+ )
+
App.Config.set('API', { prio: 1200, name: 'API', parent: '#system', target: '#system/api', controller: Index, permission: ['admin.api'] }, 'NavBarAdmin')
diff --git a/app/assets/javascripts/app/models/application.coffee b/app/assets/javascripts/app/models/application.coffee
index 85fd37030..e31faa35e 100644
--- a/app/assets/javascripts/app/models/application.coffee
+++ b/app/assets/javascripts/app/models/application.coffee
@@ -1,17 +1,16 @@
class App.Application extends App.Model
- @configure 'Application', 'name', 'scopes', 'redirect_uri'
+ @configure 'Application', 'name', 'redirect_uri'
@extend Spine.Model.Ajax
@url: @apiPath + '/applications'
@configure_attributes = [
{ name: 'name', display: 'Name', tag: 'input', type: 'text', limit: 100, null: false },
- { name: 'redirect_uri', display: 'Redirect URI', tag: 'textarea', limit: 250, null: false, note: 'Use one line per URI' },
- { name: 'scopes', display: 'Scopes', tag: 'input', note: 'Scopes define the access for' },
- { name: 'clients', display: 'Clients', tag: 'input', readonly: 1 },
+ { name: 'redirect_uri', display: 'Callback URL', tag: 'textarea', limit: 250, null: false, note: 'Use one line per URI' },
+ { name: 'clients', display: 'Clients', tag: 'input', readonly: 1 },
{ name: 'created_at', display: 'Created', tag: 'datetime', readonly: 1 },
{ name: 'updated_at', display: 'Updated', tag: 'datetime', readonly: 1 },
]
@configure_overview = [
- 'name', 'scopes', 'clients'
+ 'name', 'redirect_uri', 'clients'
]
@configure_delete = true
diff --git a/app/assets/javascripts/app/views/api.jst.eco b/app/assets/javascripts/app/views/api.jst.eco
index ddffb1fd9..de29d157c 100644
--- a/app/assets/javascripts/app/views/api.jst.eco
+++ b/app/assets/javascripts/app/views/api.jst.eco
@@ -51,6 +51,7 @@ curl -u <%= @S('email') %>:some_password <%= @C('http_type') %>://<%= @C('fqdn')
<%- @T('New Application') %>
+
@@ -59,7 +60,7 @@ OAuth URLs are:
- <%- @T('Title') %>
+ <%- @T('Action') %>
<%- @T('URL') %>
@@ -69,9 +70,6 @@ OAuth URLs are:
<%- @T('Getting an Access Token') %>
<%= @C('http_type') %>://<%= @C('fqdn') %>/oauth/token
-
- <%- @T('Revoking Access') %>
- <%= @C('http_type') %>://<%= @C('fqdn') %>/oauth/applications
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index b732d50aa..d6c2a8451 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -301,7 +301,6 @@ class ApplicationController < ActionController::Base
return authentication_check_prerequesits(user, 'token_auth', auth_param) if user
end
-=begin
# check oauth2 token based authentication
token = Doorkeeper::OAuth::Token.from_bearer_authorization(request)
if token
@@ -309,19 +308,23 @@ class ApplicationController < ActionController::Base
logger.debug "oauth2 token auth check '#{token}'"
access_token = Doorkeeper::AccessToken.by_token(token)
+ if !access_token
+ raise Exceptions::NotAuthorized, 'Invalid token!'
+ end
+
# check expire
if access_token.expires_in && (access_token.created_at + access_token.expires_in) < Time.zone.now
raise Exceptions::NotAuthorized, 'OAuth2 token is expired!'
end
- if access_token.scopes.empty?
- raise Exceptions::NotAuthorized, 'OAuth2 scope missing for token!'
- end
+ # if access_token.scopes.empty?
+ # raise Exceptions::NotAuthorized, 'OAuth2 scope missing for token!'
+ # end
user = User.find(access_token.resource_owner_id)
return authentication_check_prerequesits(user, 'token_auth', auth_param) if user
end
-=end
+
false
end
diff --git a/app/controllers/applications_controller.rb b/app/controllers/applications_controller.rb
new file mode 100644
index 000000000..1b44c54c2
--- /dev/null
+++ b/app/controllers/applications_controller.rb
@@ -0,0 +1,72 @@
+# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
+
+class ApplicationsController < ApplicationController
+ before_action { authentication_check(permission: 'admin.api') }
+
+ def index
+ all = Doorkeeper::Application.all
+ if params[:full]
+ assets = {}
+ item_ids = []
+ all.each { |item|
+ item_ids.push item.id
+ if !assets[:Application]
+ assets[:Application] = {}
+ end
+ application = item.attributes
+ application[:clients] = Doorkeeper::AccessToken.where(application_id: item.id).count
+ assets[:Application][item.id] = application
+ }
+ render json: {
+ record_ids: item_ids,
+ assets: assets,
+ }, status: :ok
+ return
+ end
+
+ render json: all, status: :ok
+ end
+
+ def token
+ access_token = Doorkeeper::AccessToken.create!(application_id: params[:id], resource_owner_id: current_user.id)
+ render json: { token: access_token.token }, status: :ok
+ end
+
+ def show
+ application = Doorkeeper::Application.find(params[:id])
+ render json: application, status: :ok
+ end
+
+ def create
+ application = Doorkeeper::Application.new(clean_params)
+ application.save!
+ render json: application, status: :ok
+ end
+
+ def update
+ application = Doorkeeper::Application.find(params[:id])
+ application.update_attributes!(clean_params)
+ render json: application, status: :ok
+ end
+
+ def destroy
+ application = Doorkeeper::Application.find(params[:id])
+ application.destroy!
+ render json: {}, status: :ok
+ end
+
+ private
+
+ def clean_params
+ params_data = params.permit! #.to_h
+ params_data.delete('application')
+ params_data.delete('action')
+ params_data.delete('controller')
+ params_data.delete('id')
+ params_data.delete('uid')
+ params_data.delete('secret')
+ params_data.delete('created_at')
+ params_data.delete('updated_at')
+ params_data
+ end
+end
diff --git a/app/models/organization.rb b/app/models/organization.rb
index fcebf68c6..ad984b287 100644
--- a/app/models/organization.rb
+++ b/app/models/organization.rb
@@ -13,6 +13,9 @@ class Organization < ApplicationModel
has_many :members, class_name: 'User'
validates :name, presence: true
+ before_create :domain_cleanup
+ before_update :domain_cleanup
+
activity_stream_support permission: 'admin.role'
history_support
search_index_support
@@ -21,6 +24,15 @@ class Organization < ApplicationModel
private
+ def domain_cleanup
+ return if !domain
+ return if domain.empty?
+ domain.gsub!(/@/, '')
+ domain.gsub!(/\s*/, '')
+ domain.strip!
+ domain.downcase!
+ end
+
def cache_delete
super
diff --git a/app/models/ticket.rb b/app/models/ticket.rb
index e76413c5f..220935ae2 100644
--- a/app/models/ticket.rb
+++ b/app/models/ticket.rb
@@ -738,22 +738,21 @@ perform changes on ticket
}
# get subject
- value['subject'].gsub!(/\#\{config\.(.+?)\}/, '<%= c "\\1", false %>')
- value['subject'].gsub!(/\#\{(.+?)\}/, '<%= d "\\1", false %>')
subject = NotificationFactory::Mailer.template(
templateInline: value['subject'],
locale: 'en-en',
objects: objects,
+ quote: false,
)
subject = subject_build(subject)
- value['body'].gsub!(/\#\{config\.(.+?)\}/, '<%= c "\\1", true %>')
- value['body'].gsub!(/\#\{(.+?)\}/, '<%= d "\\1", true %>')
body = NotificationFactory::Mailer.template(
templateInline: value['body'],
locale: 'en-en',
objects: objects,
+ quote: true,
)
+
Ticket::Article.create(
ticket_id: id,
to: recipient_string,
diff --git a/app/models/ticket/article.rb b/app/models/ticket/article.rb
index 240c0ca96..a152563e5 100644
--- a/app/models/ticket/article.rb
+++ b/app/models/ticket/article.rb
@@ -121,6 +121,49 @@ returns
Ticket::Article.where('ticket_id = ? AND sender_id NOT IN (?)', ticket_id, sender.id).order('created_at DESC').first
end
+=begin
+
+get body as html
+
+ article = Ticket::Article.find(123)
+ article.body_as_html
+
+=end
+
+ def body_as_html
+ return '' if !body
+ return body if content_type && content_type =~ %r{text/html}i
+ body.text2html
+ end
+
+=begin
+
+get body as text
+
+ article = Ticket::Article.find(123)
+ article.body_as_text
+
+=end
+
+ def body_as_text
+ return '' if !body
+ return body if !content_type || content_type.empty? || content_type =~ %r{text/plain}i
+ body.html2text
+ end
+
+=begin
+
+get body as text with quote sign "> " at the beginning of each line
+
+ article = Ticket::Article.find(123)
+ article.body_as_text
+
+=end
+
+ def body_as_text_with_quote
+ body_as_text.word_wrap.message_quote
+ end
+
private
# strip not wanted chars
diff --git a/app/models/user.rb b/app/models/user.rb
index a4652568f..6d3714fc2 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -33,7 +33,7 @@ class User < ApplicationModel
include User::SearchIndex
before_validation :check_name, :check_email, :check_login, :check_password
- before_create :check_preferences_default, :validate_roles
+ before_create :check_preferences_default, :validate_roles, :domain_based_assignment
before_update :check_preferences_default, :validate_roles
after_create :avatar_for_email_check
after_update :avatar_for_email_check
@@ -856,6 +856,20 @@ returns
}
end
+ def domain_based_assignment
+ return if !email
+ return if organization_id
+ begin
+ domain = Mail::Address.new(email).domain
+ return if !domain
+ organization = Organization.find_by(domain: domain.downcase, domain_assignment: true)
+ return if !organization
+ self.organization_id = organization.id
+ rescue
+ return
+ end
+ end
+
def avatar_for_email_check
return if !email
return if email.empty?
diff --git a/app/views/mailer/password_change/de.html.erb b/app/views/mailer/password_change/de.html.erb
index 6a433bc4e..24cf7e9b8 100644
--- a/app/views/mailer/password_change/de.html.erb
+++ b/app/views/mailer/password_change/de.html.erb
@@ -1,9 +1,9 @@
-Dein <%= c 'product_name' %> Passwort wurde geändert
+Dein #{config.product_name} Passwort wurde geändert
-Hallo <%= d 'user.firstname' %>,
+Hallo #{user.firstname},
-das Passwort für Dein <%= c 'product_name' %> Account <%= d 'user.login' %> wurde kürzlich geändert.
+das Passwort für Dein #{config.product_name} Account #{user.login} wurde kürzlich geändert.
Diese Aktivität ist Dir nicht bekannt? In diesen Fall kontaktiere Deinen System-Administrator.
-Dein <%= c 'product_name' %> Team
+Dein #{config.product_name} Team
diff --git a/app/views/mailer/password_change/en.html.erb b/app/views/mailer/password_change/en.html.erb
index 81eb723b5..80236ad12 100644
--- a/app/views/mailer/password_change/en.html.erb
+++ b/app/views/mailer/password_change/en.html.erb
@@ -1,9 +1,9 @@
-Your <%= c 'product_name' %> password has been changed
+Your #{product_name} password has been changed
-Hi <%= d 'user.firstname' %>,
+Hi #{user.firstname},
-The password for your <%= c 'product_name' %> account <%= d 'user.login' %> has been changed recently.
+The password for your #{product_name} account #{user.login} has been changed recently.
This activity is not known to you? If not, contact your system administrator.
-Your <%= c 'product_name' %> Team
+Your #{product_name} Team
diff --git a/app/views/mailer/password_reset/de.html.erb b/app/views/mailer/password_reset/de.html.erb
index 13d2f4f7b..fd03cff03 100644
--- a/app/views/mailer/password_reset/de.html.erb
+++ b/app/views/mailer/password_reset/de.html.erb
@@ -1,15 +1,15 @@
-Zurücksetzen Deines <%= c 'product_name' %> Passworts
+Zurücksetzen Deines #{config.product_name} Passworts
-Hallo <%= d 'user.firstname' %>,
+Hallo #{user.firstname},
-wir haben eine Anfrage zum Zurücksetzen des Passworts für <%= c 'product_name' %> Account <%= d 'user.login' %> erhalten.
+wir haben eine Anfrage zum Zurücksetzen des Passworts für #{config.product_name} Account #{user.login} erhalten.
Wenn Sie Ihr Passwort zurückzusetzen wollen, klicken Sie auf den unten stehenden Link (oder kopieren Sie die URL in den Browser einfügen):
-
+
Dieser Link führt Sie zu einer Seite, auf der Sie Ihr Passwort ändern können.
Wenn Sie Ihr Passwort nicht zurücksetzen wollen, ignorieren Sie diese Meldung. Das Passwort bleibt unverändert.
-Dein <%= c 'product_name' %> Team
+Dein #{config.product_name} Team
diff --git a/app/views/mailer/password_reset/en.html.erb b/app/views/mailer/password_reset/en.html.erb
index c673eead8..3a993b785 100644
--- a/app/views/mailer/password_reset/en.html.erb
+++ b/app/views/mailer/password_reset/en.html.erb
@@ -1,15 +1,15 @@
-Reset your <%= c 'product_name' %> password
+Reset your #{config.product_name} password
-Hi <%= d 'user.firstname' %>,
+Hi #{user.firstname},
-We received a request to reset the password for your <%= c 'product_name' %> account <%= d 'user.login' %> .
+We received a request to reset the password for your #{config.product_name} account #{user.login} .
If you want to reset your password, click on the link below (or copy and paste the URL into your browser):
-
+
This link takes you to a page where you can change your password.
If you don't want to reset your password, please ignore this message. Your password will not be reseted.
-Your <%= c 'product_name' %> Team
+Your #{config.product_name} Team
diff --git a/app/views/mailer/signup/de.html.erb b/app/views/mailer/signup/de.html.erb
index 9c76b8dca..d5a5ecf6c 100644
--- a/app/views/mailer/signup/de.html.erb
+++ b/app/views/mailer/signup/de.html.erb
@@ -1,9 +1,9 @@
-Bestätigung des <%= c 'product_name' %> Accounts, <%= d 'user.firstname' %> <%= d 'user.lastname' %>
+Bestätigung des #{config.product_name} Accounts, #{user.firstname} #{user.lastname}
-Hallo <%= d 'user.firstname' %>,
+Hallo #{user.firstname},
-bestätige Deine E-Mail-Adresse um Deine Registrierung bei <%= c 'product_name' %> abzuschließen. Es ist einfach - klick einfach auf den Link unten.
+bestätige Deine E-Mail-Adresse um Deine Registrierung bei #{config.product_name} abzuschließen. Es ist einfach - klick einfach auf den Link unten.
-
+
-Dein <%= c 'product_name' %> Team
+Dein #{config.product_name} Team
diff --git a/app/views/mailer/signup/en.html.erb b/app/views/mailer/signup/en.html.erb
index 168f1d067..f03b586a0 100644
--- a/app/views/mailer/signup/en.html.erb
+++ b/app/views/mailer/signup/en.html.erb
@@ -1,9 +1,9 @@
-Confirm your <%= c 'product_name' %> account, <%= d 'user.firstname' %> <%= d 'user.lastname' %>
+Confirm your #{config.product_name} account, #{user.firstname} #{user.lastname}
-Hi <%= d 'user.firstname' %>,
+Hi #{user.firstname},
-Confirm your email address to complete your <%= c 'product_name' %> account. It's easy, just click the link below.
+Confirm your email address to complete your #{config.product_name} account. It's easy, just click the link below.
-
+
-Your <%= c 'product_name' %> Team
+Your #{config.product_name} Team
diff --git a/app/views/mailer/test_ticket/de.html.erb b/app/views/mailer/test_ticket/de.html.erb
index cf4fe7d43..4e36a4b39 100644
--- a/app/views/mailer/test_ticket/de.html.erb
+++ b/app/views/mailer/test_ticket/de.html.erb
@@ -1,9 +1,9 @@
Test Ticket!
-Hallo <%= d 'agent.firstname' %>,
+Hallo #{agent.firstname},
dies ist ein Test Ticket . Ich bin ein Kunde und benötige Hilfe! :)
-<%= d 'customer.fullname' %>
+#{customer.fullname}
Das Zammad Projekt
diff --git a/app/views/mailer/test_ticket/en.html.erb b/app/views/mailer/test_ticket/en.html.erb
index fd1d00929..557c902eb 100644
--- a/app/views/mailer/test_ticket/en.html.erb
+++ b/app/views/mailer/test_ticket/en.html.erb
@@ -1,9 +1,9 @@
Test Ticket!
-Dear <%= d 'agent.firstname' %>,
+Dear #{agent.firstname},
This is a test ticket . I'm a customer and I need some help! :)
-<%= d 'customer.fullname' %>
+#{customer.fullname}
The Zammad Project
diff --git a/app/views/mailer/ticket_create/de.html.erb b/app/views/mailer/ticket_create/de.html.erb
index b1db98e71..bc666a485 100644
--- a/app/views/mailer/ticket_create/de.html.erb
+++ b/app/views/mailer/ticket_create/de.html.erb
@@ -1,24 +1,24 @@
-Neues Ticket (<%= d 'ticket.title' %>)
+Neues Ticket (#{ticket.title})
-Hallo <%= d 'recipient.firstname' %>,
+Hallo #{recipient.firstname},
-es wurde ein neues Ticket (<%= d 'ticket.title' %>) von "<%= d 'current_user.longname' %> " erstellt.
+es wurde ein neues Ticket (#{ticket.title}) von "#{current_user.longname} " erstellt.
-<%= t 'Group' %>: <%= d 'ticket.group.name' %>
-<%= t 'Owner' %>: <%= d 'ticket.owner.fullname' %>
-<%= t 'State' %>: <%= t d 'ticket.state.name' %>
+#{t('Group')}: #{ticket.group.name}
+#{t('Owner')}: #{ticket.owner.fullname}
+#{t('State')}: #{t(ticket.state.name)}
<% if @objects[:article] %>
- <%= t 'Information' %>:
+ #{t('Information')}:
- <%= a_html 'article' %>
+ #{article.body_as_html}
<% end %>
diff --git a/app/views/mailer/ticket_create/en.html.erb b/app/views/mailer/ticket_create/en.html.erb
index 408fe77b7..009784232 100644
--- a/app/views/mailer/ticket_create/en.html.erb
+++ b/app/views/mailer/ticket_create/en.html.erb
@@ -1,24 +1,24 @@
-New Ticket (<%= d 'ticket.title' %>)
+New Ticket (#{ticket.title})
-Hi <%= d 'recipient.firstname' %>,
+Hi #{recipient.firstname},
-A new ticket (<%= d 'ticket.title' %>) has been created by "<%= d 'current_user.longname' %> ".
+A new ticket (#{ticket.title}) has been created by "#{current_user.longname} ".
-<%= t 'Group' %>: <%= d 'ticket.group.name' %>
-<%= t 'Owner' %>: <%= d 'ticket.owner.fullname' %>
-<%= t 'State' %>: <%= t d 'ticket.state.name' %>
+#{t('Group')}: #{ticket.group.name}
+#{t('Owner')}: #{ticket.owner.fullname}
+#{t('State')}: #{t(ticket.state.name)}
<% if @objects[:article] %>
- <%= t 'Information' %>:
+ #{t('Information')}:
- <%= a_html 'article' %>
+ #{article.body_as_html}
<% end %>
diff --git a/app/views/mailer/ticket_escalation/de.html.erb b/app/views/mailer/ticket_escalation/de.html.erb
index 86ba3da5d..ea71cd93d 100644
--- a/app/views/mailer/ticket_escalation/de.html.erb
+++ b/app/views/mailer/ticket_escalation/de.html.erb
@@ -1,18 +1,18 @@
-Ticket ist eskaliert (<%= d 'ticket.title' %>)
+Ticket ist eskaliert (#{ticket.title})
-Hallo <%= d 'recipient.firstname' %>,
+Hallo #{recipient.firstname},
-Ticket (<%= d 'ticket.title' %>) von "<%= d 'ticket.customer.longname' %> " ist seit "<%= d 'ticket.escalation_at' %>" eskaliert!
+Ticket (#{ticket.title}) von "#{ticket.customer.longname} " ist seit "#{ticket.escalation_at}" eskaliert!
<% if @objects[:article] %>
- <%= t 'Information' %>:
+ #{t('Information')}:
- <%= a_html 'article' %>
+ #{article.body_as_html}
<% end %>
diff --git a/app/views/mailer/ticket_escalation/en.html.erb b/app/views/mailer/ticket_escalation/en.html.erb
index 078a55262..bb779fba0 100644
--- a/app/views/mailer/ticket_escalation/en.html.erb
+++ b/app/views/mailer/ticket_escalation/en.html.erb
@@ -1,18 +1,18 @@
-Ticket is escalated (<%= d 'ticket.title' %>)
+Ticket is escalated (#{ticket.title})
-Hi <%= d 'recipient.firstname' %>,
+Hi #{recipient.firstname},
-A ticket (<%= d 'ticket.title' %>) from "<%= d 'ticket.customer.longname' %> " is escalated since "<%= d 'ticket.escalation_at' %>"!
+A ticket (#{ticket.title}) from "#{ticket.customer.longname} " is escalated since "#{ticket.escalation_at}"!
<% if @objects[:article] %>
- <%= t 'Information' %>:
+ #{t('Information')}:
- <%= a_html 'article' %>
+ #{article.body_as_html}
<% end %>
diff --git a/app/views/mailer/ticket_escalation_warning/de.html.erb b/app/views/mailer/ticket_escalation_warning/de.html.erb
index d78d8fe48..6a20eb8a7 100644
--- a/app/views/mailer/ticket_escalation_warning/de.html.erb
+++ b/app/views/mailer/ticket_escalation_warning/de.html.erb
@@ -1,18 +1,18 @@
-Ticket wird eskalieren (<%= d 'ticket.title' %>)
+Ticket wird eskalieren (#{ticket.title})
-Hallo <%= d 'recipient.firstname' %>,
+Hallo #{recipient.firstname},
-Ticket (<%= d 'ticket.title' %>) von "<%= d 'ticket.customer.longname' %> " wird um "<%= d 'ticket.escalation_at' %>" eskalieren!
+Ticket (#{ticket.title}) von "#{ticket.customer.longname} " wird um "#{ticket.escalation_at}" eskalieren!
<% if @objects[:article] %>
- <%= t 'Information' %>:
+ #{t('Information')}:
- <%= a_html 'article' %>
+ #{article.body_as_html}
<% end %>
diff --git a/app/views/mailer/ticket_escalation_warning/en.html.erb b/app/views/mailer/ticket_escalation_warning/en.html.erb
index 0952efc91..3750ebe39 100644
--- a/app/views/mailer/ticket_escalation_warning/en.html.erb
+++ b/app/views/mailer/ticket_escalation_warning/en.html.erb
@@ -1,18 +1,18 @@
-Ticket will escalate (<%= d 'ticket.title' %>)
+Ticket will escalate (#{ticket.title})
-Hi <%= d 'recipient.firstname' %>,
+Hi #{recipient.firstname},
-A ticket (<%= d 'ticket.title' %>) from "<%= d 'ticket.customer.longname' %> " will escalate at "<%= d 'ticket.escalation_at' %>"!
+A ticket (#{ticket.title}) from "#{ticket.customer.longname} " will escalate at "#{ticket.escalation_at}"!
<% if @objects[:article] %>
- <%= t 'Information' %>:
+ #{t('Information')}:
- <%= a_html 'article' %>
+ #{article.body_as_html}
<% end %>
diff --git a/app/views/mailer/ticket_reminder_reached/de.html.erb b/app/views/mailer/ticket_reminder_reached/de.html.erb
index 275660959..1e4e1785f 100644
--- a/app/views/mailer/ticket_reminder_reached/de.html.erb
+++ b/app/views/mailer/ticket_reminder_reached/de.html.erb
@@ -1,18 +1,18 @@
-Warten auf Erinnerung erreicht! (<%= d 'ticket.title' %>)
+Warten auf Erinnerung erreicht! (#{ticket.title})
-Hallo <%= d 'recipient.firstname' %>,
+Hallo #{recipient.firstname},
-dieses Ticket benötigt Deine Aufmerksamkeit, warten auf Erinnerung für (<%= d 'ticket.title' %>) mit dem Kunden "<%= d 'ticket.customer.longname' %> " ist erreicht.
+dieses Ticket benötigt Deine Aufmerksamkeit, warten auf Erinnerung für (#{ticket.title}) mit dem Kunden "#{ticket.customer.longname} " ist erreicht.
<% if @objects[:article] %>
- <%= t 'Information' %>:
+ #{t('Information')}:
- <%= a_html 'article' %>
+ #{article.body_as_html}
<% end %>
diff --git a/app/views/mailer/ticket_reminder_reached/en.html.erb b/app/views/mailer/ticket_reminder_reached/en.html.erb
index 65f7b5440..5998d8830 100644
--- a/app/views/mailer/ticket_reminder_reached/en.html.erb
+++ b/app/views/mailer/ticket_reminder_reached/en.html.erb
@@ -1,18 +1,18 @@
-Reminder reached (<%= d 'ticket.title' %>)
+Reminder reached (#{ticket.title})
-Hi <%= d 'recipient.firstname' %>,
+Hi #{recipient.firstname},
-A ticket needs attention, reminder reached for (<%= d 'ticket.title' %>) with customer "<%= d 'ticket.customer.longname' %> ".
+A ticket needs attention, reminder reached for (#{ticket.title}) with customer "#{ticket.customer.longname} ".
<% if @objects[:article] %>
- <%= t 'Information' %>:
+ #{t('Information')}:
- <%= a_html 'article' %>
+ #{article.body_as_html}
<% end %>
diff --git a/app/views/mailer/ticket_update/de.html.erb b/app/views/mailer/ticket_update/de.html.erb
index 6930d2c01..bc2afff05 100644
--- a/app/views/mailer/ticket_update/de.html.erb
+++ b/app/views/mailer/ticket_update/de.html.erb
@@ -1,14 +1,14 @@
-Ticket aktualisiert (<%= d 'ticket.title' %>)
+Ticket aktualisiert (#{ticket.title})
-Hi <%= d 'recipient.firstname' %>,
+Hi #{recipient.firstname},
-Ticket (<%= d 'ticket.title' %>) wurde von "<%= d 'current_user.longname' %> " aktualisiert.
+Ticket (#{ticket.title}) wurde von "#{current_user.longname} " aktualisiert.
<% if @objects[:changes] && !@objects[:changes].empty? %>
- <%= t 'Changes' %>:
+ #{t('Changes')}:
<% @objects[:changes].each do |key, value| %>
<%= t key %>: <%= h value[0] %> -> <%= h value[1] %>
<% end %>
@@ -17,13 +17,13 @@ Ticket (<%= d 'ticket.title' %>) wurde von "
<%= d 'current_user.longname' %><
<% if @objects[:article] %>
- <%= t 'Information' %>:
+ #{t('Information')}:
- <%= a_html 'article' %>
+ #{article.body_as_html}
<% end %>
diff --git a/app/views/mailer/ticket_update/en.html.erb b/app/views/mailer/ticket_update/en.html.erb
index 220874bcc..c0dd35ec2 100644
--- a/app/views/mailer/ticket_update/en.html.erb
+++ b/app/views/mailer/ticket_update/en.html.erb
@@ -1,14 +1,14 @@
-Updated Ticket (<%= d 'ticket.title' %>)
+Updated Ticket (#{ticket.title})
- Hi <%= d 'recipient.firstname' %>,
+Hi #{recipient.firstname},
-Ticket (<%= d 'ticket.title' %>) has been updated by "<%= d 'current_user.longname' %> ".
+Ticket (#{ticket.title}) has been updated by "#{current_user.longname} ".
<% if @objects[:changes] && !@objects[:changes].empty? %>
- <%= t 'Changes' %>:
+ #{t('Changes')}:
<% @objects[:changes].each do |key, value| %>
<%= t key %>: <%= h value[0] %> -> <%= h value[1] %>
<% end %>
@@ -17,13 +17,13 @@ Ticket (<%= d 'ticket.title' %>) has been updated by "
<%= d 'current_user.lon
<% if @objects[:article] %>
- <%= t 'Information' %>:
+ #{t('Information')}:
- <%= a_html 'article' %>
+ #{article.body_as_html}
<% end %>
diff --git a/app/views/mailer/user_device_new/de.html.erb b/app/views/mailer/user_device_new/de.html.erb
index 889cd7b9a..a4b283ae9 100644
--- a/app/views/mailer/user_device_new/de.html.erb
+++ b/app/views/mailer/user_device_new/de.html.erb
@@ -1,19 +1,19 @@
-<%= c 'product_name' %>-Anmeldung erfasst von einem neuen Gerät
+#{config.product_name}-Anmeldung erfasst von einem neuen Gerät
- Hallo <%= d 'user.firstname' %>,
+Hallo #{user.firstname},
-es sieht aus, als ob Du Dich mit einem neuen Gerät um "<%= d 'user_device.created_at' %>" angemeldet hast:
+es sieht aus, als ob Du Dich mit einem neuen Gerät um "#{user_device.created_at}" angemeldet hast:
-Dein Gerät: <%= d 'user_device.name' %>
-Deine Lokation (relativ): <%= d 'user_device.location' %>
-Deine IP: <%= d 'user_device.ip' %>
+Dein Gerät: #{user_device.name}
+Deine Lokation (relativ): #{user_device.location}
+Deine IP: #{user_device.ip}
Das Gerät wurde in die Liste der bekannten Geräte hinzugefügt, diese Liste kannst Du hier einsehen:
-<%= c 'http_type' %>://<%= c 'fqdn' %>/#profile/devices
+#{config.http_type}://#{config.fqdn}/#profile/devices
Wenn dies nicht Du warst, entferne das Gerät aus der Liste, ändere Dein Account-Passwort und kontaktieren Deinen Administrator. Jemand könnte unberechtigten Zugriff auf Dein Konto bekommen haben.
-Dein <%= c 'product_name' %> Team
+Dein #{config.product_name} Team
diff --git a/app/views/mailer/user_device_new/en.html.erb b/app/views/mailer/user_device_new/en.html.erb
index 71b792281..70fc2bbd7 100644
--- a/app/views/mailer/user_device_new/en.html.erb
+++ b/app/views/mailer/user_device_new/en.html.erb
@@ -1,19 +1,19 @@
-<%= c 'product_name' %> signin detected from a new device
+#{config.product_name} signin detected from a new device
-Hi <%= d 'user.firstname' %>,
+Hi #{user.firstname},
-It looks like you signed into your account using a new device on "<%= d 'user_device.created_at' %>":
+It looks like you signed into your account using a new device on "#{user_device.created_at}":
-Your device: <%= d 'user_device.name' %>
-Your location (relative): <%= d 'user_device.location' %>
-Your IP: <%= d 'user_device.ip' %>
+Your device: #{user_device.name}
+Your location (relative): #{user_device.location}
+Your IP: #{user_device.ip}
Your device has been added to your list of known devices, which you can view here:
-<%= c 'http_type' %>://<%= c 'fqdn' %>/#profile/devices
+#{config.http_type}://#{config.fqdn}/#profile/devices
If this wasn't you, remove the device, changing your account password, and contacting your administrator. Somebody might have gained unauthorized access to your account.
-Your <%= c 'product_name' %> Team
+Your #{config.product_name} Team
diff --git a/app/views/mailer/user_device_new_location/de.html.erb b/app/views/mailer/user_device_new_location/de.html.erb
index 31b7fd816..d59269bcf 100644
--- a/app/views/mailer/user_device_new_location/de.html.erb
+++ b/app/views/mailer/user_device_new_location/de.html.erb
@@ -1,19 +1,19 @@
-<%= c 'product_name' %>-Anmeldung von einem anderen Land erfasst
+#{config.product_name}-Anmeldung von einem anderen Land erfasst
-Hallo <%= d 'user.firstname' %>,
+Hallo #{user.firstname},
-es sieht aus, als ob Du Dich um "<%= d 'user_device.created_at' %>" von einem bekannten Gerät aus einem anderen Land angemeldet hast :
+es sieht aus, als ob Du Dich um "#{user_device.created_at}" von einem bekannten Gerät aus einem anderen Land angemeldet hast :
-Dein Gerät: <%= d 'user_device.name' %>
-Deine Lokation (relativ): <%= d 'user_device.location' %>
-Deine IP: <%= d 'user_device.ip' %>
+Dein Gerät: #{user_device.name}
+Deine Lokation (relativ): #{user_device.location}
+Deine IP: #{user_device.ip}
Das neue Land wurde in die Liste der bekannten Geräte hinzugefügt, diese Liste kannst Du hier einsehen:
-<%= c 'http_type' %>://<%= c 'fqdn' %>/#profile/devices
+#{config.http_type}://#{config.fqdn}/#profile/devices
Wenn dies nicht Du warst, entferne die neue Lokation aus der Liste, ändere Dein Account-Passwort und kontaktieren Deinen Administrator. Jemand könnte unberechtigten Zugriff auf Dein Konto bekommen haben.
-Dein <%= c 'product_name' %> Team
+Dein #{config.product_name} Team
diff --git a/app/views/mailer/user_device_new_location/en.html.erb b/app/views/mailer/user_device_new_location/en.html.erb
index 2cdfb5a6f..6b9119591 100644
--- a/app/views/mailer/user_device_new_location/en.html.erb
+++ b/app/views/mailer/user_device_new_location/en.html.erb
@@ -1,19 +1,19 @@
-<%= c 'product_name' %> signin detected from a new country
+#{config.product_name} signin detected from a new country
-Hi <%= d 'user.firstname' %>,
+Hi #{user.firstname},
-It looks like you used your account with an known device but from a new country on "<%= d 'user_device.created_at' %>":
+It looks like you used your account with an known device but from a new country on "#{user_device.created_at}":
-Your device: <%= d 'user_device.name' %>
-Your location (relative): <%= d 'user_device.location' %>
-Your IP: <%= d 'user_device.ip' %>
+Your device: #{user_device.name}
+Your location (relative): #{user_device.location}
+Your IP: #{user_device.ip}
The country has been added to your list of known devices, which you can view here:
-<%= c 'http_type' %>://<%= c 'fqdn' %>/#profile/devices
+#{config.http_type}://#{config.fqdn}/#profile/devices
If this wasn't you, remove the device, changing your account password, and contacting your administrator. Somebody might have gained unauthorized access to your account.
-Your <%= c 'product_name' %> Team
+Your #{config.product_name} Team
diff --git a/app/views/mailer/user_invite/de.html.erb b/app/views/mailer/user_invite/de.html.erb
index b83a06dd8..48504b298 100644
--- a/app/views/mailer/user_invite/de.html.erb
+++ b/app/views/mailer/user_invite/de.html.erb
@@ -1,13 +1,13 @@
-Einladung zu <%= c 'product_name' %> über <%= c 'fqdn' %>
+Einladung zu #{config.product_name} über #{config.fqdn}
-Hallo <%= d 'user.firstname' %>,
+Hallo #{user.firstname},
-Ich (<%= d 'current_user.firstname' %> <%= d 'current_user.lastname' %>) möchte Dich zu <%= c 'product_name' %> einladen - unsere Kundensupport / Ticket System Platform.
+Ich (#{current_user.firstname} #{current_user.lastname}) möchte Dich zu #{config.product_name} einladen - unsere Kundensupport / Ticket System Platform.
-Um sich anzumelden kann
hier das Password gesetzt werden.
+Um sich anzumelden kann
hier das Password gesetzt werden.
Enjoy,
-<%= d 'current_user.firstname' %> <%= d 'current_user.lastname' %>
+#{current_user.firstname} #{current_user.lastname}
-Dein <%= c 'product_name' %> Team
+Dein #{config.product_name} Team
diff --git a/app/views/mailer/user_invite/en.html.erb b/app/views/mailer/user_invite/en.html.erb
index 0dea44860..52e3b39db 100644
--- a/app/views/mailer/user_invite/en.html.erb
+++ b/app/views/mailer/user_invite/en.html.erb
@@ -1,13 +1,13 @@
-Invitation to <%= c 'product_name' %> at <%= c 'fqdn' %>
+Invitation to #{config.product_name} at #{config.fqdn}
-Hi <%= d 'user.firstname' %>,
+Hi #{user.firstname},
-I (<%= d 'current_user.firstname' %> <%= d 'current_user.lastname' %>) invite you to <%= c 'product_name' %> - our customer support / ticket system platform.
+I (#{current_user.firstname} #{current_user.lastname}) invite you to #{config.product_name} - our customer support / ticket system platform.
-Click
here and set your password.
+Click
here and set your password.
Enjoy,
-<%= d 'current_user.firstname' %> <%= d 'current_user.lastname' %>
+#{current_user.firstname} #{current_user.lastname}
-Your <%= c 'product_name' %> Team
+Your #{config.product_name} Team
diff --git a/app/views/slack/ticket_create/en.md.erb b/app/views/slack/ticket_create/en.md.erb
index 0d8268e39..e35162286 100644
--- a/app/views/slack/ticket_create/en.md.erb
+++ b/app/views/slack/ticket_create/en.md.erb
@@ -1,9 +1,9 @@
-# <%= d 'ticket.title' %>
-_<<%= c 'http_type' %>://<%= c 'fqdn' %>/#ticket/zoom/<%= d 'ticket.id' %>|Ticket#<%= d 'ticket.number' %>>: Created by <%= d 'current_user.longname' %> at <%= d 'ticket.updated_at' %>_
-* <%= t 'Group' %>: <%= d 'ticket.group.name' %>
-* <%= t 'Owner' %>: <%= d 'ticket.owner.fullname' %>
-* <%= t 'State' %>: <%= t d 'ticket.state.name' %>
+# #{ticket.title}
+_<#{config.http_type}://#{config.fqdn}/#ticket/zoom/#{ticket.id}|Ticket##{ticket.number}>: Created by #{current_user.longname} at #{ticket.updated_at}_
+* #{t('Group')}: #{ticket.group.name}
+* #{t('Owner')}: #{ticket.owner.fullname}
+* #{t('State')}: #{t(ticket.state.name)}
<% if @objects[:article] %>
-<%= a_text 'article' %>
+#{article.body_as_text}
<% end %>
diff --git a/app/views/slack/ticket_escalation/en.md.erb b/app/views/slack/ticket_escalation/en.md.erb
index e9d232544..9cd928ab3 100644
--- a/app/views/slack/ticket_escalation/en.md.erb
+++ b/app/views/slack/ticket_escalation/en.md.erb
@@ -1,7 +1,7 @@
-# <%= d 'ticket.title' %>
-_<<%= c 'http_type' %>://<%= c 'fqdn' %>/#ticket/zoom/<%= d 'ticket.id' %>|Ticket#<%= d 'ticket.number' %>>: Escalated at <%= d 'ticket.escalation_at' %>_
-A ticket (<%= d 'ticket.title' %>) from "<%= d 'ticket.customer.longname' %>" is escalated since "<%= d 'ticket.escalation_at' %>"!
+# #{ticket.title}
+_<#{config.http_type}://#{config.fqdn}/#ticket/zoom/#{ticket.id}|Ticket##{ticket.number}>: Escalated at #{ticket.escalation_at}_
+A ticket (#{ticket.title}) from "#{ticket.customer.longname}" is escalated since "#{ticket.escalation_at}"!
<% if @objects[:article] %>
-<%= a_text 'article' %>
+#{article.body_as_text}
<% end %>
diff --git a/app/views/slack/ticket_escalation_warning/en.md.erb b/app/views/slack/ticket_escalation_warning/en.md.erb
index 15068b0fb..ae976b512 100644
--- a/app/views/slack/ticket_escalation_warning/en.md.erb
+++ b/app/views/slack/ticket_escalation_warning/en.md.erb
@@ -1,7 +1,7 @@
-# <%= d 'ticket.title' %>
-_<<%= c 'http_type' %>://<%= c 'fqdn' %>/#ticket/zoom/<%= d 'ticket.id' %>|Ticket#<%= d 'ticket.number' %>>: Will escalate at <%= d 'ticket.escalation_at' %>_
-A ticket (<%= d 'ticket.title' %>) from "<%= d 'ticket.customer.longname' %>" will escalate at "<%= d 'ticket.escalation_at' %>"!
+# #{ticket.title}
+_<#{config.http_type}://#{config.fqdn}/#ticket/zoom/#{ticket.id}|Ticket##{ticket.number}>: Will escalate at #{ticket.escalation_at}_
+A ticket (#{ticket.title}) from "#{ticket.customer.longname}" will escalate at "#{ticket.escalation_at}"!
<% if @objects[:article] %>
-<%= a_text 'article' %>
+#{article.body_as_text}
<% end %>
diff --git a/app/views/slack/ticket_reminder_reached/en.md.erb b/app/views/slack/ticket_reminder_reached/en.md.erb
index 8ae47fc71..7156b6464 100644
--- a/app/views/slack/ticket_reminder_reached/en.md.erb
+++ b/app/views/slack/ticket_reminder_reached/en.md.erb
@@ -1,7 +1,7 @@
-# <%= d 'ticket.title' %>
-_<<%= c 'http_type' %>://<%= c 'fqdn' %>/#ticket/zoom/<%= d 'ticket.id' %>|Ticket#<%= d 'ticket.number' %>>: Reminder reached!_
-A ticket needs attention, reminder reached for (<%= d 'ticket.title' %>) with customer "*<%= d 'ticket.customer.longname' %>*".
+# #{ticket.title}
+_<#{config.http_type}://#{config.fqdn}/#ticket/zoom/#{ticket.id}|Ticket##{ticket.number}>: Reminder reached!_
+A ticket needs attention, reminder reached for (#{ticket.title}) with customer "*#{ticket.customer.longname}*".
<% if @objects[:article] %>
-<%= a_text 'article' %>
+#{article.body_as_text}
<% end %>
diff --git a/app/views/slack/ticket_update/en.md.erb b/app/views/slack/ticket_update/en.md.erb
index fe1a80e29..e8a9f86de 100644
--- a/app/views/slack/ticket_update/en.md.erb
+++ b/app/views/slack/ticket_update/en.md.erb
@@ -1,5 +1,5 @@
-# <%= d 'ticket.title' %>
-_<<%= c 'http_type' %>://<%= c 'fqdn' %>/#ticket/zoom/<%= d 'ticket.id' %>|Ticket#<%= d 'ticket.number' %>>: Updated by <%= d 'current_user.longname' %> at <%= d 'ticket.updated_at' %>_
+# #{ticket.title}
+_<#{config.http_type}://#{config.fqdn}/#ticket/zoom/#{ticket.id}|Ticket##{ticket.number}>: Updated by #{current_user.longname} at #{ticket.updated_at}_
<% if @objects[:changes] && !@objects[:changes].empty? %>
<% @objects[:changes].each do |key, value| %>
* <%= t key %>: <%= h value[0] %> -> <%= h value[1] %>
@@ -7,5 +7,5 @@ _<<%= c 'http_type' %>://<%= c 'fqdn' %>/#ticket/zoom/<%= d 'ticket.id' %>|Ticke
<% end %>
<% if @objects[:article] %>
-<%= a_text 'article' %>
+#{article.body_as_text}
<% end %>
diff --git a/config/initializers/doorkeeper.rb b/config/initializers/doorkeeper.rb
new file mode 100644
index 000000000..4eeb378e4
--- /dev/null
+++ b/config/initializers/doorkeeper.rb
@@ -0,0 +1,112 @@
+Doorkeeper.configure do
+ # Change the ORM that doorkeeper will use (needs plugins)
+ orm :active_record
+
+ # This block will be called to check whether the resource owner is authenticated or not.
+ resource_owner_authenticator do
+ # fail "Please configure doorkeeper resource_owner_authenticator block located in #{__FILE__}"
+ # Put your resource owner authentication logic here.
+ # Example implementation:
+ User.find_by_id(session[:user_id]) || redirect_to(new_user_session_url)
+ end
+
+ # If you want to restrict access to the web interface for adding oauth authorized applications, you need to declare the block below.
+ # admin_authenticator do
+ # # Put your admin authentication logic here.
+ # # Example implementation:
+ # Admin.find_by_id(session[:admin_id]) || redirect_to(new_admin_session_url)
+ # end
+
+ # Authorization Code expiration time (default 10 minutes).
+ # authorization_code_expires_in 10.minutes
+
+ # Access token expiration time (default 2 hours).
+ # If you want to disable expiration, set this to nil.
+ # access_token_expires_in 2.hours
+
+ # Assign a custom TTL for implicit grants.
+ # custom_access_token_expires_in do |oauth_client|
+ # oauth_client.application.additional_settings.implicit_oauth_expiration
+ # end
+
+ # Use a custom class for generating the access token.
+ # https://github.com/doorkeeper-gem/doorkeeper#custom-access-token-generator
+ # access_token_generator '::Doorkeeper::JWT'
+
+ # The controller Doorkeeper::ApplicationController inherits from.
+ # Defaults to ActionController::Base.
+ # https://github.com/doorkeeper-gem/doorkeeper#custom-base-controller
+ # base_controller 'ApplicationController'
+
+ # Reuse access token for the same resource owner within an application (disabled by default)
+ # Rationale: https://github.com/doorkeeper-gem/doorkeeper/issues/383
+ # reuse_access_token
+
+ # Issue access tokens with refresh token (disabled by default)
+ # use_refresh_token
+
+ # Provide support for an owner to be assigned to each registered application (disabled by default)
+ # Optional parameter confirmation: true (default false) if you want to enforce ownership of
+ # a registered application
+ # Note: you must also run the rails g doorkeeper:application_owner generator to provide the necessary support
+ # enable_application_owner confirmation: false
+
+ # Define access token scopes for your provider
+ # For more information go to
+ # https://github.com/doorkeeper-gem/doorkeeper/wiki/Using-Scopes
+ # default_scopes :public
+ # optional_scopes :write, :update
+
+ # Change the way client credentials are retrieved from the request object.
+ # By default it retrieves first from the `HTTP_AUTHORIZATION` header, then
+ # falls back to the `:client_id` and `:client_secret` params from the `params` object.
+ # Check out the wiki for more information on customization
+ # client_credentials :from_basic, :from_params
+
+ # Change the way access token is authenticated from the request object.
+ # By default it retrieves first from the `HTTP_AUTHORIZATION` header, then
+ # falls back to the `:access_token` or `:bearer_token` params from the `params` object.
+ # Check out the wiki for more information on customization
+ # access_token_methods :from_bearer_authorization, :from_access_token_param, :from_bearer_param
+
+ # Change the native redirect uri for client apps
+ # When clients register with the following redirect uri, they won't be redirected to any server and the authorization code will be displayed within the provider
+ # The value can be any string. Use nil to disable this feature. When disabled, clients must provide a valid URL
+ # (Similar behaviour: https://developers.google.com/accounts/docs/OAuth2InstalledApp#choosingredirecturi)
+ #
+ # native_redirect_uri 'urn:ietf:wg:oauth:2.0:oob'
+
+ # Forces the usage of the HTTPS protocol in non-native redirect uris (enabled
+ # by default in non-development environments). OAuth2 delegates security in
+ # communication to the HTTPS protocol so it is wise to keep this enabled.
+ #
+ # force_ssl_in_redirect_uri !Rails.env.development?
+
+ # Specify what grant flows are enabled in array of Strings. The valid
+ # strings and the flows they enable are:
+ #
+ # "authorization_code" => Authorization Code Grant Flow
+ # "implicit" => Implicit Grant Flow
+ # "password" => Resource Owner Password Credentials Grant Flow
+ # "client_credentials" => Client Credentials Grant Flow
+ #
+ # If not specified, Doorkeeper enables authorization_code and
+ # client_credentials.
+ #
+ # implicit and password grant flows have risks that you should understand
+ # before enabling:
+ # http://tools.ietf.org/html/rfc6819#section-4.4.2
+ # http://tools.ietf.org/html/rfc6819#section-4.4.3
+ #
+ # grant_flows %w(authorization_code client_credentials)
+
+ # Under some circumstances you might want to have applications auto-approved,
+ # so that the user skips the authorization step.
+ # For example if dealing with a trusted application.
+ # skip_authorization do |resource_owner, client|
+ # client.superapp? or resource_owner.admin?
+ # end
+
+ # WWW-Authenticate Realm (default "Doorkeeper").
+ # realm "Doorkeeper"
+end
diff --git a/config/locales/doorkeeper.en.yml b/config/locales/doorkeeper.en.yml
new file mode 100644
index 000000000..e67b778be
--- /dev/null
+++ b/config/locales/doorkeeper.en.yml
@@ -0,0 +1,124 @@
+en:
+ activerecord:
+ attributes:
+ doorkeeper/application:
+ name: 'Name'
+ redirect_uri: 'Redirect URI'
+ errors:
+ models:
+ doorkeeper/application:
+ attributes:
+ redirect_uri:
+ fragment_present: 'cannot contain a fragment.'
+ invalid_uri: 'must be a valid URI.'
+ relative_uri: 'must be an absolute URI.'
+ secured_uri: 'must be an HTTPS/SSL URI.'
+
+ doorkeeper:
+ applications:
+ confirmations:
+ destroy: 'Are you sure?'
+ buttons:
+ edit: 'Edit'
+ destroy: 'Destroy'
+ submit: 'Submit'
+ cancel: 'Cancel'
+ authorize: 'Authorize'
+ form:
+ error: 'Whoops! Check your form for possible errors'
+ help:
+ redirect_uri: 'Use one line per URI'
+ native_redirect_uri: 'Use %{native_redirect_uri} for local tests'
+ scopes: 'Separate scopes with spaces. Leave blank to use the default scopes.'
+ edit:
+ title: 'Edit application'
+ index:
+ title: 'Your applications'
+ new: 'New Application'
+ name: 'Name'
+ callback_url: 'Callback URL'
+ new:
+ title: 'New Application'
+ show:
+ title: 'Application: %{name}'
+ application_id: 'Application Id'
+ secret: 'Secret'
+ scopes: 'Scopes'
+ callback_urls: 'Callback urls'
+ actions: 'Actions'
+
+ authorizations:
+ buttons:
+ authorize: 'Authorize'
+ deny: 'Deny'
+ error:
+ title: 'An error has occurred'
+ new:
+ title: 'Authorization required'
+ prompt: 'Authorize %{client_name} to use your account?'
+ able_to: 'This application will be able to'
+ show:
+ title: 'Authorization code'
+
+ authorized_applications:
+ confirmations:
+ revoke: 'Are you sure?'
+ buttons:
+ revoke: 'Revoke'
+ index:
+ title: 'Your authorized applications'
+ application: 'Application'
+ created_at: 'Created At'
+ date_format: '%Y-%m-%d %H:%M:%S'
+
+ errors:
+ messages:
+ # Common error messages
+ invalid_request: 'The request is missing a required parameter, includes an unsupported parameter value, or is otherwise malformed.'
+ invalid_redirect_uri: 'The redirect uri included is not valid.'
+ unauthorized_client: 'The client is not authorized to perform this request using this method.'
+ access_denied: 'The resource owner or authorization server denied the request.'
+ invalid_scope: 'The requested scope is invalid, unknown, or malformed.'
+ server_error: 'The authorization server encountered an unexpected condition which prevented it from fulfilling the request.'
+ temporarily_unavailable: 'The authorization server is currently unable to handle the request due to a temporary overloading or maintenance of the server.'
+
+ #configuration error messages
+ credential_flow_not_configured: 'Resource Owner Password Credentials flow failed due to Doorkeeper.configure.resource_owner_from_credentials being unconfigured.'
+ resource_owner_authenticator_not_configured: 'Resource Owner find failed due to Doorkeeper.configure.resource_owner_authenticator being unconfiged.'
+
+ # Access grant errors
+ unsupported_response_type: 'The authorization server does not support this response type.'
+
+ # Access token errors
+ invalid_client: 'Client authentication failed due to unknown client, no client authentication included, or unsupported authentication method.'
+ invalid_grant: 'The provided authorization grant is invalid, expired, revoked, does not match the redirection URI used in the authorization request, or was issued to another client.'
+ unsupported_grant_type: 'The authorization grant type is not supported by the authorization server.'
+
+ # Password Access token errors
+ invalid_resource_owner: 'The provided resource owner credentials are not valid, or resource owner cannot be found'
+
+ invalid_token:
+ revoked: "The access token was revoked"
+ expired: "The access token expired"
+ unknown: "The access token is invalid"
+
+ flash:
+ applications:
+ create:
+ notice: 'Application created.'
+ destroy:
+ notice: 'Application deleted.'
+ update:
+ notice: 'Application updated.'
+ authorized_applications:
+ destroy:
+ notice: 'Application revoked.'
+
+ layouts:
+ admin:
+ nav:
+ oauth2_provider: 'OAuth2 Provider'
+ applications: 'Applications'
+ home: 'Home'
+ application:
+ title: 'OAuth authorization required'
diff --git a/config/routes/applications.rb b/config/routes/applications.rb
new file mode 100644
index 000000000..752e170ea
--- /dev/null
+++ b/config/routes/applications.rb
@@ -0,0 +1,14 @@
+Zammad::Application.routes.draw do
+ api_path = Rails.configuration.api_path
+
+ match api_path + '/applications', to: 'applications#index', via: :get
+ match api_path + '/applications/:id', to: 'applications#show', via: :get
+ match api_path + '/applications', to: 'applications#create', via: :post
+ match api_path + '/applications/:id', to: 'applications#update', via: :put
+ match api_path + '/applications/token', to: 'applications#token', via: :post
+
+ # oauth2 provider routes
+ use_doorkeeper do
+ skip_controllers :applications, :authorized_applications
+ end
+end
diff --git a/db/migrate/20120101000001_create_base.rb b/db/migrate/20120101000001_create_base.rb
index ecbe5c8d4..9acd58459 100644
--- a/db/migrate/20120101000001_create_base.rb
+++ b/db/migrate/20120101000001_create_base.rb
@@ -125,6 +125,8 @@ class CreateBase < ActiveRecord::Migration
create_table :organizations do |t|
t.string :name, limit: 100, null: false
t.boolean :shared, null: false, default: true
+ t.string :domain, limit: 250, null: true, default: ''
+ t.boolean :domain_assignment, null: false, default: false
t.boolean :active, null: false, default: true
t.string :note, limit: 250, null: true, default: ''
t.integer :updated_by_id, null: false
@@ -132,6 +134,7 @@ class CreateBase < ActiveRecord::Migration
t.timestamps limit: 3, null: false
end
add_index :organizations, [:name], unique: true
+ add_index :organizations, [:domain]
create_table :roles_users, id: false do |t|
t.integer :user_id
diff --git a/db/migrate/20161101131409_create_doorkeeper_tables.rb b/db/migrate/20161101131409_create_doorkeeper_tables.rb
new file mode 100644
index 000000000..da7c84353
--- /dev/null
+++ b/db/migrate/20161101131409_create_doorkeeper_tables.rb
@@ -0,0 +1,68 @@
+class CreateDoorkeeperTables < ActiveRecord::Migration
+ def change
+ create_table :oauth_applications do |t|
+ t.string :name, null: false
+ t.string :uid, null: false
+ t.string :secret, null: false
+ t.text :redirect_uri, null: false
+ t.string :scopes, null: false, default: ''
+ t.timestamps null: false
+ end
+
+ add_index :oauth_applications, :uid, unique: true
+
+ create_table :oauth_access_grants do |t|
+ t.integer :resource_owner_id, null: false
+ t.references :application, null: false
+ t.string :token, null: false
+ t.integer :expires_in, null: false
+ t.text :redirect_uri, null: false
+ t.datetime :created_at, null: false
+ t.datetime :revoked_at
+ t.string :scopes
+ end
+
+ add_index :oauth_access_grants, :token, unique: true
+ add_foreign_key(
+ :oauth_access_grants,
+ :oauth_applications,
+ column: :application_id
+ )
+
+ create_table :oauth_access_tokens do |t|
+ t.integer :resource_owner_id
+ t.references :application
+
+ # If you use a custom token generator you may need to change this column
+ # from string to text, so that it accepts tokens larger than 255
+ # characters. More info on custom token generators in:
+ # https://github.com/doorkeeper-gem/doorkeeper/tree/v3.0.0.rc1#custom-access-token-generator
+ #
+ # t.text :token, null: false
+ t.string :token, null: false
+
+ t.string :refresh_token
+ t.integer :expires_in
+ t.datetime :revoked_at
+ t.datetime :created_at, null: false
+ t.string :scopes
+
+ # If there is a previous_refresh_token column,
+ # refresh tokens will be revoked after a related access token is used.
+ # If there is no previous_refresh_token column,
+ # previous tokens are revoked as soon as a new access token is created.
+ # Comment out this line if you'd rather have refresh tokens
+ # instantly revoked.
+ t.string :previous_refresh_token, null: false, default: ''
+ end
+
+ add_index :oauth_access_tokens, :token, unique: true
+ add_index :oauth_access_tokens, :resource_owner_id
+ add_index :oauth_access_tokens, :refresh_token, unique: true
+ add_foreign_key(
+ :oauth_access_tokens,
+ :oauth_applications,
+ column: :application_id
+ )
+ end
+end
diff --git a/db/migrate/20161112000001_organization_domain_based_assignment.rb b/db/migrate/20161112000001_organization_domain_based_assignment.rb
new file mode 100644
index 000000000..9d1763379
--- /dev/null
+++ b/db/migrate/20161112000001_organization_domain_based_assignment.rb
@@ -0,0 +1,85 @@
+class OrganizationDomainBasedAssignment < ActiveRecord::Migration
+ def up
+ # return if it's a new setup
+ return if !Setting.find_by(name: 'system_init_done')
+
+ add_column :organizations, :domain, :string, limit: 250, null: true, default: ''
+ add_column :organizations, :domain_assignment, :boolean, null: false, default: false
+ add_index :organizations, [:domain]
+
+ ObjectManager::Attribute.add(
+ force: true,
+ object: 'Organization',
+ name: 'domain_assignment',
+ display: 'Domain based assignment',
+ data_type: 'boolean',
+ data_option: {
+ null: true,
+ default: false,
+ note: 'Assign Users based on users domain.',
+ item_class: 'formGroup--halfSize',
+ options: {
+ true: 'yes',
+ false: 'no',
+ },
+ translate: true,
+ },
+ editable: false,
+ active: true,
+ screens: {
+ edit: {
+ Admin: {
+ null: false,
+ },
+ },
+ view: {
+ '-all-' => {
+ shown: true,
+ },
+ },
+ },
+ to_create: false,
+ to_migrate: false,
+ to_delete: false,
+ position: 1410,
+ updated_by_id: 1,
+ created_by_id: 1,
+ )
+
+ ObjectManager::Attribute.add(
+ force: true,
+ object: 'Organization',
+ name: 'domain',
+ display: 'Domain',
+ data_type: 'input',
+ data_option: {
+ type: 'text',
+ maxlength: 150,
+ null: true,
+ item_class: 'formGroup--halfSize',
+ },
+ editable: false,
+ active: true,
+ screens: {
+ edit: {
+ '-all-' => {
+ null: true,
+ },
+ },
+ view: {
+ '-all-' => {
+ shown: true,
+ },
+ },
+ },
+ to_create: false,
+ to_migrate: false,
+ to_delete: false,
+ position: 1420,
+ updated_by_id: 1,
+ created_by_id: 1,
+ )
+
+ Cache.clear
+ end
+end
diff --git a/db/seeds.rb b/db/seeds.rb
index 2ca89c295..52b61445c 100644
--- a/db/seeds.rb
+++ b/db/seeds.rb
@@ -4660,6 +4660,75 @@ ObjectManager::Attribute.add(
position: 1400,
)
+ObjectManager::Attribute.add(
+ force: true,
+ object: 'Organization',
+ name: 'domain_assignment',
+ display: 'Domain based assignment',
+ data_type: 'boolean',
+ data_option: {
+ null: true,
+ default: false,
+ note: 'Assign Users based on users domain.',
+ item_class: 'formGroup--halfSize',
+ options: {
+ true: 'yes',
+ false: 'no',
+ },
+ translate: true,
+ },
+ editable: false,
+ active: true,
+ screens: {
+ edit: {
+ Admin: {
+ null: false,
+ },
+ },
+ view: {
+ '-all-' => {
+ shown: true,
+ },
+ },
+ },
+ to_create: false,
+ to_migrate: false,
+ to_delete: false,
+ position: 1410,
+)
+
+ObjectManager::Attribute.add(
+ force: true,
+ object: 'Organization',
+ name: 'domain',
+ display: 'Domain',
+ data_type: 'input',
+ data_option: {
+ type: 'text',
+ maxlength: 150,
+ null: true,
+ item_class: 'formGroup--halfSize',
+ },
+ editable: false,
+ active: true,
+ screens: {
+ edit: {
+ '-all-' => {
+ null: true,
+ },
+ },
+ view: {
+ '-all-' => {
+ shown: true,
+ },
+ },
+ },
+ to_create: false,
+ to_migrate: false,
+ to_delete: false,
+ position: 1420,
+)
+
ObjectManager::Attribute.add(
force: true,
object: 'Organization',
diff --git a/lib/notification_factory/mailer.rb b/lib/notification_factory/mailer.rb
index ca70330c4..79895fb84 100644
--- a/lib/notification_factory/mailer.rb
+++ b/lib/notification_factory/mailer.rb
@@ -6,7 +6,7 @@ get notification settings for user and notification type
result = NotificationFactory::Mailer.notification_settings(user, ticket, type)
- type: create | update | reminder_reached | pending
+ type: create | update | reminder_reached | escalation (escalation_warning)
returns
@@ -21,6 +21,15 @@ returns
=end
def self.notification_settings(user, ticket, type)
+
+ # map types if needed
+ map = {
+ 'escalation_warning' => 'escalation'
+ }
+ if map[type]
+ type = map[type]
+ end
+
return if !user.preferences
return if !user.preferences['notification_config']
matrix = user.preferences['notification_config']['matrix']
@@ -190,11 +199,12 @@ retunes
)
result = NotificationFactory::Mailer.template(
- templateInline: "Invitation to <%= c 'product_name' %> at <%= c 'fqdn' %>",
+ templateInline: "Invitation to \#{config.product_name} at \#{config.fqdn}",
locale: 'en-us',
objects: {
recipient: User.find(2),
},
+ quote: true, # html quoting
)
only raw subject/body
@@ -221,7 +231,7 @@ returns
def self.template(data)
if data[:templateInline]
- return NotificationFactory::Renderer.new(data[:objects], data[:locale], data[:templateInline], false).render
+ return NotificationFactory::Renderer.new(data[:objects], data[:locale], data[:templateInline], data[:quote]).render
end
template = NotificationFactory.template_read(
diff --git a/lib/notification_factory/renderer.rb b/lib/notification_factory/renderer.rb
index 86e60814f..e8d4a8697 100644
--- a/lib/notification_factory/renderer.rb
+++ b/lib/notification_factory/renderer.rb
@@ -9,7 +9,7 @@ examples how to use
ticket: Ticket.first,
},
'de-de',
- 'some template <%= d "ticket.title", false %> <%= c "fqdn", false %>',
+ 'some template #{ticket.title} {config.fqdn}',
false
).render
@@ -18,7 +18,7 @@ examples how to use
ticket: Ticket.first,
},
'de-de',
- 'some template <%= d "ticket.title", true %> <%= c "fqdn", true %>',
+ 'some template #{ticket.title} #{config.fqdn}',
).render
=end
@@ -26,7 +26,7 @@ examples how to use
def initialize(objects, locale, template, escape = true)
@objects = objects
@locale = locale || 'en-us'
- @template = NotificationFactory::Template.new(template)
+ @template = NotificationFactory::Template.new(template, escape)
@escape = escape
end
@@ -41,6 +41,25 @@ examples how to use
# do validaton, ignore some methodes
return "\#{#{key} / not allowed}" if !data_key_valid?(key)
+ # aliases
+ map = {
+ 'article.body' => 'article.body_as_text_with_quote.text2html',
+ }
+ if map[key]
+ key = map[key]
+ end
+
+ # escape in html mode
+ if escape
+ no_escape = {
+ 'article.body_as_html' => true,
+ 'article.body_as_text_with_quote.text2html' => true,
+ }
+ if no_escape[key]
+ escape = false
+ end
+ end
+
value = nil
object_methods = key.split('.')
object_name = object_methods.shift
@@ -76,7 +95,11 @@ examples how to use
value = "\#{#{object_name}.#{object_methods_s} / no such method}"
break
end
- object_refs = object_refs.send(method.to_sym)
+ begin
+ object_refs = object_refs.send(method.to_sym)
+ rescue => e
+ object_refs = "\#{#{object_name}.#{object_methods_s} / e.message}"
+ end
}
placeholder = if !value
object_refs
@@ -100,27 +123,6 @@ examples how to use
escaping(translation, escape)
end
- # a_html - article body in html
- # a_html(article)
- def a_html(article)
- content_type = d "#{article}.content_type", false
- if content_type =~ /html/
- return d "#{article}.body", false
- end
- d("#{article}.body", false).text2html
- end
-
- # a_text - article body in text
- # a_text(article)
- def a_text(article)
- content_type = d "#{article}.content_type", false
- body = d "#{article}.body", false
- if content_type =~ /html/
- body = body.html2text
- end
- (body.strip + "\n").gsub(/^(.*?)$/, '> \\1')
- end
-
# h - htmlEscape
# h('fqdn', htmlEscape)
def h(key)
@@ -137,7 +139,7 @@ examples how to use
end
def data_key_valid?(key)
- return false if key =~ /`|\.(|\s*)(save|destroy|delete|remove|drop|update|create|new|all|where|find)/i
+ return false if key =~ /`|\.(|\s*)(save|destroy|delete|remove|drop|update|create|new|all|where|find)/i && key !~ /(update|create)d_at/i
true
end
diff --git a/lib/notification_factory/slack.rb b/lib/notification_factory/slack.rb
index c0102e460..da8dc3b6c 100644
--- a/lib/notification_factory/slack.rb
+++ b/lib/notification_factory/slack.rb
@@ -33,8 +33,8 @@ returns
type: 'slack',
)
- message_subject = NotificationFactory::Renderer.new(data[:objects], data[:locale], template[:subject]).render
- message_body = NotificationFactory::Renderer.new(data[:objects], data[:locale], template[:body]).render
+ message_subject = NotificationFactory::Renderer.new(data[:objects], data[:locale], template[:subject], false).render
+ message_body = NotificationFactory::Renderer.new(data[:objects], data[:locale], template[:body], false).render
if !data[:raw]
application_template = NotificationFactory.application_template_read(
@@ -43,7 +43,7 @@ returns
)
data[:objects][:message] = message_body
data[:objects][:standalone] = data[:standalone]
- message_body = NotificationFactory::Renderer.new(data[:objects], data[:locale], application_template).render
+ message_body = NotificationFactory::Renderer.new(data[:objects], data[:locale], application_template, false).render
end
{
subject: message_subject.strip!,
diff --git a/lib/notification_factory/template.rb b/lib/notification_factory/template.rb
index 7da6e8efe..76dbe7c53 100644
--- a/lib/notification_factory/template.rb
+++ b/lib/notification_factory/template.rb
@@ -5,13 +5,15 @@ class NotificationFactory::Template
examples how to use
cleaned_template = NotificationFactory::Template.new(
- 'some template <%= d "ticket.title", false %> <%= c "fqdn", false %>',
+ 'some template #{ticket.title} #{config.fqdn}',
+ true,
).to_s
=end
- def initialize(template)
+ def initialize(template, escape)
@template = template
+ @escape = escape
end
def to_s
@@ -23,7 +25,35 @@ examples how to use
def strip_html
# some browsers start adding HTML tags
# fixes https://github.com/zammad/zammad/issues/385
- @template.gsub!(%r{#\{\s*<[^>]+>([^<]+)[^>]+>\s*\}}, '\1')
- @template.gsub!(/#\{\s*<[^>]+>([^<]+)\s*\}/, '\1')
+ @template.gsub!(/\#\{\s*t\((.+?)\)\s*\}/m) do
+ content = $1
+ if content =~ /^'(.+?)'$/
+ "<%= t \"#{strip_content($1)}\", #{@escape} %>"
+ else
+ "<%= t d\"#{strip_variable(content)}\", #{@escape} %>"
+ end
+ end
+ @template.gsub!(/\#\{\s*config\.(.+?)\s*\}/m) do
+ "<%= c \"#{strip_variable($1)}\", #{@escape} %>"
+ end
+ @template.gsub!(/\#\{(.*?)\}/m) do
+ "<%= d \"#{strip_variable($1)}\", #{@escape} %>"
+ end
end
+
+ def strip_content(string)
+ return string if !string
+ string.gsub!(/\t|\r|\n/, '')
+ string.gsub!(/"/, '\"')
+ string
+ end
+
+ def strip_variable(string)
+ return string if !string
+ string.gsub!(/\t|\r|\n|"|'|§|;/, '')
+ string.gsub!(/\s*/, '')
+ string.gsub!(/<.+?>/, '')
+ string
+ end
+
end
diff --git a/test/unit/notification_factory_renderer_test.rb b/test/unit/notification_factory_renderer_test.rb
index a6e5bb0e7..d091afeec 100644
--- a/test/unit/notification_factory_renderer_test.rb
+++ b/test/unit/notification_factory_renderer_test.rb
@@ -3,29 +3,40 @@ require 'test_helper'
class NotificationFactoryRendererTest < ActiveSupport::TestCase
- # TODO: should be mocked somehow
- Translation.load('de-de')
-
# RSpec incoming!
def described_class
NotificationFactory::Renderer
end
- Group = Struct.new(:name)
- State = Struct.new(:name)
- User = Struct.new(:firstname, :lastname, :longname, :fullname)
- Ticket = Struct.new(:id, :title, :group, :owner, :state)
-
- group = Group.new('Users')
- state = State.new('new')
- owner = User.new('Notificationxxx ', 'Agent1yyy ', 'Notificationxxx Agent1yyy ', 'Notificationxxx Agent1yyy (Zammad)')
- current_user = User.new('CurrentUserxxx ', 'Agent2yyy ', 'CurrentUserxxx Agent2yyy ', 'CurrentUserxxx Agent2yyy (Zammad)')
- recipient = User.new('Recipientxxx ', 'Customer1yyy ', 'Recipientxxx Customer1yyy ', 'Recipientxxx Customer1yyy (Zammad)')
- ticket = Ticket.new(1, 'Welcome to Zammad! ', group, owner, state)
+ group = Group.new(name: 'Users')
+ owner = User.new(firstname: 'Notificationxxx ', lastname: 'Agent1yyy ')
+ current_user = User.new(firstname: 'CurrentUserxxx ', lastname: 'Agent2yyy ')
+ recipient = User.new(firstname: 'Recipientxxx ', lastname: 'Customer1yyy ')
+ state = Ticket::State.new(name: 'new')
+ ticket = Ticket.new(
+ id: 1,
+ title: 'Welcome to Zammad! ',
+ group: group,
+ owner: owner,
+ state: state,
+ created_at: Time.zone.parse('2016-11-12 12:00:00 UTC'),
+ updated_at: Time.zone.parse('2016-11-12 14:00:00 UTC'),
+ )
+ article_html1 = Ticket::Article.new(
+ body: 'test hello some new line',
+ content_type: 'text/html',
+ )
+ article_plain1 = Ticket::Article.new(
+ body: "test hello \nsome new line",
+ content_type: 'text/plain',
+ )
+ article_plain2 = Ticket::Article.new(
+ body: "test hello \nsome new line",
+ )
test 'replace object attribute' do
- template = "<%= d 'ticket.title' %>"
+ template = "\#{ticket.title}"
result = described_class.new(
{
ticket: ticket,
@@ -35,7 +46,27 @@ class NotificationFactoryRendererTest < ActiveSupport::TestCase
).render
assert_equal(CGI.escapeHTML(ticket.title), result)
- template = "<%= d 'ticket. title' %>"
+ template = "\#{ticket.created_at}"
+ result = described_class.new(
+ {
+ ticket: ticket,
+ },
+ 'en-us',
+ template,
+ ).render
+ assert_equal(ticket.created_at.to_s, result)
+
+ template = "\#{ticket.updated_at}"
+ result = described_class.new(
+ {
+ ticket: ticket,
+ },
+ 'en-us',
+ template,
+ ).render
+ assert_equal(ticket.updated_at.to_s, result)
+
+ template = "\#{ticket. title}"
result = described_class.new(
{
ticket: ticket,
@@ -45,7 +76,7 @@ class NotificationFactoryRendererTest < ActiveSupport::TestCase
).render
assert_equal(CGI.escapeHTML(ticket.title), result)
- template = "<%= d 'ticket.\n title' %>"
+ template = "\#{ticket.\n title}"
result = described_class.new(
{
ticket: ticket,
@@ -55,7 +86,7 @@ class NotificationFactoryRendererTest < ActiveSupport::TestCase
).render
assert_equal(CGI.escapeHTML(ticket.title), result)
- template = "<%= d 'ticket.\t title' %>"
+ template = "\#{ticket.\t title}"
result = described_class.new(
{
ticket: ticket,
@@ -65,7 +96,7 @@ class NotificationFactoryRendererTest < ActiveSupport::TestCase
).render
assert_equal(CGI.escapeHTML(ticket.title), result)
- template = "<%= d 'ticket.\t\n title\t' %>"
+ template = "\#{ticket.\t\n title\t}"
result = described_class.new(
{
ticket: ticket,
@@ -75,13 +106,50 @@ class NotificationFactoryRendererTest < ActiveSupport::TestCase
).render
assert_equal(CGI.escapeHTML(ticket.title), result)
+ template = "\#{ticket.\" title\t}"
+ result = described_class.new(
+ {
+ ticket: ticket,
+ },
+ 'en-us',
+ template,
+ ).render
+ assert_equal(CGI.escapeHTML(ticket.title), result)
+
+ template = "some test \#{article.body}"
+ result = described_class.new(
+ {
+ article: article_html1,
+ },
+ 'en-us',
+ template,
+ ).render
+ assert_equal('some test > test hello > some new line ', result)
+
+ result = described_class.new(
+ {
+ article: article_plain1,
+ },
+ 'en-us',
+ template,
+ ).render
+ assert_equal('some test > test <b>hello</b> > some new line ', result)
+
+ result = described_class.new(
+ {
+ article: article_plain2,
+ },
+ 'en-us',
+ template,
+ ).render
+ assert_equal('some test > test <b>hello</b> > some new line ', result)
+
end
test 'config' do
- setting = 'fqdn'
- template = "<%= c '#{setting}' %>"
-
+ setting = 'fqdn'
+ template = "\#{config.#{setting}}"
result = described_class.new(
{
ticket: ticket,
@@ -89,13 +157,11 @@ class NotificationFactoryRendererTest < ActiveSupport::TestCase
'en-us',
template,
).render
-
assert_equal(Setting.get(setting), result)
setting1 = 'fqdn'
setting2 = 'product_name'
- template = "some <%= c '#{setting1}' %> and <%= c '#{setting2}' %>"
-
+ template = "some \#{config.#{setting1}} and \#{config.#{setting2}}"
result = described_class.new(
{
ticket: ticket,
@@ -103,14 +169,25 @@ class NotificationFactoryRendererTest < ActiveSupport::TestCase
'en-us',
template,
).render
+ assert_equal("some #{Setting.get(setting1)} and #{Setting.get(setting2)}", result)
+ setting1 = 'fqdn'
+ setting2 = 'product_name'
+ template = "some \#{ config.#{setting1}} and \#{\tconfig.#{setting2}}"
+ result = described_class.new(
+ {
+ ticket: ticket,
+ },
+ 'en-us',
+ template,
+ ).render
assert_equal("some #{Setting.get(setting1)} and #{Setting.get(setting2)}", result)
end
test 'translation' do
- template = "<%= t 'new' %>"
-
+ #template = "<%= t 'new' %>"
+ template = "\#{t('new')}"
result = described_class.new(
{
ticket: ticket,
@@ -118,11 +195,9 @@ class NotificationFactoryRendererTest < ActiveSupport::TestCase
'de-de',
template,
).render
-
assert_equal('neu', result)
- template = "some text <%= t 'new' %> and <%= t 'open' %>"
-
+ template = "some text \#{t('new')} and \#{t('open')}"
result = described_class.new(
{
ticket: ticket,
@@ -130,14 +205,33 @@ class NotificationFactoryRendererTest < ActiveSupport::TestCase
'de-de',
template,
).render
+ assert_equal('some text neu and offen', result)
+ template = "some text \#{t('new') } and \#{ t('open')}"
+ result = described_class.new(
+ {
+ ticket: ticket,
+ },
+ 'de-de',
+ template,
+ ).render
+ assert_equal('some text neu and offen', result)
+
+ template = "some text \#{\nt('new') } and \#{ t('open')\t}"
+ result = described_class.new(
+ {
+ ticket: ticket,
+ },
+ 'de-de',
+ template,
+ ).render
assert_equal('some text neu and offen', result)
end
test 'chained function calls' do
- template = "<%= t d 'ticket.state.name' %>"
+ template = "\#{t(ticket.state.name)}"
result = described_class.new(
{
@@ -152,7 +246,7 @@ class NotificationFactoryRendererTest < ActiveSupport::TestCase
test 'not existing object and attribute' do
- template = "<%= d '' %>"
+ template = "\#{}"
result = described_class.new(
{
ticket: ticket,
@@ -162,7 +256,7 @@ class NotificationFactoryRendererTest < ActiveSupport::TestCase
).render
assert_equal(CGI.escapeHTML('#{no such object}'), result)
- template = "<%= d 'notexsiting.notexsiting' %>"
+ template = "\#{notexsiting.notexsiting}"
result = described_class.new(
{
ticket: ticket,
@@ -172,7 +266,7 @@ class NotificationFactoryRendererTest < ActiveSupport::TestCase
).render
assert_equal(CGI.escapeHTML('#{notexsiting / no such object}'), result)
- template = "<%= d 'ticket.notexsiting' %>"
+ template = "\#{ticket.notexsiting}"
result = described_class.new(
{
ticket: ticket,
@@ -182,7 +276,7 @@ class NotificationFactoryRendererTest < ActiveSupport::TestCase
).render
assert_equal(CGI.escapeHTML('#{ticket.notexsiting / no such method}'), result)
- template = "<%= d 'ticket.' %>"
+ template = "\#{ticket.}"
result = described_class.new(
{
ticket: ticket,
@@ -192,7 +286,7 @@ class NotificationFactoryRendererTest < ActiveSupport::TestCase
).render
assert_equal(CGI.escapeHTML('#{ticket. / no such method}'), result)
- template = "<%= d 'ticket.title.notexsiting' %>"
+ template = "\#{ticket.title.notexsiting}"
result = described_class.new(
{
ticket: ticket,
@@ -202,7 +296,7 @@ class NotificationFactoryRendererTest < ActiveSupport::TestCase
).render
assert_equal(CGI.escapeHTML('#{ticket.title.notexsiting / no such method}'), result)
- template = "<%= d 'ticket.notexsiting.notexsiting' %>"
+ template = "\#{ticket.notexsiting.notexsiting}"
result = described_class.new(
{
ticket: ticket,
@@ -212,7 +306,7 @@ class NotificationFactoryRendererTest < ActiveSupport::TestCase
).render
assert_equal(CGI.escapeHTML('#{ticket.notexsiting / no such method}'), result)
- template = "<%= d 'notexsiting' %>"
+ template = "\#{notexsiting}"
result = described_class.new(
{
ticket: ticket,
@@ -222,7 +316,7 @@ class NotificationFactoryRendererTest < ActiveSupport::TestCase
).render
assert_equal(CGI.escapeHTML('#{notexsiting / no such object}'), result)
- template = "<%= d 'notexsiting.' %>"
+ template = "\#{notexsiting.}"
result = described_class.new(
{
ticket: ticket,
@@ -232,7 +326,7 @@ class NotificationFactoryRendererTest < ActiveSupport::TestCase
).render
assert_equal(CGI.escapeHTML('#{notexsiting / no such object}'), result)
- template = "<%= d 'string' %>"
+ template = "\#{string}"
result = described_class.new(
{
string: 'some string',
@@ -242,7 +336,7 @@ class NotificationFactoryRendererTest < ActiveSupport::TestCase
).render
assert_equal(CGI.escapeHTML('some string'), result)
- template = "<%= d 'fixum' %>"
+ template = "\#{fixum}"
result = described_class.new(
{
fixum: 123,
@@ -252,7 +346,7 @@ class NotificationFactoryRendererTest < ActiveSupport::TestCase
).render
assert_equal(CGI.escapeHTML('123'), result)
- template = "<%= d 'float' %>"
+ template = "\#{float}"
result = described_class.new(
{
float: 123.99,
@@ -266,7 +360,7 @@ class NotificationFactoryRendererTest < ActiveSupport::TestCase
test 'data key validation' do
- template = "<%= d 'ticket.title `echo 1`' %>"
+ template = "\#{ticket.title `echo 1`}"
result = described_class.new(
{
ticket: ticket,
@@ -274,9 +368,9 @@ class NotificationFactoryRendererTest < ActiveSupport::TestCase
'en-us',
template,
).render
- assert_equal(CGI.escapeHTML('#{ticket.title `echo 1` / not allowed}'), result)
+ assert_equal(CGI.escapeHTML('#{ticket.title`echo1` / not allowed}'), result)
- template = "<%= d 'ticket.destroy' %>"
+ template = "\#{ticket.destroy}"
result = described_class.new(
{
ticket: ticket,
@@ -286,7 +380,7 @@ class NotificationFactoryRendererTest < ActiveSupport::TestCase
).render
assert_equal(CGI.escapeHTML('#{ticket.destroy / not allowed}'), result)
- template = "<%= d 'ticket.save' %>"
+ template = "\#{ticket.save}"
result = described_class.new(
{
ticket: ticket,
@@ -296,7 +390,7 @@ class NotificationFactoryRendererTest < ActiveSupport::TestCase
).render
assert_equal(CGI.escapeHTML('#{ticket.save / not allowed}'), result)
- template = "<%= d 'ticket.update' %>"
+ template = "\#{ticket.update}"
result = described_class.new(
{
ticket: ticket,
@@ -306,37 +400,7 @@ class NotificationFactoryRendererTest < ActiveSupport::TestCase
).render
assert_equal(CGI.escapeHTML('#{ticket.update / not allowed}'), result)
- template = "<%= d 'ticket.delete' %>"
- result = described_class.new(
- {
- ticket: ticket,
- },
- 'en-us',
- template,
- ).render
- assert_equal(CGI.escapeHTML('#{ticket.delete / not allowed}'), result)
-
- template = "<%= d 'ticket.remove' %>"
- result = described_class.new(
- {
- ticket: ticket,
- },
- 'en-us',
- template,
- ).render
- assert_equal(CGI.escapeHTML('#{ticket.remove / not allowed}'), result)
-
- template = "<%= d 'ticket.drop' %>"
- result = described_class.new(
- {
- ticket: ticket,
- },
- 'en-us',
- template,
- ).render
- assert_equal(CGI.escapeHTML('#{ticket.drop / not allowed}'), result)
-
- template = "<%= d 'ticket.create' %>"
+ template = "\#{ticket.create}"
result = described_class.new(
{
ticket: ticket,
@@ -346,7 +410,47 @@ class NotificationFactoryRendererTest < ActiveSupport::TestCase
).render
assert_equal(CGI.escapeHTML('#{ticket.create / not allowed}'), result)
- template = "<%= d 'ticket.new' %>"
+ template = "\#{ticket.delete}"
+ result = described_class.new(
+ {
+ ticket: ticket,
+ },
+ 'en-us',
+ template,
+ ).render
+ assert_equal(CGI.escapeHTML('#{ticket.delete / not allowed}'), result)
+
+ template = "\#{ticket.remove}"
+ result = described_class.new(
+ {
+ ticket: ticket,
+ },
+ 'en-us',
+ template,
+ ).render
+ assert_equal(CGI.escapeHTML('#{ticket.remove / not allowed}'), result)
+
+ template = "\#{ticket.drop}"
+ result = described_class.new(
+ {
+ ticket: ticket,
+ },
+ 'en-us',
+ template,
+ ).render
+ assert_equal(CGI.escapeHTML('#{ticket.drop / not allowed}'), result)
+
+ template = "\#{ticket.create}"
+ result = described_class.new(
+ {
+ ticket: ticket,
+ },
+ 'en-us',
+ template,
+ ).render
+ assert_equal(CGI.escapeHTML('#{ticket.create / not allowed}'), result)
+
+ template = "\#{ticket.new}"
result = described_class.new(
{
ticket: ticket,
@@ -356,7 +460,7 @@ class NotificationFactoryRendererTest < ActiveSupport::TestCase
).render
assert_equal(CGI.escapeHTML('#{ticket.new / not allowed}'), result)
- template = "<%= d 'ticket.update_att' %>"
+ template = "\#{ticket.update_att}"
result = described_class.new(
{
ticket: ticket,
@@ -366,7 +470,7 @@ class NotificationFactoryRendererTest < ActiveSupport::TestCase
).render
assert_equal(CGI.escapeHTML('#{ticket.update_att / not allowed}'), result)
- template = "<%= d 'ticket.all' %>"
+ template = "\#{ticket.all}"
result = described_class.new(
{
ticket: ticket,
@@ -376,7 +480,7 @@ class NotificationFactoryRendererTest < ActiveSupport::TestCase
).render
assert_equal(CGI.escapeHTML('#{ticket.all / not allowed}'), result)
- template = "<%= d 'ticket.find' %>"
+ template = "\#{ticket.find}"
result = described_class.new(
{
ticket: ticket,
@@ -386,7 +490,7 @@ class NotificationFactoryRendererTest < ActiveSupport::TestCase
).render
assert_equal(CGI.escapeHTML('#{ticket.find / not allowed}'), result)
- template = "<%= d 'ticket.where' %>"
+ template = "\#{ticket.where}"
result = described_class.new(
{
ticket: ticket,
@@ -396,7 +500,7 @@ class NotificationFactoryRendererTest < ActiveSupport::TestCase
).render
assert_equal(CGI.escapeHTML('#{ticket.where / not allowed}'), result)
- template = "<%= d 'ticket. destroy' %>"
+ template = "\#{ticket. destroy}"
result = described_class.new(
{
ticket: ticket,
@@ -404,9 +508,9 @@ class NotificationFactoryRendererTest < ActiveSupport::TestCase
'en-us',
template,
).render
- assert_equal(CGI.escapeHTML('#{ticket. destroy / not allowed}'), result)
+ assert_equal(CGI.escapeHTML('#{ticket.destroy / not allowed}'), result)
- template = "<%= d 'ticket.\n destroy' %>"
+ template = "\#{ticket.\n destroy}"
result = described_class.new(
{
ticket: ticket,
@@ -414,9 +518,9 @@ class NotificationFactoryRendererTest < ActiveSupport::TestCase
'en-us',
template,
).render
- assert_equal(CGI.escapeHTML("\#{ticket.\n destroy / not allowed}"), result)
+ assert_equal(CGI.escapeHTML("\#{ticket.destroy / not allowed}"), result)
- template = "<%= d 'ticket.\t destroy' %>"
+ template = "\#{ticket.\t destroy}"
result = described_class.new(
{
ticket: ticket,
@@ -424,9 +528,9 @@ class NotificationFactoryRendererTest < ActiveSupport::TestCase
'en-us',
template,
).render
- assert_equal(CGI.escapeHTML("\#{ticket.\t destroy / not allowed}"), result)
+ assert_equal(CGI.escapeHTML("\#{ticket.destroy / not allowed}"), result)
- template = "<%= d 'ticket.\r destroy' %>"
+ template = "\#{ticket.\r destroy}"
result = described_class.new(
{
ticket: ticket,
@@ -434,7 +538,7 @@ class NotificationFactoryRendererTest < ActiveSupport::TestCase
'en-us',
template,
).render
- assert_equal(CGI.escapeHTML("\#{ticket.\r destroy / not allowed}"), result)
+ assert_equal(CGI.escapeHTML("\#{ticket.destroy / not allowed}"), result)
end
diff --git a/test/unit/notification_factory_slack_template_test.rb b/test/unit/notification_factory_slack_template_test.rb
index d746c4b42..cb3b349f0 100644
--- a/test/unit/notification_factory_slack_template_test.rb
+++ b/test/unit/notification_factory_slack_template_test.rb
@@ -78,7 +78,7 @@ class NotificationFactorySlackTemplateTest < ActiveSupport::TestCase
)
assert_match('# Welcome to Zammad!', result[:subject])
- assert_match('User<b>xxx</b>', result[:body])
+ assert_match('Userxxx ', result[:body])
assert_match('Created by', result[:body])
assert_match('test123 ', result[:body])
assert_no_match('Dein', result[:body])
@@ -113,7 +113,7 @@ class NotificationFactorySlackTemplateTest < ActiveSupport::TestCase
},
)
assert_match('# Welcome to Zammad!', result[:subject])
- assert_match('User<b>xxx</b>', result[:body])
+ assert_match('Userxxx ', result[:body])
assert_match('state: aaa -> bbb', result[:body])
assert_match('group: xxx -> yyy', result[:body])
assert_no_match('Dein', result[:body])
diff --git a/test/unit/notification_factory_template_test.rb b/test/unit/notification_factory_template_test.rb
index c8ad841f7..baee7c7ea 100644
--- a/test/unit/notification_factory_template_test.rb
+++ b/test/unit/notification_factory_template_test.rb
@@ -11,48 +11,69 @@ class NotificationFactoryTemplateTest < ActiveSupport::TestCase
test 'regular browser html' do
# ensures https://github.com/zammad/zammad/issues/385
- template_before = '<%= d "#{ticket.id }" %>'
- template_after = '<%= d "ticket.id" %>'
+ template_before = '#{ticket.id }'
+ template_after = '<%= d "ticket.id", true %>'
- result = described_class.new(template_before).to_s
+ result = described_class.new(template_before, true).to_s
+ assert_equal(template_after, result)
+
+ template_before = '#{config.fqdn }'
+ template_after = '<%= d "config.fqdn", true %>'
+
+ result = described_class.new(template_before, true).to_s
assert_equal(template_after, result)
end
test 'spaced browser html' do
# ensures https://github.com/zammad/zammad/issues/385
- template_before = '<%= d "#{ ticket.id } " %>'
- template_after = '<%= d "ticket.id " %>'
+ template_before = '#{ ticket.id }'
+ template_after = '<%= d "ticket.id", true %>'
- result = described_class.new(template_before).to_s
+ result = described_class.new(template_before, true).to_s
assert_equal(template_after, result)
end
test 'broken browser html' do
# ensures https://github.com/zammad/zammad/issues/385
- template_before = '<%= d "#{ticket.id }" %>'
- template_after = '<%= d "ticket.id " %>'
+ template_before = '#{ ticket.id }'
+ template_after = '<%= d "ticket.id", true %>'
- result = described_class.new(template_before).to_s
+ result = described_class.new(template_before, true).to_s
assert_equal(template_after, result)
end
test 'empty tag' do
- template_before = '<%= d "#{}" %>'
- template_after = '<%= d "#{}" %>'
+ template_before = '#{}'
+ template_after = '<%= d "", true %>'
- result = described_class.new(template_before).to_s
+ result = described_class.new(template_before, true).to_s
assert_equal(template_after, result)
end
test 'empty tag with space' do
- template_before = '<%= d "#{ }" %>'
- template_after = '<%= d "#{ }" %>'
+ template_before = '#{ }'
+ template_after = '<%= d "", false %>'
- result = described_class.new(template_before).to_s
+ result = described_class.new(template_before, false).to_s
+ assert_equal(template_after, result)
+ end
+
+ test 'translation' do
+
+ template_before = "\#{t('some text')}"
+ template_after = '<%= t "some text", false %>'
+
+ result = described_class.new(template_before, false).to_s
+ assert_equal(template_after, result)
+
+ template_before = "\#{t('some \"text\"')}"
+ template_after = '<%= t "some \"text\"", false %>'
+
+ result = described_class.new(template_before, false).to_s
assert_equal(template_after, result)
end
diff --git a/test/unit/organization_domain_based_assignment_test.rb b/test/unit/organization_domain_based_assignment_test.rb
new file mode 100644
index 000000000..df730b706
--- /dev/null
+++ b/test/unit/organization_domain_based_assignment_test.rb
@@ -0,0 +1,78 @@
+# encoding: utf-8
+require 'test_helper'
+
+class OrganizationDomainBasedAssignmentTest < ActiveSupport::TestCase
+ test 'organization based assignment' do
+
+ organization1 = Organization.create_if_not_exists(
+ name: 'organization based assignment 1',
+ domain: '@examPle1.com ',
+ domain_assignment: true,
+ updated_by_id: 1,
+ created_by_id: 1,
+ )
+ organization2 = Organization.create_if_not_exists(
+ name: 'organization based assignment 2',
+ domain: 'example2.com',
+ domain_assignment: false,
+ updated_by_id: 1,
+ created_by_id: 1,
+ )
+
+ roles = Role.where(name: 'Customer')
+ customer1 = User.create_or_update(
+ login: 'organization-based_assignment-customer1@example1.com',
+ firstname: 'Domain',
+ lastname: 'Agent1',
+ email: 'organization-based_assignment-customer1@example1.com',
+ password: 'customerpw',
+ active: true,
+ roles: roles,
+ updated_by_id: 1,
+ created_by_id: 1,
+ )
+ assert_equal(organization1.id, customer1.organization_id)
+
+ customer2 = User.create_or_update(
+ login: 'organization-based_assignment-customer2@example1.com',
+ firstname: 'Domain',
+ lastname: 'Agent2',
+ email: 'organization-based_assignment-customer2@example1.com',
+ password: 'customerpw',
+ active: true,
+ organization_id: organization2.id,
+ roles: roles,
+ updated_by_id: 1,
+ created_by_id: 1,
+ )
+ assert_equal(organization2.id, customer2.organization_id)
+
+ customer3 = User.create_or_update(
+ login: 'organization-based_assignment-customer3@example2.com',
+ firstname: 'Domain',
+ lastname: 'Agent2',
+ email: 'organization-based_assignment-customer3@example2.com',
+ password: 'customerpw',
+ active: true,
+ roles: roles,
+ updated_by_id: 1,
+ created_by_id: 1,
+ )
+ assert_equal(nil, customer3.organization_id)
+
+ customer4 = User.create_or_update(
+ login: 'organization-based_assignment-customer4',
+ firstname: 'Domain',
+ lastname: 'Agent2',
+ email: '@',
+ password: 'customerpw',
+ active: true,
+ roles: roles,
+ updated_by_id: 1,
+ created_by_id: 1,
+ )
+ assert_equal(nil, customer4.organization_id)
+
+ end
+
+end
diff --git a/test/unit/ticket_trigger_test.rb b/test/unit/ticket_trigger_test.rb
index 9b9adf90b..5d86c2659 100644
--- a/test/unit/ticket_trigger_test.rb
+++ b/test/unit/ticket_trigger_test.rb
@@ -13,7 +13,7 @@ class TicketTriggerTest < ActiveSupport::TestCase
},
perform: {
'notification.email' => {
- 'body' => 'some text #{ticket.customer.lastname} #{ticket.title}',
+ 'body' => 'some text #{ticket.customer.lastname} #{ticket.title} #{article.body}',
'recipient' => 'ticket_customer',
'subject' => 'Thanks for your inquiry (#{ticket.title})!',
},
@@ -60,12 +60,25 @@ class TicketTriggerTest < ActiveSupport::TestCase
created_by_id: 1,
)
assert(ticket1, 'ticket1 created')
+ Ticket::Article.create(
+ ticket_id: ticket1.id,
+ from: 'some_sender@example.com',
+ to: 'some_recipient@example.com',
+ subject: 'some subject',
+ message_id: 'some@id',
+ body: "some message note \nnew line",
+ internal: false,
+ sender: Ticket::Article::Sender.find_by(name: 'Agent'),
+ type: Ticket::Article::Type.find_by(name: 'note'),
+ updated_by_id: 1,
+ created_by_id: 1,
+ )
assert_equal('some title äöüß', ticket1.title, 'ticket1.title verify')
assert_equal('Users', ticket1.group.name, 'ticket1.group verify')
assert_equal('new', ticket1.state.name, 'ticket1.state verify')
assert_equal('2 normal', ticket1.priority.name, 'ticket1.priority verify')
- assert_equal(0, ticket1.articles.count, 'ticket1.articles verify')
+ assert_equal(1, ticket1.articles.count, 'ticket1.articles verify')
assert_equal([], Tag.tag_list(object: 'Ticket', o_id: ticket1.id))
Observer::Transaction.commit
@@ -75,13 +88,14 @@ class TicketTriggerTest < ActiveSupport::TestCase
assert_equal('Users', ticket1.group.name, 'ticket1.group verify')
assert_equal('new', ticket1.state.name, 'ticket1.state verify')
assert_equal('3 high', ticket1.priority.name, 'ticket1.priority verify')
- assert_equal(1, ticket1.articles.count, 'ticket1.articles verify')
+ assert_equal(2, ticket1.articles.count, 'ticket1.articles verify')
assert_equal(%w(aa kk), Tag.tag_list(object: 'Ticket', o_id: ticket1.id))
article1 = ticket1.articles.last
assert_match('Zammad ', article1.from)
assert_match('nicole.braun@zammad.org', article1.to)
assert_match('Thanks for your inquiry (some title äöüß)!', article1.subject)
assert_match('Braun some <b>title</b>', article1.body)
+ assert_match('> some message <b>note</b> > new line', article1.body)
assert_equal('text/html', article1.content_type)
ticket1.priority = Ticket::Priority.lookup(name: '2 normal')
@@ -93,7 +107,7 @@ class TicketTriggerTest < ActiveSupport::TestCase
assert_equal('Users', ticket1.group.name, 'ticket1.group verify')
assert_equal('new', ticket1.state.name, 'ticket1.state verify')
assert_equal('2 normal', ticket1.priority.name, 'ticket1.priority verify')
- assert_equal(1, ticket1.articles.count, 'ticket1.articles verify')
+ assert_equal(2, ticket1.articles.count, 'ticket1.articles verify')
assert_equal(%w(aa kk), Tag.tag_list(object: 'Ticket', o_id: ticket1.id))
ticket1.state = Ticket::State.lookup(name: 'open')
@@ -105,7 +119,7 @@ class TicketTriggerTest < ActiveSupport::TestCase
assert_equal('Users', ticket1.group.name, 'ticket1.group verify')
assert_equal('open', ticket1.state.name, 'ticket1.state verify')
assert_equal('2 normal', ticket1.priority.name, 'ticket1.priority verify')
- assert_equal(1, ticket1.articles.count, 'ticket1.articles verify')
+ assert_equal(2, ticket1.articles.count, 'ticket1.articles verify')
assert_equal(%w(aa kk), Tag.tag_list(object: 'Ticket', o_id: ticket1.id))
ticket1.state = Ticket::State.lookup(name: 'new')
@@ -118,7 +132,7 @@ class TicketTriggerTest < ActiveSupport::TestCase
assert_equal('Users', ticket1.group.name, 'ticket1.group verify')
assert_equal('new', ticket1.state.name, 'ticket1.state verify')
assert_equal('3 high', ticket1.priority.name, 'ticket1.priority verify')
- assert_equal(2, ticket1.articles.count, 'ticket1.articles verify')
+ assert_equal(3, ticket1.articles.count, 'ticket1.articles verify')
assert_equal(%w(aa kk), Tag.tag_list(object: 'Ticket', o_id: ticket1.id))
article1 = ticket1.articles.last
assert_match('Zammad ', article1.from)
@@ -155,6 +169,56 @@ class TicketTriggerTest < ActiveSupport::TestCase
assert_equal(0, ticket2.articles.count, 'ticket2.articles verify')
assert_equal([], Tag.tag_list(object: 'Ticket', o_id: ticket2.id))
+ ticket3 = Ticket.create(
+ title: "some title \n äöüß3",
+ group: Group.lookup(name: 'Users'),
+ customer: User.lookup(email: 'nicole.braun@zammad.org'),
+ state: Ticket::State.lookup(name: 'new'),
+ priority: Ticket::Priority.lookup(name: '2 normal'),
+ updated_by_id: 1,
+ created_by_id: 1,
+ )
+ assert(ticket3, 'ticket3 created')
+ Ticket::Article.create(
+ ticket_id: ticket3.id,
+ from: 'some_sender@example.com',
+ to: 'some_recipient@example.com',
+ subject: 'some subject',
+ message_id: 'some@id',
+ content_type: 'text/html',
+ body: 'some message note new line',
+ internal: false,
+ sender: Ticket::Article::Sender.find_by(name: 'Agent'),
+ type: Ticket::Article::Type.find_by(name: 'note'),
+ updated_by_id: 1,
+ created_by_id: 1,
+ )
+
+ assert_equal('some title äöüß3', ticket3.title, 'ticket3.title verify')
+ assert_equal('Users', ticket3.group.name, 'ticket3.group verify')
+ assert_equal('new', ticket3.state.name, 'ticket3.state verify')
+ assert_equal('2 normal', ticket3.priority.name, 'ticket3.priority verify')
+ assert_equal(1, ticket3.articles.count, 'ticket3.articles verify')
+ assert_equal([], Tag.tag_list(object: 'Ticket', o_id: ticket3.id))
+
+ Observer::Transaction.commit
+
+ ticket3 = Ticket.lookup(id: ticket3.id)
+ assert_equal('some title äöüß3', ticket3.title, 'ticket3.title verify')
+ assert_equal('Users', ticket3.group.name, 'ticket3.group verify')
+ assert_equal('new', ticket3.state.name, 'ticket3.state verify')
+ assert_equal('3 high', ticket3.priority.name, 'ticket3.priority verify')
+ assert_equal(2, ticket3.articles.count, 'ticket3.articles verify')
+ assert_equal(%w(aa kk), Tag.tag_list(object: 'Ticket', o_id: ticket3.id))
+ article3 = ticket3.articles.last
+ assert_match('Zammad ', article3.from)
+ assert_match('nicole.braun@zammad.org', article3.to)
+ assert_match('Thanks for your inquiry (some title äöüß3)!', article3.subject)
+ assert_match('Braun some <b>title</b>', article3.body)
+ assert_match('> some message note > new line', article3.body)
+ assert_no_match('> some message <b>note</b> > new line', article3.body)
+ assert_equal('text/html', article3.content_type)
+
Trigger.destroy_all
end