ruboty-slack_events 0.1.1 → 0.3.0

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: 2588ce42504b8c50d9db58ecca41e92c7b05d435ef0a75fb08dc458f7116fba3
4
- data.tar.gz: b4f8b9c8c85abd03d37bbeb9b76121659f24b8c0453f94a5ddd5862125950834
3
+ metadata.gz: c779a46edaf630035527d72df0e40a57eb8104421f8151eeb8c3623202ce8537
4
+ data.tar.gz: bcbf6cb2c83dc15cea1c270404820dd6f9bdefa570de19478425c77265915626
5
5
  SHA512:
6
- metadata.gz: e99fb912133d41ba3dd1d02a2ae9424b4f4ff89a65460678d3fc59a433797608373dca041903b5aa44a4f756110d2cea2b5c90829167f70701fb29c4798e3a63
7
- data.tar.gz: 4b997f616c0d1c28e6e322077e94242d5088426d4c9cc8b73267f353e21ee5eac8b25162c8a3c2b91d051020951d29c5aec5c0fecac5985e5f76e77cdef82449
6
+ metadata.gz: c3c5e4fd09c22b7c52adcdcc556494d83cf559d88f548c71e2f050c939e004b8d3b793be1f81dbe03e95ce327aab65009d57001a1c2d9b48be7a8c0fa20dfdb1
7
+ data.tar.gz: 0f4192b9d52fb4c49ef47cdd7986ea50b86b5af077dfc392a4d62062867b5884094ea79b222e093dd7947bff122838c37b88e7a6146e63fce54fb8b813ba89b2
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --require spec_helper
data/CHANGELOG.md CHANGED
@@ -1,4 +1,13 @@
1
1
  ## Unreleased
2
+ ## 0.3.0 - 2025-04-04
3
+
4
+ - Rewrite text filter to parse links and unescape HTML entities
5
+
6
+ ## 0.2.0 - 2025-04-03
7
+
8
+ - Support reply on threads
9
+ - Ignore message events without text field
10
+
2
11
  ## 0.1.1 - 2025-04-02
3
12
 
4
13
  - Add ./bin/run-ruboty script to run ruboty locally with this gem
data/Rakefile CHANGED
@@ -3,9 +3,11 @@
3
3
  require "bundler/gem_tasks"
4
4
  require "rubocop/rake_task"
5
5
  require "bump/tasks"
6
+ require "rspec/core/rake_task"
6
7
 
7
8
  Bump.changelog = true
8
9
 
9
10
  RuboCop::RakeTask.new
11
+ RSpec::Core::RakeTask.new(:spec)
10
12
 
11
- task default: :rubocop
13
+ task default: %i[rubocop spec]
@@ -16,6 +16,13 @@ module Ruboty
16
16
  def handle_event(message) #: void
17
17
  Ruboty::SlackEvents::Logger.debug("handle_event") { message.to_json }
18
18
 
19
+ on_generic_event(message)
20
+ end
21
+
22
+ private
23
+
24
+ # @rbs message: Slack::Messages::Message -- a generic type event
25
+ def on_generic_event(message) #: void
19
26
  case message.type
20
27
  when "message"
21
28
  on_message(message)
@@ -34,12 +41,17 @@ module Ruboty
34
41
 
35
42
  return if message.subtype == "bot_message" && adapter.ignore_bot_message?
36
43
 
44
+ # Some event subtypes (e.g. message_changed) does not have `text` field.
45
+ # Consider that these events are not a new message.
46
+ return unless message.text
47
+
37
48
  message_for_robot = {
38
49
  body: adapter.rubotify.call(message.text),
39
50
  from: channel,
40
51
  from_name: user&.name,
41
- to: channel
42
- } #: RobotMessage
52
+ to: channel,
53
+ thread_ts: message.thread_ts
54
+ } #: receivedMessage
43
55
 
44
56
  Ruboty::SlackEvents::Logger.debug("robot.receive") { message_for_robot.to_json }
45
57
 
@@ -48,12 +60,12 @@ module Ruboty
48
60
 
