slackify 0.1.4 โ†’ 0.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: 481a11f7bd67bbd0dade00117995381beb8719b0aba7f4b886372be0fb169d57
4
- data.tar.gz: 6d2fad59ffe6938d3bf0f3ba9bf754218faf1cfdeb7f64ed3fd5c586535f465f
3
+ metadata.gz: d5f1105d73a8943514708110e7b544fbaf8e300770f902103dcca4da95bfc9fa
4
+ data.tar.gz: b4a2b7dd7fcffed2cce55214fb96d2d09ea6ff40513d0360900187118857b6b8
5
5
  SHA512:
6
- metadata.gz: eec68d6c75d8537cc74036921025d68d14475d5f7f84b3d50d918d33a4f5dec96e2b2080956da0bf52717a24ee882282fd9eaced48f00abfefc30df843d7c0af
7
- data.tar.gz: 6e9888657a4a3ec71b86ed7714f21cfc275b9b1e90d0d1136ecba01dfc41853e9cc8b2a0dc58c15f8d8cbc35c3df77d6ea183190add7a2149b2bd759852ba3c2
6
+ metadata.gz: a80fbbb042403ae528e9563c7d3cdaec8462e30a6aaf033d1c93c804b9e78cb58e1b03cbd1c324cab8329eb697da35fe5d81e47dffe633643fd39192d507a802
7
+ data.tar.gz: f822f3cf7448b07f946f3a7d07b644d1ae70a57ee9cc8a9f06996c2de20f36561b4894294f5c350ab5c7a44394e75aed1e2a5ef1f127e1ee47cdac000975edbd
@@ -1,3 +1,24 @@
1
+ ## V0.3.2
2
+
3
+ * Add support for interactive block payloads ([b6cf1db](https://github.com/jusleg/slackify/commit/b6cf1dbb47b832037ebff56054efa27c9e3251dc)) by [@drose-shopify](https://github.com/drose-shopify)
4
+
5
+ ## V0.3.0
6
+
7
+ * Add code documentation and improve exception message
8
+ * Add whitelisting of bot ids in the configuration through `whitelisted_bot_ids=`
9
+ * Refactored Handler configuration into `Slackify::Router` and `Slackify::Handlers::Factory`
10
+ * Improved testing
11
+ * Remove the need to perform `Slackify.load_handler`
12
+ * **Breaking change:** Given that we now load the handlers on `Slack.configure`, the configuration step done in `config/application.rb` will have to be done in an initializer to have all the handler class loaded.
13
+
14
+ ## V0.2.0
15
+
16
+ Update `custom_event_subtype_handlers` to `custom_message_subtype_handlers` and add support for `custom_event_type_handlers`. This is a breaking change since we rename the field that was previously used. To fix, update any calls from `custom_event_subtype_handlers` to `custom_message_subtype_handlers` and you should be good to go.
17
+
18
+ ## V0.1.5
19
+
20
+ Update how the `bot_id` is set in the handler configuration. You can disable the slack auth test (which is used to obtain the bot_id) by setting `SLACK_AUTH_SKIP=1` in your environment variables. If you are running in a Rails environment other than production, development or staging and would like to use the bot for real requests, you can trigger a manual auth test by calling `Slackify.configuration.handlers.bot_auth_test`. Gemfile.lock was removed.
21
+
1
22
  ## V0.1.4
2
23
 
3
24
  Custom unhandled_handler configuration fix. It wouldn't let you set a custom one as the validation was checking for `is_a?` instead of `<`
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # Slackify [![Build Status](https://travis-ci.org/jusleg/slackify.svg?branch=master)](https://travis-ci.org/jusleg/slackify) [![Gem Version](https://badge.fury.io/rb/slackify.svg)](https://badge.fury.io/rb/slackify)
1
+ # Slackify [![Tests ๐Ÿงช](https://github.com/jusleg/slackify/workflows/Tests%20%F0%9F%A7%AA/badge.svg)](https://github.com/jusleg/slackify/actions?query=workflow%3A%22Tests+%F0%9F%A7%AA%22) [![Lint ๐Ÿ’Ž](https://github.com/jusleg/slackify/workflows/Lint%20%F0%9F%92%8E/badge.svg)](https://github.com/jusleg/slackify/actions?query=workflow%3A%22Lint+%F0%9F%92%8E%22) [![Gem Version](https://badge.fury.io/rb/slackify.svg)](https://badge.fury.io/rb/slackify) ![Gem downloads](https://img.shields.io/gem/dt/slackify)
2
2
 
3
3
  Slackify is a gem that allows to build slackbots on Rails using the [Event API](https://api.slack.com/events-api) from Slack.
4
4
 
@@ -8,7 +8,8 @@ Slackify is a gem that allows to build slackbots on Rails using the [Event API](
8
8
  * [Plain messages](#handling-plain-messages)
9
9
  * [Interactive messages](#handling-interactive-messages)
10
10
  * [Slash Command](#handling-slash-commands)
11
- * [Custom handler for event subtypes](#custom-handler-for-event-subtypes)
11
+ * [Custom handler for message subtypes](#custom-handler-for-message-subtypes)
12
+ * [Custom handler for event types](#custom-handler-for-event-types)
12
13
  * [Custom unhandled handler](#custom-unhandled-handler)
13
14
  * [Slack client](#slack-client)
14
15
  * [Sending a simple message](#sending-a-simple-message)
@@ -85,17 +86,29 @@ class DummyHandler < Slackify::Handlers::Base
85
86
  end
86
87
  ```
87
88
 
88
- ### Custom handler for event subtypes
89
+ ### Custom handler for message subtypes
89
90
 
90
- If you wish to add more functionalities to your bot, you can specify define new behaviours for different event subtypes. You can specify a hash with the event subtype as a key and the handler class as the value. Slackify will call `.handle_event` on your class and pass the controller params as parameters.
91
+ If you wish to add more functionalities to your bot, you can specify define new behaviours for different message subtypes. You can specify a hash with the event subtype as a key and the handler class as the value. Slackify will call `.handle_event` on your class and pass the controller params as parameters.
91
92
 
92
93
  ```ruby
93
- Slackify.configuration.custom_event_subtype_handlers = {
94
+ Slackify.configuration.custom_message_subtype_handlers = {
95
+ file_share: MessageImageHandler
96
+ }
97
+ ```
98
+
99
+ In this example, all message of subtype `file_share` will be sent to the `MessageImageHandler` class.
100
+
101
+ ### Custom handler for event types
102
+
103
+ If you wish to add more functionalities to your bot, you can specify define new behaviours for different event types. You can specify a hash with the event type as a key and the handler class as the value. Slackify will call `.handle_event` on your class and pass the controller params as parameters.
104
+
105
+ ```ruby
106
+ Slackify.configuration.custom_event_type_handlers = {
94
107
  file_share: ImageHandler
95
108
  }
96
109
  ```
97
110
 
98
- In this example, all events of subtype `file_share` will be sent to the `ImageHandler` class.
111
+ In this example, all events of type `file_share` will be sent to the `ImageHandler` class.
99
112
 
100
113
  ### Custom unhandled handler
101
114
 
@@ -205,29 +218,45 @@ First, you'll need to create a new app on slack. Head over to [slack api](https:
205
218
  Under the setting section, click "install app" and proceed to install the app to the workspace. Once the app is installed, go back to the "install app" page and copy the Bot User OAuth Access Token.
206
219
 
207
220
  6. **Configure Slackify**
221
+ Add a new initializer with the following code
222
+
208
223
  ```ruby
224
+ # config/initializers/slackify.rb
209
225
  Slackify.configure do |config|
210
226
  config.slack_bot_token = "xoxb-sdkjlkjsdflsd..."
211
227
  config.slack_secret_token = "1234dummysecret"
212
228
  end
213
229
  ```
214
230
 
215
- 7. **Add an initializer**
231
+ 7. **Define handlers specific subtypes** (Optional)
232
+ You can set custom [message subtype](https://api.slack.com/events/message) handlers or custom [event type](https://api.slack.com/events) handlers inside your configuration
233
+
216
234
  ```ruby
217
235
  # config/initializers/slackify.rb
218
- Slackify.load_handlers
236
+ Slackify.configure do |config|
237
+ config.slack_bot_token = "xoxb-sdkjlkjsdflsd..."
238
+ config.slack_secret_token = "1234dummysecret"
239
+ config.custom_message_subtype_handlers = {
240
+ file_share: ImageHandler,
241
+ channel_join: JoinHandler,
242
+ ...
243
+ }
244
+ config.custom_event_type_handlers = {
245
+ app_mention: ...
246
+ }
247
+ end
219
248
  ```
220
249
 
221
- 8. **Define handlers specific subtypes** (Optional)
250
+ 8. **Handle bot messages** (Highly optional)
251
+ If you want your bot to accept other bot messages (which you probably should not do), you can. In the configuration step, you can set an array of whitelisted bot ids.
222
252
 
223
253
  ```ruby
224
254
  # config/initializers/slackify.rb
225
- Slackify.load_handlers
226
- Slackify.configuration.custom_event_subtype_handlers = {
227
- file_share: ImageHandler,
228
- channel_join: JoinHandler,
229
- ...
230
- }
255
+ Slackify.configure do |config|
256
+ ...
257
+ config.whitelisted_bot_ids = ['abc123', 'def456']
258
+ ...
259
+ end
231
260
  ```
232
261
 
233
262
  **At this point, you are ready to go ๐Ÿ˜„**
@@ -9,6 +9,8 @@ module Slackify
9
9
  def event_callback
10
10
  if params[:type] == "url_verification"
11
11
  render plain: params["challenge"]
12
+ elsif Slackify.configuration.custom_event_type_handlers[params[:event][:type]]
13
+ handle_custom_event_type
12
14
  elsif params[:event][:type] == "message"
13
15
  handle_direct_message_event
14
16
  head :ok
@@ -19,7 +21,14 @@ module Slackify
19
21
 
20
22
  def interactive_callback
21
23
  parsed_payload = JSON.parse(params[:payload])
22
- response = handler_from_callback_id(parsed_payload["callback_id"]).call(parsed_payload)
24
+
25
+ callback_id = if parsed_payload.key?('view')
26
+ parsed_payload.dig('view', 'callback_id')
27
+ else
28
+ parsed_payload['callback_id']
29
+ end
30
+
31
+ response = handler_from_callback_id(callback_id).call(parsed_payload)
23
32
  if !response.nil?
24
33
  Timeout.timeout(SLACK_TIMEOUT_SECONDS) do
25
34
  render json: response
@@ -28,7 +37,7 @@ module Slackify
28
37
  head :ok
29
38
  end
30
39
  rescue Timeout::Error
31
- raise Timeout::Error, "Slack interactive callback timed out for #{parsed_payload['callback_id']}"
40
+ raise Timeout::Error, "Slack interactive callback timed out for #{callback_id}"
32
41
  end
33
42
 
34
43
  def slash_command_callback
@@ -51,25 +60,33 @@ module Slackify
51
60
  private
52
61
 
53
62
  def handle_direct_message_event
54
- if handler = Slackify.configuration.custom_event_subtype_handlers[params[:event][:subtype]]
63
+ if handler = Slackify.configuration.custom_message_subtype_handlers[params[:event][:subtype]]
55
64
  handler.handle_event(params[:slack])
56
65
  head :ok
57
66
  return
58
67
  end
59
68
 
60
- return if params[:event][:subtype] == "bot_message" || params[:event].key?(:bot_id) || params[:event][:hidden]
69
+ return if (params[:event][:subtype] == "bot_message" ||
70
+ params[:event].key?(:bot_id) ||
71
+ params[:event][:hidden]) &&
72
+ Slackify.configuration.whitelisted_bot_ids.exclude?(params.dig(:event, :bot_id))
61
73
 
62
74
  command = params[:event][:text]
63
- Slackify.configuration.handlers.call_command(command, params[:slack])
75
+ Slackify::Router.call_command(command, params[:slack])
64
76
  rescue RuntimeError => e
65
77
  raise e unless e.message == "Component not found for a command message"
66
78
  end
67
79
 
80
+ def handle_custom_event_type
81
+ Slackify.configuration.custom_event_type_handlers[params[:event][:type]].handle_event(params[:slack])
82
+ head :ok
83
+ end
84
+
68
85
  def handler_from_callback_id(callback_id)
69
86
  class_name, method_name = callback_id.split('#')
70
87
  class_name = class_name.camelize
71
88
 
72
- raise Exceptions::HandlerNotSupported, class_name unless
89
+ raise Exceptions::HandlerNotSupported, "#{class_name} is not a subclass of Slackify::Handlers::Base" unless
73
90
  Handlers::Base.supported_handlers.include?(class_name)
74
91
 
75
92
  class_name.constantize.method(method_name)
@@ -78,7 +95,7 @@ module Slackify
78
95
  def verify_handler_slash_permission(handler_class, handler_method)
79
96
  handler_class = handler_class.camelize
80
97
 
81
- raise Exceptions::HandlerNotSupported, handler_class unless
98
+ raise Exceptions::HandlerNotSupported, "#{handler_class} is not a subclass of Slackify::Handlers::Base" unless
82
99
  Handlers::Base.supported_handlers.include?(handler_class)
83
100
 
84
101
  handler = handler_class.constantize
@@ -4,6 +4,7 @@ require 'slackify/configuration'
4
4
  require 'slackify/engine'
5
5
  require 'slackify/exceptions'
6
6
  require 'slackify/handlers'
7
+ require 'slackify/router'
7
8
 
8
9
  module Slackify
9
10
  class << self
@@ -19,9 +20,5 @@ module Slackify
19
20
  def configure
20
21
  yield(configuration)
21
22
  end
22
-
23
- def load_handlers
24
- @configuration.handlers = Handlers::Configuration.new
25
- end
26
23
  end
27
24
  end
@@ -3,37 +3,75 @@
3
3
  require 'slack'
4
4
 
5
5
  module Slackify
6
+ # Where the configuration for Slackify lives
6
7
  class Configuration
7
- attr_reader :custom_event_subtype_handlers, :slack_bot_token, :unhandled_handler
8
- attr_accessor :handlers, :slack_secret_token, :slack_client
8
+ attr_reader :custom_message_subtype_handlers, :slack_bot_token, :unhandled_handler, :custom_event_type_handlers
9
+ attr_accessor :handlers, :slack_secret_token, :slack_client, :whitelisted_bot_ids
9
10
 
10
11
  def initialize
11
12
  @slack_bot_token = nil
12
13
  @slack_secret_token = nil
13
- @handlers = nil
14
+ @handlers = generate_handlers
14
15
  @slack_client = nil
15
- @custom_event_subtype_handlers = {}
16
+ @custom_message_subtype_handlers = {}
17
+ @custom_event_type_handlers = {}
16
18
  @unhandled_handler = Handlers::UnhandledHandler
19
+ @whitelisted_bot_ids = []
17
20
  end
18
21
 
22
+ # Set your own unhandled handler
19
23
  def unhandled_handler=(handler)
20
- raise Exceptions::InvalidHandler, "#{handler.class} is not a subclass of Slackify::Handlers::Base" unless
24
+ raise HandlerNotSupported, "#{handler.class} is not a subclass of Slackify::Handlers::Base" unless
21
25
  handler < Handlers::Base
22
26
 
23
27
  @unhandled_handler = handler
24
28
  end
25
29
 
30
+ # Remove unhandled handler. The bot will not reply if the message doesn't
31
+ # match any regex
26
32
  def remove_unhandled_handler
27
33
  @unhandled_handler = nil
28
34
  end
29
35
 
36
+ # Set the token that we will use to connect to slack
30
37
  def slack_bot_token=(token)
31
38
  @slack_bot_token = token
32
39
  @slack_client = Slack::Web::Client.new(token: token).freeze
33
40
  end
34
41
 
35
- def custom_event_subtype_handlers=(event_subtype_hash)
36
- @custom_event_subtype_handlers = event_subtype_hash.with_indifferent_access
42
+ # Set a handler for a specific message subtype
43
+ # That handler will have to implement `self.handle_event(params)`
44
+ # see https://api.slack.com/events/message
45
+ def custom_message_subtype_handlers=(event_subtype_hash)
46
+ @custom_message_subtype_handlers = event_subtype_hash.with_indifferent_access
47
+ end
48
+
49
+ # Set a handler for a event type
50
+ # That handler will have to implement `self.handle_event(params)`
51
+ # see https://api.slack.com/events
52
+ def custom_event_type_handlers=(event_type_hash)
53
+ @custom_event_type_handlers = event_type_hash.with_indifferent_access
54
+ end
55
+
56
+ private
57
+
58
+ # Convert a hash to a list of lambda functions that will be called to handle
59
+ # the user messages
60
+ def generate_handlers
61
+ generated_handlers = []
62
+ read_handlers_yaml.each do |handler_hash|
63
+ handler = Handlers::Factory.for(handler_hash)
64
+ generated_handlers << handler
65
+ end
66
+
67
+ generated_handlers
68
+ end
69
+
70
+ # Reads the config/handlers.yml configuration
71
+ def read_handlers_yaml
72
+ raise 'config/handlers.yml does not exist' unless File.exist?("#{Rails.root}/config/handlers.yml")
73
+
74
+ YAML.load_file("#{Rails.root}/config/handlers.yml") || []
37
75
  end
38
76
  end
39
77
  end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Slackify
4
+ # Makes the whole thing work. Adds the routes for slackify.
4
5
  class Engine < Rails::Engine
5
6
  isolate_namespace Slackify
6
7
  end
@@ -1,9 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Slackify
4
+ # When things go boom, we need these.
4
5
  module Exceptions
6
+ # You tried to call a class that was not extending the base handler
5
7
  class HandlerNotSupported < StandardError; end
8
+ # You handler is failing validations
6
9
  class InvalidHandler < StandardError; end
10
+ # The handler method was not whitelisted to be a slash command
7
11
  class MissingSlashPermission < StandardError; end
8
12
  end
9
13
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative 'handlers/base'
4
- require_relative 'handlers/configuration'
4
+ require_relative 'handlers/factory'
5
5
  require_relative 'handlers/unhandled_handler'
6
6
  require_relative 'handlers/validator'
7
7
 
@@ -2,16 +2,25 @@
2
2
 
3
3
  module Slackify
4
4
  module Handlers
5
+ # Base handler class that any user defined handlers must inherit from
5
6
  class Base
6
7
  @@supported_handlers = []
7
8
 
8
9
  class << self
9
10
  attr_reader :allowed_slash_methods
10
11
 
12
+ # Get the slack client that you can use to perform slack api calls
13
+ # @see https://github.com/slack-ruby/slack-ruby-client
11
14
  def slack_client
12
15
  Slackify.configuration.slack_client
13
16
  end
14
17
 
18
+ # Enables a method to be called for a slash command.
19
+ #
20
+ # More context:
21
+ # Slash commands have extra validations. To call a slash command, it
22
+ # needs to call a method on a supported handler and that handler needs
23
+ # to explicitly specify which methods are for slash command.
15
24
  def allow_slash_method(element)
16
25
  if @allowed_slash_methods
17
26
  @allowed_slash_methods.push(*element)
@@ -20,10 +29,14 @@ module Slackify
20
29
  end
21
30
  end
22
31
 
32
+ # Any class inheriting from Slackify::Handler::Base will be added to
33
+ # the list of supported handlers
23
34
  def inherited(subclass)
24
35
  @@supported_handlers.push(subclass.to_s)
25
36
  end
26
37
 
38
+ # Show a list of the handlers supported by the app. Since we do
39
+ # metaprogramming, we want to ensure we can only call defined handlers
27
40
  def supported_handlers
28
41
  @@supported_handlers
29
42
  end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Slackify
4
+ module Handlers
5
+ # Creates the handler structs
6
+ class Factory
7
+ def self.for(configuration)
8
+ Validator.verify_handler_integrity(configuration)
9
+
10
+ handler = OpenStruct.new
11
+ handler.name = configuration.keys.first
12
+ handler.commands = []
13
+
14
+ configuration[handler.name]['commands']&.each do |command|
15
+ built_command = OpenStruct.new
16
+ built_command.regex = command['regex']
17
+ built_command.handler = handler.name.camelize.constantize.method(command['action'])
18
+ built_command.description = command['description']
19
+ handler.commands << built_command.freeze
20
+ end
21
+
22
+ handler.commands.freeze
23
+ handler.freeze
24
+ end
25
+ end
26
+ end
27
+ end
@@ -2,6 +2,10 @@
2
2
 
3
3
  module Slackify
4
4
  module Handlers
5
+ # Default handler for any text message that is not handler by other handlers
6
+ # This can easily be replaced by setting you own unhandled handler when
7
+ # configuring slackify. Use `#unhandled_handler=` to set it. Your handler
8
+ # must implement a `self.unhandled` method.
5
9
  class UnhandledHandler < Base
6
10
  def self.unhandled(params)
7
11
  slack_client.chat_postMessage(
@@ -2,7 +2,10 @@
2
2
 
3
3
  module Slackify
4
4
  module Handlers
5
+ # Simple validator for handlers. It will blow your app up on the
6
+ # configuration step instead of crashing when handling production requests.
5
7
  class Validator
8
+ # Checks if your handler hash is valid. It's pass or raise ๐Ÿงจ๐Ÿ’ฅ
6
9
  def self.verify_handler_integrity(handler)
7
10
  handler_name = handler.keys.first
8
11
  handler_class = handler_name.camelize.constantize
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Slackify
4
+ # In charge of routing a message to its proper handler
5
+ class Router
6
+ class << self
7
+ # List all available commands
8
+ def all_commands
9
+ Slackify.configuration.handlers.collect(&:commands).flatten
10
+ end
11
+
12
+ # Find the matching command based on the message string
13
+ def matching_command(message)
14
+ all_commands.each { |command| return command if command.regex.match? message }
15
+ nil
16
+ end
17
+
18
+ # Call command based on message string
19
+ def call_command(message, params)
20
+ command = matching_command(message)
21
+ if command.nil?
22
+ return unless Slackify.configuration.unhandled_handler
23
+
24
+ Slackify.configuration.unhandled_handler.unhandled(params)
25
+ else
26
+ new_params = params.merge(command_arguments: command.regex.match(message).named_captures)
27
+ command.handler.call(new_params)
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: slackify
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.4
4
+ version: 0.3.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Justin Leger
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2019-03-17 00:00:00.000000000 Z
12
+ date: 2019-12-11 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rails
@@ -114,9 +114,10 @@ files:
114
114
  - lib/slackify/exceptions.rb
115
115
  - lib/slackify/handlers.rb
116
116
  - lib/slackify/handlers/base.rb
117
- - lib/slackify/handlers/configuration.rb
117
+ - lib/slackify/handlers/factory.rb
118
118
  - lib/slackify/handlers/unhandled_handler.rb
119
119
  - lib/slackify/handlers/validator.rb
120
+ - lib/slackify/router.rb
120
121
  homepage: https://github.com/jusleg/slackify
121
122
  licenses:
122
123
  - MIT
@@ -138,8 +139,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
138
139
  - !ruby/object:Gem::Version
139
140
  version: '0'
140
141
  requirements: []
141
- rubyforge_project:
142
- rubygems_version: 2.7.3
142
+ rubygems_version: 3.0.3
143
143
  signing_key:
144
144
  specification_version: 4
145
145
  summary: Slackbot framework for Rails using the Events API
@@ -1,84 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'ostruct'
4
-
5
- module Slackify
6
- module Handlers
7
- class Configuration
8
- attr_reader :bot_id
9
- attr_accessor :handlers
10
- delegate :each, to: :@handlers
11
-
12
- def initialize
13
- @handlers = []
14
-
15
- read_handlers_yaml.each do |handler_yaml|
16
- handler = generate_handler_from_yaml(handler_yaml)
17
- @handlers << handler
18
- end
19
-
20
- environment_configurations
21
- end
22
-
23
- def all_commands
24
- @handlers.collect(&:commands).flatten
25
- end
26
-
27
- def matching_command(message)
28
- all_commands.each { |command| return command if command.regex.match? message }
29
- nil
30
- end
31
-
32
- def call_command(message, params)
33
- return if params.dig(:event, :user) == @bot_id || params.dig(:event, :message, :user) == @bot_id
34
-
35
- command = matching_command(message)
36
- if command.nil?
37
- return unless Slackify.configuration.unhandled_handler
38
-
39
- Slackify.configuration.unhandled_handler.unhandled(params)
40
- else
41
- new_params = params.merge(command_arguments: command.regex.match(message).named_captures)
42
- command.handler.call(new_params)
43
- end
44
- end
45
-
46
- private
47
-
48
- def environment_configurations
49
- @bot_id =
50
- case Rails.env
51
- when 'production', 'staging', 'development'
52
- Slackify.configuration.slack_client.auth_test['user_id']
53
- when 'test'
54
- ''
55
- end
56
- end
57
-
58
- def read_handlers_yaml
59
- raise 'config/handlers.yml does not exist' unless File.exist?("#{Rails.root}/config/handlers.yml")
60
-
61
- YAML.load_file("#{Rails.root}/config/handlers.yml") || []
62
- end
63
-
64
- def generate_handler_from_yaml(handler_yaml)
65
- Validator.verify_handler_integrity(handler_yaml)
66
-
67
- handler = OpenStruct.new
68
- handler.name = handler_yaml.keys.first
69
- handler.commands = []
70
-
71
- handler_yaml[handler.name]['commands']&.each do |command|
72
- built_command = OpenStruct.new
73
- built_command.regex = command['regex']
74
- built_command.handler = handler.name.camelize.constantize.method(command['action'])
75
- built_command.description = command['description']
76
- handler.commands << built_command.freeze
77
- end
78
-
79
- handler.commands.freeze
80
- handler.freeze
81
- end
82
- end
83
- end
84
- end