WIP: Add Signal notification support for Zammad agents
This commit is contained in:
parent
ac42d7df78
commit
1f2809080a
10 changed files with 648 additions and 0 deletions
|
|
@ -0,0 +1,89 @@
|
||||||
|
class ProfileSignalNotifications extends App.ControllerSubContent
|
||||||
|
@requiredPermission: 'user_preferences.signal_notifications+ticket.agent'
|
||||||
|
header: __('Signal Notifications')
|
||||||
|
events:
|
||||||
|
'submit form': 'update'
|
||||||
|
|
||||||
|
constructor: ->
|
||||||
|
super
|
||||||
|
App.User.full(App.Session.get().id, @render, true, true)
|
||||||
|
|
||||||
|
render: =>
|
||||||
|
config =
|
||||||
|
enabled: false
|
||||||
|
events:
|
||||||
|
create: true
|
||||||
|
update: true
|
||||||
|
escalation: true
|
||||||
|
reminder_reached: true
|
||||||
|
|
||||||
|
user = App.User.find(App.Session.get().id)
|
||||||
|
user_config = user.preferences?.signal_notifications
|
||||||
|
if user_config
|
||||||
|
config = $.extend(true, {}, config, user_config)
|
||||||
|
|
||||||
|
@html App.view('profile/signal_notifications')
|
||||||
|
config: config
|
||||||
|
signal_uid: user.signal_uid || ''
|
||||||
|
signal_notification_enabled: App.Config.get('signal_notification_enabled')
|
||||||
|
|
||||||
|
update: (e) =>
|
||||||
|
e.preventDefault()
|
||||||
|
params = @formParam(e.target)
|
||||||
|
|
||||||
|
preferences = {}
|
||||||
|
preferences.signal_notifications =
|
||||||
|
enabled: params.enabled == 'true'
|
||||||
|
events:
|
||||||
|
create: params.event_create == 'true'
|
||||||
|
update: params.event_update == 'true'
|
||||||
|
escalation: params.event_escalation == 'true'
|
||||||
|
reminder_reached: params.event_reminder_reached == 'true'
|
||||||
|
|
||||||
|
@formDisable(e)
|
||||||
|
|
||||||
|
@ajax(
|
||||||
|
id: 'preferences_signal_notifications'
|
||||||
|
type: 'PUT'
|
||||||
|
url: @apiPath + '/users/preferences'
|
||||||
|
data: JSON.stringify(preferences)
|
||||||
|
processData: true
|
||||||
|
success: @successPreferences
|
||||||
|
error: @error
|
||||||
|
)
|
||||||
|
|
||||||
|
if params.signal_uid?
|
||||||
|
user = App.User.find(App.Session.get().id)
|
||||||
|
user.signal_uid = params.signal_uid
|
||||||
|
user.save(
|
||||||
|
done: =>
|
||||||
|
# User saved successfully
|
||||||
|
fail: (settings, details) =>
|
||||||
|
@notify(
|
||||||
|
type: 'error'
|
||||||
|
msg: details.error || __('Failed to save Signal phone number')
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
successPreferences: (data, status, xhr) =>
|
||||||
|
App.User.full(
|
||||||
|
App.Session.get('id'),
|
||||||
|
=>
|
||||||
|
App.Event.trigger('ui:rerender')
|
||||||
|
@notify(
|
||||||
|
type: 'success'
|
||||||
|
msg: __('Update successful.')
|
||||||
|
)
|
||||||
|
,
|
||||||
|
true
|
||||||
|
)
|
||||||
|
|
||||||
|
error: (xhr, status, error) =>
|
||||||
|
@render()
|
||||||
|
data = JSON.parse(xhr.responseText)
|
||||||
|
@notify(
|
||||||
|
type: 'error'
|
||||||
|
msg: data.message
|
||||||
|
)
|
||||||
|
|
||||||
|
App.Config.set('SignalNotifications', { prio: 2650, name: __('Signal Notifications'), parent: '#profile', target: '#profile/signal_notifications', permission: ['user_preferences.signal_notifications+ticket.agent'], controller: ProfileSignalNotifications }, 'NavBarProfile')
|
||||||
|
|
@ -0,0 +1,86 @@
|
||||||
|
<div class="page-header">
|
||||||
|
<div class="page-header-title"><h1><%- @T('Signal Notifications') %></h1></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<% if !@signal_notification_enabled: %>
|
||||||
|
<div class="alert alert--warning" role="alert">
|
||||||
|
<%- @T('Signal notifications are currently disabled by the administrator.') %>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<form class="page-content form--flexibleWidth">
|
||||||
|
<h2><%- @T('Signal Phone Number') %></h2>
|
||||||
|
<p class="help-text">
|
||||||
|
<%- @T('Enter your Signal phone number to receive ticket notifications via Signal.') %>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="signal-uid"><%- @T('Signal Phone Number') %></label>
|
||||||
|
<input type="text" id="signal-uid" name="signal_uid" class="form-control" value="<%= @signal_uid %>" placeholder="+1234567890">
|
||||||
|
<p class="help-block"><%- @T('Use international format with country code (e.g., +1234567890)') %></p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h2><%- @T('Notification Settings') %></h2>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="inline-label">
|
||||||
|
<span class="checkbox-replacement checkbox-replacement--inline">
|
||||||
|
<input type="checkbox" name="enabled" value="true" <% if @config.enabled: %> checked<% end %>>
|
||||||
|
<%- @Icon('checkbox', 'icon-unchecked') %>
|
||||||
|
<%- @Icon('checkbox-checked', 'icon-checked') %>
|
||||||
|
</span>
|
||||||
|
<%- @T('Enable Signal notifications') %>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h3><%- @T('Notification Events') %></h3>
|
||||||
|
<p class="help-text">
|
||||||
|
<%- @T('Select which events should trigger Signal notifications.') %>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="inline-label">
|
||||||
|
<span class="checkbox-replacement checkbox-replacement--inline">
|
||||||
|
<input type="checkbox" name="event_create" value="true" <% if @config.events?.create: %> checked<% end %>>
|
||||||
|
<%- @Icon('checkbox', 'icon-unchecked') %>
|
||||||
|
<%- @Icon('checkbox-checked', 'icon-checked') %>
|
||||||
|
</span>
|
||||||
|
<%- @T('New Ticket') %>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="inline-label">
|
||||||
|
<span class="checkbox-replacement checkbox-replacement--inline">
|
||||||
|
<input type="checkbox" name="event_update" value="true" <% if @config.events?.update: %> checked<% end %>>
|
||||||
|
<%- @Icon('checkbox', 'icon-unchecked') %>
|
||||||
|
<%- @Icon('checkbox-checked', 'icon-checked') %>
|
||||||
|
</span>
|
||||||
|
<%- @T('Ticket update') %>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="inline-label">
|
||||||
|
<span class="checkbox-replacement checkbox-replacement--inline">
|
||||||
|
<input type="checkbox" name="event_escalation" value="true" <% if @config.events?.escalation: %> checked<% end %>>
|
||||||
|
<%- @Icon('checkbox', 'icon-unchecked') %>
|
||||||
|
<%- @Icon('checkbox-checked', 'icon-checked') %>
|
||||||
|
</span>
|
||||||
|
<%- @T('Ticket escalation') %>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="inline-label">
|
||||||
|
<span class="checkbox-replacement checkbox-replacement--inline">
|
||||||
|
<input type="checkbox" name="event_reminder_reached" value="true" <% if @config.events?.reminder_reached: %> checked<% end %>>
|
||||||
|
<%- @Icon('checkbox', 'icon-unchecked') %>
|
||||||
|
<%- @Icon('checkbox-checked', 'icon-checked') %>
|
||||||
|
</span>
|
||||||
|
<%- @T('Ticket reminder reached') %>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button type="submit" class="btn btn--primary"><%- @T('Submit') %></button>
|
||||||
|
</form>
|
||||||
|
|
@ -0,0 +1,63 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class SignalNotificationJob < ApplicationJob
|
||||||
|
retry_on StandardError, attempts: 3, wait: lambda { |executions|
|
||||||
|
executions * 60.seconds
|
||||||
|
}
|
||||||
|
|
||||||
|
def perform(ticket_id:, article_id:, user_id:, type:, changes:)
|
||||||
|
ticket = Ticket.find_by(id: ticket_id)
|
||||||
|
return if !ticket
|
||||||
|
|
||||||
|
user = User.find_by(id: user_id)
|
||||||
|
return if !user
|
||||||
|
return if user.signal_uid.blank?
|
||||||
|
|
||||||
|
article = article_id ? Ticket::Article.find_by(id: article_id) : nil
|
||||||
|
|
||||||
|
channel = signal_channel
|
||||||
|
return if !channel
|
||||||
|
|
||||||
|
message = SignalNotificationSender.build_message(
|
||||||
|
ticket: ticket,
|
||||||
|
article: article,
|
||||||
|
user: user,
|
||||||
|
type: type,
|
||||||
|
changes: changes
|
||||||
|
)
|
||||||
|
|
||||||
|
return if message.blank?
|
||||||
|
|
||||||
|
SignalNotificationSender.send_message(
|
||||||
|
channel: channel,
|
||||||
|
recipient: user.signal_uid,
|
||||||
|
message: message
|
||||||
|
)
|
||||||
|
|
||||||
|
add_history(ticket, user, type)
|
||||||
|
|
||||||
|
Rails.logger.info "Sent Signal notification to #{user.signal_uid} for ticket ##{ticket.number} (#{type})"
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def signal_channel
|
||||||
|
channel_id = Setting.get('signal_notification_channel_id')
|
||||||
|
return unless channel_id
|
||||||
|
|
||||||
|
Channel.find_by(id: channel_id, area: 'Signal::Account', active: true)
|
||||||
|
end
|
||||||
|
|
||||||
|
def add_history(ticket, user, type)
|
||||||
|
identifier = user.signal_uid.presence || user.login
|
||||||
|
recipient_list = "#{identifier}(#{type}:signal)"
|
||||||
|
|
||||||
|
History.add(
|
||||||
|
o_id: ticket.id,
|
||||||
|
history_type: 'notification',
|
||||||
|
history_object: 'Ticket',
|
||||||
|
value_to: recipient_list,
|
||||||
|
created_by_id: 1
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -0,0 +1,144 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class Transaction::SignalNotification
|
||||||
|
include ChecksHumanChanges
|
||||||
|
|
||||||
|
def initialize(item, params = {})
|
||||||
|
@item = item
|
||||||
|
@params = params
|
||||||
|
end
|
||||||
|
|
||||||
|
def perform
|
||||||
|
return if Setting.get('import_mode')
|
||||||
|
return if %w[Ticket Ticket::Article].exclude?(@item[:object])
|
||||||
|
return if @params[:disable_notification]
|
||||||
|
return if !ticket
|
||||||
|
return if !signal_notifications_enabled?
|
||||||
|
return if !signal_channel
|
||||||
|
|
||||||
|
collect_signal_recipients.each do |user|
|
||||||
|
SignalNotificationJob.perform_later(
|
||||||
|
ticket_id: ticket.id,
|
||||||
|
article_id: @item[:article_id],
|
||||||
|
user_id: user.id,
|
||||||
|
type: @item[:type],
|
||||||
|
changes: human_changes(@item[:changes], ticket, user)
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def ticket
|
||||||
|
@ticket ||= Ticket.find_by(id: @item[:object_id])
|
||||||
|
end
|
||||||
|
|
||||||
|
def article
|
||||||
|
return if !@item[:article_id]
|
||||||
|
|
||||||
|
@article ||= begin
|
||||||
|
art = Ticket::Article.find_by(id: @item[:article_id])
|
||||||
|
return unless art
|
||||||
|
|
||||||
|
sender = Ticket::Article::Sender.lookup(id: art.sender_id)
|
||||||
|
if sender&.name == 'System'
|
||||||
|
return if @item[:changes].blank? && art.preferences[:notification] != true
|
||||||
|
return if art.preferences[:notification] != true
|
||||||
|
end
|
||||||
|
|
||||||
|
art
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def current_user
|
||||||
|
@current_user ||= User.lookup(id: @item[:user_id]) || User.lookup(id: 1)
|
||||||
|
end
|
||||||
|
|
||||||
|
def signal_notifications_enabled?
|
||||||
|
Setting.get('signal_notification_enabled') == true
|
||||||
|
end
|
||||||
|
|
||||||
|
def signal_channel
|
||||||
|
@signal_channel ||= begin
|
||||||
|
channel_id = Setting.get('signal_notification_channel_id')
|
||||||
|
return unless channel_id
|
||||||
|
|
||||||
|
Channel.find_by(id: channel_id, area: 'Signal::Account', active: true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def collect_signal_recipients
|
||||||
|
recipients = []
|
||||||
|
|
||||||
|
possible_recipients = possible_recipients_of_group(ticket.group_id)
|
||||||
|
|
||||||
|
mention_users = Mention.where(mentionable_type: @item[:object], mentionable_id: @item[:object_id]).map(&:user)
|
||||||
|
mention_users.each do |user|
|
||||||
|
next if !user.group_access?(ticket.group_id, 'read')
|
||||||
|
|
||||||
|
possible_recipients.push(user)
|
||||||
|
end
|
||||||
|
|
||||||
|
if ticket.owner_id != 1
|
||||||
|
possible_recipients.push(ticket.owner)
|
||||||
|
end
|
||||||
|
|
||||||
|
possible_recipients_with_ooo = Set.new(possible_recipients)
|
||||||
|
possible_recipients.each do |user|
|
||||||
|
add_out_of_office_replacement(user, possible_recipients_with_ooo)
|
||||||
|
end
|
||||||
|
|
||||||
|
possible_recipients_with_ooo.each do |user|
|
||||||
|
next if recipient_is_current_user?(user)
|
||||||
|
next if !user.active?
|
||||||
|
next if !user_has_signal_notifications_enabled?(user)
|
||||||
|
next if user.signal_uid.blank?
|
||||||
|
next if !should_notify_for_event?(user)
|
||||||
|
|
||||||
|
recipients.push(user)
|
||||||
|
end
|
||||||
|
|
||||||
|
recipients.uniq(&:id)
|
||||||
|
end
|
||||||
|
|
||||||
|
def possible_recipients_of_group(group_id)
|
||||||
|
Rails.cache.fetch("User/signal_notification/possible_recipients_of_group/#{group_id}/#{User.latest_change}", expires_in: 20.seconds) do
|
||||||
|
User.group_access(group_id, 'full').sort_by(&:login)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def add_out_of_office_replacement(user, recipients)
|
||||||
|
replacement = user.out_of_office_agent
|
||||||
|
return unless replacement
|
||||||
|
return unless TicketPolicy.new(replacement, ticket).agent_read_access?
|
||||||
|
|
||||||
|
recipients.add(replacement)
|
||||||
|
end
|
||||||
|
|
||||||
|
def recipient_is_current_user?(user)
|
||||||
|
return false if @params[:interface_handle] != 'application_server'
|
||||||
|
return true if article&.updated_by_id == user.id
|
||||||
|
return true if !article && @item[:user_id] == user.id
|
||||||
|
|
||||||
|
false
|
||||||
|
end
|
||||||
|
|
||||||
|
def user_has_signal_notifications_enabled?(user)
|
||||||
|
user.preferences.dig('signal_notifications', 'enabled') == true
|
||||||
|
end
|
||||||
|
|
||||||
|
def should_notify_for_event?(user)
|
||||||
|
event_type = @item[:type]
|
||||||
|
return false if event_type.blank?
|
||||||
|
|
||||||
|
event_key = case event_type
|
||||||
|
when 'create' then 'create'
|
||||||
|
when 'update', 'update.merged_into', 'update.received_merge', 'update.reaction' then 'update'
|
||||||
|
when 'reminder_reached' then 'reminder_reached'
|
||||||
|
when 'escalation', 'escalation_warning' then 'escalation'
|
||||||
|
else return false
|
||||||
|
end
|
||||||
|
|
||||||
|
user.preferences.dig('signal_notifications', 'events', event_key) == true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
[Ticket #<%= ticket.number %>] <%= ticket.title %>
|
||||||
|
|
||||||
|
NEW TICKET
|
||||||
|
|
||||||
|
Group: <%= ticket.group.name %>
|
||||||
|
Owner: <%= ticket.owner.fullname %>
|
||||||
|
State: <%= t(ticket.state.name) %>
|
||||||
|
Priority: <%= t(ticket.priority.name) %>
|
||||||
|
Customer: <%= ticket.customer.fullname %>
|
||||||
|
Created by: <%= current_user.fullname %>
|
||||||
|
<% if article -%>
|
||||||
|
|
||||||
|
<%= article_body_preview(500) %>
|
||||||
|
<% end -%>
|
||||||
|
|
||||||
|
<%= ticket_url %>
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
[Ticket #<%= ticket.number %>] <%= ticket.title %>
|
||||||
|
|
||||||
|
ESCALATION
|
||||||
|
|
||||||
|
Group: <%= ticket.group.name %>
|
||||||
|
Owner: <%= ticket.owner.fullname %>
|
||||||
|
State: <%= t(ticket.state.name) %>
|
||||||
|
Priority: <%= t(ticket.priority.name) %>
|
||||||
|
Customer: <%= ticket.customer.fullname %>
|
||||||
|
|
||||||
|
<%= ticket_url %>
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
[Ticket #<%= ticket.number %>] <%= ticket.title %>
|
||||||
|
|
||||||
|
REMINDER REACHED
|
||||||
|
|
||||||
|
Group: <%= ticket.group.name %>
|
||||||
|
Owner: <%= ticket.owner.fullname %>
|
||||||
|
State: <%= t(ticket.state.name) %>
|
||||||
|
Pending till: <%= ticket.pending_time&.strftime('%Y-%m-%d %H:%M') %>
|
||||||
|
|
||||||
|
<%= ticket_url %>
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
[Ticket #<%= ticket.number %>] <%= ticket.title %>
|
||||||
|
|
||||||
|
TICKET UPDATED by <%= current_user.fullname %>
|
||||||
|
<% if changes.present? -%>
|
||||||
|
|
||||||
|
Changes:
|
||||||
|
<%= changes_summary %>
|
||||||
|
<% end -%>
|
||||||
|
<% if article -%>
|
||||||
|
|
||||||
|
<%= article_body_preview(500) %>
|
||||||
|
<% end -%>
|
||||||
|
|
||||||
|
<%= ticket_url_with_article %>
|
||||||
|
|
@ -0,0 +1,76 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class AddSignalNotificationSettings < ActiveRecord::Migration[5.2]
|
||||||
|
def self.up
|
||||||
|
# Register Signal notification transaction backend
|
||||||
|
# Using 0105 to run after email notifications (0100)
|
||||||
|
Setting.create_if_not_exists(
|
||||||
|
title: 'Defines transaction backend.',
|
||||||
|
name: '0105_signal_notification',
|
||||||
|
area: 'Transaction::Backend::Async',
|
||||||
|
description: 'Defines the transaction backend to send Signal notifications.',
|
||||||
|
options: {},
|
||||||
|
state: 'Transaction::SignalNotification',
|
||||||
|
frontend: false
|
||||||
|
)
|
||||||
|
|
||||||
|
# Global enable/disable for Signal notifications
|
||||||
|
Setting.create_if_not_exists(
|
||||||
|
title: 'Signal Notifications',
|
||||||
|
name: 'signal_notification_enabled',
|
||||||
|
area: 'Integration::Switch',
|
||||||
|
description: 'Enable or disable Signal notifications for agents.',
|
||||||
|
options: {
|
||||||
|
form: [
|
||||||
|
{
|
||||||
|
display: '',
|
||||||
|
null: true,
|
||||||
|
name: 'signal_notification_enabled',
|
||||||
|
tag: 'boolean',
|
||||||
|
options: {
|
||||||
|
true => 'yes',
|
||||||
|
false => 'no',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
state: false,
|
||||||
|
preferences: {
|
||||||
|
prio: 1,
|
||||||
|
permission: ['admin.integration'],
|
||||||
|
},
|
||||||
|
frontend: true
|
||||||
|
)
|
||||||
|
|
||||||
|
# Which Signal channel/bot to use for sending notifications
|
||||||
|
Setting.create_if_not_exists(
|
||||||
|
title: 'Signal Notification Channel',
|
||||||
|
name: 'signal_notification_channel_id',
|
||||||
|
area: 'Integration::SignalNotification',
|
||||||
|
description: 'The Signal channel (bot) used to send notifications to agents.',
|
||||||
|
options: {},
|
||||||
|
state: nil,
|
||||||
|
preferences: {
|
||||||
|
prio: 2,
|
||||||
|
permission: ['admin.integration'],
|
||||||
|
},
|
||||||
|
frontend: false
|
||||||
|
)
|
||||||
|
|
||||||
|
# Permission for Signal notifications profile page
|
||||||
|
Permission.create_if_not_exists(
|
||||||
|
name: 'user_preferences.signal_notifications',
|
||||||
|
description: 'Manage Signal notification preferences',
|
||||||
|
preferences: {
|
||||||
|
translations: ['Profile - Signal Notifications']
|
||||||
|
}
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.down
|
||||||
|
Setting.find_by(name: '0105_signal_notification')&.destroy
|
||||||
|
Setting.find_by(name: 'signal_notification_enabled')&.destroy
|
||||||
|
Setting.find_by(name: 'signal_notification_channel_id')&.destroy
|
||||||
|
Permission.find_by(name: 'user_preferences.signal_notifications')&.destroy
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -0,0 +1,139 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'erb'
|
||||||
|
|
||||||
|
class SignalNotificationSender
|
||||||
|
TEMPLATE_DIR = Rails.root.join('app', 'views', 'signal_notification')
|
||||||
|
|
||||||
|
class << self
|
||||||
|
def build_message(ticket:, article:, user:, type:, changes:)
|
||||||
|
template_name = template_for_type(type)
|
||||||
|
return if template_name.blank?
|
||||||
|
|
||||||
|
locale = user.locale || Setting.get('locale_default') || 'en'
|
||||||
|
template_path = find_template(template_name, locale)
|
||||||
|
return if template_path.blank?
|
||||||
|
|
||||||
|
render_template(template_path, binding_for(ticket, article, user, changes))
|
||||||
|
end
|
||||||
|
|
||||||
|
def send_message(channel:, recipient:, message:)
|
||||||
|
return if Rails.env.test?
|
||||||
|
return if channel.blank?
|
||||||
|
return if recipient.blank?
|
||||||
|
return if message.blank?
|
||||||
|
|
||||||
|
api_url = channel.options[:api_url]
|
||||||
|
api_token = channel.options[:api_token]
|
||||||
|
|
||||||
|
return if api_url.blank? || api_token.blank?
|
||||||
|
|
||||||
|
api = CdrSignalApi.new(api_url, api_token)
|
||||||
|
api.send_message(recipient, message)
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def template_for_type(type)
|
||||||
|
case type
|
||||||
|
when 'create'
|
||||||
|
'ticket_create'
|
||||||
|
when 'update', 'update.merged_into', 'update.received_merge', 'update.reaction'
|
||||||
|
'ticket_update'
|
||||||
|
when 'reminder_reached'
|
||||||
|
'ticket_reminder_reached'
|
||||||
|
when 'escalation', 'escalation_warning'
|
||||||
|
'ticket_escalation'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def find_template(template_name, locale)
|
||||||
|
base_locale = locale.split('-').first
|
||||||
|
|
||||||
|
[locale, base_locale, 'en'].uniq.each do |try_locale|
|
||||||
|
path = TEMPLATE_DIR.join(template_name, "#{try_locale}.txt.erb")
|
||||||
|
return path if File.exist?(path)
|
||||||
|
end
|
||||||
|
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
|
||||||
|
def binding_for(ticket, article, user, changes)
|
||||||
|
TemplateContext.new(
|
||||||
|
ticket: ticket,
|
||||||
|
article: article,
|
||||||
|
user: user,
|
||||||
|
changes: changes,
|
||||||
|
config: {
|
||||||
|
http_type: Setting.get('http_type'),
|
||||||
|
fqdn: Setting.get('fqdn'),
|
||||||
|
product_name: Setting.get('product_name')
|
||||||
|
}
|
||||||
|
).get_binding
|
||||||
|
end
|
||||||
|
|
||||||
|
def render_template(template_path, binding)
|
||||||
|
template = File.read(template_path)
|
||||||
|
erb = ERB.new(template, trim_mode: '-')
|
||||||
|
erb.result(binding).strip
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class TemplateContext
|
||||||
|
attr_reader :ticket, :article, :recipient, :changes, :config
|
||||||
|
|
||||||
|
def initialize(ticket:, article:, user:, changes:, config:)
|
||||||
|
@ticket = ticket
|
||||||
|
@article = article
|
||||||
|
@recipient = user
|
||||||
|
@changes = changes
|
||||||
|
@config = OpenStruct.new(config)
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_binding
|
||||||
|
binding
|
||||||
|
end
|
||||||
|
|
||||||
|
def ticket_url
|
||||||
|
"#{config.http_type}://#{config.fqdn}/#ticket/zoom/#{ticket.id}"
|
||||||
|
end
|
||||||
|
|
||||||
|
def ticket_url_with_article
|
||||||
|
if article
|
||||||
|
"#{ticket_url}/#{article.id}"
|
||||||
|
else
|
||||||
|
ticket_url
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def current_user
|
||||||
|
@current_user ||= User.lookup(id: ticket.updated_by_id) || User.lookup(id: 1)
|
||||||
|
end
|
||||||
|
|
||||||
|
def changes_summary
|
||||||
|
return '' if changes.blank?
|
||||||
|
|
||||||
|
changes.map { |key, values| "#{key}: #{values[0]} -> #{values[1]}" }.join("\n")
|
||||||
|
end
|
||||||
|
|
||||||
|
def article_body_preview(max_length = 500)
|
||||||
|
return '' unless article
|
||||||
|
return '' if article.body.blank?
|
||||||
|
|
||||||
|
body = article.body.to_s
|
||||||
|
body = ActionController::Base.helpers.strip_tags(body) if article.content_type&.include?('html')
|
||||||
|
body = body.gsub(/\s+/, ' ').strip
|
||||||
|
|
||||||
|
if body.length > max_length
|
||||||
|
"#{body[0, max_length]}..."
|
||||||
|
else
|
||||||
|
body
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def t(text)
|
||||||
|
locale = recipient.locale || Setting.get('locale_default') || 'en'
|
||||||
|
Translation.translate(locale, text)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
Loading…
Add table
Add a link
Reference in a new issue