Refactoring: Migrated last Delayed::Job classes to ActiveJob.

This commit is contained in:
Thorsten Eckel 2020-10-27 16:36:38 +01:00
parent 3033002ae5
commit 5f3a8dc581
48 changed files with 735 additions and 660 deletions

View file

@ -48,4 +48,3 @@ before_script:
- source /etc/profile.d/rvm.sh
- bundle install -j $(nproc) --path vendor
- bundle exec ruby script/build/database_config.rb

View file

@ -31,6 +31,7 @@ RSpec/ContextWording:
- 'spec/db/migrate/issue_2345_es_attachment_max_size_in_mb_setting_lower_default_spec.rb'
- 'spec/db/migrate/issue_2368_add_indices_to_histories_and_tickets_spec.rb'
- 'spec/db/migrate/issue_2541_fix_notification_email_without_body_spec.rb'
- 'spec/jobs/communicate_twitter_job_spec.rb'
- 'spec/jobs/concerns/has_active_job_lock_spec.rb'
- 'spec/jobs/concerns/has_collection_update_spec.rb'
- 'spec/jobs/concerns/has_ticket_create_screen_impact_spec.rb'
@ -116,7 +117,6 @@ RSpec/ContextWording:
- 'spec/models/object_manager/attribute/validation/required_spec.rb'
- 'spec/models/object_manager/attribute/validation_spec.rb'
- 'spec/models/object_manager/attribute_spec.rb'
- 'spec/models/observer/ticket/article/communicate_twitter/background_job_spec.rb'
- 'spec/models/observer/ticket/article/communicate_twitter_spec.rb'
- 'spec/models/overview_spec.rb'
- 'spec/models/role_spec.rb'
@ -170,7 +170,9 @@ RSpec/ExampleLength:
- 'spec/db/migrate/issue_2867_footer_header_public_link_spec.rb'
- 'spec/db/migrate/object_manager_attribute_date_remove_future_past_spec.rb'
- 'spec/db/migrate/rename_locale_on_users_spec.rb'
- 'spec/jobs/communicate_twitter_job_spec.rb'
- 'spec/jobs/concerns/has_active_job_lock_spec.rb'
- 'spec/jobs/migrate_ldap_samaccountname_to_uid_job_spec.rb'
- 'spec/jobs/ticket_user_ticket_counter_job_spec.rb'
- 'spec/jobs/user_device_log_job_spec.rb'
- 'spec/lib/auth/internal_spec.rb'
@ -209,7 +211,6 @@ RSpec/ExampleLength:
- 'spec/lib/ldap/group_spec.rb'
- 'spec/lib/ldap/user_spec.rb'
- 'spec/lib/ldap_spec.rb'
- 'spec/lib/migration_job/ldap_samaccountname_to_uid_spec.rb'
- 'spec/lib/notification_factory/mailer_spec.rb'
- 'spec/lib/notification_factory/renderer_spec.rb'
- 'spec/lib/notification_factory/slack_spec.rb'
@ -249,7 +250,6 @@ RSpec/ExampleLength:
- 'spec/models/history_spec.rb'
- 'spec/models/import_job_spec.rb'
- 'spec/models/object_manager/attribute_spec.rb'
- 'spec/models/observer/ticket/article/communicate_twitter/background_job_spec.rb'
- 'spec/models/overview_spec.rb'
- 'spec/models/recent_view_spec.rb'
- 'spec/models/role_group_spec.rb'
@ -357,6 +357,7 @@ RSpec/InstanceVariable:
RSpec/LetSetup:
Exclude:
- 'spec/jobs/communicate_twitter_job_spec.rb'
- 'spec/jobs/ticket_online_notification_seen_job_spec.rb'
- 'spec/lib/external_credential/google_spec.rb'
- 'spec/lib/external_credential/office365_spec.rb'
@ -367,7 +368,6 @@ RSpec/LetSetup:
- 'spec/models/cti/caller_id_spec.rb'
- 'spec/models/cti/driver/base_spec.rb'
- 'spec/models/cti/log_spec.rb'
- 'spec/models/observer/ticket/article/communicate_twitter/background_job_spec.rb'
- 'spec/models/organization_spec.rb'
- 'spec/models/role_group_spec.rb'
- 'spec/models/tag_spec.rb'
@ -431,7 +431,6 @@ RSpec/MessageSpies:
- 'spec/lib/ldap/guid_spec.rb'
- 'spec/lib/ldap/user_spec.rb'
- 'spec/lib/ldap_spec.rb'
- 'spec/lib/migration_job/ldap_samaccountname_to_uid_spec.rb'
- 'spec/lib/sequencer/sequence/import/ldap/users_spec.rb'
- 'spec/lib/sequencer/unit/common/attribute_mapper_spec.rb'
- 'spec/lib/sequencer/unit/import/common/mapping/flat_keys_spec.rb'
@ -468,7 +467,9 @@ RSpec/MultipleExpectations:
- 'spec/db/migrate/issue_1905_exchange_login_from_remote_id_spec.rb'
- 'spec/db/migrate/object_manager_attribute_date_remove_future_past_spec.rb'
- 'spec/db/migrate/rename_locale_on_users_spec.rb'
- 'spec/jobs/communicate_twitter_job_spec.rb'
- 'spec/jobs/concerns/has_active_job_lock_spec.rb'
- 'spec/jobs/migrate_ldap_samaccountname_to_uid_job_spec.rb'
- 'spec/jobs/search_index_job_spec.rb'
- 'spec/jobs/ticket_user_ticket_counter_job_spec.rb'
- 'spec/lib/auth/developer_spec.rb'
@ -505,7 +506,6 @@ RSpec/MultipleExpectations:
- 'spec/lib/ldap/guid_spec.rb'
- 'spec/lib/ldap/user_spec.rb'
- 'spec/lib/ldap_spec.rb'
- 'spec/lib/migration_job/ldap_samaccountname_to_uid_spec.rb'
- 'spec/lib/notification_factory/mailer_spec.rb'
- 'spec/lib/password_hash_spec.rb'
- 'spec/lib/secure_mailing/smime_spec.rb'
@ -538,7 +538,6 @@ RSpec/MultipleExpectations:
- 'spec/models/object_manager/attribute/validation/backend_spec.rb'
- 'spec/models/object_manager/attribute/validation_spec.rb'
- 'spec/models/object_manager/attribute_spec.rb'
- 'spec/models/observer/ticket/article/communicate_twitter/background_job_spec.rb'
- 'spec/models/overview_spec.rb'
- 'spec/models/scheduler_spec.rb'
- 'spec/models/smime_certificate_spec.rb'
@ -613,6 +612,7 @@ RSpec/NamedSubject:
RSpec/NestedGroups:
Exclude:
- 'spec/db/migrate/issue_2541_fix_notification_email_without_body_spec.rb'
- 'spec/jobs/communicate_twitter_job_spec.rb'
- 'spec/jobs/concerns/has_collection_update_spec.rb'
- 'spec/jobs/concerns/has_ticket_create_screen_impact_spec.rb'
- 'spec/lib/application_handle_info_spec.rb'
@ -656,7 +656,6 @@ RSpec/NestedGroups:
- 'spec/models/object_manager/attribute/validation/required_spec.rb'
- 'spec/models/object_manager/attribute/validation_spec.rb'
- 'spec/models/object_manager/attribute_spec.rb'
- 'spec/models/observer/ticket/article/communicate_twitter/background_job_spec.rb'
- 'spec/models/organization_spec.rb'
- 'spec/models/recent_view_spec.rb'
- 'spec/models/role_spec.rb'
@ -727,6 +726,7 @@ RSpec/SubjectStub:
RSpec/VerifiedDoubles:
Exclude:
- 'spec/db/migrate/issue_2460_fix_corrupted_twitter_ids_spec.rb'
- 'spec/jobs/communicate_twitter_job_spec.rb'
- 'spec/lib/auth/ldap_spec.rb'
- 'spec/lib/external_sync_spec.rb'
- 'spec/lib/import/zendesk/object_attribute/base_examples.rb'
@ -744,7 +744,6 @@ RSpec/VerifiedDoubles:
- 'spec/lib/sequencer/unit/import/zendesk/sub_sequence/base_examples.rb'
- 'spec/lib/sequencer/unit/import/zendesk/ticket/comment/attachment/request_spec.rb'
- 'spec/lib/sequencer/unit/import/zendesk/ticket/comment/source_based_spec.rb'
- 'spec/models/observer/ticket/article/communicate_twitter/background_job_spec.rb'
- 'spec/models/ticket/number_spec.rb'
RSpec/MultipleMemoizedHelpers:

