2015-02-04 20:31:55 +00:00
|
|
|
# == Schema Information
|
|
|
|
#
|
|
|
|
# Table name: services
|
|
|
|
#
|
2015-03-04 22:14:00 +00:00
|
|
|
# id :integer not null, primary key
|
|
|
|
# type :string(255)
|
|
|
|
# title :string(255)
|
|
|
|
# project_id :integer
|
|
|
|
# created_at :datetime
|
|
|
|
# updated_at :datetime
|
|
|
|
# active :boolean default(FALSE), not null
|
|
|
|
# properties :text
|
|
|
|
# template :boolean default(FALSE)
|
|
|
|
# push_events :boolean default(TRUE)
|
|
|
|
# issues_events :boolean default(TRUE)
|
|
|
|
# merge_requests_events :boolean default(TRUE)
|
|
|
|
# tag_push_events :boolean default(TRUE)
|
2015-05-03 16:05:38 +00:00
|
|
|
# note_events :boolean default(TRUE), not null
|
2015-03-04 22:14:00 +00:00
|
|
|
#
|
2015-02-04 20:31:55 +00:00
|
|
|
|
|
|
|
require 'uri'
|
|
|
|
|
|
|
|
class IrkerService < Service
|
|
|
|
prop_accessor :colorize_messages, :recipients, :channels
|
|
|
|
validates :recipients, presence: true, if: :activated?
|
|
|
|
validate :check_recipients_count, if: :activated?
|
|
|
|
|
|
|
|
before_validation :get_channels
|
|
|
|
after_initialize :initialize_settings
|
|
|
|
|
|
|
|
# Writer for RSpec tests
|
|
|
|
attr_writer :settings
|
|
|
|
|
|
|
|
def initialize_settings
|
|
|
|
# See the documentation (doc/project_services/irker.md) for possible values
|
|
|
|
# here
|
|
|
|
@settings ||= {
|
|
|
|
server_ip: 'localhost',
|
|
|
|
server_port: 6659,
|
|
|
|
max_channels: 3,
|
|
|
|
default_irc_uri: nil
|
|
|
|
}
|
|
|
|
end
|
|
|
|
|
|
|
|
def title
|
|
|
|
'Irker (IRC gateway)'
|
|
|
|
end
|
|
|
|
|
|
|
|
def description
|
|
|
|
'Send IRC messages, on update, to a list of recipients through an Irker '\
|
|
|
|
'gateway.'
|
|
|
|
end
|
|
|
|
|
|
|
|
def help
|
|
|
|
msg = 'Recipients have to be specified with a full URI: '\
|
|
|
|
'irc[s]://irc.network.net[:port]/#channel. Special cases: if you want '\
|
|
|
|
'the channel to be a nickname instead, append ",isnick" to the channel '\
|
|
|
|
'name; if the channel is protected by a secret password, append '\
|
|
|
|
'"?key=secretpassword" to the URI.'
|
|
|
|
|
|
|
|
unless @settings[:default_irc].nil?
|
|
|
|
msg += ' Note that a default IRC URI is provided by this service\'s '\
|
|
|
|
"administrator: #{default_irc}. You can thus just give a channel name."
|
|
|
|
end
|
|
|
|
msg
|
|
|
|
end
|
|
|
|
|
|
|
|
def to_param
|
|
|
|
'irker'
|
|
|
|
end
|
|
|
|
|
2015-03-04 22:31:28 +00:00
|
|
|
def supported_events
|
|
|
|
%w(push)
|
|
|
|
end
|
|
|
|
|
|
|
|
def execute(data)
|
|
|
|
return unless supported_events.include?(data[:object_kind])
|
|
|
|
|
2015-02-04 20:31:55 +00:00
|
|
|
IrkerWorker.perform_async(project_id, channels,
|
2015-03-04 22:31:28 +00:00
|
|
|
colorize_messages, data, @settings)
|
2015-02-04 20:31:55 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
def fields
|
|
|
|
[
|
|
|
|
{ type: 'textarea', name: 'recipients',
|
|
|
|
placeholder: 'Recipients/channels separated by whitespaces' },
|
|
|
|
{ type: 'checkbox', name: 'colorize_messages' },
|
|
|
|
]
|
|
|
|
end
|
|
|
|
|
|
|
|
private
|
|
|
|
|
|
|
|
def check_recipients_count
|
|
|
|
return true if recipients.nil? || recipients.empty?
|
|
|
|
|
|
|
|
if recipients.split(/\s+/).count > max_chans
|
|
|
|
errors.add(:recipients, "are limited to #{max_chans}")
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def max_chans
|
|
|
|
@settings[:max_channels]
|
|
|
|
end
|
|
|
|
|
|
|
|
def get_channels
|
|
|
|
return true unless :activated?
|
|
|
|
return true if recipients.nil? || recipients.empty?
|
|
|
|
|
|
|
|
map_recipients
|
|
|
|
|
|
|
|
errors.add(:recipients, 'are all invalid') if channels.empty?
|
|
|
|
true
|
|
|
|
end
|
|
|
|
|
|
|
|
def map_recipients
|
|
|
|
self.channels = recipients.split(/\s+/).map do |recipient|
|
|
|
|
format_channel default_irc_uri, recipient
|
|
|
|
end
|
|
|
|
channels.reject! &:nil?
|
|
|
|
end
|
|
|
|
|
|
|
|
def default_irc_uri
|
|
|
|
default_irc = @settings[:default_irc_uri]
|
|
|
|
if !(default_irc.nil? || default_irc[-1] == '/')
|
|
|
|
default_irc += '/'
|
|
|
|
end
|
|
|
|
default_irc
|
|
|
|
end
|
|
|
|
|
|
|
|
def format_channel(default_irc, recipient)
|
|
|
|
cnt = 0
|
|
|
|
url = nil
|
|
|
|
|
|
|
|
# Try to parse the chan as a full URI
|
|
|
|
begin
|
|
|
|
uri = URI.parse(recipient)
|
|
|
|
raise URI::InvalidURIError if uri.scheme.nil? && cnt == 0
|
|
|
|
rescue URI::InvalidURIError
|
|
|
|
unless default_irc.nil?
|
|
|
|
cnt += 1
|
|
|
|
recipient = "#{default_irc}#{recipient}"
|
|
|
|
retry if cnt == 1
|
|
|
|
end
|
|
|
|
else
|
|
|
|
url = consider_uri uri
|
|
|
|
end
|
|
|
|
url
|
|
|
|
end
|
|
|
|
|
|
|
|
def consider_uri(uri)
|
|
|
|
# Authorize both irc://domain.com/#chan and irc://domain.com/chan
|
2015-04-10 16:30:02 +00:00
|
|
|
if uri.is_a?(URI) && uri.scheme[/^ircs?\z/] && !uri.path.nil?
|
2015-02-04 20:31:55 +00:00
|
|
|
# Do not authorize irc://domain.com/
|
|
|
|
if uri.fragment.nil? && uri.path.length > 1
|
|
|
|
uri.to_s
|
|
|
|
else
|
|
|
|
# Authorize irc://domain.com/smthg#chan
|
|
|
|
# The irker daemon will deal with it by concatenating smthg and
|
|
|
|
# chan, thus sending messages on #smthgchan
|
|
|
|
uri.to_s
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|