rodbot 0.2.0 → 0.3.0

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: 02bef1b6cd772c6ee27a563d3c27c8829adcbce822bc0f4ab5862061b65db2bf
4
- data.tar.gz: 94d596091931920e92bd6d1e12273241143fe8cd3e1289c14c6c14523f41518e
3
+ metadata.gz: a4e3022218a7df9e0e16b2430fa3144a9abfadc49242fd439f48945709fb20e2
4
+ data.tar.gz: b1dbe4adfd865bdcb0ee107bbff5806705470961ba721da97d04ac92e1bba3ed
5
5
  SHA512:
6
- metadata.gz: cc623cf74e5538dfa2d4c203aa17e1e3e5c5071705bef05f526418dfa6d22e3b1db0b169249dd322eb94e5a2198244ff8d0dc8c2e627efe1834da0c1a0f679d7
7
- data.tar.gz: 0b79a2c6ab679dfbcf7145e11b7ef491109d399ce88113ef1d93b914c1ee26f321e27bdc6fc5cf2441126335f72e6b8d50bc9fcd864dc4833cabe09c9c270aaf
6
+ metadata.gz: 96a4262cbeaa00e9548d962014fd63353aac9c1a48843f5d5c082c66c306aeb5ccaee1660f0a501e9af104293eb68d80108deb9d1fae1a017aaa9ec327fcaf66
7
+ data.tar.gz: b2977391b972eeafad320e4dd54cf8f51a2b79a6efcea9f05f314caf912dbc6f9c1d961998afd11d78a61e3c8e12c61226993e3c564aee9220305f2f80c4da04
checksums.yaml.gz.sig CHANGED
Binary file
data/CHANGELOG.md CHANGED
@@ -2,6 +2,11 @@
2
2
 
3
3
  Nothing so far
4
4
 
5
+ ## 0.3.0
6
+
7
+ #### Additions
8
+ * Built-in plugin for Slack
9
+
5
10
  ## 0.2.0
6
11
 
7
12
  #### Fixes
@@ -0,0 +1 @@
1
+ 789b796fc2127afbb1850f083f9b3255a31a4dfe570e0a0c75b7ed2be9bbf736c89d418233b0c855656b75e87da2d8e3c9f31ffe0932f8a5c37461f9e4ddabc5
@@ -39,7 +39,10 @@ module Rodbot
39
39
  # e.either(keyword: 2) # => 2 (memoized)
40
40
  # e.either { 3 } # => :not_nil (cannot be memoized)
41
41
  # Rodbot::Memoize.suspend do
42
- # e.either(1) # => 1 (calculated, not memoized)
42
+ # e.either(1) # => 1 (recalculated, not memoized)
43
+ # end
44
+ # Rodbot::Memoize.revisit do
45
+ # e.either(5) # => 5 (recalculated, memoized anew)
43
46
  # end
44
47
  module Memoize
45
48
  module ClassMethods
@@ -47,12 +50,12 @@ module Rodbot
47
50
  unmemoized_method = :"_unmemoized_#{method}"
48
51
  alias_method unmemoized_method, method
49
52
  define_method method do |*args, **kargs, &block|
50
- if Rodbot::Memoize.suspended? || block
53
+ if Rodbot::Memoize.suspend? || block
51
54
  send(unmemoized_method, *args, **kargs, &block)
52
55
  else
53
56
  id = method.hash ^ args.hash ^ kargs.hash
54
57
  @_memoize_cache ||= {}
55
- if @_memoize_cache.has_key? id
58
+ if !Rodbot::Memoize.revisit? && @_memoize_cache.has_key?(id)
56
59
  @_memoize_cache[id]
57
60
  else
58
61
  @_memoize_cache[id] = send(unmemoized_method, *args, **kargs)
@@ -64,16 +67,22 @@ module Rodbot
64
67
  end
65
68
 
66
69
  class << self
67
- def suspend
68
- @suspended = true
69
- yield
70
- ensure
71
- @suspended = false
72
- end
70
+ %i(suspend revisit).each do |switch|
71
+ ivar = "@#{switch}"
72
+ define_method switch do |&block|
73
+ instance_variable_set(ivar, true)
74
+ block.call
75
+ ensure
76
+ instance_variable_set(ivar, false)
77
+ end
73
78
 
74
- def suspended?
75
- @suspended = false if @suspended.nil?
76
- @suspended
79
+ define_method "#{switch}?" do
80
+ if instance_variable_defined? ivar
81
+ instance_variable_get ivar
82
+ else
83
+ instance_variable_set(ivar, false)
84
+ end
85
+ end
77
86
  end