49
61
  # @rbs message: Slack::Messages::Message -- `event_callback` type event
50
62
  def on_event_callback(message)
51
- handle_event(message.event)
63
+ on_generic_event(message.event)
52
64
  end
53
65
 
54
66
  # @rbs message: Slack::Messages::Message -- `events_api` type event
55
67
  def on_events_api(message)
56
- handle_event(message.payload)
68
+ on_generic_event(message.payload)
57
69
  end
58
70
  end
59
71
  end
@@ -14,8 +14,16 @@ module Ruboty
14
14
  # type robotMessage = {
15
15
  # body: String,
16
16
  # from: String,
17
+ # to: String,
18
+ # original: receivedMessage?,
19
+ # code: boolish?,
20
+ # }
21
+ # type receivedMessage = {
22
+ # body: String,
23
+ # from: String,
17
24
  # from_name: String,
18
25
  # to: String,
26
+ # thread_ts: String?,
19
27
  # }
20
28
 
21
29
  def run
@@ -41,7 +49,8 @@ module Ruboty
41
49
  slack_client.chat_postMessage(
42
50
  channel: message[:to],
43
51
  attachments: [],
44
- markdown_text: text
52
+ markdown_text: text,
53
+ thread_ts: message.dig(:original, :thread_ts)
45
54
  )
46
55
  end
47
56
 
@@ -53,12 +62,12 @@ module Ruboty
53
62
  @resolvers ||= ::Ruboty::SlackEvents::Resolvers.new(slack_client:)
54
63
  end
55
64
 
56
- def slackify #: ::Ruboty::SlackEvents::Mention::Slackify
57
- @slackify ||= ::Ruboty::SlackEvents::Mention::Slackify.new(resolvers:)
65
+ def slackify #: ::Ruboty::SlackEvents::Filter::Slackify
66
+ @slackify ||= ::Ruboty::SlackEvents::Filter::Slackify.new(resolvers:)
58
67
  end
59
68
 
60
- def rubotify #: ::Ruboty::SlackEvents::Mention::Rubotify
61
- @rubotify ||= ::Ruboty::SlackEvents::Mention::Rubotify.new(resolvers:)
69
+ def rubotify #: ::Ruboty::SlackEvents::Filter::Rubotify
70
+ @rubotify ||= ::Ruboty::SlackEvents::Filter::Rubotify.new(resolvers:)
62
71
  end
63
72
 
64
73
  def ignore_bot_message?
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "cgi"
4
+
5
+ module Ruboty
6
+ module SlackEvents
7
+ module Filter
8
+ # Convert Slack text format to Ruboty format
9
+ # For more details of Slack text format, see: https://api.slack.com/reference/surfaces/formatting
10
+ class Rubotify
11
+ attr_reader :resolvers #: Resolvers
12
+
13
+ # @rbs resolvers: Resolvers
14
+ def initialize(resolvers:)
15
+ @resolvers = resolvers
16
+ end
17
+
18
+ # @rbs text: String
19
+ def call(text) #: String
20
+ text
21
+ .then { replace_user_mentions(_1) }
22
+ .then { replace_link(_1) }
23
+ .then { unescape(_1) }
24
+ end
25
+
26
+ private
27
+
28
+ # @rbs text: String
29
+ def replace_user_mentions(text) #: String
30
+ text.gsub(/<@(?<user_id>\w+)>/) do |user_mention|
31
+ user_id = Regexp.last_match[:user_id]
32
+
33
+ user_info = resolvers.user_resolver.user_info_by_id(user_id)
34
+
35
+ next user_mention unless user_info
36
+
37
+ "@#{user_info.name}"
38
+ end
39
+ end
40
+
41
+ # @rbs text: String
42
+ def replace_link(text) #: String
43
+ text.gsub(/<(?<url>[^\>|]+)(?:\|(?<text>[^\>]+))?>/) do |link|
44
+ url = Regexp.last_match[:url]
45
+ text = Regexp.last_match[:text]
46
+
47
+ begin
48
+ next link unless URI.parse(url).scheme
49
+ rescue URI::InvalidURIError, URI::InvalidComponentError
50
+ next link
51
+ end
52
+
53
+ text || url
54
+ end
55
+ end
56
+
57
+ # Unescape HTML entities in the text.
58
+ # See: https://api.slack.com/reference/surfaces/formatting#escaping
59
+ # @rbs text: String
60
+ def unescape(text) #: String
61
+ CGI.unescapeHTML(text)
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
@@ -2,7 +2,8 @@
2
2
 
