pechkin 1.3.1 → 1.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 21153645eb45d32b113d2c95191e79ac5568a10829b3989ccc9f75da7b53bf9e
4
- data.tar.gz: d80b4bbbeb7e4bdfeb251e358bb0a9c99d50eae96c5078b688bce5e12a3c73e3
3
+ metadata.gz: 6a2ecda5dd85e6cb2dd48ccb18eb1966559fa8d6539239b1e6def0377324c765
4
+ data.tar.gz: 9be0c8e01ceec5f0e19f2c44a9a7d10a2c09c32ddcec26d5fba5d43f808eaec2
5
5
  SHA512:
6
- metadata.gz: 30e9654efb5c1a11c4816feb51fc494be1251e106a2fac682be9cb68738faec6e8b45c747329f90cff226ef1fe9df2c097bb0083c79d57d55b020982773dd0b8
7
- data.tar.gz: 62d6113f5ef1aedfe36c3eb86bc619d7cbac2cd9e54a37f64cbd293b1856efe47ba572bdf25efcc2a20f7b1affbbffe8cc2e74ad9784091cc69f7fa232ebe19b
6
+ metadata.gz: 2bdf5bd548de267c3cfc9a7a45be9a451df75bf288e9403dfe1ed9e3f748318fd1acd85f5070f310890b5947b3f478ea4cdab817b8cba9902cf5f23ad35cd431
7
+ data.tar.gz: c18c214ef31484ccc3dd79af5c55270f1fdcea84ee198e7ef5c3adc39b76496914ba703bc2d5e7f45beec62fb25dd71942cdf323a82b02a35d641a6aec420d6c
@@ -14,8 +14,6 @@ require_relative 'pechkin/handler'
14
14
  require_relative 'pechkin/message_matcher'
15
15
  require_relative 'pechkin/message_template'
16
16
  require_relative 'pechkin/connector'
17
- require_relative 'pechkin/connector_slack'
18
- require_relative 'pechkin/connector_telegram'
19
17
  require_relative 'pechkin/channel'
20
18
  require_relative 'pechkin/configuration'
21
19
  require_relative 'pechkin/substitute'
@@ -34,9 +34,10 @@ module Pechkin
34
34
  response(err.code, data)
35
35
  end
36
36
 
37
- def process_unhandled_error(_req, err)
37
+ def process_unhandled_error(req, err)
38
38
  data = { status: 'error', message: err.message }
39
39
  logger.error("#{err.message}\n\t" + err.backtrace.join("\n\t"))
40
+ logger.error(req.body.read)
40
41
  response(503, data)
41
42
  end
42
43
  end
@@ -13,9 +13,9 @@ module Pechkin
13
13
  def create_connector(bot)
14
14
  case bot.connector
15
15
  when 'tg', 'telegram'
16
- TelegramConnector.new(bot.token, bot.name)
16
+ Connector::Telegram.new(bot.token, bot.name)
17
17
  when 'slack'
18
- SlackConnector.new(bot.token, bot.name)
18
+ Connector::Slack.new(bot.token, bot.name)
19
19
  else
20
20
  raise 'Unknown connector ' + bot.connector + ' for ' + bot.name
21
21
  end
@@ -4,26 +4,6 @@ require 'uri'
4
4
  require 'json'
5
5
  require 'cgi'
6
6
 
