summaryrefslogtreecommitdiff
path: root/app/models/integrations/irker.rb
blob: 780f4bef0c97211fea18cdd8a16d8426e5d85f86 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
# frozen_string_literal: true

require 'uri'

module Integrations
  class Irker < Integration
    prop_accessor :server_host, :server_port, :default_irc_uri
    prop_accessor :recipients, :channels
    boolean_accessor :colorize_messages
    validates :recipients, presence: true, if: :validate_recipients?

    before_validation :get_channels

    def title
      s_('IrkerService|irker (IRC gateway)')
    end

    def description
      s_('IrkerService|Send update messages to an irker server.')
    end

    def self.to_param
      'irker'
    end

    def self.supported_events
      %w[push]
    end

    def execute(data)
      return unless supported_events.include?(data[:object_kind])

      if Feature.enabled?(:rename_integrations_workers)
        Integrations::IrkerWorker.perform_async(
          project_id, channels,
          colorize_messages, data, settings
        )
      else
        ::IrkerWorker.perform_async(
          project_id, channels,
          colorize_messages, data, settings
        )
      end
    end

    def settings
      {
        server_host: server_host.presence || 'localhost',
        server_port: server_port.presence || 6659
      }
    end

    def fields
      recipients_docs_link = ActionController::Base.helpers.link_to(
        s_('IrkerService|How to enter channels or users?'),
        Rails.application.routes.url_helpers.help_page_url(
          'user/project/integrations/irker',
          anchor: 'enter-irker-recipients'
        ),
        target: '_blank', rel: 'noopener noreferrer'
      )

      [
        { type: 'text', name: 'server_host', placeholder: 'localhost', title: s_('IrkerService|Server host (optional)'),
          help: s_('IrkerService|irker daemon hostname (defaults to localhost).') },
        { type: 'text', name: 'server_port', placeholder: 6659, title: s_('IrkerService|Server port (optional)'),
          help: s_('IrkerService|irker daemon port (defaults to 6659).') },
        { type: 'text', name: 'default_irc_uri', title: s_('IrkerService|Default IRC URI (optional)'),
          help: s_('IrkerService|URI to add before each recipient.'),
          placeholder: 'irc://irc.network.net:6697/' },
        { type: 'textarea', name: 'recipients', title: s_('IrkerService|Recipients'),
          placeholder: 'irc[s]://irc.network.net[:port]/#channel', required: true,
          help: format(
            s_('IrkerService|Channels and users separated by whitespaces. %{recipients_docs_link}').html_safe,
            recipients_docs_link: recipients_docs_link.html_safe
          ) },
        { type: 'checkbox', name: 'colorize_messages', title: _('Colorize messages') }
      ]
    end

    def help
      docs_link = ActionController::Base.helpers.link_to(
        _('Learn more.'),
        Rails.application.routes.url_helpers.help_page_url(
          'user/project/integrations/irker',
          anchor: 'set-up-an-irker-daemon'
        ),
        target: '_blank',
        rel: 'noopener noreferrer'
      )

      format(s_(
        'IrkerService|Send update messages to an irker server. ' \
        'Before you can use this, you need to set up the irker daemon. %{docs_link}'
      ).html_safe, docs_link: docs_link.html_safe)
    end

    private

    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(recipient)
      end
      channels.reject!(&:nil?)
    end

    def format_channel(recipient)
      uri = nil

      # Try to parse the chan as a full URI
      begin
        uri = consider_uri(URI.parse(recipient))
      rescue URI::InvalidURIError
      end

      unless uri.present? && default_irc_uri.nil?
        begin
          new_recipient = URI.join(default_irc_uri, '/', recipient).to_s
          uri = consider_uri(URI.parse(new_recipient))
        rescue StandardError
          log_error("Unable to create a valid URL", default_irc_uri: default_irc_uri, recipient: recipient)
        end
      end

      uri
    end

    def consider_uri(uri)
      return unless uri.is_a?(URI) && uri.scheme.present?
      # Authorize both irc://domain.com/#chan and irc://domain.com/chan
      return unless uri.scheme =~ /\Aircs?\z/ && !uri.path.nil?

      uri.to_s
    end
  end
end