Start working and refactoring
This commit is contained in:
34
.rubocop.yml
Normal file
34
.rubocop.yml
Normal file
@@ -0,0 +1,34 @@
|
||||
Rails:
|
||||
Enabled: true
|
||||
|
||||
AllCops:
|
||||
TargetRubyVersion: 2.1
|
||||
|
||||
Metrics/LineLength:
|
||||
Max: 140
|
||||
|
||||
# Offense count: 34
|
||||
# Configuration parameters: CountComments.
|
||||
Metrics/MethodLength:
|
||||
Max: 60
|
||||
|
||||
# Offense count: 11
|
||||
Metrics/CyclomaticComplexity:
|
||||
Max: 13
|
||||
|
||||
# Offense count: 10
|
||||
Metrics/PerceivedComplexity:
|
||||
Max: 14
|
||||
|
||||
# Offense count: 15
|
||||
Metrics/AbcSize:
|
||||
Max: 25
|
||||
|
||||
Style/Documentation:
|
||||
Enabled: false
|
||||
|
||||
Rails/HttpPositionalArguments:
|
||||
Enabled: false
|
||||
|
||||
Metrics/BlockLength:
|
||||
Max: 50
|
||||
1
LICENSE
1
LICENSE
@@ -2,6 +2,7 @@ Released under the MIT license.
|
||||
|
||||
Project redmine-slack is Copyright (c) 2014-2016 by Samuel Cormier-Iijima (https://github.com/sciyoshi/redmine-slack).
|
||||
Fork project redmine_mattermost is Copyright (c) 2015-2016 by AltSol (https://github.com/altsol/redmine_mattermost).
|
||||
Fork project redmine_rocketchat is Copyright (c) 20176 by Phlegx (https://github.com/phlegx/redmine_rocketchat).
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
# Rocket.Chat plugin for Redmine
|
||||
# Messenger plugin for Redmine
|
||||
|
||||
This plugin posts updates to issues in your Redmine installation to a Rocket.Chat
|
||||
channel.
|
||||
This plugin posts updates to issues in your Redmine installation to Slack, Rocket.Chat or Mattermost channel.
|
||||
|
||||
Redmine Supported versions: 3.3.x.
|
||||
|
||||
Redmine Supported versions: 2.0.x - 3.3.x.
|
||||
|
||||
## Screenshot
|
||||
|
||||
|
||||
56
init.rb
56
init.rb
@@ -1,38 +1,28 @@
|
||||
require 'redmine'
|
||||
require 'redmine_messenger'
|
||||
|
||||
require_dependency 'redmine_rocketchat/listener'
|
||||
Redmine::Plugin.register :redmine_messenger do
|
||||
name 'Redmine Messenger'
|
||||
author 'AlphaNodes GmbH'
|
||||
url 'https://github.com/alphanodes/redmine_messenger'
|
||||
author_url 'https://alphanodes.com/'
|
||||
description 'Messenger integration for Slack, Rocketchat and Mattermost support'
|
||||
version '0.6.2-dev'
|
||||
|
||||
Redmine::Plugin.register :redmine_rocketchat do
|
||||
name 'Redmine Rocket.Chat'
|
||||
author 'Egon Zemmer'
|
||||
url 'https://github.com/phlegx/redmine_rocketchat'
|
||||
author_url 'https://phlegx.com'
|
||||
description 'Rocket.Chat integration'
|
||||
version '0.6.1'
|
||||
requires_redmine version_or_higher: '3.3.0'
|
||||
|
||||
requires_redmine :version_or_higher => '2.0.0'
|
||||
|
||||
settings \
|
||||
:default => {
|
||||
'callback_url' => 'https://rocket.chat/hooks/my_rocket_chat_token',
|
||||
'channel' => 'redmine',
|
||||
'icon' => 'https://raw.githubusercontent.com/phlegx/redmine_rocketchat/assets/icon.png',
|
||||
'username' => 'redmine.bot',
|
||||
'display_watchers' => '0',
|
||||
'auto_mentions' => '1',
|
||||
'post_updates' => '1',
|
||||
'new_include_description' => '1',
|
||||
'updated_include_description' => '1',
|
||||
'post_private_issues' => '1',
|
||||
'post_private_notes' => '1',
|
||||
'post_wiki_updates' => '0'
|
||||
},
|
||||
:partial => 'settings/rocketchat_settings'
|
||||
end
|
||||
|
||||
ActionDispatch::Callbacks.to_prepare do
|
||||
require_dependency 'issue'
|
||||
unless Issue.included_modules.include? RedmineRocketchat::IssuePatch
|
||||
Issue.send(:include, RedmineRocketchat::IssuePatch)
|
||||
end
|
||||
settings default: {
|
||||
callback_url: 'https://rocket.chat/hooks/my_rocket_chat_token',
|
||||
channel: 'redmine',
|
||||
icon: 'https://raw.githubusercontent.com/phlegx/redmine_rocketchat/assets/icon.png',
|
||||
username: 'redmine.bot',
|
||||
display_watchers: '0',
|
||||
auto_mentions: '1',
|
||||
post_updates: '1',
|
||||
new_include_description: '1',
|
||||
updated_include_description: '1',
|
||||
post_private_issues: '1',
|
||||
post_private_notes: '1',
|
||||
post_wiki_updates: '0'
|
||||
}, partial: 'settings/messenger_settings'
|
||||
end
|
||||
|
||||
9
lib/redmine_messenger.rb
Normal file
9
lib/redmine_messenger.rb
Normal file
@@ -0,0 +1,9 @@
|
||||
# Redmine Messenger plugin for Redmine
|
||||
|
||||
Rails.configuration.to_prepare do
|
||||
# Patches
|
||||
require_dependency 'redmine_messenger/patches/issue_patch'
|
||||
|
||||
# Hooks
|
||||
require_dependency 'redmine_messenger/hooks'
|
||||
end
|
||||
322
lib/redmine_messenger/hooks.rb
Normal file
322
lib/redmine_messenger/hooks.rb
Normal file
@@ -0,0 +1,322 @@
|
||||
# Redmine Messenger plugin for Redmine
|
||||
|
||||
require 'httpclient'
|
||||
|
||||
module RedmineMessenger
|
||||
class MessengerListener < Redmine::Hook::Listener
|
||||
def redmine_rocketchat_issues_new_after_save(context={})
|
||||
issue = context[:issue]
|
||||
|
||||
channels = channels_for_project issue.project
|
||||
url = url_for_project issue.project
|
||||
post_private_issues = post_private_issues_for_project(issue.project)
|
||||
|
||||
return unless channels.present? && url
|
||||
return if issue.is_private? && post_private_issues != '1'
|
||||
|
||||
msg = "[#{escape issue.project}] #{escape issue.author} created <#{object_url issue}|#{escape issue}>#{mentions issue.description if Setting.plugin_redmine_rocketchat[:auto_mentions] == '1'}"
|
||||
|
||||
attachment = {}
|
||||
attachment[:text] = escape issue.description if issue.description && Setting.plugin_redmine_rocketchat[:new_include_description] == '1'
|
||||
attachment[:fields] = [{
|
||||
title: I18n.t(:field_status),
|
||||
value: escape(issue.status.to_s),
|
||||
short: true
|
||||
}, {
|
||||
title: I18n.t(:field_priority),
|
||||
value: escape(issue.priority.to_s),
|
||||
short: true
|
||||
}, {
|
||||
title: I18n.t(:field_assigned_to),
|
||||
value: escape(issue.assigned_to.to_s),
|
||||
short: true
|
||||
}]
|
||||
|
||||
attachment[:fields] << {
|
||||
title: I18n.t(:field_watcher),
|
||||
value: escape(issue.watcher_users.join(', ')),
|
||||
short: true
|
||||
} if Setting.plugin_redmine_rocketchat[:display_watchers] == '1'
|
||||
|
||||
speak msg, channels, attachment, url
|
||||
end
|
||||
|
||||
def redmine_rocketchat_issues_edit_after_save(context={})
|
||||
issue = context[:issue]
|
||||
journal = context[:journal]
|
||||
|
||||
channels = channels_for_project issue.project
|
||||
url = url_for_project issue.project
|
||||
post_private_issues = post_private_issues_for_project(issue.project)
|
||||
post_private_notes = post_private_notes_for_project(issue.project)
|
||||
|
||||
return unless channels.present? and url and Setting.plugin_redmine_rocketchat[:post_updates] == '1'
|
||||
return if issue.is_private? and post_private_issues != '1'
|
||||
return if journal.private_notes? and post_private_notes != '1'
|
||||
|
||||
msg = "[#{escape issue.project}] #{escape journal.user.to_s} updated <#{object_url issue}|#{escape issue}>#{mentions journal.notes if Setting.plugin_redmine_rocketchat[:auto_mentions] == '1'}"
|
||||
|
||||
attachment = {}
|
||||
attachment[:text] = escape journal.notes if journal.notes && Setting.plugin_redmine_rocketchat[:updated_include_description] == '1'
|
||||
attachment[:fields] = journal.details.map { |d| detail_to_field d }
|
||||
|
||||
speak msg, channels, attachment, url
|
||||
end
|
||||
|
||||
def model_changeset_scan_commit_for_issue_ids_pre_issue_update(context={})
|
||||
issue = context[:issue]
|
||||
journal = issue.current_journal
|
||||
changeset = context[:changeset]
|
||||
|
||||
channels = channels_for_project issue.project
|
||||
url = url_for_project issue.project
|
||||
post_private_issues = post_private_issues_for_project(issue.project)
|
||||
|
||||
return unless channels.present? and url and issue.save
|
||||
return if issue.is_private? and post_private_issues != '1'
|
||||
|
||||
msg = "[#{escape issue.project}] #{escape journal.user.to_s} updated <#{object_url issue}|#{escape issue}>"
|
||||
|
||||
repository = changeset.repository
|
||||
|
||||
if Setting.host_name.to_s =~ /\A(https?\:\/\/)?(.+?)(\:(\d+))?(\/.+)?\z/i
|
||||
host, port, prefix = $2, $4, $5
|
||||
revision_url = Rails.application.routes.url_for(
|
||||
:controller => 'repositories',
|
||||
:action => 'revision',
|
||||
:id => repository.project,
|
||||
:repository_id => repository.identifier_param,
|
||||
:rev => changeset.revision,
|
||||
:host => host,
|
||||
:protocol => Setting.protocol,
|
||||
:port => port,
|
||||
:script_name => prefix
|
||||
)
|
||||
else
|
||||
revision_url = Rails.application.routes.url_for(
|
||||
:controller => 'repositories',
|
||||
:action => 'revision',
|
||||
:id => repository.project,
|
||||
:repository_id => repository.identifier_param,
|
||||
:rev => changeset.revision,
|
||||
:host => Setting.host_name,
|
||||
:protocol => Setting.protocol
|
||||
)
|
||||
end
|
||||
|
||||
attachment = {}
|
||||
attachment[:text] = ll(Setting.default_language, :text_status_changed_by_changeset, "<#{revision_url}|#{escape changeset.comments}>")
|
||||
attachment[:fields] = journal.details.map { |d| detail_to_field d }
|
||||
|
||||
speak msg, channels, attachment, url
|
||||
end
|
||||
|
||||
def controller_wiki_edit_after_save(context = { })
|
||||
return unless Setting.plugin_redmine_rocketchat[:post_wiki_updates] == '1'
|
||||
|
||||
project = context[:project]
|
||||
page = context[:page]
|
||||
|
||||
user = page.content.author
|
||||
project_url = "<#{object_url project}|#{escape project}>"
|
||||
page_url = "<#{object_url page}|#{page.title}>"
|
||||
comment = "[#{project_url}] #{page_url} updated by *#{user}*"
|
||||
|
||||
channels = channels_for_project project
|
||||
url = url_for_project project
|
||||
|
||||
return unless channels.present? and url
|
||||
|
||||
attachment = nil
|
||||
unless page.content.comments.empty?
|
||||
attachment = {}
|
||||
attachment[:text] = "#{escape page.content.comments}"
|
||||
end
|
||||
|
||||
speak comment, channels, attachment, url
|
||||
end
|
||||
|
||||
def speak(msg, channels, attachment=nil, url=nil)
|
||||
return if channels.blank?
|
||||
|
||||
url = Setting.plugin_redmine_rocketchat[:rocketchat_url] unless url
|
||||
username = Setting.plugin_redmine_rocketchat[:username]
|
||||
icon = Setting.plugin_redmine_rocketchat[:icon]
|
||||
|
||||
params = {
|
||||
:text => msg,
|
||||
:link_names => 1,
|
||||
}
|
||||
|
||||
params[:username] = username if username
|
||||
|
||||
|
||||
params[:attachments] = [attachment] if attachment
|
||||
|
||||
if icon and not icon.empty?
|
||||
if icon.start_with? ':'
|
||||
params[:icon_emoji] = icon
|
||||
else
|
||||
params[:icon_url] = icon
|
||||
end
|
||||
end
|
||||
|
||||
channels.each do |channel|
|
||||
params[:channel] = channel
|
||||
|
||||
begin
|
||||
client = HTTPClient.new
|
||||
client.ssl_config.cert_store.set_default_paths
|
||||
client.ssl_config.ssl_version = :auto
|
||||
client.ssl_config.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
||||
client.post_async url, {:payload => params.to_json}
|
||||
rescue Exception => e
|
||||
Rails.logger.warn("cannot connect to #{url}")
|
||||
Rails.logger.warn(e)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def escape(msg)
|
||||
msg.to_s.gsub('&', '&').gsub('<', '<').gsub('>', '>')
|
||||
end
|
||||
|
||||
def object_url(obj)
|
||||
if Setting.host_name.to_s =~ /\A(https?\:\/\/)?(.+?)(\:(\d+))?(\/.+)?\z/i
|
||||
host, port, prefix = $2, $4, $5
|
||||
Rails.application.routes.url_for(obj.event_url({:host => host, :protocol => Setting.protocol, :port => port, :script_name => prefix}))
|
||||
else
|
||||
Rails.application.routes.url_for(obj.event_url({:host => Setting.host_name, :protocol => Setting.protocol}))
|
||||
end
|
||||
end
|
||||
|
||||
def url_for_project(proj)
|
||||
return nil if proj.blank?
|
||||
|
||||
cf = ProjectCustomField.find_by_name('Rocket.Chat URL')
|
||||
|
||||
[
|
||||
(proj.custom_value_for(cf).value rescue nil),
|
||||
(url_for_project proj.parent),
|
||||
Setting.plugin_redmine_rocketchat[:rocketchat_url],
|
||||
].flatten.find(&:present?)
|
||||
end
|
||||
|
||||
def post_private_issues_for_project(proj)
|
||||
return nil if proj.blank?
|
||||
|
||||
cf = ProjectCustomField.find_by_name('Rocket.Chat Post private issues')
|
||||
[
|
||||
(proj.custom_value_for(cf).value rescue nil),
|
||||
(post_private_issues_for_project proj.parent),
|
||||
Setting.plugin_redmine_rocketchat[:post_private_issues],
|
||||
].flatten.find(&:present?)
|
||||
end
|
||||
|
||||
def post_private_notes_for_project(proj)
|
||||
return nil if proj.blank?
|
||||
|
||||
cf = ProjectCustomField.find_by_name('Rocket.Chat Post private notes')
|
||||
[
|
||||
(proj.custom_value_for(cf).value rescue nil),
|
||||
(post_private_notes_for_project proj.parent),
|
||||
Setting.plugin_redmine_rocketchat[:post_private_notes],
|
||||
].flatten.find(&:present?)
|
||||
end
|
||||
|
||||
def channels_for_project(proj)
|
||||
return nil if proj.blank?
|
||||
|
||||
cf = ProjectCustomField.find_by_name('Rocket.Chat Channel')
|
||||
val = [
|
||||
(proj.custom_value_for(cf).value rescue nil),
|
||||
(channels_for_project proj.parent),
|
||||
Setting.plugin_redmine_rocketchat[:channel],
|
||||
].flatten.find(&:present?)
|
||||
|
||||
# Channel name '-' or empty '' is reserved for NOT notifying
|
||||
return [] if val.nil? or val.to_s == ''
|
||||
return [] if val.to_s == '-'
|
||||
return val.split(",") if val.is_a? String
|
||||
val
|
||||
end
|
||||
|
||||
def detail_to_field(detail)
|
||||
field_format = nil
|
||||
|
||||
if detail.property == "cf"
|
||||
key = CustomField.find(detail.prop_key).name rescue nil
|
||||
title = key
|
||||
field_format = CustomField.find(detail.prop_key).field_format rescue nil
|
||||
elsif detail.property == 'attachment'
|
||||
key = 'attachment'
|
||||
title = I18n.t :label_attachment
|
||||
else
|
||||
key = detail.prop_key.to_s.sub('_id', '')
|
||||
title = I18n.t "field_#{key}"
|
||||
end
|
||||
|
||||
short = true
|
||||
value = escape detail.value.to_s
|
||||
|
||||
case key
|
||||
when 'title', 'subject', 'description'
|
||||
short = false
|
||||
when 'tracker'
|
||||
tracker = Tracker.find(detail.value) rescue nil
|
||||
value = escape tracker.to_s
|
||||
when 'project'
|
||||
project = Project.find(detail.value) rescue nil
|
||||
value = escape project.to_s
|
||||
when 'status'
|
||||
status = IssueStatus.find(detail.value) rescue nil
|
||||
value = escape status.to_s
|
||||
when 'priority'
|
||||
priority = IssuePriority.find(detail.value) rescue nil
|
||||
value = escape priority.to_s
|
||||
when 'category'
|
||||
category = IssueCategory.find(detail.value) rescue nil
|
||||
value = escape category.to_s
|
||||
when 'assigned_to'
|
||||
user = User.find(detail.value) rescue nil
|
||||
value = escape user.to_s
|
||||
when 'fixed_version'
|
||||
version = Version.find(detail.value) rescue nil
|
||||
value = escape version.to_s
|
||||
when 'attachment'
|
||||
attachment = Attachment.find(detail.prop_key) rescue nil
|
||||
value = "<#{object_url attachment}|#{escape attachment.filename}>" if attachment
|
||||
when 'parent'
|
||||
issue = Issue.find(detail.value) rescue nil
|
||||
value = "<#{object_url issue}|#{escape issue}>" if issue
|
||||
end
|
||||
|
||||
case field_format
|
||||
when 'version'
|
||||
version = Version.find(detail.value) rescue nil
|
||||
value = escape version.to_s
|
||||
end
|
||||
|
||||
value = '-' if value.empty?
|
||||
|
||||
result = { title: title, value: value }
|
||||
result[:short] = true if short
|
||||
result
|
||||
end
|
||||
|
||||
def mentions(text)
|
||||
return nil if text.nil?
|
||||
names = extract_usernames text
|
||||
names.present? ? '\nTo: ' + names.join(', ') : nil
|
||||
end
|
||||
|
||||
def extract_usernames(text = '')
|
||||
text = '' if text.nil?
|
||||
|
||||
# rocketchat usernames may only contain lowercase letters, numbers,
|
||||
# dashes, dots and underscores and must start with a letter or number.
|
||||
text.scan(/@[a-z0-9][a-z0-9_\-.]*/).uniq
|
||||
end
|
||||
end
|
||||
end
|
||||
34
lib/redmine_messenger/patches/issue_patch.rb
Normal file
34
lib/redmine_messenger/patches/issue_patch.rb
Normal file
@@ -0,0 +1,34 @@
|
||||
# Redmine Messenger plugin for Redmine
|
||||
|
||||
module RedmineMessenger
|
||||
module Patches
|
||||
module IssuePatch
|
||||
def self.included(base) # :nodoc:
|
||||
base.send(:include, InstanceMethods)
|
||||
base.class_eval do
|
||||
after_create :create_from_issue
|
||||
after_save :save_from_issue
|
||||
end
|
||||
end
|
||||
|
||||
module InstanceMethods
|
||||
def create_from_issue
|
||||
@create_already_fired = true
|
||||
Redmine::Hook.call_hook(:redmine_rocketchat_issues_new_after_save, issue: self)
|
||||
true
|
||||
end
|
||||
|
||||
def save_from_issue
|
||||
unless @create_already_fired
|
||||
Redmine::Hook.call_hook(:redmine_rocketchat_issues_edit_after_save, issue: self, journal: self.current_journal) unless self.current_journal.nil?
|
||||
end
|
||||
true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
unless Issue.included_modules.include? RedmineMessenger::Patches::IssuePatch
|
||||
Issue.send(:include, RedmineMessenger::Patches::IssuePatch)
|
||||
end
|
||||
@@ -1,33 +0,0 @@
|
||||
module RedmineRocketchat
|
||||
module IssuePatch
|
||||
def self.included(base) # :nodoc:
|
||||
base.extend(ClassMethods)
|
||||
base.send(:include, InstanceMethods)
|
||||
|
||||
base.class_eval do
|
||||
unloadable # Send unloadable so it will not be unloaded in development
|
||||
after_create :create_from_issue
|
||||
after_save :save_from_issue
|
||||
end
|
||||
end
|
||||
|
||||
module ClassMethods
|
||||
end
|
||||
|
||||
module InstanceMethods
|
||||
def create_from_issue
|
||||
@create_already_fired = true
|
||||
Redmine::Hook.call_hook(:redmine_rocketchat_issues_new_after_save, { :issue => self})
|
||||
return true
|
||||
end
|
||||
|
||||
def save_from_issue
|
||||
unless @create_already_fired
|
||||
Redmine::Hook.call_hook(:redmine_rocketchat_issues_edit_after_save, {:issue => self, :journal => self.current_journal}) unless self.current_journal.nil?
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,320 +0,0 @@
|
||||
require 'httpclient'
|
||||
|
||||
class RocketchatListener < Redmine::Hook::Listener
|
||||
def redmine_rocketchat_issues_new_after_save(context={})
|
||||
issue = context[:issue]
|
||||
|
||||
channels = channels_for_project issue.project
|
||||
url = url_for_project issue.project
|
||||
post_private_issues = post_private_issues_for_project(issue.project)
|
||||
|
||||
return unless channels.present? and url
|
||||
return if issue.is_private? and post_private_issues != '1'
|
||||
|
||||
msg = "[#{escape issue.project}] #{escape issue.author} created <#{object_url issue}|#{escape issue}>#{mentions issue.description if Setting.plugin_redmine_rocketchat[:auto_mentions] == '1'}"
|
||||
|
||||
attachment = {}
|
||||
attachment[:text] = escape issue.description if issue.description and Setting.plugin_redmine_rocketchat[:new_include_description] == '1'
|
||||
attachment[:fields] = [{
|
||||
:title => I18n.t(:field_status),
|
||||
:value => escape(issue.status.to_s),
|
||||
:short => true
|
||||
}, {
|
||||
:title => I18n.t(:field_priority),
|
||||
:value => escape(issue.priority.to_s),
|
||||
:short => true
|
||||
}, {
|
||||
:title => I18n.t(:field_assigned_to),
|
||||
:value => escape(issue.assigned_to.to_s),
|
||||
:short => true
|
||||
}]
|
||||
|
||||
attachment[:fields] << {
|
||||
:title => I18n.t(:field_watcher),
|
||||
:value => escape(issue.watcher_users.join(', ')),
|
||||
:short => true
|
||||
} if Setting.plugin_redmine_rocketchat[:display_watchers] == '1'
|
||||
|
||||
speak msg, channels, attachment, url
|
||||
end
|
||||
|
||||
def redmine_rocketchat_issues_edit_after_save(context={})
|
||||
issue = context[:issue]
|
||||
journal = context[:journal]
|
||||
|
||||
channels = channels_for_project issue.project
|
||||
url = url_for_project issue.project
|
||||
post_private_issues = post_private_issues_for_project(issue.project)
|
||||
post_private_notes = post_private_notes_for_project(issue.project)
|
||||
|
||||
return unless channels.present? and url and Setting.plugin_redmine_rocketchat[:post_updates] == '1'
|
||||
return if issue.is_private? and post_private_issues != '1'
|
||||
return if journal.private_notes? and post_private_notes != '1'
|
||||
|
||||
msg = "[#{escape issue.project}] #{escape journal.user.to_s} updated <#{object_url issue}|#{escape issue}>#{mentions journal.notes if Setting.plugin_redmine_rocketchat[:auto_mentions] == '1'}"
|
||||
|
||||
attachment = {}
|
||||
attachment[:text] = escape journal.notes if journal.notes and Setting.plugin_redmine_rocketchat[:updated_include_description] == '1'
|
||||
attachment[:fields] = journal.details.map { |d| detail_to_field d }
|
||||
|
||||
speak msg, channels, attachment, url
|
||||
end
|
||||
|
||||
def model_changeset_scan_commit_for_issue_ids_pre_issue_update(context={})
|
||||
issue = context[:issue]
|
||||
journal = issue.current_journal
|
||||
changeset = context[:changeset]
|
||||
|
||||
channels = channels_for_project issue.project
|
||||
url = url_for_project issue.project
|
||||
post_private_issues = post_private_issues_for_project(issue.project)
|
||||
|
||||
return unless channels.present? and url and issue.save
|
||||
return if issue.is_private? and post_private_issues != '1'
|
||||
|
||||
msg = "[#{escape issue.project}] #{escape journal.user.to_s} updated <#{object_url issue}|#{escape issue}>"
|
||||
|
||||
repository = changeset.repository
|
||||
|
||||
if Setting.host_name.to_s =~ /\A(https?\:\/\/)?(.+?)(\:(\d+))?(\/.+)?\z/i
|
||||
host, port, prefix = $2, $4, $5
|
||||
revision_url = Rails.application.routes.url_for(
|
||||
:controller => 'repositories',
|
||||
:action => 'revision',
|
||||
:id => repository.project,
|
||||
:repository_id => repository.identifier_param,
|
||||
:rev => changeset.revision,
|
||||
:host => host,
|
||||
:protocol => Setting.protocol,
|
||||
:port => port,
|
||||
:script_name => prefix
|
||||
)
|
||||
else
|
||||
revision_url = Rails.application.routes.url_for(
|
||||
:controller => 'repositories',
|
||||
:action => 'revision',
|
||||
:id => repository.project,
|
||||
:repository_id => repository.identifier_param,
|
||||
:rev => changeset.revision,
|
||||
:host => Setting.host_name,
|
||||
:protocol => Setting.protocol
|
||||
)
|
||||
end
|
||||
|
||||
attachment = {}
|
||||
attachment[:text] = ll(Setting.default_language, :text_status_changed_by_changeset, "<#{revision_url}|#{escape changeset.comments}>")
|
||||
attachment[:fields] = journal.details.map { |d| detail_to_field d }
|
||||
|
||||
speak msg, channels, attachment, url
|
||||
end
|
||||
|
||||
def controller_wiki_edit_after_save(context = { })
|
||||
return unless Setting.plugin_redmine_rocketchat[:post_wiki_updates] == '1'
|
||||
|
||||
project = context[:project]
|
||||
page = context[:page]
|
||||
|
||||
user = page.content.author
|
||||
project_url = "<#{object_url project}|#{escape project}>"
|
||||
page_url = "<#{object_url page}|#{page.title}>"
|
||||
comment = "[#{project_url}] #{page_url} updated by *#{user}*"
|
||||
|
||||
channels = channels_for_project project
|
||||
url = url_for_project project
|
||||
|
||||
return unless channels.present? and url
|
||||
|
||||
attachment = nil
|
||||
unless page.content.comments.empty?
|
||||
attachment = {}
|
||||
attachment[:text] = "#{escape page.content.comments}"
|
||||
end
|
||||
|
||||
speak comment, channels, attachment, url
|
||||
end
|
||||
|
||||
def speak(msg, channels, attachment=nil, url=nil)
|
||||
return if channels.blank?
|
||||
|
||||
url = Setting.plugin_redmine_rocketchat[:rocketchat_url] unless url
|
||||
username = Setting.plugin_redmine_rocketchat[:username]
|
||||
icon = Setting.plugin_redmine_rocketchat[:icon]
|
||||
|
||||
params = {
|
||||
:text => msg,
|
||||
:link_names => 1,
|
||||
}
|
||||
|
||||
params[:username] = username if username
|
||||
|
||||
|
||||
params[:attachments] = [attachment] if attachment
|
||||
|
||||
if icon and not icon.empty?
|
||||
if icon.start_with? ':'
|
||||
params[:icon_emoji] = icon
|
||||
else
|
||||
params[:icon_url] = icon
|
||||
end
|
||||
end
|
||||
|
||||
channels.each do |channel|
|
||||
params[:channel] = channel
|
||||
|
||||
begin
|
||||
client = HTTPClient.new
|
||||
client.ssl_config.cert_store.set_default_paths
|
||||
client.ssl_config.ssl_version = :auto
|
||||
client.ssl_config.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
||||
client.post_async url, {:payload => params.to_json}
|
||||
rescue Exception => e
|
||||
Rails.logger.warn("cannot connect to #{url}")
|
||||
Rails.logger.warn(e)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def escape(msg)
|
||||
msg.to_s.gsub('&', '&').gsub('<', '<').gsub('>', '>')
|
||||
end
|
||||
|
||||
def object_url(obj)
|
||||
if Setting.host_name.to_s =~ /\A(https?\:\/\/)?(.+?)(\:(\d+))?(\/.+)?\z/i
|
||||
host, port, prefix = $2, $4, $5
|
||||
Rails.application.routes.url_for(obj.event_url({:host => host, :protocol => Setting.protocol, :port => port, :script_name => prefix}))
|
||||
else
|
||||
Rails.application.routes.url_for(obj.event_url({:host => Setting.host_name, :protocol => Setting.protocol}))
|
||||
end
|
||||
end
|
||||
|
||||
def url_for_project(proj)
|
||||
return nil if proj.blank?
|
||||
|
||||
cf = ProjectCustomField.find_by_name('Rocket.Chat URL')
|
||||
|
||||
[
|
||||
(proj.custom_value_for(cf).value rescue nil),
|
||||
(url_for_project proj.parent),
|
||||
Setting.plugin_redmine_rocketchat[:rocketchat_url],
|
||||
].flatten.find(&:present?)
|
||||
end
|
||||
|
||||
def post_private_issues_for_project(proj)
|
||||
return nil if proj.blank?
|
||||
|
||||
cf = ProjectCustomField.find_by_name('Rocket.Chat Post private issues')
|
||||
[
|
||||
(proj.custom_value_for(cf).value rescue nil),
|
||||
(post_private_issues_for_project proj.parent),
|
||||
Setting.plugin_redmine_rocketchat[:post_private_issues],
|
||||
].flatten.find(&:present?)
|
||||
end
|
||||
|
||||
def post_private_notes_for_project(proj)
|
||||
return nil if proj.blank?
|
||||
|
||||
cf = ProjectCustomField.find_by_name('Rocket.Chat Post private notes')
|
||||
[
|
||||
(proj.custom_value_for(cf).value rescue nil),
|
||||
(post_private_notes_for_project proj.parent),
|
||||
Setting.plugin_redmine_rocketchat[:post_private_notes],
|
||||
].flatten.find(&:present?)
|
||||
end
|
||||
|
||||
def channels_for_project(proj)
|
||||
return nil if proj.blank?
|
||||
|
||||
cf = ProjectCustomField.find_by_name('Rocket.Chat Channel')
|
||||
val = [
|
||||
(proj.custom_value_for(cf).value rescue nil),
|
||||
(channels_for_project proj.parent),
|
||||
Setting.plugin_redmine_rocketchat[:channel],
|
||||
].flatten.find(&:present?)
|
||||
|
||||
# Channel name '-' or empty '' is reserved for NOT notifying
|
||||
return [] if val.nil? or val.to_s == ''
|
||||
return [] if val.to_s == '-'
|
||||
return val.split(",") if val.is_a? String
|
||||
val
|
||||
end
|
||||
|
||||
def detail_to_field(detail)
|
||||
field_format = nil
|
||||
|
||||
if detail.property == "cf"
|
||||
key = CustomField.find(detail.prop_key).name rescue nil
|
||||
title = key
|
||||
field_format = CustomField.find(detail.prop_key).field_format rescue nil
|
||||
elsif detail.property == 'attachment'
|
||||
key = 'attachment'
|
||||
title = I18n.t :label_attachment
|
||||
else
|
||||
key = detail.prop_key.to_s.sub('_id', '')
|
||||
title = I18n.t "field_#{key}"
|
||||
end
|
||||
|
||||
short = true
|
||||
value = escape detail.value.to_s
|
||||
|
||||
case key
|
||||
when 'title', 'subject', 'description'
|
||||
short = false
|
||||
when 'tracker'
|
||||
tracker = Tracker.find(detail.value) rescue nil
|
||||
value = escape tracker.to_s
|
||||
when 'project'
|
||||
project = Project.find(detail.value) rescue nil
|
||||
value = escape project.to_s
|
||||
when 'status'
|
||||
status = IssueStatus.find(detail.value) rescue nil
|
||||
value = escape status.to_s
|
||||
when 'priority'
|
||||
priority = IssuePriority.find(detail.value) rescue nil
|
||||
value = escape priority.to_s
|
||||
when 'category'
|
||||
category = IssueCategory.find(detail.value) rescue nil
|
||||
value = escape category.to_s
|
||||
when 'assigned_to'
|
||||
user = User.find(detail.value) rescue nil
|
||||
value = escape user.to_s
|
||||
when 'fixed_version'
|
||||
version = Version.find(detail.value) rescue nil
|
||||
value = escape version.to_s
|
||||
when 'attachment'
|
||||
attachment = Attachment.find(detail.prop_key) rescue nil
|
||||
value = "<#{object_url attachment}|#{escape attachment.filename}>" if attachment
|
||||
when 'parent'
|
||||
issue = Issue.find(detail.value) rescue nil
|
||||
value = "<#{object_url issue}|#{escape issue}>" if issue
|
||||
end
|
||||
|
||||
case field_format
|
||||
when 'version'
|
||||
version = Version.find(detail.value) rescue nil
|
||||
value = escape version.to_s
|
||||
end
|
||||
|
||||
value = '-' if value.empty?
|
||||
|
||||
result = { :title => title, :value => value }
|
||||
result[:short] = true if short
|
||||
result
|
||||
end
|
||||
|
||||
def mentions text
|
||||
return nil if text.nil?
|
||||
names = extract_usernames text
|
||||
names.present? ? '\nTo: ' + names.join(', ') : nil
|
||||
end
|
||||
|
||||
def extract_usernames text = ''
|
||||
if text.nil?
|
||||
text = ''
|
||||
end
|
||||
|
||||
# rocketchat usernames may only contain lowercase letters, numbers,
|
||||
# dashes, dots and underscores and must start with a letter or number.
|
||||
text.scan(/@[a-z0-9][a-z0-9_\-.]*/).uniq
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user