3
3
  module Ruboty
4
4
  module SlackEvents
5
- module Mention
5
+ module Filter
6
+ # Convert Ruboty text format to Slack text format
6
7
  class Slackify
7
8
  attr_reader :resolvers #: Resolvers
8
9
 
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Ruboty
4
4
  module SlackEvents
5
- VERSION = "0.1.1"
5
+ VERSION = "0.3.0"
6
6
  end
7
7
  end
@@ -9,8 +9,8 @@ end
9
9
  require_relative "slack_events/version"
10
10
 
11
11
  require_relative "slack_events/api/socket_client"
12
- require_relative "slack_events/mention/slackify"
13
- require_relative "slack_events/mention/rubotify"
12
+ require_relative "slack_events/filter/slackify"
13
+ require_relative "slack_events/filter/rubotify"
14
14
  require_relative "slack_events/resolvers"
15
15
  require_relative "slack_events/logger"
16
16
 
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruboty-slack_events
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tomoya Chiba
8
8
  bindir: exe
9
9
  cert_chain: []
10
- date: 2025-04-01 00:00:00.000000000 Z
10
+ date: 2025-04-04 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: async-websocket
@@ -58,6 +58,7 @@ executables: []
58
58
  extensions: []
59
59
  extra_rdoc_files: []
60
60
  files:
61
+ - ".rspec"
61
62
  - ".rubocop.yml"
62
63
  - CHANGELOG.md
63
64
  - CODE_OF_CONDUCT.md
@@ -69,9 +70,9 @@ files:
69
70
  - lib/ruboty/slack_events.rb
70
71
  - lib/ruboty/slack_events/api/socket_client.rb
71
72
  - lib/ruboty/slack_events/app_info.rb
73
+ - lib/ruboty/slack_events/filter/rubotify.rb
74
+ - lib/ruboty/slack_events/filter/slackify.rb
72
75
  - lib/ruboty/slack_events/logger.rb
73
- - lib/ruboty/slack_events/mention/rubotify.rb
74
- - lib/ruboty/slack_events/mention/slackify.rb
75
76
  - lib/ruboty/slack_events/resolvers.rb
76
77
  - lib/ruboty/slack_events/resolvers/user_resolver.rb
77
78
  - lib/ruboty/slack_events/version.rb
@@ -97,7 +98,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
97
98
  - !ruby/object:Gem::Version
98
99
  version: '0'
99
100
  requirements: []
100
- rubygems_version: 3.6.2
101
+ rubygems_version: 3.6.3
101
102
  specification_version: 4
102
103
  summary: Ruboty adapter with Slack Events API
103
104
  test_files: []
@@ -1,34 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Ruboty
4
- module SlackEvents
5
- module Mention
6
- class Rubotify
7
- attr_reader :resolvers #: Resolvers
8
-
9
- # @rbs resolvers: Resolvers
10
- def initialize(resolvers:)
11
- @resolvers = resolvers
12
- end
13
-
14
- # @rbs text: String
15
- def call(text) #: String
16
- replace_user_mentions(text)
17
- end
18
-
19
- # @rbs text: String
20
- def replace_user_mentions(text) #: String
21
- text.gsub(/<@(?<user_id>\w+)>/) do |user_mention|
22
- user_id = Regexp.last_match[:user_id]
23
-
24
- user_info = resolvers.user_resolver.user_info_by_id(user_id)
25
-
26
- next user_mention unless user_info
27
-
28
- "@#{user_info.name}"
29
- end
30
- end
31
- end
32
- end
33
- end
34
- end