pechkin 1.3.1 → 1.3.2

Sign up to get free protection for your applications and to get access to all the features.
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