Merge branch 'develop' of git.znuny.com:zammad/zammad into develop
This commit is contained in:
commit
80676678fc
57 changed files with 1361 additions and 346 deletions
1
Gemfile
1
Gemfile
|
@ -28,6 +28,7 @@ end
|
|||
|
||||
gem 'autoprefixer-rails'
|
||||
|
||||
gem 'doorkeeper'
|
||||
gem 'oauth2'
|
||||
|
||||
gem 'omniauth'
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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: <input class=\"js-select\" type=\"text\" value=\"#{@app.uid}\">
|
||||
<br>
|
||||
Secret: <input class=\"js-select\" type=\"text\" value=\"#{@app.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')}: <input class=\"js-select\" type=\"text\" value=\"#{data.token}\">"
|
||||
@update()
|
||||
@$('.js-submit').remove()
|
||||
)
|
||||
|
||||
App.Config.set('API', { prio: 1200, name: 'API', parent: '#system', target: '#system/api', controller: Index, permission: ['admin.api'] }, 'NavBarAdmin')
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -51,6 +51,7 @@ curl -u <%= @S('email') %>:some_password <%= @C('http_type') %>://<%= @C('fqdn')
|
|||
|
||||
<button class="btn js-appNew"><%- @T('New Application') %></button>
|
||||
|
||||
<br>
|
||||
<br>
|
||||
|
||||
<div>
|
||||
|
@ -59,7 +60,7 @@ OAuth URLs are:
|
|||
<table class="settings-list" style="width: 100%;">
|
||||
<thead>
|
||||
<tr>
|
||||
<th width="40%"><%- @T('Title') %>
|
||||
<th width="40%"><%- @T('Action') %>
|
||||
<th width="60%"><%- @T('URL') %>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
@ -69,9 +70,6 @@ OAuth URLs are:
|
|||
<tr>
|
||||
<td><%- @T('Getting an Access Token') %>
|
||||
<td><%= @C('http_type') %>://<%= @C('fqdn') %>/oauth/token
|
||||
<tr>
|
||||
<td><%- @T('Revoking Access') %>
|
||||
<td><%= @C('http_type') %>://<%= @C('fqdn') %>/oauth/applications
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
72
app/controllers/applications_controller.rb
Normal file
72
app/controllers/applications_controller.rb
Normal file
|
@ -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
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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?
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
Dein <%= c 'product_name' %> Passwort wurde geändert
|
||||
Dein #{config.product_name} Passwort wurde geändert
|
||||
|
||||
<div>Hallo <%= d 'user.firstname' %>,</div>
|
||||
<div>Hallo #{user.firstname},</div>
|
||||
<br>
|
||||
<div>das Passwort für Dein <%= c 'product_name' %> Account <b><%= d 'user.login' %></b> wurde kürzlich geändert.</div>
|
||||
<div>das Passwort für Dein #{config.product_name} Account <b>#{user.login}</b> wurde kürzlich geändert.</div>
|
||||
<br>
|
||||
<div>Diese Aktivität ist Dir nicht bekannt? In diesen Fall kontaktiere Deinen System-Administrator.</div>
|
||||
<br>
|
||||
<div>Dein <%= c 'product_name' %> Team</div>
|
||||
<div>Dein #{config.product_name} Team</div>
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
Your <%= c 'product_name' %> password has been changed
|
||||
Your #{product_name} password has been changed
|
||||
|
||||
<p>Hi <%= d 'user.firstname' %>,</p>
|
||||
<p>Hi #{user.firstname},</p>
|
||||
<br>
|
||||
<p>The password for your <%= c 'product_name' %> account <b><%= d 'user.login' %></b> has been changed recently.</p>
|
||||
<p>The password for your #{product_name} account <b>#{user.login}</b> has been changed recently.</p>
|
||||
<br>
|
||||
<p>This activity is not known to you? If not, contact your system administrator.</p>
|
||||
<br>
|
||||
<p>Your <%= c 'product_name' %> Team</p>
|
||||
<p>Your #{product_name} Team</p>
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
Zurücksetzen Deines <%= c 'product_name' %> Passworts
|
||||
Zurücksetzen Deines #{config.product_name} Passworts
|
||||
|
||||
<div>Hallo <%= d 'user.firstname' %>,</div>
|
||||
<div>Hallo #{user.firstname},</div>
|
||||
<br>
|
||||
<div>wir haben eine Anfrage zum Zurücksetzen des Passworts für <%= c 'product_name' %> Account <b><%= d 'user.login' %></b> erhalten.</div>
|
||||
<div>wir haben eine Anfrage zum Zurücksetzen des Passworts für #{config.product_name} Account <b>#{user.login}</b> erhalten.</div>
|
||||
<br>
|
||||
<div>Wenn Sie Ihr Passwort zurückzusetzen wollen, klicken Sie auf den unten stehenden Link (oder kopieren Sie die URL in den Browser einfügen):</div>
|
||||
<br>
|
||||
<div><a href="<%= c 'http_type' %>://<%= c 'fqdn' %>/#password_reset_verify/<%= d 'token.name' %>"><%= c 'http_type' %>://<%= c 'fqdn' %>/#password_reset_verify/<%= d 'token.name' %></a></div>
|
||||
<div><a href="#{config.http_type}://#{config.fqdn}/#password_reset_verify/#{token.name}">#{config.http_type}://#{config.fqdn}/#password_reset_verify/#{token.name}</a></div>
|
||||
<br>
|
||||
<div>Dieser Link führt Sie zu einer Seite, auf der Sie Ihr Passwort ändern können.</div>
|
||||
<br>
|
||||
<div>Wenn Sie Ihr Passwort nicht zurücksetzen wollen, ignorieren Sie diese Meldung. Das Passwort bleibt unverändert.</div>
|
||||
<br>
|
||||
<div>Dein <%= c 'product_name' %> Team</div>
|
||||
<div>Dein #{config.product_name} Team</div>
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
Reset your <%= c 'product_name' %> password
|
||||
Reset your #{config.product_name} password
|
||||
|
||||
<div>Hi <%= d 'user.firstname' %>,</div>
|
||||
<div>Hi #{user.firstname},</div>
|
||||
<br>
|
||||
<div>We received a request to reset the password for your <%= c 'product_name' %> account <b><%= d 'user.login' %></b>.</div>
|
||||
<div>We received a request to reset the password for your #{config.product_name} account <b>#{user.login}</b>.</div>
|
||||
<br>
|
||||
<div>If you want to reset your password, click on the link below (or copy and paste the URL into your browser):</div>
|
||||
<br>
|
||||
<div><a href="<%= c 'http_type' %>://<%= c 'fqdn' %>/#password_reset_verify/<%= d 'token.name' %>"><%= c 'http_type' %>://<%= c 'fqdn' %>/#password_reset_verify/<%= d 'token.name' %></a></div>
|
||||
<div><a href="#{config.http_type}://#{config.fqdn}/#password_reset_verify/#{token.name}">#{config.http_type}://#{config.fqdn}/#password_reset_verify/#{token.name}</a></div>
|
||||
<br>
|
||||
<div>This link takes you to a page where you can change your password.</div>
|
||||
<br>
|
||||
<div>If you don't want to reset your password, please ignore this message. Your password will not be reseted.</div>
|
||||
<br>
|
||||
<div>Your <%= c 'product_name' %> Team</div>
|
||||
<div>Your #{config.product_name} Team</div>
|
||||
|
|
|
@ -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}
|
||||
|
||||
<div>Hallo <%= d 'user.firstname' %>,</div>
|
||||
<div>Hallo #{user.firstname},</div>
|
||||
<br>
|
||||
<div>bestätige Deine E-Mail-Adresse um Deine Registrierung bei <%= c 'product_name' %> abzuschließen. Es ist einfach - klick einfach auf den Link unten.</div>
|
||||
<div>bestätige Deine E-Mail-Adresse um Deine Registrierung bei #{config.product_name} abzuschließen. Es ist einfach - klick einfach auf den Link unten.</div>
|
||||
<br>
|
||||
<div><a href="<%= c 'http_type' %>://<%= c 'fqdn' %>/#email_verify/<%= d 'token.name' %>"><%= c 'http_type' %>://<%= c 'fqdn' %>/#email_verify/<%= d 'token.name' %></a></div>
|
||||
<div><a href="#{config.http_type}://#{config.fqdn}/#email_verify/#{token.name}">#{config.http_type}://#{config.fqdn}/#email_verify/#{token.name}</a></div>
|
||||
<br>
|
||||
<div>Dein <%= c 'product_name' %> Team</div>
|
||||
<div>Dein #{config.product_name} Team</div>
|
||||
|
|
|
@ -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}
|
||||
|
||||
<div>Hi <%= d 'user.firstname' %>,</div>
|
||||
<div>Hi #{user.firstname},</div>
|
||||
<br>
|
||||
<div>Confirm your email address to complete your <%= c 'product_name' %> account. It's easy, just click the link below.</div>
|
||||
<div>Confirm your email address to complete your #{config.product_name} account. It's easy, just click the link below.</div>
|
||||
<br>
|
||||
<div><a href="<%= c 'http_type' %>://<%= c 'fqdn' %>/#email_verify/<%= d 'token.name' %>"><%= c 'http_type' %>://<%= c 'fqdn' %>/#email_verify/<%= d 'token.name' %></a></div>
|
||||
<div><a href="#{config.http_type}://#{config.fqdn}/#email_verify/#{token.name}">#{config.http_type}://#{config.fqdn}/#email_verify/#{token.name}</a></div>
|
||||
<br>
|
||||
<div>Your <%= c 'product_name' %> Team</div>
|
||||
<div>Your #{config.product_name} Team</div>
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
Test Ticket!
|
||||
|
||||
<div>Hallo <%= d 'agent.firstname' %>,</div>
|
||||
<div>Hallo #{agent.firstname},</div>
|
||||
<br>
|
||||
<div>dies ist ein <b>Test Ticket</b>. Ich bin ein Kunde und benötige Hilfe! :)</div>
|
||||
<br>
|
||||
<div><%= d 'customer.fullname' %></div>
|
||||
<div>#{customer.fullname}</div>
|
||||
<br>
|
||||
<div>Das Zammad Projekt</div>
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
Test Ticket!
|
||||
|
||||
<div>Dear <%= d 'agent.firstname' %>,</div>
|
||||
<div>Dear #{agent.firstname},</div>
|
||||
<br>
|
||||
<div>This is a <b>test ticket</b>. I'm a customer and I need some help! :)</div>
|
||||
<br>
|
||||
<div><%= d 'customer.fullname' %></div>
|
||||
<div>#{customer.fullname}</div>
|
||||
<br>
|
||||
<div>The Zammad Project</div>
|
||||
|
|
|
@ -1,24 +1,24 @@
|
|||
Neues Ticket (<%= d 'ticket.title' %>)
|
||||
Neues Ticket (#{ticket.title})
|
||||
|
||||
<div>Hallo <%= d 'recipient.firstname' %>,</div>
|
||||
<div>Hallo #{recipient.firstname},</div>
|
||||
<br>
|
||||
<div>es wurde ein neues Ticket (<%= d 'ticket.title' %>) von "<b><%= d 'current_user.longname' %></b>" erstellt.</div>
|
||||
<div>es wurde ein neues Ticket (#{ticket.title}) von "<b>#{current_user.longname}</b>" erstellt.</div>
|
||||
<br>
|
||||
<div>
|
||||
<%= t 'Group' %>: <%= d 'ticket.group.name' %><br>
|
||||
<%= t 'Owner' %>: <%= d 'ticket.owner.fullname' %><br>
|
||||
<%= t 'State' %>: <%= t d 'ticket.state.name' %><br>
|
||||
#{t('Group')}: #{ticket.group.name}<br>
|
||||
#{t('Owner')}: #{ticket.owner.fullname}<br>
|
||||
#{t('State')}: #{t(ticket.state.name)}<br>
|
||||
</div>
|
||||
<br>
|
||||
<% if @objects[:article] %>
|
||||
<div>
|
||||
<%= t 'Information' %>:
|
||||
#{t('Information')}:
|
||||
<blockquote type="cite">
|
||||
<%= a_html 'article' %>
|
||||
#{article.body_as_html}
|
||||
</blockquote>
|
||||
</div>
|
||||
<% end %>
|
||||
<br>
|
||||
<div>
|
||||
<a href="<%= c 'http_type' %>://<%= c 'fqdn' %>/#ticket/zoom/<%= d 'ticket.id' %>" target="zammad_app"><%= t 'View this in Zammad' %></a>
|
||||
<a href="#{config.http_type}://#{config.fqdn}/#ticket/zoom/#{ticket.id}" target="zammad_app">#{t('View this in Zammad')}</a>
|
||||
</div>
|
||||
|
|
|
@ -1,24 +1,24 @@
|
|||
New Ticket (<%= d 'ticket.title' %>)
|
||||
New Ticket (#{ticket.title})
|
||||
|
||||
<div>Hi <%= d 'recipient.firstname' %>,</div>
|
||||
<div>Hi #{recipient.firstname},</div>
|
||||
<br>
|
||||
<div>A new ticket (<%= d 'ticket.title' %>) has been created by "<b><%= d 'current_user.longname' %></b>".</div>
|
||||
<div>A new ticket (#{ticket.title}) has been created by "<b>#{current_user.longname}</b>".</div>
|
||||
<br>
|
||||
<div>
|
||||
<%= t 'Group' %>: <%= d 'ticket.group.name' %><br>
|
||||
<%= t 'Owner' %>: <%= d 'ticket.owner.fullname' %><br>
|
||||
<%= t 'State' %>: <%= t d 'ticket.state.name' %><br>
|
||||
#{t('Group')}: #{ticket.group.name}<br>
|
||||
#{t('Owner')}: #{ticket.owner.fullname}<br>
|
||||
#{t('State')}: #{t(ticket.state.name)}<br>
|
||||
</div>
|
||||
<br>
|
||||
<% if @objects[:article] %>
|
||||
<div>
|
||||
<%= t 'Information' %>:
|
||||
#{t('Information')}:
|
||||
<blockquote type="cite">
|
||||
<%= a_html 'article' %>
|
||||
#{article.body_as_html}
|
||||
</blockquote>
|
||||
</div>
|
||||
<% end %>
|
||||
<br>
|
||||
<div>
|
||||
<a href="<%= c 'http_type' %>://<%= c 'fqdn' %>/#ticket/zoom/<%= d 'ticket.id' %>" target="zammad_app"><%= t 'View this in Zammad' %></a>
|
||||
<a href="#{config.http_type}://#{config.fqdn}/#ticket/zoom/#{ticket.id}" target="zammad_app">#{t('View this in Zammad')}</a>
|
||||
</div>
|
||||
|
|
|
@ -1,18 +1,18 @@
|
|||
Ticket ist eskaliert (<%= d 'ticket.title' %>)
|
||||
Ticket ist eskaliert (#{ticket.title})
|
||||
|
||||
<div>Hallo <%= d 'recipient.firstname' %>,</div>
|
||||
<div>Hallo #{recipient.firstname},</div>
|
||||
<br>
|
||||
<div>Ticket (<%= d 'ticket.title' %>) von "<b><%= d 'ticket.customer.longname' %></b>" ist seit "<%= d 'ticket.escalation_at' %>" eskaliert!</div>
|
||||
<div>Ticket (#{ticket.title}) von "<b>#{ticket.customer.longname}</b>" ist seit "#{ticket.escalation_at}" eskaliert!</div>
|
||||
<br>
|
||||
<% if @objects[:article] %>
|
||||
<div>
|
||||
<%= t 'Information' %>:
|
||||
#{t('Information')}:
|
||||
<blockquote type="cite">
|
||||
<%= a_html 'article' %>
|
||||
#{article.body_as_html}
|
||||
</blockquote>
|
||||
</div>
|
||||
<% end %>
|
||||
<br>
|
||||
<div>
|
||||
<a href="<%= c 'http_type' %>://<%= c 'fqdn' %>/#ticket/zoom/<%= d 'ticket.id' %>" target="zammad_app"><%= t 'View this in Zammad' %></a>
|
||||
<a href="#{config.http_type}://#{config.fqdn}/#ticket/zoom/#{ticket.id}" target="zammad_app">#{t('View this in Zammad')}</a>
|
||||
</div>
|
||||
|
|
|
@ -1,18 +1,18 @@
|
|||
Ticket is escalated (<%= d 'ticket.title' %>)
|
||||
Ticket is escalated (#{ticket.title})
|
||||
|
||||
<div>Hi <%= d 'recipient.firstname' %>,</div>
|
||||
<div>Hi #{recipient.firstname},</div>
|
||||
<br>
|
||||
<div>A ticket (<%= d 'ticket.title' %>) from "<b><%= d 'ticket.customer.longname' %></b>" is escalated since "<%= d 'ticket.escalation_at' %>"!</div>
|
||||
<div>A ticket (#{ticket.title}) from "<b>#{ticket.customer.longname}</b>" is escalated since "#{ticket.escalation_at}"!</div>
|
||||
<br>
|
||||
<% if @objects[:article] %>
|
||||
<div>
|
||||
<%= t 'Information' %>:
|
||||
#{t('Information')}:
|
||||
<blockquote type="cite">
|
||||
<%= a_html 'article' %>
|
||||
#{article.body_as_html}
|
||||
</blockquote>
|
||||
</div>
|
||||
<% end %>
|
||||
<br>
|
||||
<div>
|
||||
<a href="<%= c 'http_type' %>://<%= c 'fqdn' %>/#ticket/zoom/<%= d 'ticket.id' %>" target="zammad_app"><%= t 'View this in Zammad' %></a>
|
||||
<a href="#{config.http_type}://#{config.fqdn}/#ticket/zoom/#{ticket.id}" target="zammad_app">#{t('View this in Zammad')}</a>
|
||||
</div>
|
||||
|
|
|
@ -1,18 +1,18 @@
|
|||
Ticket wird eskalieren (<%= d 'ticket.title' %>)
|
||||
Ticket wird eskalieren (#{ticket.title})
|
||||
|
||||
<div>Hallo <%= d 'recipient.firstname' %>,</div>
|
||||
<div>Hallo #{recipient.firstname},</div>
|
||||
<br>
|
||||
<div>Ticket (<%= d 'ticket.title' %>) von "<b><%= d 'ticket.customer.longname' %></b>" wird um "<%= d 'ticket.escalation_at' %>" eskalieren!</div>
|
||||
<div>Ticket (#{ticket.title}) von "<b>#{ticket.customer.longname}</b>" wird um "#{ticket.escalation_at}" eskalieren!</div>
|
||||
<br>
|
||||
<% if @objects[:article] %>
|
||||
<div>
|
||||
<%= t 'Information' %>:
|
||||
#{t('Information')}:
|
||||
<blockquote type="cite">
|
||||
<%= a_html 'article' %>
|
||||
#{article.body_as_html}
|
||||
</blockquote>
|
||||
</div>
|
||||
<% end %>
|
||||
<br>
|
||||
<div>
|
||||
<a href="<%= c 'http_type' %>://<%= c 'fqdn' %>/#ticket/zoom/<%= d 'ticket.id' %>" target="zammad_app"><%= t 'View this in Zammad' %></a>
|
||||
<a href="#{config.http_type}://#{config.fqdn}/#ticket/zoom/#{ticket.id}" target="zammad_app">#{t('View this in Zammad')}</a>
|
||||
</div>
|
||||
|
|
|
@ -1,18 +1,18 @@
|
|||
Ticket will escalate (<%= d 'ticket.title' %>)
|
||||
Ticket will escalate (#{ticket.title})
|
||||
|
||||
<div>Hi <%= d 'recipient.firstname' %>,</div>
|
||||
<div>Hi #{recipient.firstname},</div>
|
||||
<br>
|
||||
<div>A ticket (<%= d 'ticket.title' %>) from "<b><%= d 'ticket.customer.longname' %></b>" will escalate at "<%= d 'ticket.escalation_at' %>"!</div>
|
||||
<div>A ticket (#{ticket.title}) from "<b>#{ticket.customer.longname}</b>" will escalate at "#{ticket.escalation_at}"!</div>
|
||||
<br>
|
||||
<% if @objects[:article] %>
|
||||
<div>
|
||||
<%= t 'Information' %>:
|
||||
#{t('Information')}:
|
||||
<blockquote type="cite">
|
||||
<%= a_html 'article' %>
|
||||
#{article.body_as_html}
|
||||
</blockquote>
|
||||
</div>
|
||||
<% end %>
|
||||
<br>
|
||||
<div>
|
||||
<a href="<%= c 'http_type' %>://<%= c 'fqdn' %>/#ticket/zoom/<%= d 'ticket.id' %>" target="zammad_app"><%= t 'View this in Zammad' %></a>
|
||||
<a href="#{config.http_type}://#{config.fqdn}/#ticket/zoom/#{ticket.id}" target="zammad_app">#{t('View this in Zammad')}</a>
|
||||
</div>
|
||||
|
|
|
@ -1,18 +1,18 @@
|
|||
Warten auf Erinnerung erreicht! (<%= d 'ticket.title' %>)
|
||||
Warten auf Erinnerung erreicht! (#{ticket.title})
|
||||
|
||||
<div>Hallo <%= d 'recipient.firstname' %>,</div>
|
||||
<div>Hallo #{recipient.firstname},</div>
|
||||
<br>
|
||||
<div>dieses Ticket benötigt Deine Aufmerksamkeit, warten auf Erinnerung für (<%= d 'ticket.title' %>) mit dem Kunden "<b><%= d 'ticket.customer.longname' %></b>" ist erreicht.</div>
|
||||
<div>dieses Ticket benötigt Deine Aufmerksamkeit, warten auf Erinnerung für (#{ticket.title}) mit dem Kunden "<b>#{ticket.customer.longname}</b>" ist erreicht.</div>
|
||||
<br>
|
||||
<% if @objects[:article] %>
|
||||
<div>
|
||||
<%= t 'Information' %>:
|
||||
#{t('Information')}:
|
||||
<blockquote type="cite">
|
||||
<%= a_html 'article' %>
|
||||
#{article.body_as_html}
|
||||
</blockquote>
|
||||
</div>
|
||||
<% end %>
|
||||
<br>
|
||||
<div>
|
||||
<a href="<%= c 'http_type' %>://<%= c 'fqdn' %>/#ticket/zoom/<%= d 'ticket.id' %>" target="zammad_app"><%= t 'View this in Zammad' %></a>
|
||||
<a href="#{config.http_type}://#{config.fqdn}/#ticket/zoom/#{ticket.id}" target="zammad_app">#{t('View this in Zammad')}</a>
|
||||
</div>
|
||||
|
|
|
@ -1,18 +1,18 @@
|
|||
Reminder reached (<%= d 'ticket.title' %>)
|
||||
Reminder reached (#{ticket.title})
|
||||
|
||||
<div>Hi <%= d 'recipient.firstname' %>,</div>
|
||||
<div>Hi #{recipient.firstname},</div>
|
||||
<br>
|
||||
<div>A ticket needs attention, reminder reached for (<%= d 'ticket.title' %>) with customer "<b><%= d 'ticket.customer.longname' %></b>".</div>
|
||||
<div>A ticket needs attention, reminder reached for (#{ticket.title}) with customer "<b>#{ticket.customer.longname}</b>".</div>
|
||||
<br>
|
||||
<% if @objects[:article] %>
|
||||
<div>
|
||||
<%= t 'Information' %>:
|
||||
#{t('Information')}:
|
||||
<blockquote type="cite">
|
||||
<%= a_html 'article' %>
|
||||
#{article.body_as_html}
|
||||
</blockquote>
|
||||
</div>
|
||||
<% end %>
|
||||
<br>
|
||||
<div>
|
||||
<a href="<%= c 'http_type' %>://<%= c 'fqdn' %>/#ticket/zoom/<%= d 'ticket.id' %>" target="zammad_app"><%= t 'View this in Zammad' %></a>
|
||||
<a href="#{config.http_type}://#{config.fqdn}/#ticket/zoom/#{ticket.id}" target="zammad_app">#{t('View this in Zammad')}</a>
|
||||
</div>
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
Ticket aktualisiert (<%= d 'ticket.title' %>)
|
||||
Ticket aktualisiert (#{ticket.title})
|
||||
|
||||
<div>Hi <%= d 'recipient.firstname' %>,</div>
|
||||
<div>Hi #{recipient.firstname},</div>
|
||||
<br>
|
||||
<div>
|
||||
Ticket (<%= d 'ticket.title' %>) wurde von "<b><%= d 'current_user.longname' %></b>" aktualisiert.
|
||||
Ticket (#{ticket.title}) wurde von "<b>#{current_user.longname}</b>" aktualisiert.
|
||||
</div>
|
||||
<br>
|
||||
<% if @objects[:changes] && !@objects[:changes].empty? %>
|
||||
<div>
|
||||
<%= t 'Changes' %>:<br>
|
||||
#{t('Changes')}:<br>
|
||||
<% @objects[:changes].each do |key, value| %>
|
||||
<%= t key %>: <%= h value[0] %> -> <%= h value[1] %><br>
|
||||
<% end %>
|
||||
|
@ -17,13 +17,13 @@ Ticket (<%= d 'ticket.title' %>) wurde von "<b><%= d 'current_user.longname' %><
|
|||
<br>
|
||||
<% if @objects[:article] %>
|
||||
<div>
|
||||
<%= t 'Information' %>:
|
||||
#{t('Information')}:
|
||||
<blockquote type="cite">
|
||||
<%= a_html 'article' %>
|
||||
#{article.body_as_html}
|
||||
</blockquote>
|
||||
</div>
|
||||
<% end %>
|
||||
<br>
|
||||
<div>
|
||||
<a href="<%= c 'http_type' %>://<%= c 'fqdn' %>/#ticket/zoom/<%= d 'ticket.id' %>" target="zammad_app"><%= t 'View this in Zammad' %></a>
|
||||
<a href="#{config.http_type}://#{config.fqdn}/#ticket/zoom/#{ticket.id}" target="zammad_app">#{t('View this in Zammad')}</a>
|
||||
</div>
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
Updated Ticket (<%= d 'ticket.title' %>)
|
||||
Updated Ticket (#{ticket.title})
|
||||
|
||||
<div>Hi <%= d 'recipient.firstname' %>,</div>
|
||||
<div>Hi #{recipient.firstname},</div>
|
||||
<br>
|
||||
<div>
|
||||
Ticket (<%= d 'ticket.title' %>) has been updated by "<b><%= d 'current_user.longname' %></b>".
|
||||
Ticket (#{ticket.title}) has been updated by "<b>#{current_user.longname}</b>".
|
||||
</div>
|
||||
<br>
|
||||
<% if @objects[:changes] && !@objects[:changes].empty? %>
|
||||
<div>
|
||||
<%= t 'Changes' %>:<br>
|
||||
#{t('Changes')}:<br>
|
||||
<% @objects[:changes].each do |key, value| %>
|
||||
<%= t key %>: <%= h value[0] %> -> <%= h value[1] %><br>
|
||||
<% end %>
|
||||
|
@ -17,13 +17,13 @@ Ticket (<%= d 'ticket.title' %>) has been updated by "<b><%= d 'current_user.lon
|
|||
<br>
|
||||
<% if @objects[:article] %>
|
||||
<div>
|
||||
<%= t 'Information' %>:
|
||||
#{t('Information')}:
|
||||
<blockquote type="cite">
|
||||
<%= a_html 'article' %>
|
||||
#{article.body_as_html}
|
||||
</blockquote>
|
||||
</div>
|
||||
<% end %>
|
||||
<br>
|
||||
<div>
|
||||
<a href="<%= c 'http_type' %>://<%= c 'fqdn' %>/#ticket/zoom/<%= d 'ticket.id' %>" target="zammad_app"><%= t 'View this in Zammad' %></a>
|
||||
<a href="#{config.http_type}://#{config.fqdn}/#ticket/zoom/#{ticket.id}" target="zammad_app">#{t('View this in Zammad')}</a>
|
||||
</div>
|
||||
|
|
|
@ -1,19 +1,19 @@
|
|||
<%= c 'product_name' %>-Anmeldung erfasst von einem neuen Gerät
|
||||
#{config.product_name}-Anmeldung erfasst von einem neuen Gerät
|
||||
|
||||
<div>Hallo <%= d 'user.firstname' %>,</div>
|
||||
<div>Hallo #{user.firstname},</div>
|
||||
<br>
|
||||
<div>es sieht aus, als ob Du Dich mit <b>einem neuen Gerät</b> um "<%= d 'user_device.created_at' %>" angemeldet hast:</div>
|
||||
<div>es sieht aus, als ob Du Dich mit <b>einem neuen Gerät</b> um "#{user_device.created_at}" angemeldet hast:</div>
|
||||
<br>
|
||||
<div>
|
||||
Dein Gerät: <%= d 'user_device.name' %><br>
|
||||
Deine Lokation (relativ): <%= d 'user_device.location' %><br>
|
||||
Deine IP: <%= d 'user_device.ip' %><br>
|
||||
Dein Gerät: #{user_device.name}<br>
|
||||
Deine Lokation (relativ): #{user_device.location}<br>
|
||||
Deine IP: #{user_device.ip}<br>
|
||||
</div>
|
||||
<br>
|
||||
<div>Das Gerät wurde in die Liste der bekannten Geräte hinzugefügt, diese Liste kannst Du hier einsehen:</div>
|
||||
<br>
|
||||
<div><%= c 'http_type' %>://<%= c 'fqdn' %>/#profile/devices</div>
|
||||
<div>#{config.http_type}://#{config.fqdn}/#profile/devices</div>
|
||||
<br>
|
||||
<div>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.</div>
|
||||
<br>
|
||||
<div>Dein <%= c 'product_name' %> Team</div>
|
||||
<div>Dein #{config.product_name} Team</div>
|
||||
|
|
|
@ -1,19 +1,19 @@
|
|||
<%= c 'product_name' %> signin detected from a new device
|
||||
#{config.product_name} signin detected from a new device
|
||||
|
||||
<div>Hi <%= d 'user.firstname' %>,</div>
|
||||
<div>Hi #{user.firstname},</div>
|
||||
<br>
|
||||
<div>It looks like you signed into your account <b>using a new device</b> on "<%= d 'user_device.created_at' %>":</div>
|
||||
<div>It looks like you signed into your account <b>using a new device</b> on "#{user_device.created_at}":</div>
|
||||
<br>
|
||||
<div>
|
||||
Your device: <%= d 'user_device.name' %><br>
|
||||
Your location (relative): <%= d 'user_device.location' %><br>
|
||||
Your IP: <%= d 'user_device.ip' %><br>
|
||||
Your device: #{user_device.name}<br>
|
||||
Your location (relative): #{user_device.location}<br>
|
||||
Your IP: #{user_device.ip}<br>
|
||||
</div>
|
||||
<br>
|
||||
<div>Your device has been added to your list of known devices, which you can view here:</div>
|
||||
<br>
|
||||
<div><%= c 'http_type' %>://<%= c 'fqdn' %>/#profile/devices</div>
|
||||
<div>#{config.http_type}://#{config.fqdn}/#profile/devices</div>
|
||||
<br>
|
||||
<div>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.</div>
|
||||
<br>
|
||||
<div>Your <%= c 'product_name' %> Team</div>
|
||||
<div>Your #{config.product_name} Team</div>
|
||||
|
|
|
@ -1,19 +1,19 @@
|
|||
<%= c 'product_name' %>-Anmeldung von einem anderen Land erfasst
|
||||
#{config.product_name}-Anmeldung von einem anderen Land erfasst
|
||||
|
||||
<div>Hallo <%= d 'user.firstname' %>,</div>
|
||||
<div>Hallo #{user.firstname},</div>
|
||||
<br>
|
||||
<div>es sieht aus, als ob Du Dich um "<%= d 'user_device.created_at' %>" von einem <b>bekannten Gerät aus einem anderen Land angemeldet hast</b>:</div>
|
||||
<div>es sieht aus, als ob Du Dich um "#{user_device.created_at}" von einem <b>bekannten Gerät aus einem anderen Land angemeldet hast</b>:</div>
|
||||
<br>
|
||||
<div>
|
||||
Dein Gerät: <%= d 'user_device.name' %><br>
|
||||
Deine Lokation (relativ): <%= d 'user_device.location' %><br>
|
||||
Deine IP: <%= d 'user_device.ip' %><br>
|
||||
Dein Gerät: #{user_device.name}<br>
|
||||
Deine Lokation (relativ): #{user_device.location}<br>
|
||||
Deine IP: #{user_device.ip}<br>
|
||||
</div>
|
||||
<br>
|
||||
<div>Das neue Land wurde in die Liste der bekannten Geräte hinzugefügt, diese Liste kannst Du hier einsehen:</div>
|
||||
<br>
|
||||
<div><%= c 'http_type' %>://<%= c 'fqdn' %>/#profile/devices</div>
|
||||
<div>#{config.http_type}://#{config.fqdn}/#profile/devices</div>
|
||||
<br>
|
||||
<div>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.</div>
|
||||
<br>
|
||||
<div>Dein <%= c 'product_name' %> Team</div>
|
||||
<div>Dein #{config.product_name} Team</div>
|
||||
|
|
|
@ -1,19 +1,19 @@
|
|||
<%= c 'product_name' %> signin detected from a new country
|
||||
#{config.product_name} signin detected from a new country
|
||||
|
||||
<div>Hi <%= d 'user.firstname' %>,</div>
|
||||
<div>Hi #{user.firstname},</div>
|
||||
<br>
|
||||
<div>It looks like you used your account with an <b>known device but from a new country</b> on "<%= d 'user_device.created_at' %>":</div>
|
||||
<div>It looks like you used your account with an <b>known device but from a new country</b> on "#{user_device.created_at}":</div>
|
||||
<br>
|
||||
<div>
|
||||
Your device: <%= d 'user_device.name' %><br>
|
||||
Your location (relative): <%= d 'user_device.location' %><br>
|
||||
Your IP: <%= d 'user_device.ip' %><br>
|
||||
Your device: #{user_device.name}<br>
|
||||
Your location (relative): #{user_device.location}<br>
|
||||
Your IP: #{user_device.ip}<br>
|
||||
</div>
|
||||
<br>
|
||||
<div>The country has been added to your list of known devices, which you can view here:</div>
|
||||
<br>
|
||||
<div><%= c 'http_type' %>://<%= c 'fqdn' %>/#profile/devices</div>
|
||||
<div>#{config.http_type}://#{config.fqdn}/#profile/devices</div>
|
||||
<br>
|
||||
<div>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.</div>
|
||||
<br>
|
||||
<div>Your <%= c 'product_name' %> Team</div>
|
||||
<div>Your #{config.product_name} Team</div>
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
Einladung zu <%= c 'product_name' %> über <%= c 'fqdn' %>
|
||||
Einladung zu #{config.product_name} über #{config.fqdn}
|
||||
|
||||
<div>Hallo <%= d 'user.firstname' %>,</div>
|
||||
<div>Hallo #{user.firstname},</div>
|
||||
<br>
|
||||
<div>Ich (<%= d 'current_user.firstname' %> <%= d 'current_user.lastname' %>) möchte Dich zu <%= c 'product_name' %> einladen - unsere Kundensupport / Ticket System Platform.</div>
|
||||
<div>Ich (#{current_user.firstname} #{current_user.lastname}) möchte Dich zu #{config.product_name} einladen - unsere Kundensupport / Ticket System Platform.</div>
|
||||
<br>
|
||||
<div>Um sich anzumelden kann <a href="<%= c 'http_type' %>://<%= c 'fqdn' %>/#password_reset_verify/<%= d 'token.name' %>">hier</a> das Password gesetzt werden.</div>
|
||||
<div>Um sich anzumelden kann <a href="#{config.http_type}://#{config.fqdn}/#password_reset_verify/#{token.name}">hier</a> das Password gesetzt werden.</div>
|
||||
<br>
|
||||
<div>Enjoy,</div>
|
||||
<br>
|
||||
<div><%= d 'current_user.firstname' %> <%= d 'current_user.lastname' %></div>
|
||||
<div>#{current_user.firstname} #{current_user.lastname}</div>
|
||||
<br>
|
||||
<div>Dein <%= c 'product_name' %> Team</div>
|
||||
<div>Dein #{config.product_name} Team</div>
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
Invitation to <%= c 'product_name' %> at <%= c 'fqdn' %>
|
||||
Invitation to #{config.product_name} at #{config.fqdn}
|
||||
|
||||
<div>Hi <%= d 'user.firstname' %>,</div>
|
||||
<div>Hi #{user.firstname},</div>
|
||||
<br>
|
||||
<div>I (<%= d 'current_user.firstname' %> <%= d 'current_user.lastname' %>) invite you to <%= c 'product_name' %> - our customer support / ticket system platform.</div>
|
||||
<div>I (#{current_user.firstname} #{current_user.lastname}) invite you to #{config.product_name} - our customer support / ticket system platform.</div>
|
||||
<br>
|
||||
<div>Click <a href="<%= c 'http_type' %>://<%= c 'fqdn' %>/#password_reset_verify/<%= d 'token.name' %>">here</a> and set your password.</div>
|
||||
<div>Click <a href="#{config.http_type}://#{config.fqdn}/#password_reset_verify/#{token.name}">here</a> and set your password.</div>
|
||||
<br>
|
||||
<div>Enjoy,</div>
|
||||
<br>
|
||||
<div><%= d 'current_user.firstname' %> <%= d 'current_user.lastname' %></div>
|
||||
<div>#{current_user.firstname} #{current_user.lastname}</div>
|
||||
<br>
|
||||
<div>Your <%= c 'product_name' %> Team</div>
|
||||
<div>Your #{config.product_name} Team</div>
|
||||
|
|
|
@ -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 %>
|
||||
|
|
|
@ -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 %>
|
||||
|
|
|
@ -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 %>
|
||||
|
|
|
@ -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 %>
|
||||
|
|
|
@ -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 %>
|
||||
|
|
112
config/initializers/doorkeeper.rb
Normal file
112
config/initializers/doorkeeper.rb
Normal file
|
@ -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
|
124
config/locales/doorkeeper.en.yml
Normal file
124
config/locales/doorkeeper.en.yml
Normal file
|
@ -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'
|
14
config/routes/applications.rb
Normal file
14
config/routes/applications.rb
Normal file
|
@ -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
|
|
@ -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
|
||||
|
|
68
db/migrate/20161101131409_create_doorkeeper_tables.rb
Normal file
68
db/migrate/20161101131409_create_doorkeeper_tables.rb
Normal file
|
@ -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
|
|
@ -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
|
69
db/seeds.rb
69
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',
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -9,7 +9,7 @@ examples how to use
|
|||
ticket: Ticket.first,
|
||||
},
|
||||
'de-de',
|
||||
'some template <b><%= d "ticket.title", false %></b> <%= c "fqdn", false %>',
|
||||
'some template <b>#{ticket.title}</b> {config.fqdn}',
|
||||
false
|
||||
).render
|
||||
|
||||
|
@ -18,7 +18,7 @@ examples how to use
|
|||
ticket: Ticket.first,
|
||||
},
|
||||
'de-de',
|
||||
'some template <b><%= d "ticket.title", true %></b> <%= c "fqdn", true %>',
|
||||
'some template <b>#{ticket.title}</b> #{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
|
||||
|
||||
|
|
|
@ -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!,
|
||||
|
|
|
@ -5,13 +5,15 @@ class NotificationFactory::Template
|
|||
examples how to use
|
||||
|
||||
cleaned_template = NotificationFactory::Template.new(
|
||||
'some template <b><%= d "ticket.title", false %></b> <%= c "fqdn", false %>',
|
||||
'some template <b>#{ticket.title}</b> #{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
|
||||
|
|
|
@ -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('Notification<b>xxx</b>', 'Agent1<b>yyy</b>', 'Notification<b>xxx</b> Agent1<b>yyy</b>', 'Notification<b>xxx</b> Agent1<b>yyy</b> (Zammad)')
|
||||
current_user = User.new('CurrentUser<b>xxx</b>', 'Agent2<b>yyy</b>', 'CurrentUser<b>xxx</b> Agent2<b>yyy</b>', 'CurrentUser<b>xxx</b> Agent2<b>yyy</b> (Zammad)')
|
||||
recipient = User.new('Recipient<b>xxx</b>', 'Customer1<b>yyy</b>', 'Recipient<b>xxx</b> Customer1<b>yyy</b>', 'Recipient<b>xxx</b> Customer1<b>yyy</b> (Zammad)')
|
||||
ticket = Ticket.new(1, '<b>Welcome to Zammad!</b>', group, owner, state)
|
||||
group = Group.new(name: 'Users')
|
||||
owner = User.new(firstname: 'Notification<b>xxx</b>', lastname: 'Agent1<b>yyy</b>')
|
||||
current_user = User.new(firstname: 'CurrentUser<b>xxx</b>', lastname: 'Agent2<b>yyy</b>')
|
||||
recipient = User.new(firstname: 'Recipient<b>xxx</b>', lastname: 'Customer1<b>yyy</b>')
|
||||
state = Ticket::State.new(name: 'new')
|
||||
ticket = Ticket.new(
|
||||
id: 1,
|
||||
title: '<b>Welcome to Zammad!</b>',
|
||||
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 <b>hello</b><br>some new line',
|
||||
content_type: 'text/html',
|
||||
)
|
||||
article_plain1 = Ticket::Article.new(
|
||||
body: "test <b>hello</b>\nsome new line",
|
||||
content_type: 'text/plain',
|
||||
)
|
||||
article_plain2 = Ticket::Article.new(
|
||||
body: "test <b>hello</b>\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<br>\#{article.body}"
|
||||
result = described_class.new(
|
||||
{
|
||||
article: article_html1,
|
||||
},
|
||||
'en-us',
|
||||
template,
|
||||
).render
|
||||
assert_equal('some test<br>> test hello<br>> some new line<br>', result)
|
||||
|
||||
result = described_class.new(
|
||||
{
|
||||
article: article_plain1,
|
||||
},
|
||||
'en-us',
|
||||
template,
|
||||
).render
|
||||
assert_equal('some test<br>> test <b>hello</b><br>> some new line<br>', result)
|
||||
|
||||
result = described_class.new(
|
||||
{
|
||||
article: article_plain2,
|
||||
},
|
||||
'en-us',
|
||||
template,
|
||||
).render
|
||||
assert_equal('some test<br>> test <b>hello</b><br>> some new line<br>', 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
|
||||
|
||||
|
|
|
@ -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('User<b>xxx</b>', result[:body])
|
||||
assert_match('Created by', result[:body])
|
||||
assert_match('<b>test123</b>', 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('User<b>xxx</b>', result[:body])
|
||||
assert_match('state: aaa -> bbb', result[:body])
|
||||
assert_match('group: xxx -> yyy', result[:body])
|
||||
assert_no_match('Dein', result[:body])
|
||||
|
|
|
@ -11,48 +11,69 @@ class NotificationFactoryTemplateTest < ActiveSupport::TestCase
|
|||
test 'regular browser html' do
|
||||
|
||||
# ensures https://github.com/zammad/zammad/issues/385
|
||||
template_before = '<%= d "#{<a href="http://ticket.id" title="http://ticket.id" target="_blank">ticket.id</a>}" %>'
|
||||
template_after = '<%= d "ticket.id" %>'
|
||||
template_before = '#{<a href="http://ticket.id" title="http://ticket.id" target="_blank">ticket.id</a>}'
|
||||
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 = '#{<a href="http://ticket.id" title="http://ticket.id" target="_blank">config.fqdn</a>}'
|
||||
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 "#{ <a href="http://ticket.id" title="http://ticket.id" target="_blank">ticket.id </a>} " %>'
|
||||
template_after = '<%= d "ticket.id " %>'
|
||||
template_before = '#{ <a href="http://ticket.id" title="http://ticket.id" target="_blank">ticket.id </a> }'
|
||||
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 "#{<a href="http://ticket.id" title="http://ticket.id" target="_blank">ticket.id }" %>'
|
||||
template_after = '<%= d "ticket.id " %>'
|
||||
template_before = '#{<a href="http://ticket.id" title="http://ticket.id" target="_blank">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
|
||||
|
||||
|
|
78
test/unit/organization_domain_based_assignment_test.rb
Normal file
78
test/unit/organization_domain_based_assignment_test.rb
Normal file
|
@ -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
|
|
@ -13,7 +13,7 @@ class TicketTriggerTest < ActiveSupport::TestCase
|
|||
},
|
||||
perform: {
|
||||
'notification.email' => {
|
||||
'body' => 'some text<br>#{ticket.customer.lastname}<br>#{ticket.title}',
|
||||
'body' => 'some text<br>#{ticket.customer.lastname}<br>#{ticket.title}<br>#{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 <b>note</b>\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 <b>title</b> äöüß', 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 <zammad@localhost>', article1.from)
|
||||
assert_match('nicole.braun@zammad.org', article1.to)
|
||||
assert_match('Thanks for your inquiry (some <b>title</b> äöüß)!', article1.subject)
|
||||
assert_match('Braun<br>some <b>title</b>', article1.body)
|
||||
assert_match('> some message <b>note</b><br>> 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 <zammad@localhost>', 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 <b>title</b>\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 <b>note</b><br>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 <b>title</b> äöüß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 <b>title</b> äöüß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 <zammad@localhost>', article3.from)
|
||||
assert_match('nicole.braun@zammad.org', article3.to)
|
||||
assert_match('Thanks for your inquiry (some <b>title</b> äöüß3)!', article3.subject)
|
||||
assert_match('Braun<br>some <b>title</b>', article3.body)
|
||||
assert_match('> some message note<br>> new line', article3.body)
|
||||
assert_no_match('> some message <b>note</b><br>> new line', article3.body)
|
||||
assert_equal('text/html', article3.content_type)
|
||||
|
||||
Trigger.destroy_all
|
||||
end
|
||||
|
||||
|
|
Loading…
Reference in a new issue