7
- module Pechkin
8
- # Base connector
9
- class Connector
10
- def send_message(chat, message, message_desc); end
11
-
12
- def preview(chats, message, _message_desc)
13
- "Connector: #{self.class.name}; Chats: #{chats.join(', ')}\n" \
14
- "Message:\n#{message}"
15
- end
16
-
17
- def post_data(url, data, headers: {})
18
- uri = URI.parse(url)
19
- headers = { 'Content-Type' => 'application/json' }.merge(headers)
20
- http = Net::HTTP.new(uri.host, uri.port)
21
- http.use_ssl = url.start_with?('https://')
22
-
23
- request = Net::HTTP::Post.new(uri.request_uri, headers)
24
- request.body = data.to_json
25
-
26
- http.request(request)
27
- end
28
- end
29
- end
7
+ require_relative 'connector/base'
8
+ require_relative 'connector/slack'
9
+ require_relative 'connector/telegram'
@@ -0,0 +1,29 @@
1
+ module Pechkin
2
+ module Connector
3
+ # Base connector
4
+ class Base
5
+ DEFAULT_HEADERS = {
6
+ 'Content-Type' => 'application/json; charset=UTF-8'
7
+ }.freeze
8
+
9
+ def send_message(chat, message, message_desc); end
10
+
11
+ def preview(chats, message, _message_desc)
12
+ "Connector: #{self.class.name}; Chats: #{chats.join(', ')}\n" \
13
+ "Message:\n#{message}"
14
+ end
15
+
16
+ def post_data(url, data, headers: {})
17
+ uri = URI.parse(url)
18
+ headers = DEFAULT_HEADERS.merge(headers)
19
+ http = Net::HTTP.new(uri.host, uri.port)
20
+ http.use_ssl = url.start_with?('https://')
21
+
22
+ request = Net::HTTP::Post.new(uri.request_uri, headers)
23
+ request.body = data.to_json
24
+
25
+ http.request(request)
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,30 @@
1
+ module Pechkin
2
+ module Connector
3
+ class Slack < Connector::Base # :nodoc:
4
+ attr_reader :name
5
+
6
+ def initialize(bot_token, name)
7
+ @headers = { 'Authorization' => "Bearer #{bot_token}" }
8
+ @name = name
9
+ end
10
+
11
+ def send_message(channel, message, message_desc)
12
+ text = CGI.unescape_html(message)
13
+
14
+ attachments = message_desc['slack_attachments'] || {}
15
+
16
+ if text.strip.empty? && attachments.empty?
17
+ return { channel: channel, code: 400,
18
+ response: 'Internal error: message is empty' }
19
+ end
20
+
21
+ params = { channel: channel, text: text, attachments: attachments }
22
+
23
+ url = 'https://slack.com/api/chat.postMessage'
24
+ response = post_data(url, params, headers: @headers)
25
+
26
+ { channel: channel, code: response.code.to_i, response: response.body }
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,26 @@
1
+ module Pechkin
2
+ module Connector
3
+ class Telegram < Connector::Base # :nodoc:
4
+ attr_reader :name
5
+
6
+ def initialize(bot_token, name)
7
+ @bot_token = bot_token
8
+ @name = name
9
+ end
10
+
11
+ def send_message(chat_id, message, message_desc)
12
+ options = { parse_mode: message_desc['telegram_parse_mode'] || 'HTML' }
13
+ params = options.update(chat_id: chat_id, text: message)
14
+
15
+ response = post_data(method_url('sendMessage'), params)
16
+ { chat_id: chat_id, code: response.code.to_i, response: response.body }
17
+ end
18
+
19
+ private
20
+
21
+ def method_url(method)
22
+ "https://api.telegram.org/bot#{@bot_token}/#{method}"
23
+ end
24
+ end
25
+ end
26
+ end
@@ -11,7 +11,7 @@ module Pechkin
11
11
  @logger = Logger.new(IO::NULL)
12
12
  @stdout = stdout
13
13
  @stderr = stderr
14
- @message_matcher = MessageMatcher.new
14
+ @message_matcher = MessageMatcher.new(@logger)
15
15
  end
16
16
 
17
17
  # Handles message request. Each request has three parameters: channel id,
@@ -35,7 +35,7 @@ module Pechkin
35
35
  if message_allowed?(message_config, data)
36
36
  chats.map { |chat| connector.send_message(chat, text, message_config) }
37
37
  else
38
- logger.info "#{channel_id}/#{msg_id}: " \
38
+ logger.warn "#{channel_id}/#{msg_id}: " \
39
39
  "Skip sending message. Because it's not allowed"
40
40
  []
41
41
  end
@@ -10,6 +10,13 @@ module Pechkin
10
10
  class MessageMatcher
11
11
  KEY_ALLOW = 'allow'.freeze
12
12
  KEY_FORBID = 'forbid'.freeze
13
+
14
+ attr_reader :logger
15
+
16
+ def initialize(logger)
17
+ @logger = logger
18
+ end
19
+
13
20
  # Checks data object against allow / forbid rule sets in message
14
21
  # configuration. If data object matches rules it means we can process this
15
22
  # data and send message.
@@ -23,10 +30,10 @@ module Pechkin
23
30
 
24
31
  if message_config.key?(KEY_ALLOW)
25
32
  rules = message_config[KEY_ALLOW]
26
- rules.any? { |r| check_rule(r, data) }
33
+ rules.any? { |r| check_rule(r, r, data) }
27
34
  elsif message_config.key?(KEY_FORBID)
28
35
  rules = message_config[KEY_FORBID]
29
- rules.all? { |r| !check_rule(r, data) }
36
+ rules.all? { |r| !check_rule(r, r, data) }
30
37
  else
31
38
  true
32
39
  end
@@ -43,35 +50,42 @@ module Pechkin
43
50
  # Check rule object against data. Rules are checked recursievly, i.e. we
44
51
  # can take one field in rule and check it separately as new rule. If all
45
52
  # fields are passed check then whole rule passed.