78
87
 
79
88
  def included(base)
@@ -47,7 +47,7 @@ module Routes
47
47
  end
48
48
  ```
49
49
 
50
- (As a reminder: Up until this point, `r.arguments` is a mere shortcut for `r.params['arguments']`.)
50
+ As a reminder: In the above example, `r.arguments` is a mere shortcut for `r.params['arguments']`.
51
51
 
52
52
  In order to protect this rather dangerous command with a one-time password, you have to guard the route:
53
53
 
@@ -66,7 +66,9 @@ To execute the command now, you have to add the six digit one-time password to t
66
66
  !reboot example.com 123456
67
67
  ```
68
68
 
69
- The `r.valid_otp?` guard extracts the one-time password from the message and validates it. In this example, a validation result `true` causes the server to be rebooted. Please note that `r.argument` after the guard does not contain the one-time password anymore!
69
+ The `r.valid_otp?` guard extracts the one-time password from the message and validates it. In this example, a validation result `true` causes the server to be rebooted.
70
+
71
+ Please note that `r.valid_otp?` redefines `r.arguments` to no longer include the password.
70
72
 
71
73
  If halting with a 401 error is all you want, there's even a shorter alternative `r.require_valid_otp!`:
72
74
 
@@ -80,3 +82,5 @@ end
80
82
  ```
81
83
 
82
84
  This route does exactly the same as the more verbose one above.
85
+
86
+ Please note that `r.require_valid_otp!` redefines `r.arguments` to no longer include the password.
@@ -11,6 +11,7 @@ module Rodbot
11
11
  include Rodbot::Memoize
12
12
 
13
13
  def valid_otp?
14
+ def self.arguments = params['arguments'].sub(/\s*\d{6}\s*\z/, '')
14
15
  return false unless password
15
16
  return false if Rodbot.db.get(:otp, password) # already used
16
17
  !!if totp.verify(password, drift_behind: Rodbot.config(:otp, :drift).to_i)
@@ -34,10 +35,7 @@ module Rodbot
34
35
  #
35
36
  # @return [String, nil] extracted password if any
36
37
  memoize def password
37
- if params['arguments']
38
- params['arguments'] = params['arguments'].sub(/\s*(\d{6})\s*\z/, '')
39
- $1
40
- end
38
+ params['arguments']&.match(/\s*(\d{6})\s*\z/)&.captures&.first
41
39
  end
42
40
  end
43
41
 
@@ -0,0 +1,48 @@
1
+ # Rodbot Plugin – Slack
2
+
3
+ Relay with the Slack communication network
4
+
5
+ ## Preparation
6
+
7
+ To get an `access_token`, you have to follow the [basic app setup guide](https://api.slack.com/authentication/basics):
8
+
9
+ 1. [Create a new Slack classic app](https://api.slack.com/apps?new_classic_app=1)
10
+ 2. In the overlay: Give the app a name and pick the workspace for the app and the bot.
11
+ 3. In the sidebar: Click on "Basic Information", unfold "Add features and functionality" and hit "Bots". Then click the "Add Legacy Bot User" button and in the overlay enter the display name (used e.g in the user list) and user name (used e.g. for mentions). Optionally activate "Always Show My Bot as Online".
12
+ 4. In the sidebar: Click on "Basic Information" again, scroll down to "Display Information" to set an app icon, color and descriptions. Click "Save Changes" when done".
13
+ 5. Scroll up and click the "Install to Workspace" button, then click "Allow".
14
+ 6. In the sidebar: Click on "Basic Information" again, scroll down to "App Credentials" and copy the "Signing Secret" which will be used as `signing_secret` below.
15
+ 7. In the sidebar: Click on "OAuth and Permissions" and copy the "Bot User OAuth Token" (starting with "xoxb-") which will be used as `access_token` below.
16
+
17
+ With the app in place, open the Slack client with your normal user, then:
18
+
19
+ 1. Select the channel you want the bot to be present in.
20
+ 2. In the upper right corner click on "View all members of this channel".
21
+ 3. Select the "Integrations" tab, then click on "Add apps" and add the app you've just created.
22
+ 4. Select the "About" tab, scroll all the way down and note the `channel_id` to be used below.
23
+
24
+ ## Activation
25
+
26
+ Install the required gems via the corresponding Bundler group:
27
+
28
+ ```
29
+ bundle config set --local with slack
30
+ bundle install
31
+ ```
32
+
33
+ Then activate and configure this plugin in `config/rodbot.rb`:
34
+
35
+ ```ruby
36
+ plugin :slack do
37
+ access_token '<TOKEN>'
38
+ channel_id '<CHANNEL_ID>'
39
+ end
40
+ ```
41
+
42
+ You might want to use the credentials facilities of Rodbot to encrypt the token.
43
+
44
+ ## Usage
45
+
46
+ Once Rodbot is restarted, the Slack relay starts listening. To check whether the relay works fine, just say +!ping+ in the channel, you should receive a "pong" in reply.
47
+
48
+ Any room message beginning with "!" is considered a bot command.
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'slack-ruby-client'
4
+
5
+ using Rodbot::Refinements
6
+
7
+ module Rodbot
8
+ class Plugins
9
+ class Slack
10
+ class Relay < Rodbot::Relay
11
+ include Rodbot::Memoize
12
+
13
+ def loops
14
+ ::Slack.configure do |config|
15
+ config.token = access_token
16
+ end
17
+ [method(:read_loop), method(:write_loop)]
18
+ end
19
+
20
+ private
21
+
22
+ def access_token
23
+ Rodbot.config(:plugin, :slack, :access_token)
24
+ rescue => error
25
+ raise Rodbot::PluginError.new("invalid access_token", error.message)
26
+ end
27
+
28
+ memoize def client
29
+ ::Slack::RealTime::Client.new
30
+ end
31
+
32
+ def channel_id
33
+ Rodbot.config(:plugin, :slack, :channel_id)
34
+ rescue => error
35
+ raise Rodbot::PluginError.new("invalid channel_id", error.message)
36
+ end
37
+
38
+ def write_loop
39
+ server = TCPServer.new(*bind)
40
+ loop do
41
+ Thread.start(server.accept) do |remote|
42
+ body = remote.gets("\x04")
43
+ remote.close
44
+ body.force_encoding('UTF-8')
45
+ client.web_client.chat_postMessage(channel: channel_id, text: body, as_user: true)
46
+ end
47
+ end
48
+ end
49
+
50
+ def read_loop
51
+ client.on :message do |message|
52
+ on_message(message) if message.channel == channel_id
53
+ end
54
+ client.start!
55
+ end
56
+
57
+ def on_message(message)
58
+ if message.text.start_with?('!')
59
+ md = 'pong' if message.text == '!ping'
60
+ md ||= reply_to(message)
61
+ client.web_client.chat_postMessage(channel: message.channel, text: md, as_user: true)
62
+ end
63
+ end
64
+
65
+ def reply_to(message)
66
+ command(*message.text[1..].split(/\s+/, 2)).
67
+ psub(placeholders(message.user))
68
+ end
69
+
70
+ def placeholders(sender)
71
+ {
72
+ sender: "<@#{sender}>"
73
+ }
74
+ end
75
+
76
+ end
77
+ end
78
+ end
79
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Rodbot
4
- VERSION = "0.2.0"
4
+ VERSION = "0.3.0"
5
5
  end
@@ -6,6 +6,11 @@ group :matrix, optional: true do
6
6
  gem 'matrix_sdk', '~> 2'
7
7
  end
8
8
 
9
+ group :slack, optional: true do
10
+ gem 'slack-ruby-client', '~> 2'
11
+ gem 'async-websocket', '~> 0.8.0'
12
+ end
13
+
9
14
  group :redis, optional: true do
10
15
  gem 'redis', '~> 5'
11
16
  end
data/rodbot.gemspec CHANGED
@@ -58,8 +58,10 @@ Gem::Specification.new do |spec|
58
58
 
59
59
  # Sync versions with lib/templates/new/gems.rb
60
60
  spec.add_development_dependency 'redis', '~> 5'
61
- spec.add_development_dependency 'matrix_sdk', '~> 2'
62
61
  spec.add_development_dependency 'rotp', '~> 6'
62
+ spec.add_development_dependency 'matrix_sdk', '~> 2'
63
+ spec.add_development_dependency 'slack-ruby-client', '~> 2'
64
+ spec.add_development_dependency 'async-websocket', '~> 0.8.0'
63
65
 
64
66
  spec.add_development_dependency 'rake'
65
67
  spec.add_development_dependency 'minitest'
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rodbot
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sven Schwyn
@@ -29,7 +29,7 @@ cert_chain:
29
29
  kAyiRqgxF4dJviwtqI7mZIomWL63+kXLgjOjMe1SHxfIPo/0ji6+r1p4KYa7o41v
30
30
  fwIwU1MKlFBdsjkd
31
31
  -----END CERTIFICATE-----
32
- date: 2023-09-14 00:00:00.000000000 Z
32
+ date: 2023-10-11 00:00:00.000000000 Z
33
33
  dependencies:
34
34
  - !ruby/object:Gem::Dependency
35
35
  name: zeitwerk
@@ -247,6 +247,20 @@ dependencies:
247
247
  - - "~>"
248
248
  - !ruby/object:Gem::Version
249
249
  version: '5'
250
+ - !ruby/object:Gem::Dependency
251
+ name: rotp
252
+ requirement: !ruby/object:Gem::Requirement
253
+ requirements:
254
+ - - "~>"
255
+ - !ruby/object:Gem::Version
256
+ version: '6'
257
+ type: :development
258
+ prerelease: false
259
+ version_requirements: !ruby/object:Gem::Requirement
260
+ requirements:
261
+ - - "~>"
262
+ - !ruby/object:Gem::Version
263
+ version: '6'
250
264
  - !ruby/object:Gem::Dependency
251
265
  name: matrix_sdk
252
266
  requirement: !ruby/object:Gem::Requirement
@@ -262,19 +276,33 @@ dependencies:
262
276
  - !ruby/object:Gem::Version
263
277
  version: '2'
264
278
  - !ruby/object:Gem::Dependency
265
- name: rotp
279
+ name: slack-ruby-client
266
280
  requirement: !ruby/object:Gem::Requirement
267
281
  requirements:
268
282
  - - "~>"
269
283
  - !ruby/object:Gem::Version
270
- version: '6'
284
+ version: '2'
271
285
  type: :development
272
286
  prerelease: false
273
287
  version_requirements: !ruby/object:Gem::Requirement
274
288
  requirements:
275
289
  - - "~>"
276
290
  - !ruby/object:Gem::Version
277
- version: '6'
291
+ version: '2'
292
+ - !ruby/object:Gem::Dependency
293
+ name: async-websocket
294
+ requirement: !ruby/object:Gem::Requirement
295
+ requirements:
296
+ - - "~>"
297
+ - !ruby/object:Gem::Version
298
+ version: 0.8.0
299
+ type: :development
300
+ prerelease: false
301
+ version_requirements: !ruby/object:Gem::Requirement
302
+ requirements:
303
+ - - "~>"
304
+ - !ruby/object:Gem::Version
305
+ version: 0.8.0
278
306
  - !ruby/object:Gem::Dependency
279
307
  name: rake
280
308
  requirement: !ruby/object:Gem::Requirement
@@ -421,6 +449,7 @@ files:
421
449
  - checksums/rodbot-0.1.0.pre9.gem.sha512
422
450
  - checksums/rodbot-0.1.1.gem.sha512
423
451
  - checksums/rodbot-0.2.0.gem.sha512
452
+ - checksums/rodbot-0.3.0.gem.sha512
424
453
  - doc/rodbot.afphoto
425
454
  - doc/rodbot.avif
426
455
  - exe/rodbot
@@ -462,6 +491,8 @@ files:
462
491
  - lib/rodbot/plugins/matrix/relay.rb
463
492
  - lib/rodbot/plugins/otp/README.otp.md
464
493
  - lib/rodbot/plugins/otp/app.rb
494
+ - lib/rodbot/plugins/slack/README.slack.md
495
+ - lib/rodbot/plugins/slack/relay.rb
465
496
  - lib/rodbot/plugins/word_of_the_day/README.word_of_the_day.md
466
497
  - lib/rodbot/plugins/word_of_the_day/schedule.rb
467
498
  - lib/rodbot/rack.rb
@@ -531,7 +562,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
531
562
  - !ruby/object:Gem::Version
532
563
  version: '0'
533
564
  requirements: []
534
- rubygems_version: 3.4.19
565
+ rubygems_version: 3.4.20
535
566
  signing_key:
536
567
  specification_version: 4
537
568
  summary: Minimalistic framework to build chat bots on top of a Roda backend
metadata.gz.sig CHANGED
@@ -1 +1,3 @@
1
- �Lͣ��D��*������Y*h�U���dz^�g�|����׹3�`K���
1
+ z��J����
2
+ O}ot��#�*��j�Au� �F�*ŔU��R���P�,jM-Ow�
3
+ �<m��GD���O�������5B�Q��R�e��Z-�v! ͭ�}��%� a'�?�&��4�;