Moved to new notification factory. Added notification templates to app/views/mailer/*.

This commit is contained in:
Martin Edenhofer 2016-02-19 22:05:36 +01:00
parent 159ff5f21a
commit d54bb4fa05
26 changed files with 765 additions and 394 deletions

View file

@ -43,6 +43,7 @@ class Index extends App.ControllerContent
if !@params.login && @params.email if !@params.login && @params.email
@params.login = @params.email @params.login = @params.email
@params.signup = true
@params.role_ids = [0] @params.role_ids = [0]
@log 'notice', 'updateAttributes', @params @log 'notice', 'updateAttributes', @params
user = new App.User user = new App.User

View file

@ -1,5 +1,5 @@
class App.User extends App.Model class App.User extends App.Model
@configure 'User', 'login', 'firstname', 'lastname', 'email', 'web', 'password', 'phone', 'fax', 'mobile', 'street', 'zip', 'city', 'country', 'organization_id', 'department', 'note', 'role_ids', 'group_ids', 'active', 'invite', 'updated_at' @configure 'User', 'login', 'firstname', 'lastname', 'email', 'web', 'password', 'phone', 'fax', 'mobile', 'street', 'zip', 'city', 'country', 'organization_id', 'department', 'note', 'role_ids', 'group_ids', 'active', 'invite', 'signup', 'updated_at'
@extend Spine.Model.Ajax @extend Spine.Model.Ajax
@url: @apiPath + '/users' @url: @apiPath + '/users'

View file

@ -135,46 +135,28 @@ class UsersController < ApplicationController
# send inviteation if needed / only if session exists # send inviteation if needed / only if session exists
if params[:invite] && current_user if params[:invite] && current_user
# generate token
token = Token.create(action: 'PasswordReset', user_id: user.id) token = Token.create(action: 'PasswordReset', user_id: user.id)
NotificationFactory.notification(
template: 'user_invite',
user: user,
objects: {
token: token,
user: user,
current_user: current_user,
}
)
end
# send mail # send email verify
data = {} if params[:signup] && !current_user
data[:subject] = 'Invitation to #{config.product_name} at #{config.fqdn}' token = Token.create(action: 'EmailVerify', user_id: user.id)
data[:body] = 'Hi #{user.firstname}, NotificationFactory.notification(
template: 'signup',
I (#{current_user.firstname} #{current_user.lastname}) invite you to #{config.product_name} - the customer support / ticket system platform. user: user,
objects: {
Click on the following link and set your password: token: token,
user: user,
#{config.http_type}://#{config.fqdn}/#password_reset_verify/#{token.name} }
Enjoy,
#{current_user.firstname} #{current_user.lastname}
Your #{config.product_name} Team
'
# prepare subject & body
[:subject, :body].each { |key|
data[key.to_sym] = NotificationFactory.build(
locale: user.preferences[:locale],
string: data[key.to_sym],
objects: {
token: token,
user: user,
current_user: current_user,
}
)
}
# send notification
NotificationFactory.send(
recipient: user,
subject: data[:subject],
body: data[:body]
) )
end end
user_new = User.find(user.id) user_new = User.find(user.id)
@ -434,12 +416,20 @@ curl http://localhost/api/v1/users/password_reset.json -v -u #{login}:#{password
return return
end end
token = User.password_reset_send(params[:username]) result = User.password_reset_new_token(params[:username])
if token if result && result[:token]
# send mail
user = result[:user]
NotificationFactory.notification(
template: 'password_reset',
user: user,
objects: result
)
# only if system is in develop mode, send token back to browser for browser tests # only if system is in develop mode, send token back to browser for browser tests
if Setting.get('developer_mode') == true if Setting.get('developer_mode') == true
render json: { message: 'ok', token: token.name }, status: :ok render json: { message: 'ok', token: result[:token].name }, status: :ok
return return
end end
@ -485,6 +475,19 @@ curl http://localhost/api/v1/users/password_reset_verify.json -v -u #{login}:#{p
# set new password with token # set new password with token
user = User.password_reset_via_token(params[:token], params[:password]) user = User.password_reset_via_token(params[:token], params[:password])
# send mail
if user
NotificationFactory.notification(
template: 'password_change',
user: user,
objects: {
user: user,
current_user: current_user,
}
)
end
else else
user = User.password_reset_check(params[:token]) user = User.password_reset_check(params[:token])
end end
@ -543,6 +546,16 @@ curl http://localhost/api/v1/users/password_change.json -v -u #{login}:#{passwor
end end
user.update_attributes(password: params[:password_new]) user.update_attributes(password: params[:password_new])
NotificationFactory.notification(
template: 'password_change',
user: user,
objects: {
user: user,
current_user: current_user,
}
)
render json: { message: 'ok', user_login: user.login }, status: :ok render json: { message: 'ok', user_login: user.login }, status: :ok
end end

View file

@ -10,7 +10,7 @@ process emails from STDIN
e. g. e. g.
cat test/fixtures/mail1.box | rails r 'Channel::Driver::MailStdin.new' cat test/fixtures/mail1.box | rails r 'Channel::Driver::MailStdin.new'
=end =end

View file

@ -133,7 +133,7 @@ class Observer::Ticket::Notification::BackgroundJob
created_by_id: ticket.updated_by_id || 1, created_by_id: ticket.updated_by_id || 1,
user_id: user.id, user_id: user.id,
) )
Rails.logger.info "send ticket online notifiaction to agent (#{@p[:type]}/#{ticket.id}/#{user.email})" Rails.logger.debug "sent ticket online notifiaction to agent (#{@p[:type]}/#{ticket.id}/#{user.email})"
end end
# ignore email channel notificaiton and empty emails # ignore email channel notificaiton and empty emails
@ -147,39 +147,26 @@ class Observer::Ticket::Notification::BackgroundJob
# get user based notification template # get user based notification template
# if create, send create message / block update messages # if create, send create message / block update messages
template = nil
if @p[:type] == 'create' if @p[:type] == 'create'
template = template_create(user, ticket, article, changes) template = 'ticket_create'
elsif @p[:type] == 'update' elsif @p[:type] == 'update'
template = template_update(user, ticket, article, changes) template = 'ticket_update'
else else
fail "unknown type for notification #{@p[:type]}" fail "unknown type for notification #{@p[:type]}"
end end
# prepare subject & body NotificationFactory.notification(
notification = {} template: template,
[:subject, :body].each { |key| user: user,
notification[key.to_sym] = NotificationFactory.build( objects: {
locale: user.preferences[:locale], ticket: ticket,
string: template[key], article: article,
objects: { recipient: user,
ticket: ticket, changes: changes,
article: article, }
recipient: user,
}
)
}
# rebuild subject
notification[:subject] = ticket.subject_build(notification[:subject])
Rails.logger.info "send ticket email notifiaction to agent (#{@p[:type]}/#{ticket.id}/#{user.email})"
NotificationFactory.send(
recipient: user,
subject: notification[:subject],
body: notification[:body],
content_type: 'text/html',
) )
Rails.logger.debug "sent ticket email notifiaction to agent (#{@p[:type]}/#{ticket.id}/#{user.email})"
end end
end end
@ -203,6 +190,7 @@ class Observer::Ticket::Notification::BackgroundJob
def human_changes(user, record) def human_changes(user, record)
return {} if !@p[:changes] return {} if !@p[:changes]
locale = user.preferences[:locale] || 'en-us'
# only show allowed attributes # only show allowed attributes
attribute_list = ObjectManager::Attribute.by_object_as_hash('Ticket', user) attribute_list = ObjectManager::Attribute.by_object_as_hash('Ticket', user)
@ -278,7 +266,9 @@ class Observer::Ticket::Notification::BackgroundJob
display = object_manager_attribute[:display].to_s display = object_manager_attribute[:display].to_s
end end
changes[display] = if object_manager_attribute && object_manager_attribute[:translate] changes[display] = if object_manager_attribute && object_manager_attribute[:translate]
["i18n(#{value_str[0]})", "i18n(#{value_str[1]})"] from = Translation.translate(locale, value_str[0])
to = Translation.translate(locale, value_str[1])
[from, to]
else else
[value_str[0].to_s, value_str[1].to_s] [value_str[0].to_s, value_str[1].to_s]
end end
@ -286,176 +276,4 @@ class Observer::Ticket::Notification::BackgroundJob
changes changes
end end
def template_create(user, ticket, article, _ticket_changes)
article_content = ''
if article
article_content = 'i18n(Information):
<blockquote type="cite">
#{article.body.text2html}
</blockquote>
<br>
<br>'
end
if user.preferences[:locale] =~ /^de/i
subject = 'Neues Ticket (#{ticket.title})'
body = '<div>Hallo #{recipient.firstname.text2html},</div>
<br>
<div>
es wurde ein neues Ticket (#{ticket.title.text2html}) von "<b>#{ticket.updated_by.fullname.text2html}</b>" erstellt.
</div>
<br>
<div>
i18n(Group): #{ticket.group.name.text2html}<br>
i18n(Owner): #{ticket.owner.fullname.text2html}<br>
i18n(State): i18n(#{ticket.state.name.text2html})<br>
</div>
<br>
<div>
' + article_content + '
</div>
'
else
subject = 'New Ticket (#{ticket.title})'
body = '<div>Hi #{recipient.firstname.text2html},</div>
<br>
<div>
a new Ticket (#{ticket.title.text2html}) has been created by "<b>#{ticket.updated_by.fullname.text2html}</b>".
</div>
<br>
<div>
Group: #{ticket.group.name.text2html}<br>
Owner: #{ticket.owner.fullname.text2html}<br>
State: i18n(#{ticket.state.name.text2html})<br>
</div>
<br>
<div>
' + article_content + '
</div>
'
end
body = template_header(user) + body
body += template_footer(user, ticket, article)
template = {
subject: subject,
body: body,
}
template
end
def template_update(user, ticket, article, ticket_changes)
changes = ''
ticket_changes.each {|key, value|
changes += "i18n(#{key.to_s.text2html}): #{value[0].to_s.text2html} -> #{value[1].to_s.text2html}<br>\n"
}
article_content = ''
if article
article_content = 'i18n(Information):
<blockquote type="cite">
#{article.body.text2html}
</blockquote>
<br>
<br>'
end
if user.preferences[:locale] =~ /^de/i
subject = 'Ticket aktualisiert (#{ticket.title})'
body = '<div>Hallo #{recipient.firstname.text2html},</div>
<br>
<div>
Ticket (#{ticket.title.text2html}) wurde von "<b>#{ticket.updated_by.fullname.text2html}</b>" aktualisiert.
</div>
<br>
<div>
i18n(Changes):<br>
' + changes + '
</div>
<br>
<div>
' + article_content + '
</div>
'
else
subject = 'Updated Ticket (#{ticket.title})'
body = '<div>Hi #{recipient.firstname.text2html},</div>
<br>
<div>
Ticket (#{ticket.title.text2html}) has been updated by "<b>#{ticket.updated_by.fullname.text2html}</b>".
</div>
<br>
<div>
i18n(Changes):<br>
' + changes + '
</div>
<br>
<div>
' + article_content + '
</div>
'
end
body = template_header(user) + body
body += template_footer(user, ticket, article)
template = {
subject: subject,
body: body,
}
template
end
def template_header(_user)
'
<style type="text/css">
blockquote {
border-left: 2px solid blue;
padding-left: 1em;
}
.header {
color: #aaaaaa;
border-bottom-style:solid;
border-bottom-width:1px;
border-bottom-color:#aaaaaa;
width: 100%;
max-width: 600px;
padding-bottom: 6px;
margin-bottom: 16px;
padding-top: 6px;
font-size: 16px;
}
.footer {
color: #aaaaaa;
border-top-style:solid;
border-top-width:1px;
border-top-color:#aaaaaa;
width: 100%;
max-width: 600px;
padding-top: 6px;
margin-top: 16px;
padding-botton: 6px;
}
.footer a {
color: #aaaaaa;
}
</style>
<div class="header">
#{config.product_name} i18n(Notification)
</div>
'
end
def template_footer(_user, _ticket, _article)
'
<p>
<a href="#{config.http_type}://#{config.fqdn}/#ticket/zoom/#{ticket.id}" target="zammad_app">i18n(View this in Zammad)</a>
</p>
<div class="footer">
<a href="#{config.http_type}://#{config.fqdn}/#profile/notifications">i18n(Manage your notifications settings)</a>
</div>
'
end
end end

View file

@ -283,17 +283,20 @@ returns
=begin =begin
send reset password email with token to user generate new token for reset password
result = User.password_reset_send(username) result = User.password_reset_new_token(username)
returns returns
result = token result = {
token: token,
user: user,
}
=end =end
def self.password_reset_send(username) def self.password_reset_new_token(username)
return if !username || username == '' return if !username || username == ''
# try to find user based on login # try to find user based on login
@ -311,42 +314,10 @@ returns
# generate token # generate token
token = Token.create(action: 'PasswordReset', user_id: user.id) token = Token.create(action: 'PasswordReset', user_id: user.id)
# send mail {
data = {} token: token,
data[:subject] = 'Reset your #{config.product_name} password' user: user,
data[:body] = 'Forgot your password?
We received a request to reset the password for your #{config.product_name} account (#{user.login}).
If you want to reset your password, click on the link below (or copy and paste the URL into your browser):
#{config.http_type}://#{config.fqdn}/#password_reset_verify/#{token.name}
This link takes you to a page where you can change your password.
If you don\'t want to reset your password, please ignore this message. Your password will not be reset.
Your #{config.product_name} Team'
# prepare subject & body
[:subject, :body].each { |key|
data[key.to_sym] = NotificationFactory.build(
locale: user.preferences[:locale],
string: data[key.to_sym],
objects: {
token: token,
user: user,
}
)
} }
# send notification
NotificationFactory.send(
recipient: user,
subject: data[:subject],
body: data[:body]
)
token
end end
=begin =begin

View file

@ -154,41 +154,13 @@ send new user device info
def send_notification def send_notification
user = User.find(user_id) user = User.find(user_id)
# send mail NotificationFactory.notification(
data = {} template: 'user_device',
data[:subject] = '#{config.product_name} signin detected from a new device' user: user,
data[:body] = 'Hi #{user.firstname}, objects: {
user_device: self,
it looks like you signed into your #{config.product_name} account using a new device on "#{user_device.created_at}": user: user,
}
Your Location: #{user_device.location}
Your IP: #{user_device.ip}
Your device has been added to your list of known devices, which you can view here:
#{config.http_type}://#{config.fqdn}/#profile/devices
If this wasn\'t you, remove the device, changing your account password, and contacting your administrator. Somebody might have gained unauthorized access to your account.
Your #{config.product_name} Team'
# prepare subject & body
[:subject, :body].each { |key|
data[key.to_sym] = NotificationFactory.build(
locale: user.preferences[:locale],
string: data[key.to_sym],
objects: {
user_device: self,
user: user,
}
)
}
# send notification
NotificationFactory.send(
recipient: user,
subject: data[:subject],
body: data[:body]
) )
end end
end end

View file

@ -0,0 +1,42 @@
<style type="text/css">
blockquote {
border-left: 2px solid blue;
padding-left: 1em;
}
.header {
color: #aaaaaa;
border-bottom-style:solid;
border-bottom-width:1px;
border-bottom-color:#aaaaaa;
width: 100%;
max-width: 600px;
padding-bottom: 6px;
margin-bottom: 16px;
padding-top: 6px;
font-size: 16px;
}
.footer {
color: #aaaaaa;
border-top-style:solid;
border-top-width:1px;
border-top-color:#aaaaaa;
width: 100%;
max-width: 600px;
padding-top: 6px;
margin-top: 16px;
padding-botton: 6px;
}
.footer a {
color: #aaaaaa;
}
</style>
<div class="header">
<%= c 'product_name' %> <%= t 'Notification' %>
</div>
<%= d 'message', false %>
<div class="footer">
<a href="<%= c 'http_type' %>://<%= c 'fqdn' %>/#profile/notifications"><%= t 'Manage your notifications settings' %></a> | <%= c 'organization' %>
</div>

View file

@ -0,0 +1,9 @@
Dein <%= c 'product_name' %> Passwort wurde geändert
<p>Hallo <%= d 'user.firstname' %>,</p>
<br>
<p>das Passwort für Dein <%= c 'product_name' %> Account <b><%= d 'user.login' %></b> wurde kürzlich geändert.</p>
<br>
<p>Diese Aktivität ist Dir nicht bekannt? In diesen Fall kontaktiere Deinen System-Administrator.</p>
<br>
<p>Dein <%= c 'product_name' %> Team</p>

View file

@ -0,0 +1,9 @@
Your <%= c 'product_name' %> password has been changed
<p>Hi <%= d 'user.firstname' %>,</p>
<br>
<p>the password for your <%= c 'product_name' %> account <b><%= d '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>

View file

@ -0,0 +1,17 @@
Zurücksetzen Deines <%= c 'product_name' %> Passworts
<p>
Hallo <%= d 'user.firstname' %>,
</p>
<br>
<p>wir haben eine Anfrage zum Zurücksetzen des Passworts für <%= c 'product_name' %> Account <b><%= d 'user.login' %></b> erhalten.</p>
<br>
<p>Wenn Sie Ihr Passwort zurückzusetzen wollen, klicken Sie auf den unten stehenden Link (oder kopieren Sie die URL in den Browser einfügen):</p>
<br>
<p><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></p>
<br>
<p>Dieser Link führt Sie zu einer Seite, auf der Sie Ihr Passwort ändern können.</p>
<br>
<p>Wenn Sie Ihr Passwort nicht zurücksetzen wollen, ignorieren Sie diese Meldung. Das Passwort bleibt unverändert.</p>
<br>
<p>Dein <%= c 'product_name' %> Team</p>

View file

@ -0,0 +1,15 @@
Reset your <%= c 'product_name' %> password
<p>Hi <%= d 'user.firstname' %>,</p>
<br>
<p>We received a request to reset the password for your <%= c 'product_name' %> account <b><%= d 'user.login' %></b>.</p>
<br>
<p>If you want to reset your password, click on the link below (or copy and paste the URL into your browser):</p>
<br>
<p><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></p>
<br>
<p>This link takes you to a page where you can change your password.</p>
<br>
<p>If you don't want to reset your password, please ignore this message. Your password will not be reset.</p>
<br>
<p>Your <%= c 'product_name' %> Team</p>

View file

@ -0,0 +1,9 @@
Bestätigung des <%= c 'product_name' %> Accounts, <%= d 'user.firstname' %> <%= d 'user.lastname' %>
<p>Hallo <%= d 'user.firstname' %>,</p>
<br>
<p>bestätige Deine E-Mail-Adresse um Deine Registrierung bei <%= c 'product_name' %> abzuschließen. Es ist einfach - klick einfach auf den Link unten.</p>
<br>
<p><a href="<%= c 'http_type' %>://<%= c 'fqdn' %>/#email_verify/<%= d 'token.name' %>"><%= c 'http_type' %>://<%= c 'fqdn' %>/#email_verify/<%= d 'token.name' %></a></p>
<br>
<p>Dein <%= c 'product_name' %> Team</p>

View file

@ -0,0 +1,9 @@
Confirm your <%= c 'product_name' %> account, <%= d 'user.firstname' %> <%= d 'user.lastname' %>
<p>Hi <%= d 'user.firstname' %>,</p>
<br>
<p>confirm your email address to complete your <%= c 'product_name' %> account. It's easy, just click the link below.</p>
<br>
<p><a href="<%= c 'http_type' %>://<%= c 'fqdn' %>/#email_verify/<%= d 'token.name' %>"><%= c 'http_type' %>://<%= c 'fqdn' %>/#email_verify/<%= d 'token.name' %></a></p>
<br>
<p>Your <%= c 'product_name' %> Team</p>

View file

@ -0,0 +1,24 @@
Neues Ticket (<%= d 'ticket.title' %>)
<p>Hallo <%= d 'recipient.firstname' %>,</p>
<br>
<p>es wurde ein neues Ticket (<%= d 'ticket.title' %>) von "<b><%= d 'ticket.updated_by.fullname' %></b>" erstellt.</p>
<br>
<p>
<%= t 'Group' %>: <%= d 'ticket.group.name' %><br>
<%= t 'Owner' %>: <%= d 'ticket.owner.fullname' %><br>
<%= t 'State' %>: <%= t d 'ticket.state.name' %><br>
</p>
<br>
<% if @objects[:article] %>
<p>
<%= t 'Information' %>:
<blockquote type="cite">
<%= d('article.body').text2html %>
</blockquote>
</p>
<% end %>
<br>
<p>
<a href="<%= c 'http_type' %>://<%= c 'fqdn' %>/#ticket/zoom/<%= d 'ticket.id' %>" target="zammad_app"><%= t 'View this in Zammad' %></a>
</p>

View file

@ -0,0 +1,24 @@
New Ticket (<%= d 'ticket.title' %>)
<p>Hi <%= d 'recipient.firstname' %>,</p>
<br>
<p>a new Ticket (<%= d 'ticket.title' %>) has been created by "<b><%= d 'ticket.updated_by.fullname' %></b>".</p>
<br>
<p>
<%= t 'Group' %>: <%= d 'ticket.group.name' %><br>
<%= t 'Owner' %>: <%= d 'ticket.owner.fullname' %><br>
<%= t 'State' %>: <%= t d 'ticket.state.name' %><br>
</p>
<br>
<% if @objects[:article] %>
<p>
<%= t 'Information' %>:
<blockquote type="cite">
<%= d('article.body').text2html %>
</blockquote>
</p>
<% end %>
<br>
<p>
<a href="<%= c 'http_type' %>://<%= c 'fqdn' %>/#ticket/zoom/<%= d 'ticket.id' %>" target="zammad_app"><%= t 'View this in Zammad' %></a>
</p>

View file

@ -0,0 +1,29 @@
Ticket aktualisiert (<%= d 'ticket.title' %>)
<p>Hi <%= d 'recipient.firstname' %>,</p>
<br>
<div>
Ticket (<%= d 'ticket.title' %>) wurde von "<b><%= d 'ticket.updated_by.fullname' %></b>" aktualisiert.
</div>
<br>
<% if @objects[:changes] && !@objects[:changes].empty? %>
<p>
<%= t 'Changes' %>:<br>
<% @objects[:changes].each do |key, value| %>
<%= t key %>: <%= h value[0] %> -&gt; <%= h value[1] %><br>
<% end %>
</p>
<% end %>
<br>
<% if @objects[:article] %>
<p>
<%= t 'Information' %>:
<blockquote type="cite">
<%= a 'article' %>
</blockquote>
</p>
<% end %>
<br>
<p>
<a href="<%= c 'http_type' %>://<%= c 'fqdn' %>/#ticket/zoom/<%= d 'ticket.id' %>" target="zammad_app"><%= t 'View this in Zammad' %></a>
</p>

View file

@ -0,0 +1,29 @@
Updated Ticket (<%= d 'ticket.title' %>)
<p>Hi <%= d 'recipient.firstname' %>,</p>
<br>
<div>
Ticket (<%= d 'ticket.title' %>) has been updated by "<b><%= d 'ticket.updated_by.fullname' %></b>".
</div>
<br>
<% if @objects[:changes] && !@objects[:changes].empty? %>
<p>
<%= t 'Changes' %>:<br>
<% @objects[:changes].each do |key, value| %>
<%= t key %>: <%= h value[0] %> -&gt; <%= h value[1] %><br>
<% end %>
</p>
<% end %>
<br>
<% if @objects[:article] %>
<p>
<%= t 'Information' %>:
<blockquote type="cite">
<%= d('article.body').text2html %>
</blockquote>
</p>
<% end %>
<br>
<p>
<a href="<%= c 'http_type' %>://<%= c 'fqdn' %>/#ticket/zoom/<%= d 'ticket.id' %>" target="zammad_app"><%= t 'View this in Zammad' %></a>
</p>

View file

@ -0,0 +1,18 @@
<%= c 'product_name' %>-Anmeldung erfasst von einem neuen Gerät
<p>Hallo <%= d 'user.firstname' %>,</p>
<br>
<p>es sieht aus, als ob Du Dich bei <%= c 'product_name' %> mit einem neuen Gerät um "<%= d 'user_device.created_at' %>" angemeldet hast:</p>
<br>
<p>
Deine Lokation (relativ): <%= d 'user_device.location' %><br>
Deine IP: <%= d 'user_device.ip' %><br
</p>
<br>
<p>Das Gerät wurde in die Liste der bekannten Geräte hinzugefügt, diese Liste kannst Du hier einsehen:</p>
<br>
<p><%= c 'http_type' %>://<%= c 'fqdn' %>/#profile/devices</p>
<br>
<p>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.</p>
<br>
<p>Dein <%= c 'product_name' %> Team</p>

View file

@ -0,0 +1,18 @@
<%= c 'product_name' %> signin detected from a new device
<p>Hi <%= d 'user.firstname' %>,</p>
<br>
<p>it looks like you signed into your <%= c 'product_name' %> account using a new device on "<%= d 'user_device.created_at' %>":</p>
<br>
<p>
Your Location: <%= d 'user_device.location' %><br>
Your IP: <%= d 'user_device.ip' %><br
</p>
<br>
<p>Your device has been added to your list of known devices, which you can view here:</p>
<br>
<p><%= c 'http_type' %>://<%= c 'fqdn' %>/#profile/devices</p>
<br>
<p>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.</p>
<br>
<p>Your <%= c 'product_name' %> Team</p>

View file

@ -0,0 +1,13 @@
Einladung zu <%= c 'product_name' %> über <%= c 'fqdn' %>
<p>Hallo <%= d 'user.firstname' %>,</p>
<br>
<p>Ich (<%= d 'current_user.firstname' %> <%= d 'current_user.lastname' %>) möchte Dich zu <%= c 'product_name' %> einladen - unsere Kundensupport / Ticket System Platform.</p>
<br>
<p>Um sich anzumelden kann <a href="<%= c 'http_type' %>://<%= c 'fqdn' %>/#password_reset_verify/<%= d 'token.name' %>">hier</a> das Password gesetzt werden.</p>
<br>
<p>Enjoy,</p>
<br>
<p><%= d 'current_user.firstname' %> <%= d 'current_user.lastname' %></p>
<br>
<p>Dein <%= c 'product_name' %> Team</p>

View file

@ -0,0 +1,13 @@
Invitation to <%= c 'product_name' %> at <%= c 'fqdn' %>
<p>Hi <%= d 'user.firstname' %>,</p>
<br>
<p>I (<%= d 'current_user.firstname' %> <%= d 'current_user.lastname' %>) invite you to <%= c 'product_name' %> - our customer support / ticket system platform.</p>
<br>
<p>Click <a href="<%= c 'http_type' %>://<%= c 'fqdn' %>/#password_reset_verify/<%= d 'token.name' %>">here</a> and set your password.</p>
<br>
<p>Enjoy,</p>
<br>
<p><%= d 'current_user.firstname' %> <%= d 'current_user.lastname' %></p>
<br>
<p>Your <%= c 'product_name' %> Team</p>

View file

@ -2,6 +2,8 @@ module NotificationFactory
=begin =begin
# deprecated, will be removed with 2.0
result_string = NotificationFactory.build( result_string = NotificationFactory.build(
string: 'Hi #{recipient.firstname},', string: 'Hi #{recipient.firstname},',
objects: { objects: {
@ -125,4 +127,172 @@ module NotificationFactory
true true
) )
end end
=begin
NotificationFactory.notification(
template: 'password_reset',
user: User.find(2),
objects: {
recipient: User.find(2),
},
)
=end
def self.notification(data)
# get subject
result = NotificationFactory.template(
template: data[:template],
locale: data[:user].preferences[:locale],
objects: data[:objects],
)
NotificationFactory.send(
recipient: data[:user],
subject: result[:subject],
body: result[:body],
content_type: 'text/html',
)
end
=begin
result = NotificationFactory.template(
template: 'password_reset',
locale: 'en-us',
objects: {
recipient: User.find(2),
},
)
result = NotificationFactory.template(
templateInline: "Invitation to <%= c 'product_name' %> at <%= c 'fqdn' %>",
locale: 'en-us',
objects: {
recipient: User.find(2),
},
)
=end
def self.template(data)
if data[:templateInline]
return NotificationFactory::Template.new(data[:objects], data[:locale], data[:templateInline], false).render
end
template_subject = nil
template_body = ''
locale = data[:locale] || 'en'
template = data[:template]
location = "app/views/mailer/#{template}/#{locale}.html.erb"
# as fallback, use 2 char locale
if !File.exist?(location)
locale = locale[0, 2]
location = "app/views/mailer/#{template}/#{locale}.html.erb"
end
# as fallback, use en
if !File.exist?(location)
location = "app/views/mailer/#{template}/en.html.erb"
end
File.open(location, 'r:UTF-8').each do |line|
if !template_subject
template_subject = line
next
end
template_body += line
end
message_subject = NotificationFactory::Template.new(data[:objects], data[:locale], template_subject, false).render
message_body = NotificationFactory::Template.new(data[:objects], data[:locale], template_body).render
application_template = nil
File.open('app/views/mailer/application.html.erb', 'r:UTF-8') do |file|
application_template = file.read
end
data[:objects][:message] = message_body
message_body = NotificationFactory::Template.new(data[:objects], data[:locale], application_template).render
{
subject: message_subject,
body: message_body,
}
end
class Template
def initialize(objects, locale, template, escape = true)
@objects = objects
@locale = locale || 'en-us'
@template = template
@escape = escape
end
def render
ERB.new(@template).result(binding)
end
def d(key, escape = nil)
# do validaton, ignore some methodes
if key =~ /(`|\.(|\s*)(save|destroy|delete|remove|drop|update\(|update_att|create\(|new|all|where|find))/i
return "#{key} (not allowed)"
end
value = nil
object_methods = key.split('.')
object_name = object_methods.shift.to_sym
object_refs = @objects[object_name]
object_methods_s = ''
object_methods.each {|method|
if object_methods_s != ''
object_methods_s += '.'
end
object_methods_s += method
# if method exists
if !object_refs.respond_to?( method.to_sym )
value = "\#{#{object_name}.#{object_methods_s} / no such method}"
break
end
object_refs = object_refs.send( method.to_sym )
}
placeholder = if !value
object_refs
else
value
end
return placeholder if escape == false || (escape.nil? && !@escape)
h placeholder
end
def c(key, escape = nil)
config = Setting.get(key)
return config if escape == false || (escape.nil? && !@escape)
h config
end
def t(key, escape = nil)
translation = Translation.translate(@locale, key)
return translation if escape == false || (escape.nil? && !@escape)
h translation
end
def a(article)
content_type = d "#{article}.content_type", false
if content_type =~ /html/
return d "#{article}.body", false
end
d("#{article}.content_type", false).text2html
end
def h(key)
return key if !key
CGI.escapeHTML(key.to_s)
end
end
end end

View file

@ -122,7 +122,7 @@ returns
# store hash in config # store hash in config
if list && list[0] if list && list[0]
file = Store.find(list[0]) file = Store.find(list[0].id)
filelocation = filename(file) filelocation = filename(file)
Setting.set('product_logo', filelocation) Setting.set('product_logo', filelocation)
return file return file

View file

@ -296,4 +296,139 @@ next line, Group: Users',
ticket.destroy ticket.destroy
end end
test 'notifications template' do
groups = Group.where(name: 'Users')
roles = Role.where(name: 'Agent')
agent1 = User.create_or_update(
login: 'notification-template-agent1@example.com',
firstname: 'Notification<b>xxx</b>',
lastname: 'Agent1<b>yyy</b>',
email: 'notification-template-agent1@example.com',
password: 'agentpw',
active: true,
roles: roles,
groups: groups,
preferences: {
locale: 'de-de',
},
updated_by_id: 1,
created_by_id: 1,
)
result = NotificationFactory.template(
template: 'password_reset',
locale: 'de-de',
objects: {
user: agent1,
},
)
assert_match('Zurücksetzen Deines', result[:subject])
assert_match('wir haben eine Anfrage zum Zurücksetzen', result[:body])
assert_match('Dein', result[:body])
assert_match('Dein', result[:body])
assert_match('Notification&lt;b&gt;xxx&lt;/b&gt;', result[:body])
assert_no_match('Your', result[:body])
result = NotificationFactory.template(
template: 'password_reset',
locale: 'de',
objects: {
user: agent1,
},
)
assert_match('Zurücksetzen Deines', result[:subject])
assert_match('wir haben eine Anfrage zum Zurücksetzen', result[:body])
assert_match('Dein', result[:body])
assert_match('Notification&lt;b&gt;xxx&lt;/b&gt;', result[:body])
assert_no_match('Your', result[:body])
result = NotificationFactory.template(
template: 'password_reset',
locale: 'es-us',
objects: {
user: agent1,
},
)
assert_match('Reset your', result[:subject])
assert_match('We received a request to reset the password', result[:body])
assert_match('Your', result[:body])
assert_match('Notification&lt;b&gt;xxx&lt;/b&gt;', result[:body])
assert_no_match('Dein', result[:body])
ticket = Ticket.first
article = ticket.articles.first
changes = {}
result = NotificationFactory.template(
template: 'ticket_create',
locale: 'es-us',
objects: {
ticket: ticket,
article: article,
recipient: agent1,
changes: changes,
},
)
assert_match('New Ticket', result[:subject])
assert_match('Notification&lt;b&gt;xxx&lt;/b&gt;', result[:body])
assert_match('has been created by', result[:body])
assert_match('Manage your notifications settings', result[:body])
assert_no_match('Dein', result[:body])
result = NotificationFactory.template(
template: 'ticket_create',
locale: 'de-de',
objects: {
ticket: ticket,
article: article,
recipient: agent1,
changes: changes,
},
)
assert_match('Neues Ticket', result[:subject])
assert_match('Notification&lt;b&gt;xxx&lt;/b&gt;', result[:body])
assert_match('es wurde ein neues Ticket', result[:body])
assert_match('Manage your notifications settings', result[:body])
assert_no_match('Your', result[:body])
ticket = Ticket.first
article = ticket.articles.first
changes = {
state: %w(aaa bbb),
group: %w(xxx yyy),
}
result = NotificationFactory.template(
template: 'ticket_update',
locale: 'es-us',
objects: {
ticket: ticket,
article: article,
recipient: agent1,
changes: changes,
},
)
assert_match('Updated Ticket', result[:subject])
assert_match('Notification&lt;b&gt;xxx&lt;/b&gt;', result[:body])
assert_match('has been updated by', result[:body])
assert_match('Manage your notifications settings', result[:body])
assert_no_match('Dein', result[:body])
result = NotificationFactory.template(
template: 'ticket_update',
locale: 'de-de',
objects: {
ticket: ticket,
article: article,
recipient: agent1,
changes: changes,
},
)
assert_match('Ticket aktualisiert', result[:subject])
assert_match('Notification&lt;b&gt;xxx&lt;/b&gt;', result[:body])
assert_match('wurde von', result[:body])
assert_match('Manage your notifications settings', result[:body])
assert_no_match('Your', result[:body])
end
end end

View file

@ -927,129 +927,142 @@ class TicketNotificationTest < ActiveSupport::TestCase
) )
# check changed attributes # check changed attributes
human_changes = bg.human_changes(agent1, ticket1) human_changes = bg.human_changes(agent2, ticket1)
assert( human_changes['Priority'], 'Check if attributes translated based on ObjectManager::Attribute' ) assert( human_changes['Priority'], 'Check if attributes translated based on ObjectManager::Attribute' )
assert( human_changes['Pending till'], 'Check if attributes translated based on ObjectManager::Attribute' ) assert( human_changes['Pending till'], 'Check if attributes translated based on ObjectManager::Attribute' )
assert_equal( 'i18n(1 low)', human_changes['Priority'][0] ) assert_equal( '1 low', human_changes['Priority'][0] )
assert_equal( 'i18n(2 normal)', human_changes['Priority'][1] ) assert_equal( '2 normal', human_changes['Priority'][1] )
assert_equal( 'i18n()', human_changes['Pending till'][0] ) assert_equal( '', human_changes['Pending till'][0].to_s )
assert_equal( 'i18n(2015-01-11 23:33:47 UTC)', human_changes['Pending till'][1] ) assert_equal( '2015-01-11 23:33:47 UTC', human_changes['Pending till'][1].to_s )
assert_not( human_changes['priority_id'] ) assert_not( human_changes['priority_id'] )
assert_not( human_changes['pending_time'] ) assert_not( human_changes['pending_time'] )
assert_not( human_changes['pending_till'] ) assert_not( human_changes['pending_till'] )
# en template
template = bg.template_update(agent2, ticket1, article, human_changes)
assert( template[:subject] )
assert( template[:body] )
assert_match( /Priority/, template[:body] )
assert_match( /1 low/, template[:body] )
assert_match( /2 normal/, template[:body] )
assert_match( /Pending till/, template[:body] )
assert_match( /2015-01-11 23:33:47 UTC/, template[:body] )
assert_match( /updated/i, template[:subject] )
# en notification # en notification
subject = NotificationFactory.build( result = NotificationFactory.template(
locale: agent2.preferences[:locale], locale: agent2.preferences[:locale],
string: template[:subject], template: 'ticket_update',
objects: { objects: {
ticket: ticket1, ticket: ticket1,
article: article, article: article,
recipient: agent2, recipient: agent2,
changes: human_changes,
} }
) )
assert_match( /Bobs's resumé/, subject ) assert_match(/Bobs's resumé/, result[:subject])
body = NotificationFactory.build( assert_match(/Priority/, result[:body])
locale: agent2.preferences[:locale], assert_match(/1 low/, result[:body])
string: template[:body], assert_match(/2 normal/, result[:body])
objects: { assert_match(/Pending till/, result[:body])
ticket: ticket1, assert_match(/2015-01-11 23:33:47 UTC/, result[:body])
article: article, assert_match(/update/, result[:body])
recipient: agent2, assert_no_match(/pending_till/, result[:body])
} assert_no_match(/i18n/, result[:body])
)
assert_match(/Priority/, body)
assert_match(/1 low/, body)
assert_match(/2 normal/, body)
assert_match(/Pending till/, body)
assert_match(/2015-01-11 23:33:47 UTC/, body)
assert_match(/update/, body)
assert_no_match(/pending_till/, body)
assert_no_match(/i18n/, body)
# de template human_changes = bg.human_changes(agent1, ticket1)
template = bg.template_update(agent1, ticket1, article, human_changes) assert( human_changes['Priority'], 'Check if attributes translated based on ObjectManager::Attribute' )
assert(template[:subject]) assert( human_changes['Pending till'], 'Check if attributes translated based on ObjectManager::Attribute' )
assert(template[:body]) assert_equal( '1 niedrig', human_changes['Priority'][0] )
assert_match(/Priority/, template[:body]) assert_equal( '2 normal', human_changes['Priority'][1] )
assert_match(/1 low/, template[:body]) assert_equal( '', human_changes['Pending till'][0].to_s )
assert_match(/2 normal/, template[:body]) assert_equal( '2015-01-11 23:33:47 UTC', human_changes['Pending till'][1].to_s )
assert_match(/Pending till/, template[:body]) assert_not( human_changes['priority_id'] )
assert_match(/2015-01-11 23:33:47 UTC/, template[:body]) assert_not( human_changes['pending_time'] )
assert_match(/aktualis/, template[:subject]) assert_not( human_changes['pending_till'] )
# de notification # de notification
subject = NotificationFactory.build( result = NotificationFactory.template(
locale: agent1.preferences[:locale], locale: agent1.preferences[:locale],
string: template[:subject], template: 'ticket_update',
objects: {
ticket: ticket1,
article: article,
recipient: agent2,
}
)
assert_match(/Bobs's resumé/, subject)
body = NotificationFactory.build(
locale: agent1.preferences[:locale],
string: template[:body],
objects: { objects: {
ticket: ticket1, ticket: ticket1,
article: article, article: article,
recipient: agent1, recipient: agent1,
changes: human_changes,
} }
) )
assert_match(/Priorität/, body) assert_match(/Bobs's resumé/, result[:subject])
assert_match(/1 niedrig/, body) assert_match(/Priorität/, result[:body])
assert_match(/2 normal/, body) assert_match(/1 niedrig/, result[:body])
assert_match(/Warten/, body) assert_match(/2 normal/, result[:body])
assert_match(/2015-01-11 23:33:47 UTC/, body) assert_match(/Warten/, result[:body])
assert_match(/aktualis/, body) assert_match(/2015-01-11 23:33:47 UTC/, result[:body])
assert_no_match(/pending_till/, body) assert_match(/aktualis/, result[:body])
assert_no_match(/i18n/, body) assert_no_match(/pending_till/, result[:body])
assert_no_match(/i18n/, result[:body])
bg = Observer::Ticket::Notification::BackgroundJob.new( bg = Observer::Ticket::Notification::BackgroundJob.new(
ticket_id: ticket1.id, ticket_id: ticket1.id,
article_id: article.id, article_id: article.id,
type: 'update', type: 'update',
changes: { changes: {
title: ['some notification template test 1', 'some notification template test 1 #2'], title: ['some notification template test old 1', 'some notification template test 1 #2'],
priority_id: [2, 3], priority_id: [2, 3],
}, },
) )
#puts "hc #{human_changes.inspect}"
# check changed attributes # check changed attributes
human_changes = bg.human_changes(agent1, ticket1) human_changes = bg.human_changes(agent1, ticket1)
assert(human_changes['Title'], 'Check if attributes translated based on ObjectManager::Attribute') assert(human_changes['Title'], 'Check if attributes translated based on ObjectManager::Attribute')
assert(human_changes['Priority'], 'Check if attributes translated based on ObjectManager::Attribute') assert(human_changes['Priority'], 'Check if attributes translated based on ObjectManager::Attribute')
assert_equal('i18n(2 normal)', human_changes['Priority'][0]) assert_equal('2 normal', human_changes['Priority'][0])
assert_equal('i18n(3 high)', human_changes['Priority'][1]) assert_equal('3 hoch', human_changes['Priority'][1])
assert_equal('some notification template test 1', human_changes['Title'][0]) assert_equal('some notification template test old 1', human_changes['Title'][0])
assert_equal('some notification template test 1 #2', human_changes['Title'][1]) assert_equal('some notification template test 1 #2', human_changes['Title'][1])
assert_not(human_changes['priority_id']) assert_not(human_changes['priority_id'])
assert_not(human_changes['pending_time']) assert_not(human_changes['pending_time'])
assert_not(human_changes['pending_till']) assert_not(human_changes['pending_till'])
# de notification
result = NotificationFactory.template(
locale: agent1.preferences[:locale],
template: 'ticket_update',
objects: {
ticket: ticket1,
article: article,
recipient: agent1,
changes: human_changes,
}
)
assert_match(/Bobs's resumé/, result[:subject])
assert_match(/Titel/, result[:body])
assert_no_match(/Title/, result[:body])
assert_match(/some notification template test old 1/, result[:body])
assert_match(/some notification template test 1 #2/, result[:body])
assert_match(/Priorität/, result[:body])
assert_no_match(/Priority/, result[:body])
assert_match(/3 hoch/, result[:body])
assert_match(/2 normal/, result[:body])
assert_match(/aktualisier/, result[:body])
human_changes = bg.human_changes(agent2, ticket1) human_changes = bg.human_changes(agent2, ticket1)
#puts "hc2 #{human_changes.inspect}"
template = bg.template_update(agent1, ticket1, article, human_changes) # en notification
#puts "t1 #{template.inspect}" result = NotificationFactory.template(
locale: agent2.preferences[:locale],
template: 'ticket_update',
objects: {
ticket: ticket1,
article: article,
recipient: agent2,
changes: human_changes,
}
)
template = bg.template_update(agent2, ticket1, article, human_changes) assert_match(/Bobs's resumé/, result[:subject])
#puts "t2 #{template.inspect}" assert_match(/Title/, result[:body])
assert_match(/some notification template test old 1/, result[:body])
assert_match(/some notification template test 1 #2/, result[:body])
assert_match(/Priority/, result[:body])
assert_match(/3 high/, result[:body])
assert_match(/2 normal/, result[:body])
assert_no_match(/Pending till/, result[:body])
assert_no_match(/2015-01-11 23:33:47 UTC/, result[:body])
assert_match(/update/, result[:body])
assert_no_match(/pending_till/, result[:body])
assert_no_match(/i18n/, result[:body])
end end