diff --git a/CHANGELOG.md b/CHANGELOG.md
index c43c7b0..eca6c42 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,9 @@
+# 1.3.0
+
+* Use redmine_bots instead of redmine_telegram_common
+* Add Slack support (and transparent support for custom protocols)
+* Fix redmine_helpdesk integration
+
# 1.2.1
* Fix helpdesk support
diff --git a/README.md b/README.md
index 668e9de..5aaef71 100644
--- a/README.md
+++ b/README.md
@@ -17,8 +17,7 @@ Please help us make this plugin better telling us of any [issues](https://github
* **Ruby 2.3+**
* **Redmine 3.1+**
-* Configured [redmine_telegram_common](https://github.com/centosadmin/redmine_telegram_common)
-* You should have Telegram bot account
+* Configured [redmine_bots](https://github.com/centosadmin/redmine_bots)
* Install [Redis](https://redis.io) 2.8 or higher. Run Redis and add it to autorun.
* Install the [redmine_sidekiq](https://github.com/ogom/redmine_sidekiq) plugin. [Redis](https://redis.io) 2.8 or greater is required.
* You need to configure Sidekiq queues `default` and `telegram`. [Config example](https://github.com/centosadmin/redmine_intouch/blob/master/extras/sidekiq.yml) - place it to `redmine/config` directory (Or copy from plugins/redmine_intouch/extras/sidekiq.yml to config/sidekiq.yml).
@@ -33,6 +32,11 @@ bundle exec rake redmine:plugins:migrate RAILS_ENV=production
The `extras` folder has the examples of the plugin config files and the `init.d` startup script
+### Upgrade from 1.2 to 1.3+
+
+From 1.3.0 redmine_intouch depends on [redmine_bots](https://github.com/centosadmin/redmine_bots) instead of redmine_telegram_common.
+Make sure to remove redmine_telegram_common from plugins and follow installation instruction for [redmine_bots](https://github.com/centosadmin/redmine_bots).
+
### Upgrade from 1.0.2 to 1.1.0+
From 1.1.0 redmine_intouch (as well as other Southbridge telegram plugins) is using bot from redmine_telegram_common.
@@ -66,7 +70,7 @@ Since 0.4 version, model `TelegramUser` will be removed, also table `telegram_us
## General settings
-You should specify all the necessary notification protocols in the "Protocols" section. These are 'telegram' and 'email' available at the moment.
+You should specify all the necessary notification protocols in the "Protocols" section. These are 'telegram', 'slack' and 'email' available at the moment.
The section "Working days" should contain:
diff --git a/app/models/intouch_sender.rb b/app/models/intouch_sender.rb
deleted file mode 100644
index ce63e54..0000000
--- a/app/models/intouch_sender.rb
+++ /dev/null
@@ -1,27 +0,0 @@
-class IntouchSender
- unloadable
-
- def self.send_email_message(issue_id, state)
- EmailSenderWorker.perform_async(issue_id, state)
- end
-
- def self.send_telegram_message(issue_id, state)
- TelegramSenderWorker.perform_async(issue_id, state)
- end
-
- def self.send_telegram_group_message(issue_id, group_ids, state)
- TelegramGroupSenderWorker.perform_async(issue_id, group_ids, state)
- end
-
- def self.send_live_email_message(issue_id, journal_id, required_recipients = [])
- EmailLiveSenderWorker.perform_async(issue_id, journal_id, required_recipients)
- end
-
- def self.send_live_telegram_message(issue_id, journal_id, required_recipients = [])
- TelegramLiveSenderWorker.perform_async(issue_id, journal_id, required_recipients)
- end
-
- def self.send_live_telegram_group_message(issue_id, journal_id)
- TelegramGroupLiveSenderWorker.perform_async(issue_id, journal_id)
- end
-end
diff --git a/app/models/settings_template.rb b/app/models/settings_template.rb
index caaead6..5918a3a 100644
--- a/app/models/settings_template.rb
+++ b/app/models/settings_template.rb
@@ -3,7 +3,7 @@ class SettingsTemplate < ActiveRecord::Base
attr_accessible :name, :intouch_settings
- store :intouch_settings, accessors: %w[assigner_groups assigner_roles reminder_settings telegram_settings email_settings]
+ store :intouch_settings, accessors: %w[assigner_groups assigner_roles reminder_settings] | Intouch.protocols.keys.map { |p| "#{p}_settings" }
def copy_from(settings_template)
self.attributes = settings_template.attributes.dup.except('id', 'created_on', 'updated_on')
diff --git a/app/views/projects/settings/intouch/issue_update/_common.html.erb b/app/views/projects/settings/intouch/issue_update/_common.html.erb
index c24b4bd..a6f680e 100644
--- a/app/views/projects/settings/intouch/issue_update/_common.html.erb
+++ b/app/views/projects/settings/intouch/issue_update/_common.html.erb
@@ -47,7 +47,7 @@
<% IssuePriority.order(:position).each do |priority| %>
<% %w(author watchers).each do |receiver| %>
- <% Intouch.active_protocols.each do |protocol| %>
+ <% Intouch.active_protocols.each do |protocol, _| %>
<%= check_box_tag "intouch_settings[#{protocol}_settings][unassigned][#{receiver}]", '1',
settings_source.send("#{protocol}_settings").try(:[], 'unassigned').try(:[], receiver),
class: "#{protocol}_#{receiver}",
diff --git a/app/views/settings/_common.html.erb b/app/views/settings/_common.html.erb
index fea52f6..ab22420 100644
--- a/app/views/settings/_common.html.erb
+++ b/app/views/settings/_common.html.erb
@@ -4,7 +4,7 @@
<%= t 'intouch.settings.common.protocols.description' %>
- <% Intouch::AVAILABLE_PROTOCOLS.each do |protocol| %>
+ <% Intouch.protocols.each do |protocol, _| %>
-
<%= check_box_tag "settings[active_protocols][]", protocol,
@settings["active_protocols"].try(:include?, protocol),
diff --git a/app/views/settings/_intouch.html.erb b/app/views/settings/_intouch.html.erb
index f4c8cd7..2d86c59 100644
--- a/app/views/settings/_intouch.html.erb
+++ b/app/views/settings/_intouch.html.erb
@@ -5,13 +5,6 @@
{name: 'sidekiq_cron_jobs', partial: 'settings/sidekiq_cron_jobs', label: 'intouch.label.sidekiq_cron_jobs'}
] %>
-<% unless Redmine::Plugin.installed?('redmine_telegram_common') %>
-
- !!! redmine_telegram_common
- <%= t('intouch.settings.required') %> !!!
-
-<% end %>
-
<% unless Redmine::Plugin.installed?('redmine_sidekiq') %>
!!! redmine_sidekiq
diff --git a/app/workers/cron_feedback_regular_notification.rb b/app/workers/cron_feedback_regular_notification.rb
index da125c9..3519cd5 100644
--- a/app/workers/cron_feedback_regular_notification.rb
+++ b/app/workers/cron_feedback_regular_notification.rb
@@ -3,6 +3,6 @@ class CronFeedbackRegularNotification
def perform
# Feedback
- Intouch.send_notifications Issue.open.joins(:project).feedbacks, 'feedback'
+ Intouch.send_notifications Issue.open.joins(:project).feedbacks.distinct, 'feedback'
end
end
diff --git a/app/workers/cron_overdue_regular_notification.rb b/app/workers/cron_overdue_regular_notification.rb
index d59bb5d..3548c74 100644
--- a/app/workers/cron_overdue_regular_notification.rb
+++ b/app/workers/cron_overdue_regular_notification.rb
@@ -2,7 +2,7 @@ class CronOverdueRegularNotification
include Sidekiq::Worker
def perform
- if Intouch.active_protocols.include? 'email'
+ if Intouch.active_protocols.keys.include? 'email'
# Overdue and Without due date (email only)
overdue_issue_ids = Issue.open.joins(:project).where('due_date < ?', Date.today).pluck :id
without_due_date_issue_ids = Issue.open.where(due_date: nil).where('created_on < ?', 1.day.ago).pluck :id
@@ -15,13 +15,9 @@ def perform
Intouch.send_bulk_email_notifications Issue.open.where(id: issue_ids), 'overdue'
end
- if Intouch.active_protocols.include? 'telegram'
- # Overdue (telegram only)
- Intouch.send_notifications Issue.open.joins(:project).where('due_date < ?', Date.today), 'overdue'
+ Intouch.send_notifications Issue.open.joins(:project).where('due_date < ?', Date.today).distinct, 'overdue'
- # Without due date (telegram only)
- Intouch.send_notifications Issue.open.where(due_date: nil)
- .where('created_on < ?', 1.day.ago), 'overdue'
- end
+ Intouch.send_notifications Issue.open.where(due_date: nil)
+ .where('created_on < ?', 1.day.ago).distinct, 'overdue'
end
end
diff --git a/app/workers/cron_unassigned_regular_notification.rb b/app/workers/cron_unassigned_regular_notification.rb
index 063ddf4..baef64a 100644
--- a/app/workers/cron_unassigned_regular_notification.rb
+++ b/app/workers/cron_unassigned_regular_notification.rb
@@ -3,9 +3,9 @@ class CronUnassignedRegularNotification
def perform
# Unassigned
- Intouch.send_notifications Issue.open.joins(:project).where(assigned_to_id: nil), 'unassigned'
+ Intouch.send_notifications Issue.open.joins(:project).where(assigned_to_id: nil).distinct, 'unassigned'
# Assigned to Group
- Intouch.send_notifications Issue.open.joins(:project, :assigned_to).where(users: { type: 'Group' }), 'unassigned'
+ Intouch.send_notifications Issue.open.joins(:project, :assigned_to).where(users: { type: 'Group' }).distinct, 'unassigned'
end
end
diff --git a/app/workers/cron_working_regular_notification.rb b/app/workers/cron_working_regular_notification.rb
index 5b7b15a..46380aa 100644
--- a/app/workers/cron_working_regular_notification.rb
+++ b/app/workers/cron_working_regular_notification.rb
@@ -3,6 +3,6 @@ class CronWorkingRegularNotification
def perform
# Working
- Intouch.send_notifications Issue.open.joins(:project).working, 'working'
+ Intouch.send_notifications Issue.open.joins(:project).working.distinct, 'working'
end
end
diff --git a/app/workers/email_live_sender_worker.rb b/app/workers/email_live_sender_worker.rb
index 5ebb910..919ab76 100644
--- a/app/workers/email_live_sender_worker.rb
+++ b/app/workers/email_live_sender_worker.rb
@@ -2,12 +2,14 @@ class EmailLiveSenderWorker
include Sidekiq::Worker
EMAIL_LIVE_SENDER_LOG = Logger.new(Rails.root.join('log/intouch', 'email-live-sender.log'))
- def perform(issue_id, journal_id, _required_recipients = [])
+ def perform(issue_id, journal_id, grouped_recipient_ids)
Intouch.set_locale
- issue = Intouch::IssueDecorator.new(Issue.find(issue_id), journal_id)
+ issue = Intouch::IssueDecorator.new(Issue.find(issue_id), journal_id, protocol: 'email')
- issue.intouch_live_recipients('email').each do |user|
- IntouchMailer.reminder_email(user, issue).deliver if user.present?
+ grouped_recipient_ids.each do |klass, ids|
+ klass.constantize.where(id: ids).each do |user|
+ IntouchMailer.reminder_email(user, issue).deliver
+ end
end
rescue ActiveRecord::RecordNotFound => e
EMAIL_LIVE_SENDER_LOG.error "#{e.class}: #{e.message}"
diff --git a/app/workers/slack_live_worker.rb b/app/workers/slack_live_worker.rb
new file mode 100644
index 0000000..1fdddd9
--- /dev/null
+++ b/app/workers/slack_live_worker.rb
@@ -0,0 +1,24 @@
+class SlackLiveWorker
+ include Sidekiq::Worker
+
+ def perform(issue_id, journal_id, recipient_ids)
+ return if recipient_ids.blank?
+
+ issue = Issue.find_by(id: issue_id) || return
+ journal = Journal.find_by(id: journal_id)
+
+ issue = Intouch::IssueDecorator.new(issue, journal, protocol: 'slack')
+
+ slack_accounts = SlackAccount.where(user_id: recipient_ids)
+
+ client = RedmineBots::Slack.bot_client
+
+ channels = client.im_list
+
+ return unless channels['ok']
+
+ channels.ims.select { |im| im.user.in?(slack_accounts.map(&:slack_id)) }.each do |channel|
+ client.chat_postMessage(text: issue.as_markdown, channel: channel.id)
+ end
+ end
+end
diff --git a/app/workers/slack_regular_worker.rb b/app/workers/slack_regular_worker.rb
new file mode 100644
index 0000000..245d4d6
--- /dev/null
+++ b/app/workers/slack_regular_worker.rb
@@ -0,0 +1,38 @@
+class SlackRegularWorker
+ include Sidekiq::Worker
+
+ def perform(issue_id, state)
+ issue = Issue.find_by(id: issue_id) || return
+ project = issue.project
+
+ return unless Intouch::Regular::Checker::Base.new(
+ issue: issue,
+ state: state,
+ project: project
+ ).required?
+
+ slack_accounts = SlackAccount.where(
+ user_id: Intouch::Regular::RecipientsList.new(
+ issue: issue,
+ state: state,
+ protocol: 'slack'
+ ).call.map(&:id)
+ ).to_a
+
+ return if slack_accounts.empty?
+
+ client = RedmineBots::Slack.bot_client
+
+ channels = client.im_list
+
+ return unless channels['ok']
+
+ channels = client.im_list
+
+ return unless channels['ok']
+
+ channels.ims.select { |im| im.user.in?(slack_accounts.map(&:slack_id)) }.each do |channel|
+ client.chat_postMessage(text: issue.as_markdown, channel: channel.id)
+ end
+ end
+end
diff --git a/app/workers/telegram_group_live_sender_worker.rb b/app/workers/telegram_group_live_sender_worker.rb
index 9f8b57b..34eb47d 100644
--- a/app/workers/telegram_group_live_sender_worker.rb
+++ b/app/workers/telegram_group_live_sender_worker.rb
@@ -5,7 +5,7 @@ def perform(issue_id, journal_id)
logger.debug "START for issue_id #{issue_id}"
Intouch.set_locale
- issue = Intouch::IssueDecorator.new(Issue.find(issue_id), journal_id)
+ issue = Intouch::IssueDecorator.new(Issue.find(issue_id), journal_id, protocol: 'telegram')
logger.debug issue.inspect
telegram_groups_settings = issue.project.active_telegram_settings.try(:[], 'groups')
@@ -44,7 +44,7 @@ def perform(issue_id, journal_id)
return unless group_for_send_ids.present?
- message = issue.telegram_live_message
+ message = issue.as_markdown
logger.debug "message: #{message}"
diff --git a/app/workers/telegram_live_sender_worker.rb b/app/workers/telegram_live_sender_worker.rb
index aa90dfc..05c9e71 100644
--- a/app/workers/telegram_live_sender_worker.rb
+++ b/app/workers/telegram_live_sender_worker.rb
@@ -1,53 +1,22 @@
class TelegramLiveSenderWorker
include Sidekiq::Worker
- def perform(issue_id, journal_id, required_recipients = [])
- @required_recipients = required_recipients
+ def perform(issue_id, journal_id, recipient_ids)
logger.debug "START for issue_id #{issue_id}"
Intouch.set_locale
- issue = Intouch::IssueDecorator.new(Issue.find(issue_id), journal_id)
+ issue = Intouch::IssueDecorator.new(Issue.find(issue_id), journal_id, protocol: 'telegram')
logger.debug issue.inspect
- base_message = issue.telegram_live_message
-
- logger.debug "base_message: #{base_message}"
-
- issue.intouch_live_recipients('telegram').each do |user|
+ User.where(id: recipient_ids).each do |user|
+ message = issue.as_markdown(user_id: user.id)
+
logger.debug "user: #{user.inspect}"
- telegram_account = user.telegram_account
+ telegram_account = TelegramAccount.find_by(user_id: user.id)
logger.debug "telegram_account: #{telegram_account.inspect}"
- next unless telegram_account.present? && telegram_account.active?
-
- roles_in_issue = []
-
- roles_in_issue << 'assigned_to' if issue.assigned_to_id == user.id
- roles_in_issue << 'watchers' if issue.watchers.pluck(:user_id).include?(user.id) || IntouchSubscription.find_by(user_id: user.id, project_id: issue.project_id)&.active?
- roles_in_issue << 'author' if issue.author_id == user.id
-
- logger.debug "roles_in_issue: #{roles_in_issue.inspect}"
-
- next unless need_notification?(roles_in_issue)
-
- project = issue.project
- settings = project.active_telegram_settings
-
- if settings.present?
- recipients = settings.select do |key, value|
- %w(author assigned_to watchers).include?(key) &&
- value.try(:[], issue.status_id.to_s).try(:include?, issue.priority_id.to_s)
- end.keys
-
- prefix = roles_for_prefix(recipients, roles_in_issue).map do |role|
- I18n.t("intouch.telegram_message.recipient.#{role}")
- end.join(', ')
- else
- prefix = nil
- end
-
- message = prefix.present? ? "#{prefix}\n#{base_message}" : base_message
+ next unless telegram_account.present?
logger.debug message
@@ -63,21 +32,7 @@ def perform(issue_id, journal_id, required_recipients = [])
private
- attr_reader :required_recipients
-
def logger
@logger ||= Logger.new(Rails.root.join('log/intouch', 'telegram-live-sender.log'))
end
-
- def need_notification?(roles_in_issue)
- return roles_in_issue unless required_recipients.present?
-
- (roles_in_issue & required_recipients).present?
- end
-
- def roles_for_prefix(recipients, roles_in_issue)
- return roles_in_issue & recipients unless required_recipients.present?
-
- roles_in_issue & recipients & required_recipients
- end
end
diff --git a/app/workers/telegram_message_sender.rb b/app/workers/telegram_message_sender.rb
index d9f6320..022be25 100644
--- a/app/workers/telegram_message_sender.rb
+++ b/app/workers/telegram_message_sender.rb
@@ -26,13 +26,11 @@ def perform(telegram_account_id, message)
TELEGRAM_MESSAGE_SENDER_ERRORS_LOG.info "MESSAGE: #{message}"
telegram_account = (telegram_account_id > 0) ?
- TelegramCommon::Account.find_by(telegram_id: telegram_account_id) :
+ TelegramAccount.find_by(telegram_id: telegram_account_id) :
TelegramGroupChat.find_by(tid: telegram_account_id.abs)
if e.message.include? 'Bot was kicked'
-
- telegram_account.deactivate! if telegram_account.is_a? TelegramCommon::Account
- TELEGRAM_MESSAGE_SENDER_ERRORS_LOG.info "Bot was kicked from chat. Deactivate #{telegram_account.inspect}"
+ TELEGRAM_MESSAGE_SENDER_ERRORS_LOG.info "Bot was kicked from chat."
elsif e.message.include?('429') || e.message.include?('retry later')
diff --git a/config/locales/en.yml b/config/locales/en.yml
index 4b7f9d0..b5c4c71 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -105,6 +105,7 @@ en:
protocols:
email: E-mail
telegram: Telegram
+ slack: Slack
title: Protocols
recipient:
assigned_to: Assigner
diff --git a/config/locales/ru.yml b/config/locales/ru.yml
index b9b63d4..8f4a404 100644
--- a/config/locales/ru.yml
+++ b/config/locales/ru.yml
@@ -105,6 +105,7 @@ ru:
protocols:
email: E-mail
telegram: Telegram
+ slack: Slack
title: "Протоколы"
recipient:
assigned_to: "Исполнитель"
diff --git a/init.rb b/init.rb
index 4cd9232..71b9db8 100644
--- a/init.rb
+++ b/init.rb
@@ -1,4 +1,4 @@
-require_dependency Rails.root.join('plugins','redmine_telegram_common', 'init')
+require_dependency Rails.root.join('plugins','redmine_bots', 'init')
FileUtils.mkdir_p(Rails.root.join('log/intouch')) unless Dir.exist?(Rails.root.join('log/intouch'))
@@ -13,23 +13,28 @@
require_dependency file
end
- require_dependency 'telegram_common'
- TelegramCommon.update_manager.add_handler(->(message) { Intouch.handle_message(message) } )
+ require_dependency 'redmine_bots'
+ RedmineBots::Telegram.update_manager.add_handler(->(message) { Intouch.handle_message(message) } )
end
Rails.application.config.eager_load_paths += Dir.glob("#{Rails.application.config.root}/plugins/redmine_intouch/{lib,app/workers,app/models,app/controllers}")
+Intouch.register_protocol('telegram', Intouch::Protocols::Telegram.new)
+Intouch.register_protocol('slack', Intouch::Protocols::Slack.new)
+Intouch.register_protocol('email', Intouch::Protocols::Email.new)
+
+
Redmine::Plugin.register :redmine_intouch do
name 'Redmine Intouch plugin'
url 'https://github.com/centosadmin/redmine_intouch'
description 'This is a plugin for Redmine which sends a reminder email and Telegram messages to the assignee workign on a task, whose status is not updated with-in allowed duration'
- version '1.2.1'
+ version '1.3.0'
author 'Southbridge'
author_url 'https://github.com/centosadmin'
requires_redmine version_or_higher: '3.0'
- requires_redmine_plugin :redmine_telegram_common, '0.7.0'
+ requires_redmine_plugin :redmine_bots, '0.1.0'
settings(
default: {
diff --git a/lib/intouch.rb b/lib/intouch.rb
index bff4eb8..00c3755 100644
--- a/lib/intouch.rb
+++ b/lib/intouch.rb
@@ -1,12 +1,19 @@
module Intouch
- AVAILABLE_PROTOCOLS = %w(telegram email)
+ @@mutex = Mutex.new
+ @@protocols = {}
+
+ mattr_reader :protocols
+
+ def self.register_protocol(name, protocol)
+ @@mutex.synchronize { @@protocols[name.to_s] = protocol }
+ end
def self.set_locale
I18n.locale = Setting['default_language']
end
def self.bot_token
- Setting.plugin_redmine_telegram_common['bot_token']
+ Setting.plugin_redmine_bots['telegram_bot_token']
end
def self.web_hook_url
@@ -19,7 +26,7 @@ def self.sidekiq_cron_jobs
end
def self.active_protocols
- Setting.plugin_redmine_intouch['active_protocols'] || []
+ protocols.slice(*Setting.plugin_redmine_intouch['active_protocols'])
end
def self.handle_message(message)
@@ -59,19 +66,12 @@ def self.send_notifications(issues, state)
last_notification = issue.last_notification.try(:[], state)
if active &&
- interval.present? &&
- Intouch::Regular::Message::Base.new(issue).latest_action_on < interval.to_i.hours.ago &&
- (last_notification.nil? || last_notification < interval.to_i.hours.ago)
-
- if active_protocols.include? 'email'
- IntouchSender.send_email_message(issue.id, state) unless %w(overdue without_due_date).include? state
- end
-
- if active_protocols.include? 'telegram'
- IntouchSender.send_telegram_message(issue.id, state)
+ interval.present? &&
+ Intouch::Regular::Message::Base.new(issue).latest_action_on < interval.to_i.hours.ago &&
+ (last_notification.nil? || last_notification < interval.to_i.hours.ago)
- group_ids = telegram_settings.try(:[], state).try(:[], 'groups')
- IntouchSender.send_telegram_group_message(issue.id, group_ids, state) if group_ids.present?
+ active_protocols.each do |_, protocol|
+ protocol.send_regular_notification(issue, state)
end
last_notification = issue.last_notification
diff --git a/lib/intouch/issue_decorator.rb b/lib/intouch/issue_decorator.rb
index 4004524..7b5327f 100644
--- a/lib/intouch/issue_decorator.rb
+++ b/lib/intouch/issue_decorator.rb
@@ -1,13 +1,14 @@
module Intouch
class IssueDecorator < SimpleDelegator
- def initialize(issue, journal_id)
+ def initialize(issue, journal_id, protocol:)
super(issue)
@journal = journals.find_by(id: journal_id)
+ @protocol = protocol
end
- def telegram_live_message
- message = "`#{project.title}: #{subject}`"
+ def as_markdown(user_id: nil)
+ message = "#{prefix(user_id) if user_id}\n`#{project.title}: #{subject}`"
message += "\n#{I18n.t('intouch.telegram_message.issue.updated_by')}: #{updated_by}" if updated_by.present?
@@ -27,39 +28,15 @@ def telegram_live_message
message += "\n#{Intouch.issue_url(id)}"
- if defined?(telegram_group) && telegram_group&.shared_url.present?
- message += ", [#{I18n.t('intouch.telegram_message.issue.telegram_link')}](#{telegram_group.shared_url})"
- end
+ # if defined?(telegram_group) && telegram_group&.shared_url.present?
+ # message += ", [#{I18n.t('intouch.telegram_message.issue.telegram_link')}](#{telegram_group.shared_url})"
+ # end
message
end
- def live_recipient_ids(protocol)
- settings = project.send("active_#{protocol}_settings")
- return [] if settings.blank?
- recipients = settings.select { |k, _v| %w(author assigned_to watchers).include? k }
-
- subscribed_user_ids = IntouchSubscription.where(project_id: project_id).select(&:active?).map(&:user_id)
-
- user_ids = []
- recipients.each_pair do |key, value|
- next unless value.try(:[], status_id.to_s).try(:include?, priority_id.to_s)
- case key
- when 'author'
- user_ids << author.id
- when 'assigned_to'
- user_ids << assigned_to_id if assigned_to.class == User
- when 'watchers'
- user_ids += watchers.pluck(:user_id)
- end
- end
- (user_ids.flatten + [assigner_id] + subscribed_user_ids - [updated_by.try(:id)]).uniq
- end
-
- def intouch_live_recipients(protocol)
- users = User.where(id: live_recipient_ids(protocol))
- contacts = protocol == 'email' && project.module_enabled?(:contacts) ? ([self.customer] + self.contacts.to_a).uniq : []
- users + contacts.compact - [User.anonymous]
+ def updated_by
+ @journal&.user
end
private
@@ -97,10 +74,6 @@ def updated_details_text
end
end
- def updated_by
- @journal&.user
- end
-
def updated_priority_text
priority_journal = @journal.details.find_by(prop_key: 'priority_id')
old_priority = IssuePriority.find(priority_journal.old_value)
@@ -122,6 +95,39 @@ def updated_status_text
old_status = IssueStatus.find status_journal.old_value
"#{old_status.name} -> #{status.name}"
end
+
+ def required_recipients
+ @required_recipients ||= Intouch::Live::Checker::Private.new(self, project).required_recipients
+ end
+
+ def prefix(user_id)
+ roles_in_issue = []
+
+ roles_in_issue << 'assigned_to' if assigned_to_id == user_id
+ roles_in_issue << 'watchers' if watchers.pluck(:user_id).include? user_id
+ roles_in_issue << 'author' if author_id == user_id
+
+ settings = project.public_send("active_#{@protocol}_settings")
+
+ if settings.present?
+ recipients = settings.select do |key, value|
+ %w(author assigned_to watchers).include?(key) &&
+ value.try(:[], status_id.to_s).try(:include?, priority_id.to_s)
+ end.keys
+
+ roles_for_prefix(recipients, roles_in_issue).map do |role|
+ I18n.t("intouch.telegram_message.recipient.#{role}")
+ end.join(', ')
+ else
+ ''
+ end
+ end
+
+ def roles_for_prefix(recipients, roles_in_issue)
+ return roles_in_issue & recipients unless required_recipients.present?
+
+ roles_in_issue & recipients & required_recipients
+ end
end
end
diff --git a/lib/intouch/issue_update.rb b/lib/intouch/issue_update.rb
new file mode 100644
index 0000000..f7e060e
--- /dev/null
+++ b/lib/intouch/issue_update.rb
@@ -0,0 +1,53 @@
+module Intouch
+ class IssueUpdate
+ attr_reader :issue, :journal
+
+ def initialize(issue, journal, protocol_name)
+ @journal, @protocol_name = journal, protocol_name
+ @issue = IssueDecorator.new(issue, journal&.id, protocol: protocol_name)
+ end
+
+ def live_recipients
+ return [] unless need_notification?
+ @live_recipients ||= User.where(id: live_recipient_ids(@protocol_name)).to_a + [customer(@protocol_name)].compact
+ end
+
+ private
+
+ def live_recipient_ids(protocol)
+ settings = issue.project.send("active_#{protocol}_settings")
+ return [] if settings.blank?
+ recipients = settings.select { |k, _| %w(author assigned_to watchers).include? k }
+
+ subscribed_user_ids = IntouchSubscription.where(project_id: issue.project_id).select(&:active?).map(&:user_id)
+
+ user_ids = []
+ recipients.each_pair do |key, value|
+ next unless value.try(:[], issue.status_id.to_s).try(:include?, issue.priority_id.to_s)
+ case key
+ when 'author'
+ user_ids << issue.author.id
+ when 'assigned_to'
+ user_ids << issue.assigned_to_id if issue.assigned_to.class == User
+ when 'watchers'
+ user_ids += issue.watchers.pluck(:user_id)
+ end
+ end
+ (user_ids.flatten + [issue.assigner_id] + subscribed_user_ids - [User.anonymous.id] - [issue.updated_by&.id]).uniq
+ end
+
+ def customer(protocol)
+ return unless protocol == 'email' && issue.project.module_enabled?(:contacts)
+
+ settings = issue.project.send("active_#{protocol}_settings")
+ recipients = settings.select { |k, _| %w(author).include? k }
+
+ return unless recipients['author'].try(:[], issue.status_id.to_s).try(:include?, issue.priority_id.to_s)
+ issue.customer
+ end
+
+ def need_notification?
+ Intouch::Live::Checker::Private.new(issue, issue.project).required?
+ end
+ end
+end
diff --git a/lib/intouch/live/handler/new_issue.rb b/lib/intouch/live/handler/new_issue.rb
index 21da392..2abb02d 100644
--- a/lib/intouch/live/handler/new_issue.rb
+++ b/lib/intouch/live/handler/new_issue.rb
@@ -8,8 +8,10 @@ def initialize(issue)
def call
return unless notification_required?
- send_private_messages
- send_group_messages
+ Intouch.active_protocols.each do |name, protocol|
+ update = Intouch::IssueUpdate.new(issue, nil, name)
+ protocol.handle_update(update)
+ end
end
private
@@ -22,13 +24,5 @@ def notification_required?
project: project
).required?
end
-
- def send_private_messages
- Intouch::Live::Message::Private.new(issue, project).send
- end
-
- def send_group_messages
- Intouch::Live::Message::Group.new(issue, project).send
- end
end
end
diff --git a/lib/intouch/live/handler/updated_issue.rb b/lib/intouch/live/handler/updated_issue.rb
index 4394352..a441c05 100644
--- a/lib/intouch/live/handler/updated_issue.rb
+++ b/lib/intouch/live/handler/updated_issue.rb
@@ -14,8 +14,10 @@ def call
logger.info 'notification required'
- send_private_messages
- send_group_messages
+ Intouch.active_protocols.each do |name, protocol|
+ update = Intouch::IssueUpdate.new(issue, journal, name)
+ protocol.handle_update(update)
+ end
end
private
@@ -30,20 +32,6 @@ def notification_required?
).required?
end
- def send_private_messages
- Intouch::Live::Message::Private.new(issue, project, journal: @journal).send
- end
-
- def send_group_messages
- return unless need_group_message?
-
- Intouch::Live::Message::Group.new(issue, project, journal: @journal).send
- end
-
- def need_group_message?
- (journal.details.pluck(:prop_key) & %w[priority_id status_id project_id]).present?
- end
-
def logger
@logger ||= Logger.new(Rails.root.join('log/intouch', 'live-updated.log'))
end
diff --git a/lib/intouch/live/message/group.rb b/lib/intouch/live/message/group.rb
deleted file mode 100644
index c21bba4..0000000
--- a/lib/intouch/live/message/group.rb
+++ /dev/null
@@ -1,23 +0,0 @@
-module Intouch::Live::Message
- class Group
- attr_reader :project, :issue
-
- def initialize(issue, project, journal: nil)
- @issue = issue
- @project = project
- @journal = journal
- end
-
- def send
- return unless telegram_enabled?
-
- IntouchSender.send_live_telegram_group_message(issue.id, @journal&.id)
- end
-
- private
-
- def telegram_enabled?
- Intouch.active_protocols.include?('telegram')
- end
- end
-end
diff --git a/lib/intouch/live/message/private.rb b/lib/intouch/live/message/private.rb
deleted file mode 100644
index 26cd9d4..0000000
--- a/lib/intouch/live/message/private.rb
+++ /dev/null
@@ -1,51 +0,0 @@
-module Intouch::Live::Message
- class Private
- attr_reader :project, :issue
-
- def initialize(issue, project, journal: nil)
- @issue = issue
- @project = project
- @journal = journal
- end
-
- def send
- return unless need_private_message?
- send_telegram_private_messages
- send_email_messages
- end
-
- private
-
- def need_private_message?
- required_checker.required?
- end
-
- def required_recipients
- required_checker.required_recipients
- end
-
- def send_telegram_private_messages
- return unless telegram_enabled?
-
- ::IntouchSender.send_live_telegram_message(issue.id, @journal&.id, required_recipients)
- end
-
- def send_email_messages
- return unless email_enabled?
-
- ::IntouchSender.send_live_email_message(issue.id, @journal&.id, required_recipients)
- end
-
- def telegram_enabled?
- Intouch.active_protocols.include?('telegram')
- end
-
- def email_enabled?
- Intouch.active_protocols.include?('email')
- end
-
- def required_checker
- @required_checker ||= Intouch::Live::Checker::Private.new(issue, project)
- end
- end
-end
diff --git a/lib/intouch/patches/project_patch.rb b/lib/intouch/patches/project_patch.rb
index cf52704..c4cb8c2 100644
--- a/lib/intouch/patches/project_patch.rb
+++ b/lib/intouch/patches/project_patch.rb
@@ -6,7 +6,7 @@ def self.included(base) # :nodoc:
unloadable
# noinspection RubyArgCount
- store :intouch_settings, accessors: %w[settings_template_id assigner_groups assigner_roles reminder_settings telegram_settings email_settings]
+ store :intouch_settings, accessors: %w[settings_template_id assigner_groups assigner_roles reminder_settings] | Intouch.protocols.keys.map { |p| "#{p}_settings" }
before_create :copy_settings_from_parent
@@ -27,12 +27,10 @@ def active_reminder_settings
settings_template ? settings_template.reminder_settings : reminder_settings
end
- def active_telegram_settings
- settings_template ? settings_template.telegram_settings : telegram_settings
- end
-
- def active_email_settings
- settings_template ? settings_template.email_settings : email_settings
+ Intouch.protocols.each do |protocol, _|
+ define_method("active_#{protocol}_settings") do
+ settings_template ? settings_template.public_send("#{protocol}_settings") : send("#{protocol}_settings")
+ end
end
def active_intouch_settings
diff --git a/lib/intouch/protocols/base.rb b/lib/intouch/protocols/base.rb
new file mode 100644
index 0000000..8776861
--- /dev/null
+++ b/lib/intouch/protocols/base.rb
@@ -0,0 +1,17 @@
+module Intouch::Protocols
+ class Base
+ def handle_update(update)
+ raise NotImplementedError
+ end
+
+ def send_regular_notification(issue, state)
+ raise NotImplementedError
+ end
+
+ protected
+
+ def need_group_message?(journal)
+ journal.blank? || (journal.details.pluck(:prop_key) & %w[priority_id status_id project_id]).present?
+ end
+ end
+end
diff --git a/lib/intouch/protocols/email.rb b/lib/intouch/protocols/email.rb
new file mode 100644
index 0000000..11f19d7
--- /dev/null
+++ b/lib/intouch/protocols/email.rb
@@ -0,0 +1,13 @@
+module Intouch::Protocols
+ class Email
+ def handle_update(update)
+ EmailLiveSenderWorker.perform_async(update.issue.id, update&.journal&.id, update.live_recipients.group_by(&:class).map do |klass, recepients|
+ { klass.name => recepients.map(&:id) }
+ end.reduce(:merge))
+ end
+
+ def send_regular_notification(issue, state)
+ EmailSenderWorker.perform_async(issue.id, state)
+ end
+ end
+end
diff --git a/lib/intouch/protocols/slack.rb b/lib/intouch/protocols/slack.rb
new file mode 100644
index 0000000..2989def
--- /dev/null
+++ b/lib/intouch/protocols/slack.rb
@@ -0,0 +1,11 @@
+module Intouch::Protocols
+ class Slack < Base
+ def handle_update(update)
+ SlackLiveWorker.perform_async(update.issue.id, update&.journal&.id, update.live_recipients.map(&:id))
+ end
+
+ def send_regular_notification(issue, state)
+ SlackRegularWorker.perform_async(issue.id, state)
+ end
+ end
+end
diff --git a/lib/intouch/protocols/telegram.rb b/lib/intouch/protocols/telegram.rb
new file mode 100644
index 0000000..363962e
--- /dev/null
+++ b/lib/intouch/protocols/telegram.rb
@@ -0,0 +1,21 @@
+module Intouch::Protocols
+ class Telegram < Base
+ def handle_update(update)
+ issue = update.issue
+ journal = update.journal
+
+ TelegramLiveSenderWorker.perform_in(5.seconds, issue.id, journal&.id, update.live_recipients.map(&:id))
+ TelegramGroupLiveSenderWorker.perform_in(5.seconds, issue.id, journal&.id) if need_group_message?(journal)
+ end
+
+ def send_regular_notification(issue, state)
+ project = issue.project
+ telegram_settings = project.active_telegram_settings
+
+ TelegramSenderWorker.perform_in(5.seconds, issue.id, state)
+
+ group_ids = telegram_settings.try(:[], state).try(:[], 'groups')
+ TelegramGroupSenderWorker.perform_in(5.seconds, issue.id, group_ids, state) if group_ids.present?
+ end
+ end
+end
diff --git a/lib/intouch/regular/message/private.rb b/lib/intouch/regular/message/private.rb
index 33206f6..61c54ac 100644
--- a/lib/intouch/regular/message/private.rb
+++ b/lib/intouch/regular/message/private.rb
@@ -12,7 +12,7 @@ def initialize(issue:, user:, state:, project:)
attr_reader :issue, :user, :state, :project
def send
- return unless telegram_account.present? && telegram_account.active?
+ return unless telegram_account.present?
logger.info '========================================='
logger.info "Notification for state: #{state}"
@@ -25,7 +25,7 @@ def send
end
def telegram_account
- @telegram_account ||= user.telegram_account
+ @telegram_account ||= TelegramAccount.find_by(user_id: user.id)
end
def message
diff --git a/lib/intouch/regular/recipients_list.rb b/lib/intouch/regular/recipients_list.rb
index cf8d206..0e201e8 100644
--- a/lib/intouch/regular/recipients_list.rb
+++ b/lib/intouch/regular/recipients_list.rb
@@ -12,8 +12,8 @@ def call
return [] unless recipient_ids.present?
users = User.where(id: recipient_ids).status(User::STATUS_ACTIVE)
- contacts = @protocol == 'email' && @issue.project.module_enabled?(:contacts) ? ([@issue.customer] + @issue.contacts.to_a).uniq : []
- users + contacts.compact - [User.anonymous]
+ customer = @issue.customer if @protocol == 'email' && @issue.project.module_enabled?(:contacts)
+ users + [customer].compact - [User.anonymous]
end
def recipient_ids
diff --git a/lib/intouch/telegram_bot.rb b/lib/intouch/telegram_bot.rb
index 2885c9a..9f5acac 100644
--- a/lib/intouch/telegram_bot.rb
+++ b/lib/intouch/telegram_bot.rb
@@ -1,4 +1,4 @@
-class Intouch::TelegramBot < TelegramCommon::Bot
+class Intouch::TelegramBot < RedmineBots::Telegram::Bot
def initialize(command)
@logger = Logger.new(Rails.root.join('log/intouch', 'bot.log'))
@command = command.is_a?(Telegram::Bot::Types::Message) ? command : Telegram::Bot::Types::Update.new(command).message
diff --git a/test/unit/intouch/live/handler/new_issue_test.rb b/test/unit/intouch/live/handler/new_issue_test.rb
index 2fee2bc..a9c0c55 100644
--- a/test/unit/intouch/live/handler/new_issue_test.rb
+++ b/test/unit/intouch/live/handler/new_issue_test.rb
@@ -7,22 +7,28 @@ class Intouch::Live::Handler::NewIssueTest < ActiveSupport::TestCase
let(:project) { Project.first }
let(:issue) { Issue.new(project: project) }
+ let(:protocols) { }
describe 'send' do
before do
Intouch::Live::Checker::Base.any_instance
.stubs(:required?)
.returns(true)
+ @telegram = Intouch::Protocols::Telegram.new
+ @slack = Intouch::Protocols::Slack.new
+ Intouch.stubs(:active_protocols).returns(telegram: @telegram, slack: @slack)
end
it 'private message' do
- Intouch::Live::Message::Private.any_instance.expects(:send)
+ @telegram.expects(:handle_update)
+ @slack.expects(:handle_update)
subject
end
it 'group message' do
- Intouch::Live::Message::Group.any_instance.expects(:send)
+ @telegram.expects(:handle_update)
+ @slack.expects(:handle_update)
subject
end
@@ -33,16 +39,22 @@ class Intouch::Live::Handler::NewIssueTest < ActiveSupport::TestCase
Intouch::Live::Checker::Base.any_instance
.stubs(:required?)
.returns(false)
+
+ @telegram = Intouch::Protocols::Telegram.new
+ @slack = Intouch::Protocols::Slack.new
+ Intouch.stubs(:active_protocols).returns(telegram: @telegram, slack: @slack)
end
it 'private message' do
- Intouch::Live::Message::Private.any_instance.expects(:send).never
+ @telegram.expects(:handle_update).never
+ @slack.expects(:handle_update).never
subject
end
it 'group message' do
- Intouch::Live::Message::Group.any_instance.expects(:send).never
+ @telegram.expects(:handle_update).never
+ @slack.expects(:handle_update).never
subject
end
diff --git a/travis.sh b/travis.sh
index 0664865..df1ce5d 100644
--- a/travis.sh
+++ b/travis.sh
@@ -40,7 +40,7 @@ mv $TESTSPACE/additional_environment.rb config/
# add telegram_common plugin
-git clone git://github.com/centosadmin/redmine_telegram_common.git $PATH_TO_REDMINE/plugins/redmine_telegram_common
+git clone git://github.com/centosadmin/redmine_bots.git $PATH_TO_REDMINE/plugins/redmine_bots
# create a link to the backlogs plugin
ln -sf $PATH_TO_PLUGIN plugins/$NAME_OF_PLUGIN
|