View file

@ -75,8 +75,13 @@ Metrics/AbcSize:
- 'app/controllers/users_controller.rb'
- 'app/helpers/knowledge_base_rich_text_helper.rb'
- 'app/jobs/collection_update_job.rb'
- 'app/jobs/communicate_facebook_job.rb'
- 'app/jobs/communicate_sms_job.rb'
- 'app/jobs/communicate_telegram_job.rb'
- 'app/jobs/communicate_twitter_job.rb'
- 'app/jobs/concerns/has_active_job_lock.rb'
- 'app/jobs/imap_authentication_migration_cleanup_job.rb'
- 'app/jobs/migrate_ldap_samaccountname_to_uid_job.rb'
- 'app/jobs/ticket_article_communicate_email_job.rb'
- 'app/jobs/ticket_user_ticket_counter_job.rb'
- 'app/models/activity_stream.rb'
@ -154,13 +159,9 @@ Metrics/AbcSize:
- 'app/models/observer/sla/ticket_rebuild_escalation.rb'
- 'app/models/observer/ticket/article/communicate_email.rb'
- 'app/models/observer/ticket/article/communicate_facebook.rb'
- 'app/models/observer/ticket/article/communicate_facebook/background_job.rb'
- 'app/models/observer/ticket/article/communicate_sms.rb'
- 'app/models/observer/ticket/article/communicate_sms/background_job.rb'
- 'app/models/observer/ticket/article/communicate_telegram.rb'
- 'app/models/observer/ticket/article/communicate_telegram/background_job.rb'
- 'app/models/observer/ticket/article/communicate_twitter.rb'
- 'app/models/observer/ticket/article/communicate_twitter/background_job.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'
@ -290,7 +291,6 @@ Metrics/AbcSize:
- 'lib/knowledge_base/menu_item_update_action.rb'
- 'lib/ldap/group.rb'
- 'lib/ldap/user.rb'
- 'lib/migration_job/ldap_samaccountname_to_uid.rb'
- 'lib/models.rb'
- 'lib/notification_factory/mailer.rb'
- 'lib/notification_factory/renderer.rb'
@ -486,6 +486,10 @@ Metrics/CyclomaticComplexity:
- 'app/controllers/user_access_token_controller.rb'
- 'app/controllers/users_controller.rb'
- 'app/jobs/collection_update_job.rb'
- 'app/jobs/communicate_facebook_job.rb'
- 'app/jobs/communicate_sms_job.rb'
- 'app/jobs/communicate_telegram_job.rb'
- 'app/jobs/communicate_twitter_job.rb'
- 'app/jobs/ticket_article_communicate_email_job.rb'
- 'app/jobs/ticket_create_screen_job.rb'
- 'app/jobs/ticket_user_ticket_counter_job.rb'
@ -545,12 +549,8 @@ Metrics/CyclomaticComplexity:
- 'app/models/observer/sla/ticket_rebuild_escalation.rb'
- 'app/models/observer/ticket/article/communicate_email.rb'
- 'app/models/observer/ticket/article/communicate_facebook.rb'
- 'app/models/observer/ticket/article/communicate_facebook/background_job.rb'
- 'app/models/observer/ticket/article/communicate_sms.rb'
- 'app/models/observer/ticket/article/communicate_sms/background_job.rb'
- 'app/models/observer/ticket/article/communicate_telegram/background_job.rb'
- 'app/models/observer/ticket/article/communicate_twitter.rb'
- 'app/models/observer/ticket/article/communicate_twitter/background_job.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'
@ -720,6 +720,10 @@ Metrics/PerceivedComplexity:
- 'app/controllers/time_accountings_controller.rb'
- 'app/controllers/users_controller.rb'
- 'app/jobs/collection_update_job.rb'
- 'app/jobs/communicate_facebook_job.rb'
- 'app/jobs/communicate_sms_job.rb'
- 'app/jobs/communicate_telegram_job.rb'
- 'app/jobs/communicate_twitter_job.rb'
- 'app/jobs/ticket_article_communicate_email_job.rb'
- 'app/models/activity_stream/assets.rb'
- 'app/models/application_model/can_assets.rb'
@ -775,12 +779,8 @@ Metrics/PerceivedComplexity:
- 'app/models/observer/sla/ticket_rebuild_escalation.rb'
- 'app/models/observer/ticket/article/communicate_email.rb'
- 'app/models/observer/ticket/article/communicate_facebook.rb'
- 'app/models/observer/ticket/article/communicate_facebook/background_job.rb'
- 'app/models/observer/ticket/article/communicate_sms.rb'
- 'app/models/observer/ticket/article/communicate_sms/background_job.rb'
- 'app/models/observer/ticket/article/communicate_telegram/background_job.rb'
- 'app/models/observer/ticket/article/communicate_twitter.rb'
- 'app/models/observer/ticket/article/communicate_twitter/background_job.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'

View file

