Refactoring: Migrate Rails Observers to Concerns.
This commit is contained in:
parent
5b6f0327c6
commit
cb2286fae4
54 changed files with 903 additions and 556 deletions
|
@ -138,6 +138,18 @@ Metrics/AbcSize:
|
|||
- 'app/models/concerns/has_rich_text.rb'
|
||||
- 'app/models/concerns/has_search_index_backend.rb'
|
||||
- 'app/models/concerns/has_search_sortable.rb'
|
||||
- 'app/models/concerns/ticket/article/adds_metadata_email.rb'
|
||||
- 'app/models/concerns/ticket/article/adds_metadata_general.rb'
|
||||
- 'app/models/concerns/ticket/article/adds_metadata_origin_by_id.rb'
|
||||
- 'app/models/concerns/ticket/article/enqueue_communicate_email_job.rb'
|
||||
- 'app/models/concerns/ticket/article/enqueue_communicate_facebook_job.rb'
|
||||
- 'app/models/concerns/ticket/article/enqueue_communicate_sms_job.rb'
|
||||
- 'app/models/concerns/ticket/article/enqueue_communicate_telegram_job.rb'
|
||||
- 'app/models/concerns/ticket/article/enqueue_communicate_twitter_job.rb'
|
||||
- 'app/models/concerns/ticket/article/resets_ticket_state.rb'
|
||||
- 'app/models/concerns/ticket/sets_last_owner_update_time.rb'
|
||||
- 'app/models/concerns/ticket/touches_associations.rb'
|
||||
- 'app/models/concerns/user/performs_geo_lookup.rb'
|
||||
- 'app/models/cti/caller_id.rb'
|
||||
- 'app/models/cti/driver/base.rb'
|
||||
- 'app/models/cti/driver/placetel.rb'
|
||||
|
@ -156,19 +168,7 @@ Metrics/AbcSize:
|
|||
- 'app/models/link.rb'
|
||||
- 'app/models/object_manager/attribute.rb'
|
||||
- 'app/models/observer/chat/leave/background_job.rb'
|
||||
- 'app/models/observer/ticket/article/communicate_email.rb'
|
||||
- 'app/models/observer/ticket/article/communicate_facebook.rb'
|
||||
- 'app/models/observer/ticket/article/communicate_sms.rb'
|
||||
- 'app/models/observer/ticket/article/communicate_telegram.rb'
|
||||
- 'app/models/observer/ticket/article/communicate_twitter.rb'
|
||||
- 'app/models/observer/ticket/article/fillup_from_email.rb'
|
||||
- 'app/models/observer/ticket/article/fillup_from_general.rb'
|
||||
- 'app/models/observer/ticket/article/fillup_from_origin_by_id.rb'
|
||||
- 'app/models/observer/ticket/last_owner_update.rb'
|
||||
- 'app/models/observer/ticket/ref_object_touch.rb'
|
||||
- 'app/models/observer/ticket/reset_new_state.rb'
|
||||
- 'app/models/observer/transaction.rb'
|
||||
- 'app/models/observer/user/geo.rb'
|
||||
- 'app/models/online_notification.rb'
|
||||
- 'app/models/online_notification/assets.rb'
|
||||
- 'app/models/organization/assets.rb'
|
||||
|
@ -533,6 +533,17 @@ Metrics/CyclomaticComplexity:
|
|||
- 'app/models/concerns/has_rich_text.rb'
|
||||
- 'app/models/concerns/has_search_index_backend.rb'
|
||||
- 'app/models/concerns/has_search_sortable.rb'
|
||||
- 'app/models/concerns/ticket/article/adds_metadata_email.rb'
|
||||
- 'app/models/concerns/ticket/article/adds_metadata_general.rb'
|
||||
- 'app/models/concerns/ticket/article/adds_metadata_origin_by_id.rb'
|
||||
- 'app/models/concerns/ticket/article/enqueue_communicate_email_job.rb'
|
||||
- 'app/models/concerns/ticket/article/enqueue_communicate_facebook_job.rb'
|
||||
- 'app/models/concerns/ticket/article/enqueue_communicate_sms_job.rb'
|
||||
- 'app/models/concerns/ticket/article/enqueue_communicate_twitter_job.rb'
|
||||
- 'app/models/concerns/ticket/article/resets_ticket_state.rb'
|
||||
- 'app/models/concerns/ticket/sets_last_owner_update_time.rb'
|
||||
- 'app/models/concerns/ticket/touches_associations.rb'
|
||||
- 'app/models/concerns/user/performs_geo_lookup.rb'
|
||||
- 'app/models/cti/caller_id.rb'
|
||||
- 'app/models/cti/driver/base.rb'
|
||||
- 'app/models/cti/driver/placetel.rb'
|
||||
|
@ -545,18 +556,7 @@ Metrics/CyclomaticComplexity:
|
|||
- 'app/models/karma/activity_log.rb'
|
||||
- 'app/models/knowledge_base.rb'
|
||||
- 'app/models/object_manager/attribute.rb'
|
||||
- 'app/models/observer/ticket/article/communicate_email.rb'
|
||||
- 'app/models/observer/ticket/article/communicate_facebook.rb'
|
||||
- 'app/models/observer/ticket/article/communicate_sms.rb'
|
||||
- 'app/models/observer/ticket/article/communicate_twitter.rb'
|
||||
- 'app/models/observer/ticket/article/fillup_from_email.rb'
|
||||
- 'app/models/observer/ticket/article/fillup_from_general.rb'
|
||||
- 'app/models/observer/ticket/article/fillup_from_origin_by_id.rb'
|
||||
- 'app/models/observer/ticket/last_owner_update.rb'
|
||||
- 'app/models/observer/ticket/ref_object_touch.rb'
|
||||
- 'app/models/observer/ticket/reset_new_state.rb'
|
||||
- 'app/models/observer/transaction.rb'
|
||||
- 'app/models/observer/user/geo.rb'
|
||||
- 'app/models/online_notification/assets.rb'
|
||||
- 'app/models/organization/assets.rb'
|
||||
- 'app/models/organization/search.rb'
|
||||
|
@ -763,6 +763,16 @@ Metrics/PerceivedComplexity:
|
|||
- 'app/models/concerns/has_rich_text.rb'
|
||||
- 'app/models/concerns/has_search_index_backend.rb'
|
||||
- 'app/models/concerns/has_search_sortable.rb'
|
||||
- 'app/models/concerns/ticket/article/adds_metadata_email.rb'
|
||||
- 'app/models/concerns/ticket/article/adds_metadata_general.rb'
|
||||
- 'app/models/concerns/ticket/article/adds_metadata_origin_by_id.rb'
|
||||
- 'app/models/concerns/ticket/article/enqueue_communicate_email_job.rb'
|
||||
- 'app/models/concerns/ticket/article/enqueue_communicate_facebook_job.rb'
|
||||
- 'app/models/concerns/ticket/article/enqueue_communicate_twitter_job.rb'
|
||||
- 'app/models/concerns/ticket/article/resets_ticket_state.rb'
|
||||
- 'app/models/concerns/ticket/sets_last_owner_update_time.rb'
|
||||
- 'app/models/concerns/ticket/touches_associations.rb'
|
||||
- 'app/models/concerns/user/performs_geo_lookup.rb'
|
||||
- 'app/models/cti/caller_id.rb'
|
||||
- 'app/models/cti/driver/base.rb'
|
||||
- 'app/models/cti/driver/placetel.rb'
|
||||
|
@ -775,16 +785,6 @@ Metrics/PerceivedComplexity:
|
|||
- 'app/models/karma/activity_log.rb'
|
||||
- 'app/models/knowledge_base.rb'
|
||||
- 'app/models/object_manager/attribute.rb'
|
||||
- 'app/models/observer/ticket/article/communicate_email.rb'
|
||||
- 'app/models/observer/ticket/article/communicate_facebook.rb'
|
||||
- 'app/models/observer/ticket/article/communicate_sms.rb'
|
||||
- 'app/models/observer/ticket/article/communicate_twitter.rb'
|
||||
- 'app/models/observer/ticket/article/fillup_from_email.rb'
|
||||
- 'app/models/observer/ticket/article/fillup_from_general.rb'
|
||||
- 'app/models/observer/ticket/article/fillup_from_origin_by_id.rb'
|
||||
- 'app/models/observer/ticket/last_owner_update.rb'
|
||||
- 'app/models/observer/ticket/ref_object_touch.rb'
|
||||
- 'app/models/observer/ticket/reset_new_state.rb'
|
||||
- 'app/models/observer/transaction.rb'
|
||||
- 'app/models/online_notification/assets.rb'
|
||||
- 'app/models/organization/assets.rb'
|
||||
|
|
41
app/models/concerns/tag/writes_to_ticket_history.rb
Normal file
41
app/models/concerns/tag/writes_to_ticket_history.rb
Normal file
|
@ -0,0 +1,41 @@
|
|||
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
|
||||
|
||||
# Records added/removed tags also in the ticket history.
|
||||
module Tag::WritesToTicketHistory
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
after_create :write_tag_added_to_ticket_history
|
||||
after_destroy :write_tag_removed_to_ticket_history
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def write_tag_added_to_ticket_history
|
||||
|
||||
return true if tag_object.name != 'Ticket'
|
||||
|
||||
History.add(
|
||||
o_id: o_id,
|
||||
history_type: 'added',
|
||||
history_object: 'Ticket',
|
||||
history_attribute: 'tag',
|
||||
value_to: tag_item.name,
|
||||
created_by_id: created_by_id,
|
||||
)
|
||||
end
|
||||
|
||||
def write_tag_removed_to_ticket_history
|
||||
|
||||
return true if tag_object.name != 'Ticket'
|
||||
|
||||
History.add(
|
||||
o_id: o_id,
|
||||
history_type: 'removed',
|
||||
history_object: 'Ticket',
|
||||
history_attribute: 'tag',
|
||||
value_to: tag_item.name,
|
||||
created_by_id: created_by_id,
|
||||
)
|
||||
end
|
||||
end
|
|
@ -1,9 +1,16 @@
|
|||
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
|
||||
|
||||
class Observer::Ticket::Article::FillupFromEmail < ActiveRecord::Observer
|
||||
observe 'ticket::_article'
|
||||
# Adds certain (missing) meta data when creating email articles.
|
||||
module Ticket::Article::AddsMetadataEmail
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
def before_create(record)
|
||||
included do
|
||||
before_create :ticket_article_add_metadata_email
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def ticket_article_add_metadata_email
|
||||
|
||||
# return if we run import mode
|
||||
return true if Setting.get('import_mode')
|
||||
|
@ -13,36 +20,36 @@ class Observer::Ticket::Article::FillupFromEmail < ActiveRecord::Observer
|
|||
return if ApplicationHandleInfo.postmaster?
|
||||
|
||||
# if sender is customer, do not change anything
|
||||
return true if !record.sender_id
|
||||
return true if !sender_id
|
||||
|
||||
sender = Ticket::Article::Sender.lookup(id: record.sender_id)
|
||||
sender = Ticket::Article::Sender.lookup(id: sender_id)
|
||||
return true if sender.nil?
|
||||
return true if sender.name == 'Customer'
|
||||
|
||||
# set email attributes
|
||||
return true if !record.type_id
|
||||
return true if !type_id
|
||||
|
||||
type = Ticket::Article::Type.lookup(id: record.type_id)
|
||||
type = Ticket::Article::Type.lookup(id: type_id)
|
||||
return true if type.nil?
|
||||
return true if type.name != 'email'
|
||||
|
||||
# set subject if empty
|
||||
ticket = record.ticket
|
||||
if !record.subject || record.subject == ''
|
||||
record.subject = ticket.title
|
||||
ticket = self.ticket
|
||||
if !subject || subject == ''
|
||||
self.subject = ticket.title
|
||||
end
|
||||
|
||||
# clean subject
|
||||
record.subject = ticket.subject_clean(record.subject)
|
||||
self.subject = ticket.subject_clean(subject)
|
||||
|
||||
# generate message id, force it in production, in test allow to set it for testing reasons
|
||||
if !record.message_id || Rails.env.production?
|
||||
if !message_id || Rails.env.production?
|
||||
fqdn = Setting.get('fqdn')
|
||||
record.message_id = "<#{DateTime.current.to_s(:number)}.#{record.ticket_id}.#{rand(999_999_999_999)}@#{fqdn}>"
|
||||
self.message_id = "<#{DateTime.current.to_s(:number)}.#{ticket_id}.#{rand(999_999_999_999)}@#{fqdn}>"
|
||||
end
|
||||
|
||||
# generate message_id_md5
|
||||
record.check_message_id_md5
|
||||
check_message_id_md5
|
||||
|
||||
# set sender
|
||||
email_address = ticket.group.email_address
|
||||
|
@ -51,20 +58,20 @@ class Observer::Ticket::Article::FillupFromEmail < ActiveRecord::Observer
|
|||
end
|
||||
|
||||
# remember email address for background job
|
||||
record.preferences['email_address_id'] = email_address.id
|
||||
preferences['email_address_id'] = email_address.id
|
||||
|
||||
# fill from
|
||||
if record.created_by_id != 1 && Setting.get('ticket_define_email_from') == 'AgentNameSystemAddressName'
|
||||
if created_by_id != 1 && Setting.get('ticket_define_email_from') == 'AgentNameSystemAddressName'
|
||||
separator = Setting.get('ticket_define_email_from_separator')
|
||||
sender = User.find(record.created_by_id)
|
||||
sender = User.find(created_by_id)
|
||||
realname = "#{sender.firstname} #{sender.lastname} #{separator} #{email_address.realname}"
|
||||
record.from = Channel::EmailBuild.recipient_line(realname, email_address.email)
|
||||
self.from = Channel::EmailBuild.recipient_line(realname, email_address.email)
|
||||
elsif Setting.get('ticket_define_email_from') == 'AgentName'
|
||||
sender = User.find(record.created_by_id)
|
||||
sender = User.find(created_by_id)
|
||||
realname = "#{sender.firstname} #{sender.lastname}"
|
||||
record.from = Channel::EmailBuild.recipient_line(realname, email_address.email)
|
||||
self.from = Channel::EmailBuild.recipient_line(realname, email_address.email)
|
||||
else
|
||||
record.from = Channel::EmailBuild.recipient_line(email_address.realname, email_address.email)
|
||||
self.from = Channel::EmailBuild.recipient_line(email_address.realname, email_address.email)
|
||||
end
|
||||
true
|
||||
end
|
|
@ -1,9 +1,17 @@
|
|||
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
|
||||
|
||||
class Observer::Ticket::Article::FillupFromGeneral < ActiveRecord::Observer
|
||||
observe 'ticket::_article'
|
||||
# Adds certain (missing) meta data when creating articles.
|
||||
# This module depends on AddsMetadataOriginById to run before it.
|
||||
module Ticket::Article::AddsMetadataGeneral
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
def before_create(record)
|
||||
included do
|
||||
before_create :ticket_article_add_metadata_general
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def ticket_article_add_metadata_general
|
||||
|
||||
# return if we run import mode
|
||||
return true if Setting.get('import_mode')
|
||||
|
@ -13,9 +21,9 @@ class Observer::Ticket::Article::FillupFromGeneral < ActiveRecord::Observer
|
|||
return true if ApplicationHandleInfo.postmaster?
|
||||
|
||||
# set from on all article types excluding email|twitter status|twitter direct-message|facebook feed post|facebook feed comment
|
||||
return true if record.type_id.blank?
|
||||
return true if type_id.blank?
|
||||
|
||||
type = Ticket::Article::Type.lookup(id: record.type_id)
|
||||
type = Ticket::Article::Type.lookup(id: type_id)
|
||||
|
||||
# from will be set by channel backend
|
||||
return true if type.nil?
|
||||
|
@ -26,31 +34,31 @@ class Observer::Ticket::Article::FillupFromGeneral < ActiveRecord::Observer
|
|||
return true if type.name == 'facebook feed comment'
|
||||
return true if type.name == 'sms'
|
||||
|
||||
user_id = record.created_by_id
|
||||
user_id = created_by_id
|
||||
|
||||
if record.origin_by_id.present?
|
||||
if origin_by_id.present?
|
||||
|
||||
# in case the customer is using origin_by_id, force it to current session user
|
||||
# and set sender to Customer
|
||||
if !record.created_by.permissions?('ticket.agent')
|
||||
record.origin_by_id = record.created_by_id
|
||||
record.sender_id = Ticket::Article::Sender.lookup(name: 'Customer').id
|
||||
if !created_by.permissions?('ticket.agent')
|
||||
self.origin_by_id = created_by_id
|
||||
self.sender_id = Ticket::Article::Sender.lookup(name: 'Customer').id
|
||||
end
|
||||
|
||||
# in case origin_by is different than created_by, set sender to Customer
|
||||
# Customer in context of this conversation, not as a permission
|
||||
if record.origin_by != record.created_by_id
|
||||
record.sender_id = Ticket::Article::Sender.lookup(name: 'Customer').id
|
||||
user_id = record.origin_by_id
|
||||
if origin_by != created_by_id
|
||||
self.sender_id = Ticket::Article::Sender.lookup(name: 'Customer').id
|
||||
user_id = origin_by_id
|
||||
end
|
||||
end
|
||||
return true if user_id.blank?
|
||||
|
||||
user = User.find(user_id)
|
||||
if type.name == 'web' || type.name == 'phone'
|
||||
record.from = "#{user.firstname} #{user.lastname} <#{user.email}>"
|
||||
self.from = "#{user.firstname} #{user.lastname} <#{user.email}>"
|
||||
return
|
||||
end
|
||||
record.from = "#{user.firstname} #{user.lastname}"
|
||||
self.from = "#{user.firstname} #{user.lastname}"
|
||||
end
|
||||
end
|
|
@ -0,0 +1,34 @@
|
|||
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
|
||||
|
||||
# Adds origin_by_id field (if missing) when creating articles.
|
||||
module Ticket::Article::AddsMetadataOriginById
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
before_create :ticket_article_add_metadata_origin_by_id
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def ticket_article_add_metadata_origin_by_id
|
||||
|
||||
# return if we run import mode
|
||||
return true if Setting.get('import_mode')
|
||||
|
||||
# only do fill origin_by_id if article got created via application_server (e. g. not
|
||||
# if article and sender type is set via *.postmaster)
|
||||
return true if ApplicationHandleInfo.postmaster?
|
||||
|
||||
# check if origin_by_id exists
|
||||
return true if origin_by_id.present?
|
||||
return true if ticket.blank?
|
||||
return true if ticket.customer_id.blank?
|
||||
return true if sender_id.blank?
|
||||
return true if sender.name != 'Customer'
|
||||
|
||||
type_name = type.name
|
||||
return true if type_name != 'phone' && type_name != 'note' && type_name != 'web'
|
||||
|
||||
self.origin_by_id = ticket.customer_id
|
||||
end
|
||||
end
|
|
@ -1,9 +1,16 @@
|
|||
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
|
||||
|
||||
class Observer::Ticket::Article::CommunicateEmail < ActiveRecord::Observer
|
||||
observe 'ticket::_article'
|
||||
# Schedules a backgrond communication job for new email articles.
|
||||
module Ticket::Article::EnqueueCommunicateEmailJob
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
def after_create(record)
|
||||
included do
|
||||
after_create :ticket_article_enqueue_communicate_email_job
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def ticket_article_enqueue_communicate_email_job
|
||||
|
||||
# return if we run import mode
|
||||
return true if Setting.get('import_mode')
|
||||
|
@ -13,20 +20,20 @@ class Observer::Ticket::Article::CommunicateEmail < ActiveRecord::Observer
|
|||
return true if ApplicationHandleInfo.postmaster?
|
||||
|
||||
# if sender is customer, do not communicate
|
||||
return true if !record.sender_id
|
||||
return true if !sender_id
|
||||
|
||||
sender = Ticket::Article::Sender.lookup(id: record.sender_id)
|
||||
sender = Ticket::Article::Sender.lookup(id: sender_id)
|
||||
return true if sender.nil?
|
||||
return true if sender.name == 'Customer'
|
||||
|
||||
# only apply on emails
|
||||
return true if !record.type_id
|
||||
return true if !type_id
|
||||
|
||||
type = Ticket::Article::Type.lookup(id: record.type_id)
|
||||
type = Ticket::Article::Type.lookup(id: type_id)
|
||||
return true if type.nil?
|
||||
return true if type.name != 'email'
|
||||
|
||||
# send background job
|
||||
TicketArticleCommunicateEmailJob.perform_later(record.id)
|
||||
TicketArticleCommunicateEmailJob.perform_later(id)
|
||||
end
|
||||
end
|
|
@ -1,8 +1,16 @@
|
|||
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
|
||||
class Observer::Ticket::Article::CommunicateFacebook < ActiveRecord::Observer
|
||||
observe 'ticket::_article'
|
||||
|
||||
def after_create(record)
|
||||
# Schedules a backgrond communication job for new facebook articles.
|
||||
module Ticket::Article::EnqueueCommunicateFacebookJob
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
after_create :ticket_article_enqueue_communicate_facebook_job
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def ticket_article_enqueue_communicate_facebook_job
|
||||
|
||||
# return if we run import mode
|
||||
return true if Setting.get('import_mode')
|
||||
|
@ -12,20 +20,20 @@ class Observer::Ticket::Article::CommunicateFacebook < ActiveRecord::Observer
|
|||
return true if ApplicationHandleInfo.postmaster?
|
||||
|
||||
# if sender is customer, do not communicate
|
||||
return true if !record.sender_id
|
||||
return true if !sender_id
|
||||
|
||||
sender = Ticket::Article::Sender.lookup(id: record.sender_id)
|
||||
sender = Ticket::Article::Sender.lookup(id: sender_id)
|
||||
return true if sender.nil?
|
||||
return true if sender.name == 'Customer'
|
||||
|
||||
# only apply for facebook
|
||||
return true if !record.type_id
|
||||
return true if !type_id
|
||||
|
||||
type = Ticket::Article::Type.lookup(id: record.type_id)
|
||||
type = Ticket::Article::Type.lookup(id: type_id)
|
||||
return true if type.nil?
|
||||
return true if !type.name.start_with?('facebook')
|
||||
|
||||
CommunicateFacebookJob.perform_later(record.id)
|
||||
CommunicateFacebookJob.perform_later(id)
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,34 @@
|
|||
# Copyright (C) 2012-2021 Zammad Foundation, http://zammad-foundation.org/
|
||||
|
||||
# Schedules a backgrond communication job for new SMS articles.
|
||||
module Ticket::Article::EnqueueCommunicateSmsJob
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
after_create :ticket_article_enqueue_communicate_sms_job
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def ticket_article_enqueue_communicate_sms_job
|
||||
|
||||
# return if we run import mode
|
||||
return true if Setting.get('import_mode')
|
||||
|
||||
# if sender is customer, do not communicate
|
||||
return true if !sender_id
|
||||
|
||||
sender = Ticket::Article::Sender.lookup(id: sender_id)
|
||||
return true if sender.nil?
|
||||
return true if sender.name == 'Customer'
|
||||
|
||||
# only apply on sms
|
||||
return true if !type_id
|
||||
|
||||
type = Ticket::Article::Type.lookup(id: type_id)
|
||||
return true if type.nil?
|
||||
return true if type.name != 'sms'
|
||||
|
||||
CommunicateSmsJob.perform_later(id)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,34 @@
|
|||
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
|
||||
|
||||
# Schedules a backgrond communication job for new telegram articles.
|
||||
module Ticket::Article::EnqueueCommunicateTelegramJob
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
after_create :ticket_article_enqueue_communicate_telegram_job
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def ticket_article_enqueue_communicate_telegram_job
|
||||
|
||||
# return if we run import mode
|
||||
return true if Setting.get('import_mode')
|
||||
|
||||
# if sender is customer, do not communicate
|
||||
return true if !sender_id
|
||||
|
||||
sender = Ticket::Article::Sender.lookup(id: sender_id)
|
||||
return true if sender.nil?
|
||||
return true if sender.name == 'Customer'
|
||||
|
||||
# only apply on telegram messages
|
||||
return true if !type_id
|
||||
|
||||
type = Ticket::Article::Type.lookup(id: type_id)
|
||||
return true if !type.name.match?(/\Atelegram/i)
|
||||
|
||||
CommunicateTelegramJob.perform_later(id)
|
||||
end
|
||||
|
||||
end
|
|
@ -1,9 +1,16 @@
|
|||
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
|
||||
|
||||
class Observer::Ticket::Article::CommunicateTwitter < ActiveRecord::Observer
|
||||
observe 'ticket::_article'
|
||||
# Schedules a backgrond communication job for new twitter articles.
|
||||
module Ticket::Article::EnqueueCommunicateTwitterJob
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
def after_create(record)
|
||||
included do
|
||||
after_create :ticket_article_enqueue_communicate_twitter_job
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def ticket_article_enqueue_communicate_twitter_job
|
||||
|
||||
# return if we run import mode
|
||||
return true if Setting.get('import_mode')
|
||||
|
@ -13,22 +20,22 @@ class Observer::Ticket::Article::CommunicateTwitter < ActiveRecord::Observer
|
|||
return true if ApplicationHandleInfo.postmaster?
|
||||
|
||||
# if sender is customer, do not communicate
|
||||
return true if !record.sender_id
|
||||
return true if !sender_id
|
||||
|
||||
sender = Ticket::Article::Sender.lookup(id: record.sender_id)
|
||||
sender = Ticket::Article::Sender.lookup(id: sender_id)
|
||||
return true if sender.nil?
|
||||
return true if sender.name == 'Customer'
|
||||
|
||||
# only apply on tweets
|
||||
return true if !record.type_id
|
||||
return true if !type_id
|
||||
|
||||
type = Ticket::Article::Type.lookup(id: record.type_id)
|
||||
type = Ticket::Article::Type.lookup(id: type_id)
|
||||
return true if type.nil?
|
||||
return true if !type.name.match?(/\Atwitter/i)
|
||||
|
||||
raise Exceptions::UnprocessableEntity, 'twitter to: parameter is missing' if record.to.blank? && type['name'] == 'twitter direct-message'
|
||||
raise Exceptions::UnprocessableEntity, 'twitter to: parameter is missing' if to.blank? && type['name'] == 'twitter direct-message'
|
||||
|
||||
CommunicateTwitterJob.perform_later(record.id)
|
||||
CommunicateTwitterJob.perform_later(id)
|
||||
end
|
||||
|
||||
end
|
|
@ -1,9 +1,16 @@
|
|||
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
|
||||
|
||||
class Observer::Ticket::ResetNewState < ActiveRecord::Observer
|
||||
observe 'ticket::_article'
|
||||
# Reopens the ticket in case certain new articles are created.
|
||||
module Ticket::Article::ResetsTicketState
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
def after_create(record)
|
||||
included do
|
||||
after_create :ticket_article_reset_ticket_state
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def ticket_article_reset_ticket_state
|
||||
|
||||
# return if we run import mode
|
||||
return true if Setting.get('import_mode')
|
||||
|
@ -12,16 +19,16 @@ class Observer::Ticket::ResetNewState < ActiveRecord::Observer
|
|||
return true if ApplicationHandleInfo.postmaster?
|
||||
|
||||
# if article in internal
|
||||
return true if record.internal
|
||||
return true if internal
|
||||
|
||||
# if sender is agent
|
||||
return true if Ticket::Article::Sender.lookup(id: record.sender_id).name != 'Agent'
|
||||
return true if Ticket::Article::Sender.lookup(id: sender_id).name != 'Agent'
|
||||
|
||||
# if article is a message to customer
|
||||
return true if !Ticket::Article::Type.lookup(id: record.type_id).communication
|
||||
return true if !Ticket::Article::Type.lookup(id: type_id).communication
|
||||
|
||||
# if current ticket state is still new
|
||||
ticket = Ticket.find_by(id: record.ticket_id)
|
||||
ticket = Ticket.find_by(id: ticket_id)
|
||||
return true if !ticket
|
||||
|
||||
new_state = Ticket::State.find_by(default_create: true)
|
23
app/models/concerns/ticket/calls_stats_ticket_reopen_log.rb
Normal file
23
app/models/concerns/ticket/calls_stats_ticket_reopen_log.rb
Normal file
|
@ -0,0 +1,23 @@
|
|||
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
|
||||
|
||||
require_dependency 'stats/ticket_reopen'
|
||||
|
||||
# Adds new and updated tickets to the reopen log processing.
|
||||
module Ticket::CallsStatsTicketReopenLog
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
before_create :ticket_call_stats_ticket_reopen_log
|
||||
before_update :ticket_call_stats_ticket_reopen_log
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def ticket_call_stats_ticket_reopen_log
|
||||
|
||||
# return if we run import mode
|
||||
return if Setting.get('import_mode')
|
||||
|
||||
Stats::TicketReopen.log('Ticket', id, saved_changes, updated_by_id)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,30 @@
|
|||
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
|
||||
|
||||
# Adds a background job to update the user's ticket counter on ticket changes.
|
||||
module Ticket::EnqueuesUserTicketCounterJob
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
after_commit :enqueue_user_ticket_counter_job
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def enqueue_user_ticket_counter_job
|
||||
# return if we run import mode
|
||||
return true if Setting.get('import_mode')
|
||||
|
||||
return true if BulkImportInfo.enabled?
|
||||
|
||||
return true if destroyed?
|
||||
|
||||
return true if !customer_id
|
||||
|
||||
# send background job
|
||||
TicketUserTicketCounterJob.perform_later(
|
||||
customer_id,
|
||||
UserInfo.current_user_id || updated_by_id,
|
||||
)
|
||||
end
|
||||
|
||||
end
|
21
app/models/concerns/ticket/resets_pending_time_seconds.rb
Normal file
21
app/models/concerns/ticket/resets_pending_time_seconds.rb
Normal file
|
@ -0,0 +1,21 @@
|
|||
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
|
||||
|
||||
# Ensures pending time is always zero-seconds.
|
||||
module Ticket::ResetsPendingTimeSeconds
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
before_create :ticket_reset_pending_time_seconds
|
||||
before_update :ticket_reset_pending_time_seconds
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def ticket_reset_pending_time_seconds
|
||||
return true if pending_time.blank?
|
||||
return true if !pending_time_changed?
|
||||
return true if pending_time.sec.zero?
|
||||
|
||||
self.pending_time = pending_time.change sec: 0
|
||||
end
|
||||
end
|
|
@ -1,34 +1,32 @@
|
|||
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
|
||||
|
||||
class Observer::Ticket::CloseTime < ActiveRecord::Observer
|
||||
observe 'ticket'
|
||||
# Adds close time (if missing) when tickets are closed.
|
||||
module Ticket::SetsCloseTime
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
def before_create(record)
|
||||
_check(record)
|
||||
end
|
||||
|
||||
def before_update(record)
|
||||
_check(record)
|
||||
included do
|
||||
before_create :ticket_set_close_time
|
||||
before_update :ticket_set_close_time
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def _check(record)
|
||||
def ticket_set_close_time
|
||||
|
||||
# return if we run import mode
|
||||
return true if Setting.get('import_mode')
|
||||
|
||||
# check if close_at is already set
|
||||
return true if record.close_at
|
||||
return true if close_at
|
||||
|
||||
# check if ticket is closed now
|
||||
return true if !record.state_id
|
||||
return true if !state_id
|
||||
|
||||
state = Ticket::State.lookup(id: record.state_id)
|
||||
state = Ticket::State.lookup(id: state_id)
|
||||
state_type = Ticket::StateType.lookup(id: state.state_type_id)
|
||||
return true if state_type.name != 'closed'
|
||||
|
||||
# set close_at
|
||||
record.close_at = Time.zone.now
|
||||
self.close_at = Time.zone.now
|
||||
end
|
||||
end
|
49
app/models/concerns/ticket/sets_last_owner_update_time.rb
Normal file
49
app/models/concerns/ticket/sets_last_owner_update_time.rb
Normal file
|
@ -0,0 +1,49 @@
|
|||
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
|
||||
|
||||
# Adds a last_owner_update time on ticket changes.
|
||||
module Ticket::SetsLastOwnerUpdateTime
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
before_create :ticket_set_last_owner_update_time
|
||||
before_update :ticket_set_last_owner_update_time
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def ticket_set_last_owner_update_time
|
||||
|
||||
# return if we run import mode
|
||||
return true if Setting.get('import_mode')
|
||||
# check if owner, state or group has changed
|
||||
return true if changes_to_save['owner_id'].blank? && changes_to_save['state_id'].blank? && changes_to_save['group_id'].blank? && changes_to_save['last_contact_agent_at'].blank?
|
||||
|
||||
# check if owner is nobody
|
||||
if changes_to_save['owner_id'].present? && changes_to_save['owner_id'][1] == 1
|
||||
self.last_owner_update_at = nil
|
||||
return true
|
||||
end
|
||||
|
||||
# check if group is change
|
||||
if changes_to_save['group_id'].present?
|
||||
group = Group.lookup(id: changes_to_save['group_id'][1])
|
||||
return true if !group
|
||||
|
||||
if group.assignment_timeout.blank? || group.assignment_timeout.zero?
|
||||
self.last_owner_update_at = nil
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
# check if state is not new/open
|
||||
if changes_to_save['state_id'].present?
|
||||
state_ids = Ticket::State.by_category(:work_on).pluck(:id)
|
||||
if state_ids.exclude?(changes_to_save['state_id'][1])
|
||||
self.last_owner_update_at = nil
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
self.last_owner_update_at = Time.zone.now
|
||||
end
|
||||
end
|
30
app/models/concerns/ticket/sets_online_notification_seen.rb
Normal file
30
app/models/concerns/ticket/sets_online_notification_seen.rb
Normal file
|
@ -0,0 +1,30 @@
|
|||
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
|
||||
|
||||
# Schedules a background job to update the user's ticket seen information on ticket changes.
|
||||
module Ticket::SetsOnlineNotificationSeen
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
after_create :ticket_set_online_notification_seen
|
||||
after_update :ticket_set_online_notification_seen
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def ticket_set_online_notification_seen
|
||||
|
||||
# return if we run import mode
|
||||
return false if Setting.get('import_mode')
|
||||
|
||||
# set seen only if state has changes
|
||||
return false if !saved_changes?
|
||||
return false if saved_changes['state_id'].blank?
|
||||
|
||||
# check if existing online notifications for this ticket should be set to seen
|
||||
return true if !online_notification_seen_state
|
||||
|
||||
# set all online notifications to seen
|
||||
# send background job
|
||||
TicketOnlineNotificationSeenJob.perform_later(id, updated_by_id)
|
||||
end
|
||||
end
|
37
app/models/concerns/ticket/touches_associations.rb
Normal file
37
app/models/concerns/ticket/touches_associations.rb
Normal file
|
@ -0,0 +1,37 @@
|
|||
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
|
||||
|
||||
# Update assigned customer and organization change_time information on ticket changes.
|
||||
module Ticket::TouchesAssociations
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
after_create :ticket_touch_associations
|
||||
after_update :ticket_touch_associations
|
||||
after_destroy :ticket_touch_associations
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def ticket_touch_associations
|
||||
|
||||
# return if we run import mode
|
||||
return true if Setting.get('import_mode')
|
||||
|
||||
# touch old customer if changed
|
||||
customer_id_changed = saved_changes['customer_id']
|
||||
if customer_id_changed && customer_id_changed[0] != customer_id_changed[1] && customer_id_changed[0]
|
||||
User.find(customer_id_changed[0]).touch # rubocop:disable Rails/SkipsModelValidations
|
||||
end
|
||||
|
||||
# touch new/current customer
|
||||
customer&.touch # rubocop:disable Rails/SkipsModelValidations
|
||||
|
||||
# touch old organization if changed
|
||||
organization_id_changed = saved_changes['organization_id']
|
||||
if organization_id_changed && organization_id_changed[0] != organization_id_changed[1] && organization_id_changed[0]
|
||||
Organization.find(organization_id_changed[0]).touch # rubocop:disable Rails/SkipsModelValidations
|
||||
end
|
||||
|
||||
organization&.touch # rubocop:disable Rails/SkipsModelValidations
|
||||
end
|
||||
end
|
|
@ -1,26 +1,23 @@
|
|||
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
|
||||
|
||||
class Observer::User::Geo < ActiveRecord::Observer
|
||||
observe 'user'
|
||||
# Perform geo data lookup on user changes.
|
||||
module User::PerformsGeoLookup
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
def before_create(record)
|
||||
check_geo(record)
|
||||
true
|
||||
included do
|
||||
before_create :user_check_geo_location
|
||||
before_update :user_check_geo_location
|
||||
end
|
||||
|
||||
def before_update(record)
|
||||
check_geo(record)
|
||||
true
|
||||
end
|
||||
private
|
||||
|
||||
# check if geo need to be updated
|
||||
def check_geo(record)
|
||||
def user_check_geo_location
|
||||
|
||||
location = %w[address street zip city country]
|
||||
|
||||
# check if geo update is needed based on old/new location
|
||||
if record.id
|
||||
current = User.find_by(id: record.id)
|
||||
if id
|
||||
current = User.find_by(id: id)
|
||||
return if !current
|
||||
|
||||
current_location = {}
|
||||
|
@ -32,27 +29,26 @@ class Observer::User::Geo < ActiveRecord::Observer
|
|||
# get full address
|
||||
next_location = {}
|
||||
location.each do |item|
|
||||
next_location[item] = record[item]
|
||||
next_location[item] = attributes[item]
|
||||
end
|
||||
|
||||
# return if address hasn't changed and geo data is already available
|
||||
return if (current_location == next_location) && record.preferences['lat'] && record.preferences['lng']
|
||||
return if (current_location == next_location) && preferences['lat'] && preferences['lng']
|
||||
|
||||
# geo update
|
||||
geo_update(record)
|
||||
user_update_geo_location
|
||||
end
|
||||
|
||||
# update geo data of user
|
||||
def geo_update(record)
|
||||
def user_update_geo_location
|
||||
address = ''
|
||||
location = %w[address street zip city country]
|
||||
location.each do |item|
|
||||
next if record[item].blank?
|
||||
next if attributes[item].blank?
|
||||
|
||||
if address.present?
|
||||
address += ', '
|
||||
end
|
||||
address += record[item]
|
||||
address += attributes[item]
|
||||
end
|
||||
|
||||
# return if no address is given
|
||||
|
@ -60,10 +56,11 @@ class Observer::User::Geo < ActiveRecord::Observer
|
|||
|
||||
# lookup
|
||||
latlng = Service::GeoLocation.geocode(address)
|
||||
|
||||
return if !latlng
|
||||
|
||||
# store data
|
||||
record.preferences['lat'] = latlng[0]
|
||||
record.preferences['lng'] = latlng[1]
|
||||
preferences['lat'] = latlng[0]
|
||||
preferences['lng'] = latlng[1]
|
||||
end
|
||||
end
|
36
app/models/concerns/user/touches_organization.rb
Normal file
36
app/models/concerns/user/touches_organization.rb
Normal file
|
@ -0,0 +1,36 @@
|
|||
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
|
||||
|
||||
# Update assigned organization change_time information on user changes.
|
||||
module User::TouchesOrganization
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
after_create :touch_user_organization
|
||||
after_update :touch_user_organization
|
||||
after_destroy :touch_user_organization
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def touch_user_organization
|
||||
|
||||
# return if we run import mode
|
||||
return true if Setting.get('import_mode')
|
||||
|
||||
organization_id_changed = saved_changes['organization_id']
|
||||
return true if !organization_id_changed
|
||||
|
||||
return true if organization_id_changed[0] == organization_id_changed[1]
|
||||
|
||||
# touch old organization
|
||||
if organization_id_changed[0]
|
||||
old_organization = Organization.find(organization_id_changed[0])
|
||||
old_organization&.touch # rubocop:disable Rails/SkipsModelValidations
|
||||
end
|
||||
|
||||
# touch new/current organization
|
||||
organization&.touch # rubocop:disable Rails/SkipsModelValidations
|
||||
|
||||
true
|
||||
end
|
||||
end
|
28
app/models/concerns/user/updates_ticket_organization.rb
Normal file
28
app/models/concerns/user/updates_ticket_organization.rb
Normal file
|
@ -0,0 +1,28 @@
|
|||
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
|
||||
|
||||
# If a user is assigned to another organization, also assign their latest tickets to it.
|
||||
module User::UpdatesTicketOrganization
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
after_create :user_update_ticket_organization
|
||||
after_update :user_update_ticket_organization
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def user_update_ticket_organization
|
||||
|
||||
# check if organization has changed
|
||||
return true if !saved_change_to_attribute?('organization_id')
|
||||
|
||||
# update last 100 tickets of user
|
||||
tickets = Ticket.where(customer_id: id).limit(100)
|
||||
tickets.each do |ticket|
|
||||
if ticket.organization_id != organization_id
|
||||
ticket.organization_id = organization_id
|
||||
ticket.save
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,36 +0,0 @@
|
|||
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
|
||||
class Observer::Tag::TicketHistory < ActiveRecord::Observer
|
||||
observe 'tag'
|
||||
|
||||
def after_create(record)
|
||||
|
||||
# just process ticket object tags
|
||||
return true if record.tag_object.name != 'Ticket'
|
||||
|
||||
# add ticket history
|
||||
History.add(
|
||||
o_id: record.o_id,
|
||||
history_type: 'added',
|
||||
history_object: 'Ticket',
|
||||
history_attribute: 'tag',
|
||||
value_to: record.tag_item.name,
|
||||
created_by_id: record.created_by_id,
|
||||
)
|
||||
end
|
||||
|
||||
def after_destroy(record)
|
||||
|
||||
# just process ticket object tags
|
||||
return true if record.tag_object.name != 'Ticket'
|
||||
|
||||
# add ticket history
|
||||
History.add(
|
||||
o_id: record.o_id,
|
||||
history_type: 'removed',
|
||||
history_object: 'Ticket',
|
||||
history_attribute: 'tag',
|
||||
value_to: record.tag_item.name,
|
||||
created_by_id: record.created_by_id,
|
||||
)
|
||||
end
|
||||
end
|
|
@ -1,25 +0,0 @@
|
|||
class Observer::Ticket::Article::CommunicateSms < ActiveRecord::Observer
|
||||
observe 'ticket::_article'
|
||||
|
||||
def after_create(record)
|
||||
|
||||
# return if we run import mode
|
||||
return true if Setting.get('import_mode')
|
||||
|
||||
# if sender is customer, do not communicate
|
||||
return true if !record.sender_id
|
||||
|
||||
sender = Ticket::Article::Sender.lookup(id: record.sender_id)
|
||||
return true if sender.nil?
|
||||
return true if sender.name == 'Customer'
|
||||
|
||||
# only apply on sms
|
||||
return true if !record.type_id
|
||||
|
||||
type = Ticket::Article::Type.lookup(id: record.type_id)
|
||||
return true if type.nil?
|
||||
return true if type.name != 'sms'
|
||||
|
||||
CommunicateSmsJob.perform_later(record.id)
|
||||
end
|
||||
end
|
|
@ -1,27 +0,0 @@
|
|||
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
|
||||
|
||||
class Observer::Ticket::Article::CommunicateTelegram < ActiveRecord::Observer
|
||||
observe 'ticket::_article'
|
||||
|
||||
def after_create(record)
|
||||
|
||||
# return if we run import mode
|
||||
return true if Setting.get('import_mode')
|
||||
|
||||
# if sender is customer, do not communicate
|
||||
return true if !record.sender_id
|
||||
|
||||
sender = Ticket::Article::Sender.lookup(id: record.sender_id)
|
||||
return true if sender.nil?
|
||||
return true if sender.name == 'Customer'
|
||||
|
||||
# only apply on telegram messages
|
||||
return true if !record.type_id
|
||||
|
||||
type = Ticket::Article::Type.lookup(id: record.type_id)
|
||||
return true if !type.name.match?(/\Atelegram/i)
|
||||
|
||||
CommunicateTelegramJob.perform_later(record.id)
|
||||
end
|
||||
|
||||
end
|
|
@ -1,27 +0,0 @@
|
|||
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
|
||||
|
||||
class Observer::Ticket::Article::FillupFromOriginById < ActiveRecord::Observer
|
||||
observe 'ticket::_article'
|
||||
|
||||
def before_create(record)
|
||||
|
||||
# return if we run import mode
|
||||
return true if Setting.get('import_mode')
|
||||
|
||||
# only do fill origin_by_id if article got created via application_server (e. g. not
|
||||
# if article and sender type is set via *.postmaster)
|
||||
return true if ApplicationHandleInfo.postmaster?
|
||||
|
||||
# check if origin_by_id exists
|
||||
return true if record.origin_by_id.present?
|
||||
return true if record.ticket.blank?
|
||||
return true if record.ticket.customer_id.blank?
|
||||
return true if record.sender_id.blank?
|
||||
return true if record.sender.name != 'Customer'
|
||||
|
||||
type_name = record.type.name
|
||||
return true if type_name != 'phone' && type_name != 'note' && type_name != 'web'
|
||||
|
||||
record.origin_by_id = record.ticket.customer_id
|
||||
end
|
||||
end
|
|
@ -1,52 +0,0 @@
|
|||
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
|
||||
|
||||
class Observer::Ticket::LastOwnerUpdate < ActiveRecord::Observer
|
||||
observe 'ticket'
|
||||
|
||||
def before_create(record)
|
||||
_check(record)
|
||||
end
|
||||
|
||||
def before_update(record)
|
||||
_check(record)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def _check(record)
|
||||
|
||||
# return if we run import mode
|
||||
return true if Setting.get('import_mode')
|
||||
|
||||
# check if owner, state or group has changed
|
||||
return true if record.changes_to_save['owner_id'].blank? && record.changes_to_save['state_id'].blank? && record.changes_to_save['group_id'].blank? && record.changes_to_save['last_contact_agent_at'].blank?
|
||||
|
||||
# check if owner is nobody
|
||||
if record.changes_to_save['owner_id'].present? && record.changes_to_save['owner_id'][1] == 1
|
||||
record.last_owner_update_at = nil
|
||||
return true
|
||||
end
|
||||
|
||||
# check if group is change
|
||||
if record.changes_to_save['group_id'].present?
|
||||
group = Group.lookup(id: record.changes_to_save['group_id'][1])
|
||||
return true if !group
|
||||
|
||||
if group.assignment_timeout.blank? || group.assignment_timeout.zero?
|
||||
record.last_owner_update_at = nil
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
# check if state is not new/open
|
||||
if record.changes_to_save['state_id'].present?
|
||||
state_ids = Ticket::State.by_category(:work_on).pluck(:id)
|
||||
if state_ids.exclude?(record.changes_to_save['state_id'][1])
|
||||
record.last_owner_update_at = nil
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
record.last_owner_update_at = Time.zone.now
|
||||
end
|
||||
end
|
|
@ -1,32 +0,0 @@
|
|||
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
|
||||
|
||||
class Observer::Ticket::OnlineNotificationSeen < ActiveRecord::Observer
|
||||
observe 'ticket'
|
||||
|
||||
def after_create(record)
|
||||
_check(record)
|
||||
end
|
||||
|
||||
def after_update(record)
|
||||
_check(record)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def _check(record)
|
||||
|
||||
# return if we run import mode
|
||||
return false if Setting.get('import_mode')
|
||||
|
||||
# set seen only if state has changes
|
||||
return false if !record.saved_changes?
|
||||
return false if record.saved_changes['state_id'].blank?
|
||||
|
||||
# check if existing online notifications for this ticket should be set to seen
|
||||
return true if !record.online_notification_seen_state
|
||||
|
||||
# set all online notifications to seen
|
||||
# send background job
|
||||
TicketOnlineNotificationSeenJob.perform_later(record.id, record.updated_by_id)
|
||||
end
|
||||
end
|
|
@ -1,22 +0,0 @@
|
|||
# Ensures pending time is always zero-seconds
|
||||
class Observer::Ticket::PendingTime < ActiveRecord::Observer
|
||||
observe 'ticket'
|
||||
|
||||
def before_create(record)
|
||||
_check(record)
|
||||
end
|
||||
|
||||
def before_update(record)
|
||||
_check(record)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def _check(record)
|
||||
return true if record.pending_time.blank?
|
||||
return true if !record.pending_time_changed?
|
||||
return true if record.pending_time.sec.zero?
|
||||
|
||||
record.pending_time = record.pending_time.change sec: 0
|
||||
end
|
||||
end
|
|
@ -1,43 +0,0 @@
|
|||
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
|
||||
|
||||
class Observer::Ticket::RefObjectTouch < ActiveRecord::Observer
|
||||
observe 'ticket'
|
||||
|
||||
def after_create(record)
|
||||
ref_object_touch(record)
|
||||
end
|
||||
|
||||
def after_update(record)
|
||||
ref_object_touch(record)
|
||||
end
|
||||
|
||||
def after_destroy(record)
|
||||
ref_object_touch(record)
|
||||
end
|
||||
|
||||
def ref_object_touch(record)
|
||||
|
||||
# return if we run import mode
|
||||
return true if Setting.get('import_mode')
|
||||
|
||||
# touch old customer if changed
|
||||
cutomer_id_changed = record.saved_changes['customer_id']
|
||||
if cutomer_id_changed && cutomer_id_changed[0] != cutomer_id_changed[1] && cutomer_id_changed[0]
|
||||
User.find(cutomer_id_changed[0]).touch # rubocop:disable Rails/SkipsModelValidations
|
||||
end
|
||||
|
||||
# touch new/current customer
|
||||
record.customer&.touch # rubocop:disable Rails/SkipsModelValidations
|
||||
|
||||
# touch old organization if changed
|
||||
organization_id_changed = record.saved_changes['organization_id']
|
||||
if organization_id_changed && organization_id_changed[0] != organization_id_changed[1] && organization_id_changed[0]
|
||||
Organization.find(organization_id_changed[0]).touch # rubocop:disable Rails/SkipsModelValidations
|
||||
end
|
||||
|
||||
# touch new/current organization
|
||||
return true if !record.organization
|
||||
|
||||
record.organization.touch # rubocop:disable Rails/SkipsModelValidations
|
||||
end
|
||||
end
|
|
@ -1,26 +0,0 @@
|
|||
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
|
||||
|
||||
require_dependency 'stats/ticket_reopen'
|
||||
|
||||
class Observer::Ticket::StatsReopen < ActiveRecord::Observer
|
||||
|
||||
observe 'ticket'
|
||||
|
||||
def after_create(record)
|
||||
_check(record)
|
||||
end
|
||||
|
||||
def after_update(record)
|
||||
_check(record)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def _check(record)
|
||||
|
||||
# return if we run import mode
|
||||
return if Setting.get('import_mode')
|
||||
|
||||
Stats::TicketReopen.log('Ticket', record.id, record.saved_changes, record.updated_by_id)
|
||||
end
|
||||
end
|
|
@ -1,28 +0,0 @@
|
|||
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
|
||||
|
||||
class Observer::Ticket::UserTicketCounter < ActiveRecord::Observer
|
||||
observe 'ticket'
|
||||
|
||||
def after_commit(record)
|
||||
user_ticket_counter_update(record)
|
||||
end
|
||||
|
||||
def user_ticket_counter_update(record)
|
||||
|
||||
# return if we run import mode
|
||||
return true if Setting.get('import_mode')
|
||||
|
||||
return true if BulkImportInfo.enabled?
|
||||
|
||||
return true if record.destroyed?
|
||||
|
||||
return true if !record.customer_id
|
||||
|
||||
# send background job
|
||||
TicketUserTicketCounterJob.perform_later(
|
||||
record.customer_id,
|
||||
UserInfo.current_user_id || record.updated_by_id,
|
||||
)
|
||||
end
|
||||
|
||||
end
|
|
@ -1,41 +0,0 @@
|
|||
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
|
||||
|
||||
class Observer::User::RefObjectTouch < ActiveRecord::Observer
|
||||
observe 'user'
|
||||
|
||||
def after_create(record)
|
||||
ref_object_touch(record)
|
||||
end
|
||||
|
||||
def after_update(record)
|
||||
ref_object_touch(record)
|
||||
end
|
||||
|
||||
def after_destroy(record)
|
||||
ref_object_touch(record)
|
||||
end
|
||||
|
||||
def ref_object_touch(record)
|
||||
|
||||
# return if we run import mode
|
||||
return true if Setting.get('import_mode')
|
||||
|
||||
organization_id_changed = record.saved_changes['organization_id']
|
||||
return true if !organization_id_changed
|
||||
|
||||
return true if organization_id_changed[0] == organization_id_changed[1]
|
||||
|
||||
# touch old organization
|
||||
if organization_id_changed[0]
|
||||
organization = Organization.find(organization_id_changed[0])
|
||||
organization.touch # rubocop:disable Rails/SkipsModelValidations
|
||||
end
|
||||
|
||||
# touch new/current organization
|
||||
if record&.organization
|
||||
record.organization.touch # rubocop:disable Rails/SkipsModelValidations
|
||||
end
|
||||
|
||||
true
|
||||
end
|
||||
end
|
|
@ -1,30 +0,0 @@
|
|||
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
|
||||
|
||||
class Observer::User::TicketOrganization < ActiveRecord::Observer
|
||||
observe 'user'
|
||||
|
||||
def after_create(record)
|
||||
check_organization(record)
|
||||
end
|
||||
|
||||
def after_update(record)
|
||||
check_organization(record)
|
||||
end
|
||||
|
||||
# check if organization need to be updated
|
||||
def check_organization(record)
|
||||
|
||||
# check if organization has changed
|
||||
return true if !record.saved_change_to_attribute?('organization_id')
|
||||
|
||||
# update last 100 tickets of user
|
||||
tickets = Ticket.where(customer_id: record.id).limit(100)
|
||||
tickets.each do |ticket|
|
||||
if ticket.organization_id != record.organization_id
|
||||
ticket.organization_id = record.organization_id
|
||||
ticket.save
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
|
@ -1,6 +1,7 @@
|
|||
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
|
||||
|
||||
class Tag < ApplicationModel
|
||||
include Tag::WritesToTicketHistory
|
||||
|
||||
belongs_to :tag_object, class_name: 'Tag::Object', optional: true
|
||||
belongs_to :tag_item, class_name: 'Tag::Item', optional: true
|
||||
|
|
|
@ -15,6 +15,12 @@ class Ticket < ApplicationModel
|
|||
include HasLinks
|
||||
include HasObjectManagerAttributesValidation
|
||||
include HasTaskbars
|
||||
include Ticket::CallsStatsTicketReopenLog
|
||||
include Ticket::EnqueuesUserTicketCounterJob
|
||||
include Ticket::ResetsPendingTimeSeconds
|
||||
include Ticket::SetsCloseTime
|
||||
include Ticket::SetsOnlineNotificationSeen
|
||||
include Ticket::TouchesAssociations
|
||||
|
||||
include ::Ticket::Escalation
|
||||
include ::Ticket::Subject
|
||||
|
@ -27,6 +33,9 @@ class Ticket < ApplicationModel
|
|||
before_create :check_generate, :check_defaults, :check_title, :set_default_state, :set_default_priority
|
||||
before_update :check_defaults, :check_title, :reset_pending_time, :check_owner_active
|
||||
|
||||
# This must be loaded late as it depends on the internal before_create and before_update handlers of ticket.rb.
|
||||
include Ticket::SetsLastOwnerUpdateTime
|
||||
|
||||
validates :group_id, presence: true
|
||||
|
||||
activity_stream_permission 'ticket.agent'
|
||||
|
|
|
@ -10,7 +10,18 @@ class Ticket::Article < ApplicationModel
|
|||
include HasObjectManagerAttributesValidation
|
||||
|
||||
include Ticket::Article::Assets
|
||||
include Ticket::Article::EnqueueCommunicateEmailJob
|
||||
include Ticket::Article::EnqueueCommunicateFacebookJob
|
||||
include Ticket::Article::EnqueueCommunicateSmsJob
|
||||
include Ticket::Article::EnqueueCommunicateTelegramJob
|
||||
include Ticket::Article::EnqueueCommunicateTwitterJob
|
||||
include Ticket::Article::HasTicketContactAttributesImpact
|
||||
include Ticket::Article::ResetsTicketState
|
||||
|
||||
# AddsMetadataGeneral depends on AddsMetadataOriginById, so load that first
|
||||
include Ticket::Article::AddsMetadataOriginById
|
||||
include Ticket::Article::AddsMetadataGeneral
|
||||
include Ticket::Article::AddsMetadataEmail
|
||||
|
||||
belongs_to :ticket, optional: true
|
||||
has_one :ticket_time_accounting, class_name: 'Ticket::TimeAccounting', foreign_key: :ticket_article_id, dependent: :destroy, inverse_of: :ticket_article
|
||||
|
|
|
@ -19,6 +19,9 @@ class User < ApplicationModel
|
|||
include User::Assets
|
||||
include User::Search
|
||||
include User::SearchIndex
|
||||
include User::TouchesOrganization
|
||||
include User::PerformsGeoLookup
|
||||
include User::UpdatesTicketOrganization
|
||||
|
||||
has_and_belongs_to_many :organizations, after_add: :cache_update, after_remove: :cache_update, class_name: 'Organization'
|
||||
has_and_belongs_to_many :overviews, dependent: :nullify
|
||||
|
|
|
@ -27,26 +27,6 @@ module Zammad
|
|||
# config.active_record.observers = :cacher, :garbage_collector, :forum_observer
|
||||
config.active_record.observers =
|
||||
'observer::_session',
|
||||
'observer::_ticket::_close_time',
|
||||
'observer::_ticket::_last_owner_update',
|
||||
'observer::_ticket::_pending_time',
|
||||
'observer::_ticket::_user_ticket_counter',
|
||||
'observer::_ticket::_article::_fillup_from_origin_by_id',
|
||||
'observer::_ticket::_article::_fillup_from_general',
|
||||
'observer::_ticket::_article::_fillup_from_email',
|
||||
'observer::_ticket::_article::_communicate_email',
|
||||
'observer::_ticket::_article::_communicate_facebook',
|
||||
'observer::_ticket::_article::_communicate_sms',
|
||||
'observer::_ticket::_article::_communicate_twitter',
|
||||
'observer::_ticket::_article::_communicate_telegram',
|
||||
'observer::_ticket::_reset_new_state',
|
||||
'observer::_ticket::_ref_object_touch',
|
||||
'observer::_ticket::_online_notification_seen',
|
||||
'observer::_ticket::_stats_reopen',
|
||||
'observer::_tag::_ticket_history',
|
||||
'observer::_user::_ref_object_touch',
|
||||
'observer::_user::_ticket_organization',
|
||||
'observer::_user::_geo',
|
||||
'observer::_transaction'
|
||||
|
||||
config.active_job.queue_adapter = :delayed_job
|
||||
|
|
|
@ -5,13 +5,6 @@ RSpec.describe CommunicateTwitterJob, type: :job do
|
|||
let(:article) { create(:twitter_article, **(try(:factory_options) || {})) }
|
||||
|
||||
describe 'core behavior', :use_vcr do
|
||||
# This job runs automatically whenever an article is created.
|
||||
# We disable this auto-execution so we can invoke it manually in the tests below.
|
||||
around do |example|
|
||||
ActiveRecord::Base.observers.disable('observer::_ticket::_article::_communicate_twitter')
|
||||
example.run
|
||||
ActiveRecord::Base.observers.enable('observer::_ticket::_article::_communicate_twitter')
|
||||
end
|
||||
|
||||
context 'for tweets' do
|
||||
let(:tweet_attributes) do
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
RSpec.shared_examples 'TagWritesToTicketHistory' do
|
||||
subject { create(described_class.name.underscore) }
|
||||
|
||||
# The concern is for the tag model, but the shared example needs to be loaded in the ticket test.
|
||||
it 'can only be loaded for tickets' do
|
||||
expect(described_class).to eq Ticket
|
||||
end
|
||||
|
||||
it 'creates a ticket history entry for tag_add' do # rubocop:disable RSpec/ExampleLength
|
||||
subject.tag_add('foo', 1)
|
||||
expect(subject.history_get.last).to include(
|
||||
'object' => described_class.name,
|
||||
'o_id' => subject.id,
|
||||
'type' => 'added',
|
||||
'attribute' => 'tag',
|
||||
'value_to' => 'foo',
|
||||
'value_from' => nil
|
||||
)
|
||||
end
|
||||
|
||||
it 'creates a ticket history entry for tag_remove' do # rubocop:disable RSpec/ExampleLength
|
||||
subject.tag_add('foo', 1)
|
||||
subject.tag_remove('foo', 1)
|
||||
expect(subject.history_get.last).to include(
|
||||
'object' => described_class.name,
|
||||
'o_id' => subject.id,
|
||||
'type' => 'removed',
|
||||
'attribute' => 'tag',
|
||||
'value_to' => 'foo',
|
||||
'value_from' => nil
|
||||
)
|
||||
end
|
||||
end
|
|
@ -1,6 +1,6 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe Observer::Ticket::Article::FillupFromGeneral, current_user_id: -> { agent.id } do
|
||||
RSpec.describe Ticket::Article::AddsMetadataGeneral, current_user_id: -> { agent.id } do
|
||||
let(:agent) { create(:agent) }
|
||||
|
||||
context 'when customer is agent' do
|
|
@ -0,0 +1,41 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe Ticket::Article::EnqueueCommunicateEmailJob, performs_jobs: true do
|
||||
before { allow(Delayed::Job).to receive(:enqueue).and_call_original }
|
||||
|
||||
let(:article) { create(:ticket_article, **(try(:factory_options) || {})) }
|
||||
|
||||
shared_examples 'for no-op' do
|
||||
it 'is a no-op' do
|
||||
expect { article }.not_to have_enqueued_job(TicketArticleCommunicateEmailJob)
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples 'for success' do
|
||||
it 'enqueues the Email background job' do
|
||||
expect { article }.to have_enqueued_job(TicketArticleCommunicateEmailJob)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when in Import Mode' do
|
||||
before { Setting.set('import_mode', true) }
|
||||
|
||||
include_examples 'for no-op'
|
||||
end
|
||||
|
||||
context 'when article is created during Channel::EmailParser#process', application_handle: 'scheduler.postmaster' do
|
||||
include_examples 'for no-op'
|
||||
end
|
||||
|
||||
context 'when article is from a customer' do
|
||||
let(:factory_options) { { sender_name: 'Customer' } }
|
||||
|
||||
include_examples 'for no-op'
|
||||
end
|
||||
|
||||
context 'when article is an email' do
|
||||
let(:factory_options) { { sender_name: 'Agent', type_name: 'email' } }
|
||||
|
||||
include_examples 'for success'
|
||||
end
|
||||
end
|
|
@ -0,0 +1,41 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe Ticket::Article::EnqueueCommunicateFacebookJob, performs_jobs: true do
|
||||
before { allow(Delayed::Job).to receive(:enqueue).and_call_original }
|
||||
|
||||
let(:article) { create(:ticket_article, **(try(:factory_options) || {})) }
|
||||
|
||||
shared_examples 'for no-op' do
|
||||
it 'is a no-op' do
|
||||
expect { article }.not_to have_enqueued_job(CommunicateFacebookJob)
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples 'for success' do
|
||||
it 'enqueues the Facebook background job' do
|
||||
expect { article }.to have_enqueued_job(CommunicateFacebookJob)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when in Import Mode' do
|
||||
before { Setting.set('import_mode', true) }
|
||||
|
||||
include_examples 'for no-op'
|
||||
end
|
||||
|
||||
context 'when article is created during Channel::EmailParser#process', application_handle: 'scheduler.postmaster' do
|
||||
include_examples 'for no-op'
|
||||
end
|
||||
|
||||
context 'when article is from a customer' do
|
||||
let(:factory_options) { { sender_name: 'Customer' } }
|
||||
|
||||
include_examples 'for no-op'
|
||||
end
|
||||
|
||||
context 'when article is a facebook post' do
|
||||
let(:factory_options) { { sender_name: 'Agent', type_name: 'facebook feed post' } }
|
||||
|
||||
include_examples 'for success'
|
||||
end
|
||||
end
|
|
@ -0,0 +1,41 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe Ticket::Article::EnqueueCommunicateSmsJob, performs_jobs: true do
|
||||
before { allow(Delayed::Job).to receive(:enqueue).and_call_original }
|
||||
|
||||
let(:article) { create(:ticket_article, **(try(:factory_options) || {})) }
|
||||
|
||||
shared_examples 'for no-op' do
|
||||
it 'is a no-op' do
|
||||
expect { article }.not_to have_enqueued_job(CommunicateSmsJob)
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples 'for success' do
|
||||
it 'enqueues the SMS background job' do
|
||||
expect { article }.to have_enqueued_job(CommunicateSmsJob)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when in Import Mode' do
|
||||
before { Setting.set('import_mode', true) }
|
||||
|
||||
include_examples 'for no-op'
|
||||
end
|
||||
|
||||
context 'when article is created during Channel::EmailParser#process', application_handle: 'scheduler.postmaster' do
|
||||
include_examples 'for no-op'
|
||||
end
|
||||
|
||||
context 'when article is from a customer' do
|
||||
let(:factory_options) { { sender_name: 'Customer' } }
|
||||
|
||||
include_examples 'for no-op'
|
||||
end
|
||||
|
||||
context 'when article is an sms' do
|
||||
let(:factory_options) { { sender_name: 'Agent', type_name: 'sms' } }
|
||||
|
||||
include_examples 'for success'
|
||||
end
|
||||
end
|
|
@ -0,0 +1,41 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Ticket::Article::EnqueueCommunicateTelegramJob', performs_jobs: true do
|
||||
before { allow(Delayed::Job).to receive(:enqueue).and_call_original }
|
||||
|
||||
let(:article) { create(:ticket_article, **(try(:factory_options) || {})) }
|
||||
|
||||
shared_examples 'for no-op' do
|
||||
it 'is a no-op' do
|
||||
expect { article }.not_to have_enqueued_job(CommunicateTelegramJob)
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples 'for success' do
|
||||
it 'enqueues the Telegram background job' do
|
||||
expect { article }.to have_enqueued_job(CommunicateTelegramJob)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when in Import Mode' do
|
||||
before { Setting.set('import_mode', true) }
|
||||
|
||||
include_examples 'for no-op'
|
||||
end
|
||||
|
||||
context 'when article is created during Channel::EmailParser#process', application_handle: 'scheduler.postmaster' do
|
||||
include_examples 'for no-op'
|
||||
end
|
||||
|
||||
context 'when article is from a customer' do
|
||||
let(:factory_options) { { sender_name: 'Customer' } }
|
||||
|
||||
include_examples 'for no-op'
|
||||
end
|
||||
|
||||
context 'when article is a Telegram message' do
|
||||
let(:factory_options) { { sender_name: 'Agent', type_name: 'telegram personal-message' } }
|
||||
|
||||
include_examples 'for success'
|
||||
end
|
||||
end
|
|
@ -1,6 +1,6 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe Observer::Ticket::Article::CommunicateTwitter, performs_jobs: true do
|
||||
RSpec.describe Ticket::Article::EnqueueCommunicateTwitterJob, performs_jobs: true do
|
||||
before { allow(Delayed::Job).to receive(:enqueue).and_call_original }
|
||||
|
||||
let(:article) { create(:ticket_article, **(try(:factory_options) || {})) }
|
||||
|
@ -17,7 +17,7 @@ RSpec.describe Observer::Ticket::Article::CommunicateTwitter, performs_jobs: tru
|
|||
end
|
||||
end
|
||||
|
||||
context 'in Import Mode' do
|
||||
context 'when in Import Mode' do
|
||||
before { Setting.set('import_mode', true) }
|
||||
|
||||
include_examples 'for no-op'
|
||||
|
@ -50,7 +50,7 @@ RSpec.describe Observer::Ticket::Article::CommunicateTwitter, performs_jobs: tru
|
|||
|
||||
include_examples 'for success'
|
||||
|
||||
context 'but #to attribute is missing' do
|
||||
context 'when #to attribute is missing' do
|
||||
let(:factory_options) { { sender_name: 'Agent', type_name: 'twitter direct-message', to: nil } }
|
||||
|
||||
it 'raises an error' do
|
|
@ -0,0 +1,12 @@
|
|||
RSpec.shared_examples 'TicketCallsStatsTicketReopenLog' do
|
||||
|
||||
it 'can only be loaded for Ticket' do
|
||||
expect(described_class).to eq Ticket
|
||||
end
|
||||
|
||||
it 'calls Stats::TicketReopen.log' do
|
||||
allow(Stats::TicketReopen).to receive(:log)
|
||||
create(described_class.name.underscore)
|
||||
expect(Stats::TicketReopen).to have_received(:log)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,10 @@
|
|||
RSpec.shared_examples 'TicketEnqueuesTicketUserTicketCounterJob', type: :job do
|
||||
subject { create(described_class.name.underscore) }
|
||||
|
||||
let(:customer) { create('customer') }
|
||||
|
||||
it 'enqueues a job for the customer' do
|
||||
subject.customer = customer
|
||||
expect { subject.save }.to have_enqueued_job(TicketUserTicketCounterJob)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,12 @@
|
|||
RSpec.shared_examples 'TicketResetsPendingTimeSeconds' do
|
||||
subject { create(described_class.name.underscore) }
|
||||
|
||||
it 'can only be loaded for tickets' do
|
||||
expect(described_class).to eq Ticket
|
||||
end
|
||||
|
||||
it 'resets pending_time seconds' do
|
||||
subject.update(pending_time: Time.zone.parse('2007-02-10 15:30:45'))
|
||||
expect(subject.pending_time).to eq(Time.zone.parse('2007-02-10 15:30:00'))
|
||||
end
|
||||
end
|
18
spec/models/concerns/ticket/sets_close_time_examples.rb
Normal file
18
spec/models/concerns/ticket/sets_close_time_examples.rb
Normal file
|
@ -0,0 +1,18 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.shared_examples 'TicketSetsCloseTime' do
|
||||
subject { create(described_class.name.underscore) }
|
||||
|
||||
it 'can only be loaded for tickets' do
|
||||
expect(described_class).to eq Ticket
|
||||
end
|
||||
|
||||
before do
|
||||
travel_to Time.zone.now
|
||||
end
|
||||
|
||||
it 'resets pending_time seconds' do
|
||||
subject.update(state: Ticket::State.lookup(name: 'closed'))
|
||||
expect(subject.close_at).to eq(Time.zone.now)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,24 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.shared_examples 'TicketSetsLastOwnerUpdateTime' do
|
||||
subject { create(described_class.name.underscore) }
|
||||
|
||||
let(:new_owner) { create(:agent, groups: [subject.group]) }
|
||||
|
||||
it 'can only be loaded for tickets' do
|
||||
expect(described_class).to eq Ticket
|
||||
end
|
||||
|
||||
before do
|
||||
travel_to Time.zone.now
|
||||
end
|
||||
|
||||
it 'has no last_owner_update_at initially' do
|
||||
expect(subject.last_owner_update_at).to be_nil
|
||||
end
|
||||
|
||||
it 'gets last_owner_update_at after user change' do
|
||||
subject.update(owner: new_owner)
|
||||
expect(subject.last_owner_update_at).to eq(Time.zone.now)
|
||||
end
|
||||
end
|
16
spec/models/concerns/user/performs_geo_lookup_examples.rb
Normal file
16
spec/models/concerns/user/performs_geo_lookup_examples.rb
Normal file
|
@ -0,0 +1,16 @@
|
|||
RSpec.shared_examples 'UserPerformsGeoLookup' do
|
||||
|
||||
it 'can only be loaded for User' do
|
||||
expect(described_class).to eq User
|
||||
end
|
||||
|
||||
it 'performs geo lookup' do
|
||||
|
||||
# Mock the geo lookup as it requires an API key.
|
||||
allow(Service::GeoLocation).to receive(:geocode).with('Marienstraße 18, 10117, Berlin, Germany').and_return([10.0, 20.0])
|
||||
|
||||
user = create(described_class.name.underscore, street: 'Marienstraße 18', zip: '10117', city: 'Berlin', country: 'Germany')
|
||||
|
||||
expect(user.preferences).to include(lat: 10.0, lng: 20.0)
|
||||
end
|
||||
end
|
|
@ -4,9 +4,15 @@ require 'models/concerns/can_be_imported_examples'
|
|||
require 'models/concerns/can_csv_import_examples'
|
||||
require 'models/concerns/has_history_examples'
|
||||
require 'models/concerns/has_tags_examples'
|
||||
require 'models/concerns/tag/writes_to_ticket_history_examples'
|
||||
require 'models/concerns/has_taskbars_examples'
|
||||
require 'models/concerns/has_xss_sanitized_note_examples'
|
||||
require 'models/concerns/has_object_manager_attributes_validation_examples'
|
||||
require 'models/concerns/ticket/calls_stats_ticket_reopen_log_examples'
|
||||
require 'models/concerns/ticket/enqueues_user_ticket_counter_job_examples'
|
||||
require 'models/concerns/ticket/resets_pending_time_seconds_examples'
|
||||
require 'models/concerns/ticket/sets_close_time_examples'
|
||||
require 'models/concerns/ticket/sets_last_owner_update_time_examples'
|
||||
require 'models/ticket/escalation_examples'
|
||||
|
||||
RSpec.describe Ticket, type: :model do
|
||||
|
@ -17,10 +23,16 @@ RSpec.describe Ticket, type: :model do
|
|||
it_behaves_like 'CanCsvImport'
|
||||
it_behaves_like 'HasHistory', history_relation_object: 'Ticket::Article'
|
||||
it_behaves_like 'HasTags'
|
||||
it_behaves_like 'TagWritesToTicketHistory'
|
||||
it_behaves_like 'HasTaskbars'
|
||||
it_behaves_like 'HasXssSanitizedNote', model_factory: :ticket
|
||||
it_behaves_like 'HasObjectManagerAttributesValidation'
|
||||
it_behaves_like 'Ticket::Escalation'
|
||||
it_behaves_like 'TicketCallsStatsTicketReopenLog'
|
||||
it_behaves_like 'TicketEnqueuesTicketUserTicketCounterJob'
|
||||
it_behaves_like 'TicketResetsPendingTimeSeconds'
|
||||
it_behaves_like 'TicketSetsCloseTime'
|
||||
it_behaves_like 'TicketSetsLastOwnerUpdateTime'
|
||||
|
||||
describe 'Class methods:' do
|
||||
describe '.selectors' do
|
||||
|
|
|
@ -7,6 +7,7 @@ require 'models/concerns/has_groups_permissions_examples'
|
|||
require 'models/concerns/has_xss_sanitized_note_examples'
|
||||
require 'models/concerns/can_be_imported_examples'
|
||||
require 'models/concerns/has_object_manager_attributes_validation_examples'
|
||||
require 'models/concerns/user/performs_geo_lookup_examples'
|
||||
require 'models/user/has_ticket_create_screen_impact_examples'
|
||||
require 'models/user/can_lookup_search_index_attributes_examples'
|
||||
require 'models/concerns/has_taskbars_examples'
|
||||
|
@ -29,6 +30,7 @@ RSpec.describe User, type: :model do
|
|||
it_behaves_like 'User::HasTicketCreateScreenImpact'
|
||||
it_behaves_like 'CanLookupSearchIndexAttributes'
|
||||
it_behaves_like 'HasTaskbars'
|
||||
it_behaves_like 'UserPerformsGeoLookup'
|
||||
|
||||
describe 'Class methods:' do
|
||||
describe '.authenticate' do
|
||||
|
|
Loading…
Reference in a new issue