46
- def check_rule(rule, data)
47
- if rule.is_a?(Hash)
48
- check_hash_rule(rule, data)
49
- elsif rule.is_a?(Array)
50
- check_array_rule(rule, data)
51
- elsif rule.is_a?(String)
52
- check_string_rule(rule, data)
53
- else
54
- rule.eql?(data)
53
+ def check_rule(top_rule, sub_rule, data)
54
+ result = if sub_rule.is_a?(Hash)
55
+ check_hash_rule(top_rule, sub_rule, data)
56
+ elsif sub_rule.is_a?(Array)
57
+ check_array_rule(top_rule, sub_rule, data)
58
+ elsif sub_rule.is_a?(String)
59
+ check_string_rule(top_rule, sub_rule, data)
60
+ else
61
+ sub_rule.eql?(data)
62
+ end
63
+
64
+ unless result
65
+ logger.info "Expected #{sub_rule.to_json} got #{data.to_json} when" \
66
+ " checking #{top_rule.to_json}"
55
67
  end
68
+
69
+ result
56
70
  end
57
71
 
58
- def check_hash_rule(hash, data)
72
+ def check_hash_rule(top_rule, hash, data)
59
73
  return false unless data.is_a?(Hash)
60
74
 
61
75
  hash.all? do |key, value|
62
- data.key?(key) && check_rule(value, data[key])
76
+ data.key?(key) && check_rule(top_rule, value, data[key])
63
77
  end
64
78
  end
65
79
 
66
- def check_array_rule(array, data)
80
+ def check_array_rule(top_rule, array, data)
67
81
  return false unless data.is_a?(Array)
68
82
 
69
83
  # Deep array check needs to be done against all elements so we zip arrays
70
84
  # to pair each rule with data element
71
- array.zip(data).all? { |r, d| check_rule(r, d) }
85
+ array.zip(data).all? { |r, d| check_rule(top_rule, r, d) }
72
86
  end
73
87
 
74
- def check_string_rule(str, data)
88
+ def check_string_rule(_top_rule, str, data)
75
89
  str.eql? data
76
90
  end
77
91
  end
@@ -1,7 +1,7 @@
1
1
  module Pechkin
2
2
  # Keeps actual version
3
3
  module Version
4
- VERSION = [1, 3, 1].freeze
4
+ VERSION = [1, 3, 2].freeze
5
5
  class << self
6
6
  def version_string
7
7
  VERSION.join('.')
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pechkin
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.1
4
+ version: 1.3.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ilya Arkhanhelsky
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-02-07 00:00:00.000000000 Z
11
+ date: 2020-04-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: htauth
@@ -97,8 +97,9 @@ files:
97
97
  - lib/pechkin/configuration/configuration_loader_views.rb
98
98
  - lib/pechkin/configuration/model.rb
99
99
  - lib/pechkin/connector.rb
100
- - lib/pechkin/connector_slack.rb
101
- - lib/pechkin/connector_telegram.rb
100
+ - lib/pechkin/connector/base.rb
101
+ - lib/pechkin/connector/slack.rb
102
+ - lib/pechkin/connector/telegram.rb
102
103
  - lib/pechkin/exceptions.rb
103
104
  - lib/pechkin/handler.rb
104
105
  - lib/pechkin/message_matcher.rb
@@ -1,28 +0,0 @@
1
- module Pechkin # :nodoc:
2
- class SlackConnector < Connector # :nodoc:
3
- attr_reader :name
4
-
5
- def initialize(bot_token, name)
6
- @headers = { 'Authorization' => "Bearer #{bot_token}" }
7
- @name = name
8
- end
9
-
10
- def send_message(channel, message, message_desc)
11
- text = CGI.unescape_html(message)
12
-
13
- attachments = message_desc['slack_attachments'] || {}
14
-
15
- if text.strip.empty? && attachments.empty?
16
- return { channel: channel, code: 400,
17
- response: 'Internal error: message is empty' }
18
- end
19
-
20
- params = { channel: channel, text: text, attachments: attachments }
21
-
22
- url = 'https://slack.com/api/chat.postMessage'
23
- response = post_data(url, params, headers: @headers)
24
-
25
- { channel: channel, code: response.code.to_i, response: response.body }
26
- end
27
- end
28
- end
@@ -1,24 +0,0 @@
1
- module Pechkin
2
- class TelegramConnector < Connector #:nodoc:
3
- attr_reader :name
4
-
5
- def initialize(bot_token, name)
6
- @bot_token = bot_token
7
- @name = name
8
- end
9
-
10
- def send_message(chat_id, message, message_desc)
11
- options = { parse_mode: message_desc['telegram_parse_mode'] || 'HTML' }
12
- params = options.update(chat_id: chat_id, text: message)
13
-
14
- response = post_data(method_url('sendMessage'), params)
15
- { chat_id: chat_id, code: response.code.to_i, response: response.body }
16
- end
17
-
18
- private
19
-
20
- def method_url(method)
21
- "https://api.telegram.org/bot#{@bot_token}/#{method}"
22
- end
23
- end
24
- end