@ -22,7 +22,7 @@ module Integration::ImportJobBase
def job_start_create
if !ImportJob.exists?(name: backend, finished_at: nil)
job = ImportJob.create(name: backend)
job.delay.start
AsyncImportJob.perform_later(job)
end
render json: {
result: 'ok',

View file

@ -115,7 +115,7 @@ class ImportOtrsController < ApplicationController
end
# start migration
Import::OTRS.delay.start_bg
AsyncOtrsImportJob.perform_later
render json: {
result: 'ok',

View file

@ -98,7 +98,7 @@ class ImportZendeskController < ApplicationController
Setting.set('import_backend', 'zendesk')
job = ImportJob.create(name: 'Import::Zendesk')
job.delay.start
AsyncImportJob.perform_later(job)
render json: {
result: 'ok',

View file

@ -0,0 +1,5 @@
class AsyncImportJob < ApplicationJob
def perform(import_job)
import_job.start
end
end

View file

@ -0,0 +1,5 @@
class AsyncOtrsImportJob < ApplicationJob
def perform
Import::OTRS.start_bg
end
end

View file

@ -0,0 +1,34 @@
class ChatLeaveJob < ApplicationJob
def perform(chat_session_id, client_id, session)
# check if customer has permanently left the conversation
chat_session = Chat::Session.find_by(id: chat_session_id)
return if !chat_session
return if chat_session.recipients_active?
chat_session.state = 'closed'
chat_session.save
realname = 'Anonymous'
# if it is a agent session, use the realname if the agent for close message
if session && session['id'] && chat_session.user_id
agent_user = chat_session.agent_user
if agent_user[:name]
realname = agent_user[:name]
end
end
# notify participants
message = {
event: 'chat_session_left',
data: {
realname: realname,
session_id: chat_session.session_id,
},
}
chat_session.send_to_recipients(message, client_id)
Chat.broadcast_agent_state_update([chat_session.chat_id])
end
end

View file

@ -0,0 +1,94 @@
class CommunicateFacebookJob < ApplicationJob
retry_on StandardError, attempts: 4, wait: lambda { |executions|
executions * 120.seconds
}
def perform(article_id)
article = Ticket::Article.find(article_id)
# set retry count
article.preferences['delivery_retry'] ||= 0
article.preferences['delivery_retry'] += 1
ticket = Ticket.lookup(id: article.ticket_id)
log_error(article, "Can't find ticket.preferences for Ticket.find(#{article.ticket_id})") if !ticket.preferences
log_error(article, "Can't find ticket.preferences['channel_id'] for Ticket.find(#{article.ticket_id})") if !ticket.preferences['channel_id']
channel = Channel.lookup(id: ticket.preferences['channel_id'])
log_error(article, "Channel.find(#{channel.id}) isn't a twitter channel!") if !channel.options[:adapter].match?(/\Afacebook/i)
# check source object id
if !ticket.preferences['channel_fb_object_id']
log_error(article, "fb object id is missing in ticket.preferences['channel_fb_object_id'] for Ticket.find(#{ticket.id})")
end
# fill in_reply_to
if article.in_reply_to.blank?
article.in_reply_to = ticket.articles.first.message_id
end
begin
facebook = Channel::Driver::Facebook.new
post = facebook.send(
channel.options,
ticket.preferences[:channel_fb_object_id],
{
type: article.type.name,
to: article.to,
body: article.body,
in_reply_to: article.in_reply_to,
}
)
rescue => e
log_error(article, e.message)
return
end
if !post
log_error(article, 'Got no post!')
return
end
# fill article with post info
article.from = post['from']['name']
article.message_id = post['id']
# set delivery status
article.preferences['delivery_status_message'] = nil
article.preferences['delivery_status'] = 'success'
article.preferences['delivery_status_date'] = Time.zone.now
article.save!
Rails.logger.info "Send facebook to: '#{article.to}' (from #{article.from})"
article
end
def log_error(local_record, message)
local_record.preferences['delivery_status'] = 'fail'
local_record.preferences['delivery_status_message'] = message.encode!('UTF-8', 'UTF-8', invalid: :replace, replace: '?')
local_record.preferences['delivery_status_date'] = Time.zone.now
local_record.save
Rails.logger.error message
if local_record.preferences['delivery_retry'] > 3
Ticket::Article.create(
ticket_id: local_record.ticket_id,
content_type: 'text/plain',
body: "Unable to send post: #{message}",
internal: true,
sender: Ticket::Article::Sender.find_by(name: 'System'),
type: Ticket::Article::Type.find_by(name: 'note'),
preferences: {
delivery_article_id_related: local_record.id,
delivery_message: true,
},
updated_by_id: 1,
created_by_id: 1,
)
end
raise message
end
end

View file

@ -0,0 +1,110 @@
class CommunicateSmsJob < ApplicationJob
retry_on StandardError, attempts: 4, wait: lambda { |executions|
executions * 120.seconds
}
def perform(article_id)
article = Ticket::Article.find(article_id)
# set retry count
article.preferences['delivery_retry'] ||= 0
article.preferences['delivery_retry'] += 1
ticket = Ticket.lookup(id: article.ticket_id)
log_error(article, "Can't find article.preferences for Ticket::Article.find(#{article.id})") if !article.preferences
# if sender is system, take article channel
if article.sender.name == 'System'
log_error(article, "Can't find article.preferences['sms_recipients'] for Ticket::Article.find(#{article.id})") if !article.preferences['sms_recipients']
log_error(article, "Can't find article.preferences['channel_id'] for Ticket::Article.find(#{article.id})") if !article.preferences['channel_id']
channel = Channel.lookup(id: article.preferences['channel_id'])
log_error(article, "No such channel id #{article.preferences['channel_id']}") if !channel
# if sender is agent, take create channel
else
log_error(article, "Can't find ticket.preferences['channel_id'] for Ticket.find(#{ticket.id})") if !ticket.preferences['channel_id']
channel = Channel.lookup(id: ticket.preferences['channel_id'])
log_error(article, "No such channel id #{ticket.preferences['channel_id']}") if !channel
end
begin
if article.sender.name == 'System'
article.preferences['sms_recipients'].each do |recipient|
channel.deliver(
recipient: recipient,
message: article.body.first(160),
)
end
else
channel.deliver(
recipient: article.to,
message: article.body.first(160),
)
end
rescue => e
log_error(article, e.message)
return
end
log_success(article)
return if article.sender.name == 'Agent'
log_history(article, ticket, 'sms', article.to)
end
# log successful delivery
def log_success(article)
article.preferences['delivery_status_message'] = nil
article.preferences['delivery_status'] = 'success'
article.preferences['delivery_status_date'] = Time.zone.now
article.save!
end
def log_error(local_record, message)
local_record.preferences['delivery_status'] = 'fail'
local_record.preferences['delivery_status_message'] = message
local_record.preferences['delivery_status_date'] = Time.zone.now
local_record.save!
Rails.logger.error message
if local_record.preferences['delivery_retry'] >= max_attempts
Ticket::Article.create(
ticket_id: local_record.ticket_id,
content_type: 'text/plain',
body: "#{log_error_prefix}: #{message}",
internal: true,
sender: Ticket::Article::Sender.find_by(name: 'System'),
type: Ticket::Article::Type.find_by(name: 'note'),
preferences: {
delivery_article_id_related: local_record.id,
delivery_message: true,
},
updated_by_id: 1,
created_by_id: 1,
)
end
raise message
end
def log_history(article, ticket, history_type, recipient_list)
return if recipient_list.blank?
History.add(
o_id: article.id,
history_type: history_type,
history_object: 'Ticket::Article',
related_o_id: ticket.id,
related_history_object: 'Ticket',
value_from: article.subject,
value_to: recipient_list,
created_by_id: article.created_by_id,
)
end
def log_error_prefix
'Unable to send sms message'
end
end

View file

@ -0,0 +1,113 @@
class CommunicateTelegramJob < ApplicationJob
retry_on StandardError, attempts: 4, wait: lambda { |executions|
executions * 120.seconds
}
def perform(article_id)
article = Ticket::Article.find(article_id)
# set retry count
article.preferences['delivery_retry'] ||= 0
article.preferences['delivery_retry'] += 1
ticket = Ticket.lookup(id: article.ticket_id)
log_error(article, "Can't find ticket.preferences for Ticket.find(#{article.ticket_id})") if !ticket.preferences
log_error(article, "Can't find ticket.preferences['telegram'] for Ticket.find(#{article.ticket_id})") if !ticket.preferences['telegram']
log_error(article, "Can't find ticket.preferences['telegram']['chat_id'] for Ticket.find(#{article.ticket_id})") if !ticket.preferences['telegram']['chat_id']
if ticket.preferences['telegram'] && ticket.preferences['telegram']['bid']
channel = Telegram.bot_by_bot_id(ticket.preferences['telegram']['bid'])
end
if !channel
channel = Channel.lookup(id: ticket.preferences['channel_id'])
end
log_error(article, "No such channel for bot #{ticket.preferences['bid']} or channel id #{ticket.preferences['channel_id']}") if !channel
#log_error(article, "Channel.find(#{channel.id}) isn't a telegram channel!") if channel.options[:adapter] !~ /\Atelegram/i
log_error(article, "Channel.find(#{channel.id}) has not telegram api token!") if channel.options[:api_token].blank?
begin
api = TelegramAPI.new(channel.options[:api_token])
chat_id = ticket.preferences[:telegram][:chat_id]
result = api.sendMessage(chat_id, article.body)
me = api.getMe()
article.attachments.each do |file|
parts = file.filename.split(/^(.*)(\..+?)$/)
t = Tempfile.new([parts[1], parts[2]])
t.binmode
t.write(file.content)
t.rewind
api.sendDocument(chat_id, t.path.to_s)
end
rescue => e
log_error(article, e.message)
return
end
Rails.logger.debug { "result info: #{result}" }
# only private, group messages. channel messages do not have from key
if result['from'] && result['chat']
# fill article with message info
article.from = "@#{result['from']['username']}"
article.to = "@#{result['chat']['username']}"
article.preferences['telegram'] = {
date: result['date'],
from_id: result['from']['id'],
chat_id: result['chat']['id'],
message_id: result['message_id']
}
else
# fill article with message info (telegram channel)
article.from = "@#{me['username']}"
article.to = "#{result['chat']['title']} Channel"
article.preferences['telegram'] = {
date: result['date'],
from_id: me['id'],
chat_id: result['chat']['id'],
message_id: result['message_id']
}
end
# set delivery status
article.preferences['delivery_status_message'] = nil
article.preferences['delivery_status'] = 'success'
article.preferences['delivery_status_date'] = Time.zone.now
article.message_id = "telegram.#{result['message_id']}.#{result['chat']['id']}"
article.save!
Rails.logger.info "Send telegram message to: '#{article.to}' (from #{article.from})"
article
end
def log_error(local_record, message)
local_record.preferences['delivery_status'] = 'fail'
local_record.preferences['delivery_status_message'] = message.encode!('UTF-8', 'UTF-8', invalid: :replace, replace: '?')
local_record.preferences['delivery_status_date'] = Time.zone.now
local_record.save
Rails.logger.error message
if local_record.preferences['delivery_retry'] > 3
Ticket::Article.create(
ticket_id: local_record.ticket_id,
content_type: 'text/plain',
body: "Unable to send telegram message: #{message}",
internal: true,
sender: Ticket::Article::Sender.find_by(name: 'System'),
type: Ticket::Article::Type.find_by(name: 'note'),
preferences: {
delivery_article_id_related: local_record.id,
delivery_message: true,
},
updated_by_id: 1,
created_by_id: 1,
)
end
raise message
end
end

View file

@ -0,0 +1,156 @@
class CommunicateTwitterJob < ApplicationJob
retry_on StandardError, attempts: 4, wait: lambda { |executions|
executions * 120.seconds
}
def perform(article_id)
article = Ticket::Article.find(article_id)
# set retry count
article.preferences['delivery_retry'] ||= 0
article.preferences['delivery_retry'] += 1
ticket = Ticket.lookup(id: article.ticket_id)
log_error(article, "Can't find ticket.preferences['channel_id'] for Ticket.find(#{article.ticket_id})") if !ticket.preferences['channel_id']
channel = Channel.lookup(id: ticket.preferences['channel_id'])
# search for same channel channel_screen_name, in case the channel got re-added
if !channel
Channel.where(area: 'Twitter::Account', active: true).each do |local_channel|
next if ticket.preferences[:channel_screen_name].blank?
next if !local_channel.options
next if local_channel.options[:user].blank?
next if local_channel.options[:user][:screen_name].blank?
next if local_channel.options[:user][:screen_name] != ticket.preferences[:channel_screen_name]
channel = local_channel
break
end
end
log_error(article, "No such channel id #{ticket.preferences['channel_id']}") if !channel
log_error(article, "Channel.find(#{channel.id}) isn't a twitter channel!") if !channel.options[:adapter].try(:match?, /\Atwitter/i)
begin
tweet = channel.deliver(
type: article.type.name,
to: article.to,
body: article.body,
in_reply_to: article.in_reply_to
)
rescue => e
log_error(article, e.message)
return
end
if !tweet
log_error(article, 'Got no tweet!')
return
end
# fill article with tweet info
# direct message
if tweet.is_a?(Hash)
tweet_type = 'DirectMessage'
article.message_id = tweet[:event][:id].to_s
if tweet[:event] && tweet[:event][:type] == 'message_create'
#article.from = "@#{tweet.sender.screen_name}"
#article.to = "@#{tweet.recipient.screen_name}"
article.preferences['twitter'] = {
recipient_id: tweet[:event][:message_create][:target][:recipient_id],
sender_id: tweet[:event][:message_create][:sender_id],
}
article.preferences['links'] = [
{
url: TwitterSync::DM_URL_TEMPLATE % article.preferences[:twitter].slice(:recipient_id, :sender_id).values.map(&:to_i).sort.join('-'),
target: '_blank',
name: 'on Twitter',
},
]
end
# regular tweet
elsif tweet.instance_of?(Twitter::Tweet)
tweet_type = 'Tweet'
tweet_id = tweet.id.to_s
article.from = "@#{tweet.user.screen_name}"
if tweet.user_mentions
to = ''
mention_ids = []
tweet.user_mentions.each do |user|
if to != ''
to += ' '
end
to += "@#{user.screen_name}"
mention_ids.push user.id
end
article.to = to
article.preferences['twitter'] = TwitterSync.preferences_cleanup(
mention_ids: mention_ids,
geo: tweet.geo,
retweeted: tweet.retweeted?,
possibly_sensitive: tweet.possibly_sensitive?,
in_reply_to_user_id: tweet.in_reply_to_user_id,
place: tweet.place,
retweet_count: tweet.retweet_count,
source: tweet.source,
favorited: tweet.favorited?,
truncated: tweet.truncated?,
created_at: tweet.created_at,
)
article.message_id = tweet_id
article.preferences['links'] = [
{
url: TwitterSync::STATUS_URL_TEMPLATE % tweet.id,
target: '_blank',
name: 'on Twitter',
},
]
end
else
raise "Unknown tweet type '#{tweet.class}'"
end
# set delivery status
article.preferences['delivery_status_message'] = nil
article.preferences['delivery_status'] = 'success'
article.preferences['delivery_status_date'] = Time.zone.now
article.save!
Rails.logger.info "Send twitter (#{tweet_type}) to: '#{article.to}' (from #{article.from})"
article
end
def log_error(local_record, message)
local_record.preferences['delivery_status'] = 'fail'
local_record.preferences['delivery_status_message'] = message.encode!('UTF-8', 'UTF-8', invalid: :replace, replace: '?')
local_record.preferences['delivery_status_date'] = Time.zone.now
local_record.save
Rails.logger.error message
if local_record.preferences['delivery_retry'] > 3
Ticket::Article.create(
ticket_id: local_record.ticket_id,
content_type: 'text/plain',
body: "Unable to send tweet: #{message}",
internal: true,
sender: Ticket::Article::Sender.find_by(name: 'System'),
type: Ticket::Article::Type.find_by(name: 'note'),
preferences: {
delivery_article_id_related: local_record.id,
delivery_message: true,
},
updated_by_id: 1,
created_by_id: 1,
)
end
raise message
end
end

View file

@ -0,0 +1,56 @@
require_dependency 'ldap'
require_dependency 'ldap/user'
class MigrateLdapSamaccountnameToUidJob < ApplicationJob
def perform
Rails.logger.info 'Checking for active LDAP configuration...'
if ldap_config.blank?
Rails.logger.info 'Blank LDAP configuration. Exiting.'
return
end
Rails.logger.info 'Checking for different LDAP uid attribute...'
if uid_attribute_obsolete == uid_attribute_new
Rails.logger.info 'Equal LDAP uid attributes. Exiting.'
return
end
Rails.logger.info 'Starting to migrate LDAP config to new uid attribute...'
migrate_ldap_config
Rails.logger.info 'LDAP uid attribute migration completed.'
end
private
def ldap
@ldap ||= ::Ldap.new(ldap_config)
end
def ldap_config
@ldap_config ||= Import::Ldap.config
end
def uid_attribute_new
@uid_attribute_new ||= begin
config = {
filter: ldap_config['user_filter']
}
::Ldap::User.new(config, ldap: ldap).uid_attribute
end
end
def uid_attribute_obsolete
@uid_attribute_obsolete ||= ldap_config['user_uid']
end
def migrate_ldap_config
ldap_config_new = ldap_config.merge(
'user_uid' => uid_attribute_new
)
Setting.set('ldap_config', ldap_config_new)
end
end

View file

@ -0,0 +1,26 @@
class TransactionJob < ApplicationJob
=begin
{
object: 'Ticket',
type: 'update',
ticket_id: 123,
interface_handle: 'application_server', # application_server|websocket|scheduler
changes: {
'attribute1' => [before,now],
'attribute2' => [before,now],
},
created_at: Time.zone.now,
user_id: 123,
},
=end
def perform(item, params = {})
Setting.where(area: 'Transaction::Backend::Async').order(:name).each do |setting|
backend = Setting.get(setting.name)
next if params[:disable]&.include?(backend)
Observer::Transaction.execute_singel_backend(backend.constantize, item, params)
end
end
end

View file

@ -75,12 +75,12 @@ class ImportJob < ApplicationModel
return if exists?(name: params[:name], dry_run: true, finished_at: nil)
params[:dry_run] = true
instance = create(params.except(:delay))
job = create(params.except(:delay))
if params.fetch(:delay, true)
instance.delay.start
AsyncImportJob.perform_later(job)
else
instance.start
job.start
end
end

View file

@ -6,36 +6,10 @@ class Observer::Chat::Leave::BackgroundJob
end
def perform
# check if customer has permanently left the conversation
chat_session = Chat::Session.find_by(id: @chat_session_id)
return if !chat_session
return if chat_session.recipients_active?
chat_session.state = 'closed'
chat_session.save
realname = 'Anonymous'
# if it is a agent session, use the realname if the agent for close message
if @session && @session['id'] && chat_session.user_id
agent_user = chat_session.agent_user
if agent_user[:name]
realname = agent_user[:name]
end
if Gem::Version.new(Version.get) >= Gem::Version.new('4.0.x')
ActiveSupport::Deprecation.warn("This file has been migrated to the ActiveJob 'ChatLeaveJob' and is therefore deprecated and should get removed.")
end
# notify participants
message = {
event: 'chat_session_left',
data: {
realname: realname,
session_id: chat_session.session_id,
},
}
chat_session.send_to_recipients(message, @client_id)
Chat.broadcast_agent_state_update([chat_session.chat_id])
ChatLeaveJob.perform_now(@chat_session_id, @client_id, @session)
end
end

View file

@ -25,7 +25,7 @@ class Observer::Ticket::Article::CommunicateFacebook < ActiveRecord::Observer
return true if type.nil?
return true if !type.name.start_with?('facebook')
Delayed::Job.enqueue(Observer::Ticket::Article::CommunicateFacebook::BackgroundJob.new(record.id))
CommunicateFacebookJob.perform_later(record.id)
end
end

View file

@ -4,102 +4,10 @@ class Observer::Ticket::Article::CommunicateFacebook::BackgroundJob
end
def perform
article = Ticket::Article.find(@article_id)
# set retry count
article.preferences['delivery_retry'] ||= 0
article.preferences['delivery_retry'] += 1
ticket = Ticket.lookup(id: article.ticket_id)
log_error(article, "Can't find ticket.preferences for Ticket.find(#{article.ticket_id})") if !ticket.preferences
log_error(article, "Can't find ticket.preferences['channel_id'] for Ticket.find(#{article.ticket_id})") if !ticket.preferences['channel_id']
channel = Channel.lookup(id: ticket.preferences['channel_id'])
log_error(article, "Channel.find(#{channel.id}) isn't a twitter channel!") if !channel.options[:adapter].match?(/\Afacebook/i)
# check source object id
if !ticket.preferences['channel_fb_object_id']
log_error(article, "fb object id is missing in ticket.preferences['channel_fb_object_id'] for Ticket.find(#{ticket.id})")
if Gem::Version.new(Version.get) >= Gem::Version.new('4.0.x')
ActiveSupport::Deprecation.warn("This file has been migrated to the ActiveJob 'CommunicateFacebookJob' and is therefore deprecated and should get removed.")
end
# fill in_reply_to
if article.in_reply_to.blank?
article.in_reply_to = ticket.articles.first.message_id
end
begin
facebook = Channel::Driver::Facebook.new
post = facebook.send(
channel.options,
ticket.preferences[:channel_fb_object_id],
{
type: article.type.name,
to: article.to,
body: article.body,
in_reply_to: article.in_reply_to,
}
)
rescue => e
log_error(article, e.message)
return
end
if !post
log_error(article, 'Got no post!')
return
end
# fill article with post info
article.from = post['from']['name']
article.message_id = post['id']
# set delivery status
article.preferences['delivery_status_message'] = nil
article.preferences['delivery_status'] = 'success'
article.preferences['delivery_status_date'] = Time.zone.now
article.save!
Rails.logger.info "Send facebook to: '#{article.to}' (from #{article.from})"
article
end
def log_error(local_record, message)
local_record.preferences['delivery_status'] = 'fail'
local_record.preferences['delivery_status_message'] = message.encode!('UTF-8', 'UTF-8', invalid: :replace, replace: '?')
local_record.preferences['delivery_status_date'] = Time.zone.now
local_record.save
Rails.logger.error message
if local_record.preferences['delivery_retry'] > 3
Ticket::Article.create(
ticket_id: local_record.ticket_id,
content_type: 'text/plain',
body: "Unable to send post: #{message}",
internal: true,
sender: Ticket::Article::Sender.find_by(name: 'System'),
type: Ticket::Article::Type.find_by(name: 'note'),
preferences: {
delivery_article_id_related: local_record.id,
delivery_message: true,
},
updated_by_id: 1,
created_by_id: 1,
)
end
raise message
end
def max_attempts
4
end
def reschedule_at(current_time, attempts)
if Rails.env.production?
return current_time + attempts * 120.seconds
end
current_time + 5.seconds
CommunicateFacebookJob.perform_now(@article_id)
end
end

View file

@ -20,6 +20,6 @@ class Observer::Ticket::Article::CommunicateSms < ActiveRecord::Observer
return true if type.nil?
return true if type.name != 'sms'
Delayed::Job.enqueue(Observer::Ticket::Article::CommunicateSms::BackgroundJob.new(record.id))
CommunicateSmsJob.perform_later(record.id)
end
end

View file

@ -4,119 +4,10 @@ class Observer::Ticket::Article::CommunicateSms::BackgroundJob
end
def perform
article = Ticket::Article.find(@article_id)
# set retry count
article.preferences['delivery_retry'] ||= 0
article.preferences['delivery_retry'] += 1
ticket = Ticket.lookup(id: article.ticket_id)
log_error(article, "Can't find article.preferences for Ticket::Article.find(#{article.id})") if !article.preferences
# if sender is system, take article channel
if article.sender.name == 'System'
log_error(article, "Can't find article.preferences['sms_recipients'] for Ticket::Article.find(#{article.id})") if !article.preferences['sms_recipients']
log_error(article, "Can't find article.preferences['channel_id'] for Ticket::Article.find(#{article.id})") if !article.preferences['channel_id']
channel = Channel.lookup(id: article.preferences['channel_id'])
log_error(article, "No such channel id #{article.preferences['channel_id']}") if !channel
# if sender is agent, take create channel
else
log_error(article, "Can't find ticket.preferences['channel_id'] for Ticket.find(#{ticket.id})") if !ticket.preferences['channel_id']
channel = Channel.lookup(id: ticket.preferences['channel_id'])
log_error(article, "No such channel id #{ticket.preferences['channel_id']}") if !channel
if Gem::Version.new(Version.get) >= Gem::Version.new('4.0.x')
ActiveSupport::Deprecation.warn("This file has been migrated to the ActiveJob 'CommunicateSmsJob' and is therefore deprecated and should get removed.")
end
begin
if article.sender.name == 'System'
article.preferences['sms_recipients'].each do |recipient|
channel.deliver(
recipient: recipient,
message: article.body.first(160),
)
end
else
channel.deliver(
recipient: article.to,
message: article.body.first(160),
)
end
rescue => e
log_error(article, e.message)
return
end
log_success(article)
return if article.sender.name == 'Agent'
log_history(article, ticket, 'sms', article.to)
CommunicateSmsJob.perform_now(@article_id)
end
# log successful delivery
def log_success(article)
article.preferences['delivery_status_message'] = nil
article.preferences['delivery_status'] = 'success'
article.preferences['delivery_status_date'] = Time.zone.now
article.save!
end
def log_error(local_record, message)
local_record.preferences['delivery_status'] = 'fail'
local_record.preferences['delivery_status_message'] = message
local_record.preferences['delivery_status_date'] = Time.zone.now
local_record.save!
Rails.logger.error message
if local_record.preferences['delivery_retry'] >= max_attempts
Ticket::Article.create(
ticket_id: local_record.ticket_id,
content_type: 'text/plain',
body: "#{log_error_prefix}: #{message}",
internal: true,
sender: Ticket::Article::Sender.find_by(name: 'System'),
type: Ticket::Article::Type.find_by(name: 'note'),
preferences: {
delivery_article_id_related: local_record.id,
delivery_message: true,
},
updated_by_id: 1,
created_by_id: 1,
)
end
raise message
end
def log_history(article, ticket, history_type, recipient_list)
return if recipient_list.blank?
History.add(
o_id: article.id,
history_type: history_type,
history_object: 'Ticket::Article',
related_o_id: ticket.id,
related_history_object: 'Ticket',
value_from: article.subject,
value_to: recipient_list,
created_by_id: article.created_by_id,
)
end
def log_error_prefix
'Unable to send sms message'
end
def max_attempts
4
end
def reschedule_at(current_time, attempts)
if Rails.env.production?
return current_time + attempts * 120.seconds
end
current_time + 5.seconds
end
end

View file

@ -21,7 +21,7 @@ class Observer::Ticket::Article::CommunicateTelegram < ActiveRecord::Observer
type = Ticket::Article::Type.lookup(id: record.type_id)
return true if !type.name.match?(/\Atelegram/i)
Delayed::Job.enqueue(Observer::Ticket::Article::CommunicateTelegram::BackgroundJob.new(record.id))
CommunicateTelegramJob.perform_later(record.id)
end
end

View file

@ -4,121 +4,10 @@ class Observer::Ticket::Article::CommunicateTelegram::BackgroundJob
end
def perform
article = Ticket::Article.find(@article_id)
# set retry count
article.preferences['delivery_retry'] ||= 0
article.preferences['delivery_retry'] += 1
ticket = Ticket.lookup(id: article.ticket_id)
log_error(article, "Can't find ticket.preferences for Ticket.find(#{article.ticket_id})") if !ticket.preferences
log_error(article, "Can't find ticket.preferences['telegram'] for Ticket.find(#{article.ticket_id})") if !ticket.preferences['telegram']
log_error(article, "Can't find ticket.preferences['telegram']['chat_id'] for Ticket.find(#{article.ticket_id})") if !ticket.preferences['telegram']['chat_id']
if ticket.preferences['telegram'] && ticket.preferences['telegram']['bid']
channel = Telegram.bot_by_bot_id(ticket.preferences['telegram']['bid'])
end
if !channel
channel = Channel.lookup(id: ticket.preferences['channel_id'])
end
log_error(article, "No such channel for bot #{ticket.preferences['bid']} or channel id #{ticket.preferences['channel_id']}") if !channel
#log_error(article, "Channel.find(#{channel.id}) isn't a telegram channel!") if channel.options[:adapter] !~ /\Atelegram/i
log_error(article, "Channel.find(#{channel.id}) has not telegram api token!") if channel.options[:api_token].blank?
begin
api = TelegramAPI.new(channel.options[:api_token])
chat_id = ticket.preferences[:telegram][:chat_id]
result = api.sendMessage(chat_id, article.body)
me = api.getMe()
article.attachments.each do |file|
parts = file.filename.split(/^(.*)(\..+?)$/)
t = Tempfile.new([parts[1], parts[2]])
t.binmode
t.write(file.content)
t.rewind
api.sendDocument(chat_id, t.path.to_s)
end
rescue => e
log_error(article, e.message)
return
if Gem::Version.new(Version.get) >= Gem::Version.new('4.0.x')
ActiveSupport::Deprecation.warn("This file has been migrated to the ActiveJob 'CommunicateTelegramJob' and is therefore deprecated and should get removed.")
end
Rails.logger.debug { "result info: #{result}" }
# only private, group messages. channel messages do not have from key
if result['from'] && result['chat']
# fill article with message info
article.from = "@#{result['from']['username']}"
article.to = "@#{result['chat']['username']}"
article.preferences['telegram'] = {
date: result['date'],
from_id: result['from']['id'],
chat_id: result['chat']['id'],
message_id: result['message_id']
}
else
# fill article with message info (telegram channel)
article.from = "@#{me['username']}"
article.to = "#{result['chat']['title']} Channel"
article.preferences['telegram'] = {
date: result['date'],
from_id: me['id'],
chat_id: result['chat']['id'],
message_id: result['message_id']
}
end
# set delivery status
article.preferences['delivery_status_message'] = nil
article.preferences['delivery_status'] = 'success'
article.preferences['delivery_status_date'] = Time.zone.now
article.message_id = "telegram.#{result['message_id']}.#{result['chat']['id']}"
article.save!
Rails.logger.info "Send telegram message to: '#{article.to}' (from #{article.from})"
article
end
def log_error(local_record, message)
local_record.preferences['delivery_status'] = 'fail'
local_record.preferences['delivery_status_message'] = message.encode!('UTF-8', 'UTF-8', invalid: :replace, replace: '?')
local_record.preferences['delivery_status_date'] = Time.zone.now
local_record.save
Rails.logger.error message
if local_record.preferences['delivery_retry'] > 3
Ticket::Article.create(
ticket_id: local_record.ticket_id,
content_type: 'text/plain',
body: "Unable to send telegram message: #{message}",
internal: true,
sender: Ticket::Article::Sender.find_by(name: 'System'),
type: Ticket::Article::Type.find_by(name: 'note'),
preferences: {
delivery_article_id_related: local_record.id,
delivery_message: true,
},
updated_by_id: 1,
created_by_id: 1,
)
end
raise message
end
def max_attempts
4
end
def reschedule_at(current_time, attempts)
if Rails.env.production?
return current_time + attempts * 120.seconds
end
current_time + 5.seconds
CommunicateTelegramJob.perform_now(@article_id)
end
end

View file

@ -28,7 +28,7 @@ class Observer::Ticket::Article::CommunicateTwitter < ActiveRecord::Observer
raise Exceptions::UnprocessableEntity, 'twitter to: parameter is missing' if record.to.blank? && type['name'] == 'twitter direct-message'
Delayed::Job.enqueue(Observer::Ticket::Article::CommunicateTwitter::BackgroundJob.new(record.id))
CommunicateTwitterJob.perform_later(record.id)
end
end

View file

@ -4,163 +4,10 @@ class Observer::Ticket::Article::CommunicateTwitter::BackgroundJob
end
def perform
article = Ticket::Article.find(@article_id)
# set retry count
article.preferences['delivery_retry'] ||= 0
article.preferences['delivery_retry'] += 1
ticket = Ticket.lookup(id: article.ticket_id)
log_error(article, "Can't find ticket.preferences['channel_id'] for Ticket.find(#{article.ticket_id})") if !ticket.preferences['channel_id']
channel = Channel.lookup(id: ticket.preferences['channel_id'])
# search for same channel channel_screen_name, in case the channel got re-added
if !channel
Channel.where(area: 'Twitter::Account', active: true).each do |local_channel|
next if ticket.preferences[:channel_screen_name].blank?
next if !local_channel.options
next if local_channel.options[:user].blank?
next if local_channel.options[:user][:screen_name].blank?
next if local_channel.options[:user][:screen_name] != ticket.preferences[:channel_screen_name]
channel = local_channel
break
end
if Gem::Version.new(Version.get) >= Gem::Version.new('4.0.x')
ActiveSupport::Deprecation.warn("This file has been migrated to the ActiveJob 'CommunicateTwitterJob' and is therefore deprecated and should get removed.")
end
log_error(article, "No such channel id #{ticket.preferences['channel_id']}") if !channel
log_error(article, "Channel.find(#{channel.id}) isn't a twitter channel!") if !channel.options[:adapter].try(:match?, /\Atwitter/i)
begin
tweet = channel.deliver(
type: article.type.name,
to: article.to,
body: article.body,
in_reply_to: article.in_reply_to
)
rescue => e
log_error(article, e.message)
return
end
if !tweet
log_error(article, 'Got no tweet!')
return
end
# fill article with tweet info
# direct message
if tweet.is_a?(Hash)
tweet_type = 'DirectMessage'
article.message_id = tweet[:event][:id].to_s
if tweet[:event] && tweet[:event][:type] == 'message_create'
#article.from = "@#{tweet.sender.screen_name}"
#article.to = "@#{tweet.recipient.screen_name}"
article.preferences['twitter'] = {
recipient_id: tweet[:event][:message_create][:target][:recipient_id],
sender_id: tweet[:event][:message_create][:sender_id],
}
article.preferences['links'] = [
{
url: TwitterSync::DM_URL_TEMPLATE % article.preferences[:twitter].slice(:recipient_id, :sender_id).values.map(&:to_i).sort.join('-'),
target: '_blank',
name: 'on Twitter',
},
]
end
# regular tweet
elsif tweet.instance_of?(Twitter::Tweet)
tweet_type = 'Tweet'
article.from = "@#{tweet.user.screen_name}"
if tweet.user_mentions
to = ''
mention_ids = []
tweet.user_mentions.each do |user|
if to != ''
to += ' '
end
to += "@#{user.screen_name}"
mention_ids.push user.id
end
article.to = to
article.preferences['twitter'] = TwitterSync.preferences_cleanup(
mention_ids: mention_ids,
geo: tweet.geo,
retweeted: tweet.retweeted?,
possibly_sensitive: tweet.possibly_sensitive?,
in_reply_to_user_id: tweet.in_reply_to_user_id,
place: tweet.place,
retweet_count: tweet.retweet_count,
source: tweet.source,
favorited: tweet.favorited?,
truncated: tweet.truncated?,
created_at: tweet.created_at,
)
end
article.message_id = tweet.id.to_s
article.preferences['links'] = [
{
url: TwitterSync::STATUS_URL_TEMPLATE % tweet.id,
target: '_blank',
name: 'on Twitter',
},
]
else
raise "Unknown tweet type '#{tweet.class}'"
end
# set delivery status
article.preferences['delivery_status_message'] = nil
article.preferences['delivery_status'] = 'success'
article.preferences['delivery_status_date'] = Time.zone.now
article.save!
Rails.logger.info "Send twitter (#{tweet_type}) to: '#{article.to}' (from #{article.from})"
article
end
def log_error(local_record, message)
local_record.preferences['delivery_status'] = 'fail'
local_record.preferences['delivery_status_message'] = message.encode!('UTF-8', 'UTF-8', invalid: :replace, replace: '?')
local_record.preferences['delivery_status_date'] = Time.zone.now
local_record.save
Rails.logger.error message
if local_record.preferences['delivery_retry'] > 3
Ticket::Article.create(
ticket_id: local_record.ticket_id,
content_type: 'text/plain',
body: "Unable to send tweet: #{message}",
internal: true,
sender: Ticket::Article::Sender.find_by(name: 'System'),
type: Ticket::Article::Type.find_by(name: 'note'),
preferences: {
delivery_article_id_related: local_record.id,
delivery_message: true,
},
updated_by_id: 1,
created_by_id: 1,
)
end
raise message
end
def max_attempts
4
end
def reschedule_at(current_time, attempts)
if Rails.env.production?
return current_time + attempts * 120.seconds
end
current_time + 5.seconds
CommunicateTwitterJob.perform_now(@article_id)
end
end

View file

@ -49,7 +49,7 @@ class Observer::Transaction < ActiveRecord::Observer
end
# execute async backends
Delayed::Job.enqueue(Transaction::BackgroundJob.new(item, params))
TransactionJob.perform_later(item, params)
end
end
end

View file

@ -179,7 +179,7 @@ returns
end
# send notification
Transaction::BackgroundJob.run(
TransactionJob.perform_now(
object: 'Ticket',
type: 'reminder_reached',
object_id: ticket.id,
@ -220,7 +220,7 @@ returns
# send escalation
if ticket.escalation_at < Time.zone.now
Transaction::BackgroundJob.run(
TransactionJob.perform_now(
object: 'Ticket',
type: 'escalation',
object_id: ticket.id,
@ -232,7 +232,7 @@ returns
end
# check if warning need to be sent
Transaction::BackgroundJob.run(
TransactionJob.perform_now(
object: 'Ticket',
type: 'escalation_warning',
object_id: ticket.id,
@ -1067,7 +1067,7 @@ perform active triggers on ticket
local_options[:reset_user_id] = true
local_options[:disable] = ['Transaction::Notification']
local_options[:trigger_ids] ||= {}
local_options[:trigger_ids][ticket.id] ||= []
local_options[:trigger_ids][ticket.id.to_s] ||= []
local_options[:loop_count] ||= 0
local_options[:loop_count] += 1
@ -1220,11 +1220,11 @@ perform active triggers on ticket
end
end
if local_options[:trigger_ids][ticket.id].include?(trigger.id)
if local_options[:trigger_ids][ticket.id.to_s].include?(trigger.id)
logger.info { "Skip trigger (#{trigger.name}/#{trigger.id}) because was already executed for this object (Ticket:#{ticket.id}/Loop:#{local_options[:loop_count]})" }
next
end
local_options[:trigger_ids][ticket.id].push trigger.id
local_options[:trigger_ids][ticket.id.to_s].push trigger.id
logger.info { "Execute trigger (#{trigger.name}/#{trigger.id}) for this object (Ticket:#{ticket.id}/Loop:#{local_options[:loop_count]})" }
ticket.perform_changes(trigger.perform, 'trigger', item, user_id)

View file

@ -1,5 +1,3 @@
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
class Transaction::BackgroundJob
def initialize(item, params = {})
@ -23,17 +21,10 @@ class Transaction::BackgroundJob
end
def perform
Setting.where(area: 'Transaction::Backend::Async').order(:name).each do |setting|
backend = Setting.get(setting.name)
next if @params[:disable]&.include?(backend)
Observer::Transaction.execute_singel_backend(backend.constantize, @item, @params)
if Gem::Version.new(Version.get) >= Gem::Version.new('4.0.x')
ActiveSupport::Deprecation.warn("This file has been migrated to the ActiveJob 'TransactionJob' and is therefore deprecated and should get removed.")
end
end
def self.run(item, params = {})
generic = new(item, params)
generic.perform
TransactionJob.perform_now(@item, @params)
end
end

View file

@ -0,0 +1,45 @@
# Required workaround to serialize ActiveSupport::TimeWithZone, Time, Date and DateTime for ActiveJob
# until Rails 6 is used. See:
# - https://github.com/rails/rails/issues/18519
# - https://github.com/rails/rails/pull/32026
# - https://github.com/rails/rails/tree/6-0-stable/activejob/lib/active_job/serializers
class ActiveSupport::TimeWithZone
include GlobalID::Identification
alias id iso8601
def self.find(iso8601)
Time.iso8601(iso8601).in_time_zone
end
end
class Time
include GlobalID::Identification
alias id iso8601
def self.find(iso8601)
Time.iso8601(iso8601)
end
end
class Date
include GlobalID::Identification
alias id iso8601
def self.find(iso8601)
Date.iso8601(iso8601)
end
end
class DateTime
include GlobalID::Identification
alias id iso8601
def self.find(iso8601)
DateTime.iso8601(iso8601)
end
end

View file

@ -4,7 +4,7 @@ class LdapSamaccountnameToUid < ActiveRecord::Migration[5.1]
# return if it's a new setup to avoid running the migration
return if !Setting.exists?(name: 'system_init_done')
Delayed::Job.enqueue MigrationJob::LdapSamaccountnameToUid.new
MigrateLdapSamaccountnameToUidJob.perform_later
end
end

View file

@ -1,58 +0,0 @@
require_dependency 'ldap'
require_dependency 'ldap/user'
module MigrationJob
class LdapSamaccountnameToUid
def perform
Rails.logger.info 'Checking for active LDAP configuration...'
if ldap_config.blank?
Rails.logger.info 'Blank LDAP configuration. Exiting.'
return
end
Rails.logger.info 'Checking for different LDAP uid attribute...'
if uid_attribute_obsolete == uid_attribute_new
Rails.logger.info 'Equal LDAP uid attributes. Exiting.'
return
end
Rails.logger.info 'Starting to migrate LDAP config to new uid attribute...'
migrate_ldap_config
Rails.logger.info 'LDAP uid attribute migration completed.'
end
private
def ldap
@ldap ||= ::Ldap.new(ldap_config)
end
def ldap_config
@ldap_config ||= Import::Ldap.config
end
def uid_attribute_new
@uid_attribute_new ||= begin
config = {
filter: ldap_config['user_filter']
}
::Ldap::User.new(config, ldap: ldap).uid_attribute
end
end
def uid_attribute_obsolete
@uid_attribute_obsolete ||= ldap_config['user_uid']
end
def migrate_ldap_config
ldap_config_new = ldap_config.merge(
'user_uid' => uid_attribute_new
)
Setting.set('ldap_config', ldap_config_new)
end
end
end

View file

@ -6,12 +6,7 @@ class Sessions::Event::ChatSessionLeaveTemporary < Sessions::Event::ChatBase
chat_session = current_chat_session
Delayed::Job.enqueue(
Observer::Chat::Leave::BackgroundJob.new(chat_session.id, @client_id, @session),
{
run_at: Time.zone.now + 0.5.minutes
}
)
ChatLeaveJob.set(wait: 0.5.minutes).perform_later(chat_session.id, @client_id, @session)
false
end

View file

@ -1,6 +1,7 @@
require 'rails_helper'
RSpec.describe Observer::Ticket::Article::CommunicateTwitter::BackgroundJob, type: :job do
RSpec.describe CommunicateTwitterJob, type: :job do
let(:article) { create(:twitter_article, **(try(:factory_options) || {})) }
describe 'core behavior', :use_vcr do
@ -37,12 +38,12 @@ RSpec.describe Observer::Ticket::Article::CommunicateTwitter::BackgroundJob, typ
end
it 'increments the "delivery_retry" preference' do
expect { described_class.new(article.id).perform }
expect { described_class.perform_now(article.id) }
.to change { article.reload.preferences[:delivery_retry] }.to(1)
end
it 'dispatches the tweet' do
described_class.new(article.id).perform
described_class.perform_now(article.id)
expect(WebMock)
.to have_requested(:post, 'https://api.twitter.com/1.1/statuses/update.json')
@ -50,14 +51,14 @@ RSpec.describe Observer::Ticket::Article::CommunicateTwitter::BackgroundJob, typ
end
it 'updates the article with tweet attributes' do
expect { described_class.new(article.id).perform }
expect { described_class.perform_now(article.id) }
.to change { article.reload.message_id }.to('1244937367435108360')
.and change { article.reload.preferences[:twitter] }.to(hash_including(tweet_attributes))
.and change { article.reload.preferences[:links] }.to(links_array)
end
it 'sets the appropriate delivery status attributes' do
expect { described_class.new(article.id).perform }
expect { described_class.perform_now(article.id) }
.to change { article.reload.preferences[:delivery_status] }.to('success')
.and change { article.reload.preferences[:delivery_status_date] }.to(an_instance_of(ActiveSupport::TimeWithZone))
.and not_change { article.reload.preferences[:delivery_status_message] }.from(nil)
@ -67,7 +68,7 @@ RSpec.describe Observer::Ticket::Article::CommunicateTwitter::BackgroundJob, typ
let(:factory_options) { { body: '@twitter @twitterlive Dont mind me, just testing the API' } }
it 'updates the article with tweet recipients' do
expect { described_class.new(article.id).perform }
expect { described_class.perform_now(article.id) }
.to change { article.reload.to }.to('@Twitter @TwitterLive')
end
end
@ -105,12 +106,12 @@ RSpec.describe Observer::Ticket::Article::CommunicateTwitter::BackgroundJob, typ
end
it 'increments the "delivery_retry" preference' do
expect { described_class.new(article.id).perform }
expect { described_class.perform_now(article.id) }
.to change { article.reload.preferences[:delivery_retry] }.to(1)
end
it 'dispatches the DM' do
described_class.new(article.id).perform
described_class.perform_now(article.id)
expect(WebMock)
.to have_requested(:post, 'https://api.twitter.com/1.1/direct_messages/events/new.json')
@ -118,14 +119,14 @@ RSpec.describe Observer::Ticket::Article::CommunicateTwitter::BackgroundJob, typ
end
it 'updates the article with DM attributes' do
expect { described_class.new(article.id).perform }
expect { described_class.perform_now(article.id) }
.to change { article.reload.message_id }.to('1244953398509617156')
.and change { article.reload.preferences[:twitter] }.to(hash_including(dm_attributes))
.and change { article.reload.preferences[:links] }.to(links_array)
end
it 'sets the appropriate delivery status attributes' do
expect { described_class.new(article.id).perform }
expect { described_class.perform_now(article.id) }
.to change { article.reload.preferences[:delivery_status] }.to('success')
.and change { article.reload.preferences[:delivery_status_date] }.to(an_instance_of(ActiveSupport::TimeWithZone))
.and not_change { article.reload.preferences[:delivery_status_message] }.from(nil)
@ -135,9 +136,8 @@ RSpec.describe Observer::Ticket::Article::CommunicateTwitter::BackgroundJob, typ
describe 'failure cases' do
shared_examples 'for failure cases' do
it 'raises an error and sets the appropriate delivery status messages' do
expect { described_class.new(article.id).perform }
.to raise_error(error_message)
.and change { article.reload.preferences[:delivery_status] }.to('fail')
expect { described_class.perform_now(article.id) }
.to change { article.reload.preferences[:delivery_status] }.to('fail')
.and change { article.reload.preferences[:delivery_status_date] }.to(an_instance_of(ActiveSupport::TimeWithZone))
.and change { article.reload.preferences[:delivery_status_message] }.to(error_message)
end
@ -166,7 +166,7 @@ RSpec.describe Observer::Ticket::Article::CommunicateTwitter::BackgroundJob, typ
let!(:new_channel) { create(:twitter_channel, custom_options: { user: { screen_name: channel.options[:user][:screen_name] } }) }
it 'uses that channel' do
described_class.new(article.id).perform
described_class.perform_now(article.id)
expect(WebMock)
.to have_requested(:post, 'https://api.twitter.com/1.1/statuses/update.json')
@ -216,9 +216,8 @@ RSpec.describe Observer::Ticket::Article::CommunicateTwitter::BackgroundJob, typ
let(:factory_options) { { preferences: { delivery_retry: 3 } } }
it 'adds a delivery failure note (article) to the ticket' do
expect { described_class.new(article.id).perform }
.to raise_error(error_message)
.and change { article.ticket.reload.articles.count }.by(1)
expect { described_class.perform_now(article.id) }
.to change { article.ticket.reload.articles.count }.by(1)
expect(Ticket::Article.last.attributes).to include(
'content_type' => 'text/plain',

View file

@ -1,12 +1,14 @@
require 'rails_helper'
RSpec.describe MigrationJob::LdapSamaccountnameToUid do
RSpec.describe MigrateLdapSamaccountnameToUidJob, type: :job do
it 'performs no changes if no LDAP config present' do
allow(Setting).to receive(:set)
allow(Import::Ldap).to receive(:config).and_return(nil)
described_class.new.perform
described_class.perform_now
expect(Import::Ldap).to have_received(:config)
expect(Setting).not_to have_received(:set)
end
@ -24,8 +26,12 @@ RSpec.describe MigrationJob::LdapSamaccountnameToUid do
allow(::Ldap).to receive(:new)
described_class.new.perform
described_class.perform_now
expect(Setting).not_to have_received(:set)
expect(Import::Ldap).to have_received(:config)
expect(ldap_user).to have_received(:uid_attribute)
expect(::Ldap::User).to have_received(:new)
end
it 'performs Setting change if uid attribute differ' do
@ -37,6 +43,7 @@ RSpec.describe MigrationJob::LdapSamaccountnameToUid do
}
allow(Setting).to receive(:set)
allow(Setting).to receive(:set).with('ldap_config', ldap_config_new)
allow(Import::Ldap).to receive(:config).and_return(ldap_config_obsolete)
@ -46,8 +53,9 @@ RSpec.describe MigrationJob::LdapSamaccountnameToUid do
allow(::Ldap).to receive(:new)
described_class.new.perform
described_class.perform_now
expect(Setting).to have_received(:set).with('ldap_config', ldap_config_new)
expect(ldap_user).to have_received(:uid_attribute)
end
end

View file

@ -677,7 +677,7 @@ RSpec.describe Channel::Driver::Twitter do
describe '#send', :use_vcr do
shared_examples 'for #send' do
# Channel#deliver takes a hash in the following format
# (see Observer::Ticket::Article::CommunicateTwitter::BackgroundJob#perform)
# (see CommunicateTwitterJob#perform)
#
# Why not just accept the whole article?
# Presumably so all channels have a consistent interface...
@ -990,10 +990,7 @@ RSpec.describe Channel::Driver::Twitter do
# and then manually copied into the existing VCR cassette for this example.
context '…but before the BG job has "synced" article.message_id with tweet.id)' do
let(:twitter_job) { Delayed::Job.find_by(handler: <<~YML) }
--- !ruby/object:Observer::Ticket::Article::CommunicateTwitter::BackgroundJob
article_id: #{tweet.id}
YML
let(:twitter_job) { Delayed::Job.where("handler LIKE '%job_class: CommunicateTwitterJob%#{tweet.id}%'").first }
around do |example|
# Run BG job (Why not use Scheduler.worker?

View file

@ -1,27 +1,19 @@
require 'rails_helper'
RSpec.describe Observer::Ticket::Article::CommunicateTwitter do
RSpec.describe Observer::Ticket::Article::CommunicateTwitter, 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(Delayed::Job)
.not_to receive(:enqueue)
.with(instance_of(Observer::Ticket::Article::CommunicateTwitter::BackgroundJob))
article
expect { article }.not_to have_enqueued_job(CommunicateTwitterJob)
end
end
shared_examples 'for success' do
it 'enqueues the Twitter background job' do
expect(Delayed::Job)
.to receive(:enqueue)
.with(an_instance_of(Observer::Ticket::Article::CommunicateTwitter::BackgroundJob))
article
expect { article }.to have_enqueued_job(CommunicateTwitterJob)
end
end