Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Slack Username registration feature #112

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
91 changes: 83 additions & 8 deletions lib/redmine_slack/listener.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
require 'httpclient'

class SlackListener < Redmine::Hook::Listener

def initialize
@slack_username_custom_field = UserCustomField.find_by_name("Slack Username")
end

def controller_issues_new_after_save(context={})
issue = context[:issue]

Expand All @@ -10,7 +15,8 @@ def controller_issues_new_after_save(context={})
return unless channel and url
return if issue.is_private?

msg = "[#{escape issue.project}] #{escape issue.author} created <#{object_url issue}|#{escape issue}>#{mentions issue.description}"
mentions = build_mentions(issue.assigned_to, issue.description, issue.project.identifier)
msg = "[#{escape issue.project}] #{escape issue.author} created <#{object_url issue}|#{escape issue}>#{mentions}"

attachment = {}
attachment[:text] = escape issue.description if issue.description
Expand Down Expand Up @@ -48,7 +54,9 @@ def controller_issues_edit_after_save(context={})
return if issue.is_private?
return if journal.private_notes?

msg = "[#{escape issue.project}] #{escape journal.user.to_s} updated <#{object_url issue}|#{escape issue}>#{mentions journal.notes}"
assignee_user = get_assignee_user journal
mentions = build_mentions(assignee_user, journal.notes, issue.project.identifier)
msg = "[#{escape issue.project}] #{escape journal.user.to_s} updated <#{object_url issue}#change-#{journal.id}|#{escape issue}>#{mentions}"

attachment = {}
attachment[:text] = escape journal.notes if journal.notes
Expand Down Expand Up @@ -265,18 +273,85 @@ def detail_to_field(detail)
result
end

def mentions text
names = extract_usernames text
names.present? ? "\nTo: " + names.join(', ') : nil
def to_slack_usernames(usernames, project_id)
return [] if usernames.empty?

slack_usernames = usernames.map { |username| find_slack_username(username, project_id) }
slack_usernames.select { |n| n.present? }
end

def find_slack_username(redmine_user, project_id)
return nil if redmine_user.nil?

if redmine_user.is_a? User
user = redmine_user
else
user = User.find_by_login(redmine_user)
end

if user.present?
val = user.custom_value_for(@slack_username_custom_field).value rescue nil
if val.nil?
return val
end

result = nil
slack_usernames = val.split(/\s?,\s*/)
slack_usernames.each { |n|
if n.include? ':'
proj_id, slack_username = n.split(':')
if project_id == proj_id
if slack_username != '-'
result = slack_username
else
result = nil
end
break
end
elsif n != '-'
result = n
end
}
result
end
end

def extract_usernames text = ''
# Extracts the @xxxxx from the given text and returns a list of usernames (only xxxxx parts)

if text.nil?
text = ''
end

# slack usernames may only contain lowercase letters, numbers,
# dashes and underscores and must start with a letter or number.
text.scan(/@[a-z0-9][a-z0-9_\-]*/).uniq
text.scan(/@[a-z0-9][a-z0-9_\-.]*/).uniq.each do |username|
# Remove the leading @
username.slice!(0)
end
end

def get_assignee_user(journal)
assignee_detail = journal.details.find do |detail|
detail.prop_key.to_s.sub('_id', '') == 'assigned_to'
end
if assignee_detail.present?
User.find(assignee_detail.value) rescue nil
end
end

def build_mentions(assignee_user, text, project_id)
# Get the assignee's Redmine User instance
assignee_slack_username = find_slack_username(assignee_user, project_id)

# Retrieve the mentioned Redmine usernames from the given text
mentioned_usernames = extract_usernames text
slack_usernames = to_slack_usernames(mentioned_usernames, project_id)

if assignee_slack_username.present?
slack_usernames << assignee_slack_username
end

# Slack usernames to be mentioned
slack_usernames = slack_usernames.uniq.map { |name| '@' + name }
slack_usernames.present? ? "\n" + slack_usernames.join(' ') : nil
end
end