waylon-core 0.1.1 → 0.1.4

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.
@@ -0,0 +1,174 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Waylon
4
+ module Skills
5
+ # A Skill for providing help
6
+ class Help < Skill
7
+ # Ask for some help.
8
+ # Defaults to all things a user has access to, but allows specifying either a Skill name or a Skill and Route
9
+ route(
10
+ /^help(?<skill_clause>\s+(?<skill>\w+)(?<action_clause>#(?<action>\w+)|\s+(?<action>\w+))?)?$/i,
11
+ :help,
12
+ help: {
13
+ usage: "help [skill [action]]",
14
+ description: "Allows asking for help, either for all skills or for a particular skill or action"
15
+ }
16
+ )
17
+
18
+ # Responds to "help" requests
19
+ def help
20
+ skill = named_tokens[:skill]
21
+ action = named_tokens[:action]
22
+
23
+ react :book
24
+
25
+ immediate_responses = [
26
+ "I'll send you a DM to go over that with you.",
27
+ "I'll DM you the details.",
28
+ "Look for a private message with those details.",
29
+ "You should have a private message with that information shortly."
30
+ ]
31
+
32
+ # Only send this if you aren't already in a DM
33
+ threaded_reply "#{acknowledgement} #{immediate_responses.sample}" unless message.private?
34
+
35
+ if sense.supports?(:blocks)
36
+ reply_with_blocks(help_blocks(skill, action), private: true)
37
+ else
38
+ reply(help_text(skill, action), private: true)
39
+ end
40
+ end
41
+
42
+ def help_text(skill = nil, action = nil) # rubocop:disable Metrics/AbcSize
43
+ allowed_routes = SkillRegistry.instance.help(message.author)
44
+ resp = []
45
+ if skill
46
+ if action
47
+ resp << "## Help for #{skill}##{action}:"
48
+ this_route = allowed_routes[skill].find do |r|
49
+ r[:name].to_s == "#{skill}##{action}"
50
+ end
51
+ return "I couldn't find #{action} on #{skill}..." unless this_route
52
+
53
+ resp << build_help_text(this_route)
54
+ else
55
+ resp << "## Help for #{skill}:\n"
56
+ routes = allowed_routes[skill]
57
+ (routes || []).each { |r| resp << build_help_text(r) }
58
+ end
59
+ else
60
+ help_text_for_all(allowed_routes)
61
+ end
62
+ end
63
+
64
+ def help_blocks(skill = nil, action = nil) # rubocop:disable Metrics/AbcSize
65
+ allowed_routes = SkillRegistry.instance.help(message.author)
66
+ if skill
67
+ if action
68
+ this_route = allowed_routes[skill].find do |r|
69
+ r[:name].to_s == "#{skill}##{action}"
70
+ end
71
+
72
+ return not_found_block(skill, action) unless this_route
73
+
74
+ [build_header_block(skill, action), build_help_block(this_route)]
75
+ else
76
+ routes = allowed_routes[skill]
77
+ return not_found_block(skill, nil) unless routes
78
+
79
+ resp = [build_header_block(skill, nil)]
80
+ routes.each { |r| resp << build_help_block(r) }
81
+ resp
82
+ end
83
+ else
84
+ allowed_routes = SkillRegistry.instance.help(message.author)
85
+ help_blocks_for_all(allowed_routes)
86
+ end
87
+ end
88
+
89
+ def help_blocks_for_all(routes)
90
+ resp = [
91
+ { type: "header", text: { type: "plain_text", text: "All known actions:", emoji: true } }
92
+ ]
93
+
94
+ routes.each do |k, v|
95
+ resp += [
96
+ { type: "divider" },
97
+ {
98
+ type: "section",
99
+ text: {
100
+ type: "mrkdwn",
101
+ text: "*Actions for '#{k}':*"
102
+ }
103
+ }
104
+ ]
105
+ v.each { |r| resp << build_help_block(r) }
106
+ end
107
+ resp
108
+ end
109
+
110
+ def help_text_for_all(routes)
111
+ resp = []
112
+ resp << "*All known actions:*\n"
113
+ routes.each do |k, v|
114
+ resp << "* *#{k}*:"
115
+ v.each do |r|
116
+ resp << build_help_text(r)
117
+ end
118
+ resp << " --- "
119
+ end
120
+ resp.join("\n")
121
+ end
122
+
123
+ def build_header_block(skill, action)
124
+ text = if action
125
+ "Help for #{skill}##{action}:"
126
+ else
127
+ "Help for #{skill}:"
128
+ end
129
+ { type: "header", text: { type: "plain_text", text: text, emoji: true } }
130
+ end
131
+
132
+ def build_help_block(this_route)
133
+ {
134
+ type: "section",
135
+ text: {
136
+ type: "mrkdwn",
137
+ text: " *#{this_route[:name]}*\n#{build_help_text(this_route)}"
138
+ }
139
+ }
140
+ end
141
+
142
+ def build_help_text(this_route)
143
+ route_help_text = []
144
+ case this_route[:help]
145
+ when String
146
+ route_help_text << " *Usage:* #{this_route[:help]}"
147
+ when Hash
148
+ route_help_text << " *Usage:* #{this_route.dig(:help, :usage)}"
149
+ if this_route.dig(:help, :description)
150
+ route_help_text << "\n *Description:* #{this_route.dig(:help, :description)}"
151
+ end
152
+ end
153
+ route_help_text.join
154
+ end
155
+
156
+ def not_found_block(skill, action)
157
+ sentence = if action
158
+ "I couldn't find any '#{action}' action on the '#{skill}' skill..."
159
+ else
160
+ "I couldn't find any routes related to a '#{skill}' skill..."
161
+ end
162
+ [
163
+ {
164
+ type: "section",
165
+ text: {
166
+ type: "mrkdwn",
167
+ text: sentence
168
+ }
169
+ }
170
+ ]
171
+ end
172
+ end
173
+ end
174
+ end
data/lib/waylon/user.rb CHANGED
@@ -18,6 +18,11 @@ module Waylon
18
18
  raise NotImplementedError, "find_by_handle isn't implemented"
19
19
  end
20
20
 
21
+ # This should be overridden by subclasses to provide a mechanism for looking up Users based on mention strings
22
+ def from_mention(_mention_string)
23
+ raise NotImplementedError, "from_mention isn't implemented"
24
+ end
25
+
21
26
  # Provides a simple mechanism for referencing User subclass's Sense
22
27
  # @return [Class] A Sense subclass
23
28
  def sense
@@ -6,7 +6,7 @@ module Waylon
6
6
  VERSION = [
7
7
  0, # Major
8
8
  1, # Minor
9
- 1 # Patch
9
+ 4 # Patch
10
10
  ].join(".")
11
11
  end
12
12
  end
@@ -21,7 +21,7 @@ module Waylon
21
21
  # @return [Class] The name of the corresponding Sense class
22
22
  def sense_class
23
23
  last = self.class.name.split("::").last
24
- Module.const_get("Senses::#{last}")
24
+ Module.const_get("Waylon::Senses::#{last}")
25
25
  end
26
26
 
27
27
  # This must be implemented on every Webhook to provide a mechanism to ensure received payloads are legit
@@ -38,36 +38,35 @@ module Waylon
38
38
  end
39
39
 
40
40
  before do
41
- content_type "application/json"
42
-
43
- begin
44
- unless request.get? || request.options?
45
- request.body.rewind
46
- @parsed_body = JSON.parse(request.body.read, symbolize_names: true)
47
- end
48
- rescue StandardError => e
49
- halt(400, { error: "Request must be JSON: #{e.message}" }.to_json)
41
+ unless request.get? || request.options?
42
+ request.body.rewind
43
+ @parsed_body = JSON.parse(request.body.read, symbolize_names: true)
50
44
  end
45
+ rescue StandardError => e
46
+ content_type "application/json"
47
+ halt(400, { error: "Request must be JSON: #{e.message}" }.to_json)
51
48
  end
52
49
 
53
50
  after do
54
51
  request.options? && headers("Access-Control-Allow-Methods" => @allowed_types || %w[OPTIONS POST])
55
52
  end
56
53
 
57
- post "/" do
58
- begin
59
- request.body.rewind
60
- verify request.body.read, request.env
61
- enqueue @parsed_body
62
- rescue StandardError => e
63
- halt(422, { error: "Unprocessable entity: #{e.message}" }.to_json)
64
- end
65
-
66
- { status: :ok }.to_json
67
- end
68
-
69
- options "/" do
70
- halt 200
71
- end
54
+ ## Example incoming webhook
55
+ #
56
+ # post "/" do
57
+ # begin
58
+ # request.body.rewind
59
+ # verify request.body.read, request.env
60
+ # enqueue @parsed_body
61
+ # rescue StandardError => e
62
+ # halt(422, { error: "Unprocessable entity: #{e.message}" }.to_json)
63
+ # end
64
+ #
65
+ # { status: :ok }.to_json
66
+ # end
67
+ #
68
+ # options "/" do
69
+ # halt 200
70
+ # end
72
71
  end
73
72
  end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Waylon
4
+ # Registry of Webhook subclasses known to Waylon
5
+ class WebhookRegistry
6
+ include Singleton
7
+
8
+ attr_reader :webhooks
9
+
10
+ # A convenience wrapper around the singleton instance #register method
11
+ # @param (see #register)
12
+ # @return (see #register)
13
+ def self.register(name, class_name)
14
+ instance.register(name, class_name)
15
+ end
16
+
17
+ # Add the provided Webhook class to the registry under `name`
18
+ # @param name [String] The name of the Webhook in the registry
19
+ # @param class_name [Class] The Webhook subclass to add
20
+ # @return [Class] The Webhook subclass
21
+ def register(name, class_name)
22
+ @webhooks ||= {}
23
+ @webhooks[name.to_s] = class_name
24
+ end
25
+
26
+ # Provides a Hash version of this registry
27
+ # @return [Hash]
28
+ def to_hash
29
+ (@webhooks || {}).transform_keys { |k| "/hooks/#{k}" }
30
+ end
31
+ end
32
+ end
data/lib/waylon.rb CHANGED
@@ -2,4 +2,7 @@
2
2
 
3
3
  require "waylon/core"
4
4
  require "waylon/skills/default"
5
+ require "waylon/skills/diagnostics"
5
6
  require "waylon/skills/fun"
7
+ require "waylon/skills/groups"
8
+ require "waylon/skills/help"
@@ -0,0 +1,7 @@
1
+ #!/bin/sh
2
+
3
+ gem install bundler -v '~> 2.3'
4
+ bundle install
5
+ rm -rf pkg/*.gem
6
+ bundle exec rake build
7
+ bundle exec gem push pkg/*.gem
data/scripts/test.sh CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/bin/sh
2
2
 
3
- gem install bundler -v '~> 2.2'
3
+ gem install bundler -v '~> 2.3'
4
4
  bundle install
5
5
  bundle exec rake
data/waylon-core.gemspec CHANGED
@@ -35,7 +35,7 @@ Gem::Specification.new do |spec|
35
35
  spec.add_dependency "puma", "~> 5.5"
36
36
  spec.add_dependency "resque", "~> 2.2"
37
37
 
38
- spec.add_development_dependency "bundler", "~> 2.2"
38
+ spec.add_development_dependency "bundler", "~> 2.3"
39
39
  spec.add_development_dependency "rake", "~> 13.0"
40
40
  spec.add_development_dependency "rspec", "~> 3.10"
41
41
  spec.add_development_dependency "rubocop", "~> 1.23"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: waylon-core
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jonathan Gnagy
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-01-07 00:00:00.000000000 Z
11
+ date: 2022-06-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: addressable
@@ -114,14 +114,14 @@ dependencies:
114
114
  requirements:
115
115
  - - "~>"
116
116
  - !ruby/object:Gem::Version
117
- version: '2.2'
117
+ version: '2.3'
118
118
  type: :development
119
119
  prerelease: false
120
120
  version_requirements: !ruby/object:Gem::Requirement
121
121
  requirements:
122
122
  - - "~>"
123
123
  - !ruby/object:Gem::Version
124
- version: '2.2'
124
+ version: '2.3'
125
125
  - !ruby/object:Gem::Dependency
126
126
  name: rake
127
127
  requirement: !ruby/object:Gem::Requirement
@@ -249,6 +249,7 @@ files:
249
249
  - lib/waylon.rb
250
250
  - lib/waylon/base_component.rb
251
251
  - lib/waylon/condition.rb
252
+ - lib/waylon/conditions/black_hole.rb
252
253
  - lib/waylon/conditions/default.rb
253
254
  - lib/waylon/conditions/permission_denied.rb
254
255
  - lib/waylon/conditions/regex.rb
@@ -261,6 +262,7 @@ files:
261
262
  - lib/waylon/logger.rb
262
263
  - lib/waylon/message.rb
263
264
  - lib/waylon/route.rb
265
+ - lib/waylon/routes/black_hole.rb
264
266
  - lib/waylon/routes/default.rb
265
267
  - lib/waylon/routes/permission_denied.rb
266
268
  - lib/waylon/rspec.rb
@@ -274,13 +276,19 @@ files:
274
276
  - lib/waylon/rspec/test_worker.rb
275
277
  - lib/waylon/sense.rb
276
278
  - lib/waylon/sense_registry.rb
279
+ - lib/waylon/services/ping.rb
277
280
  - lib/waylon/skill.rb
278
281
  - lib/waylon/skill_registry.rb
279
282
  - lib/waylon/skills/default.rb
283
+ - lib/waylon/skills/diagnostics.rb
280
284
  - lib/waylon/skills/fun.rb
285
+ - lib/waylon/skills/groups.rb
286
+ - lib/waylon/skills/help.rb
281
287
  - lib/waylon/user.rb
282
288
  - lib/waylon/version.rb
283
289
  - lib/waylon/webhook.rb
290
+ - lib/waylon/webhook_registry.rb
291
+ - scripts/release.sh
284
292
  - scripts/test.sh
285
293
  - waylon-core.gemspec
286
294
  homepage: https://github.com/jgnagy/waylon-core
@@ -290,7 +298,7 @@ metadata:
290
298
  homepage_uri: https://github.com/jgnagy/waylon-core
291
299
  source_code_uri: https://github.com/jgnagy/waylon-core
292
300
  changelog_uri: https://github.com/jgnagy/waylon-core/blob/main/CHANGELOG.md
293
- post_install_message:
301
+ post_install_message:
294
302
  rdoc_options: []
295
303
  require_paths:
296
304
  - lib
@@ -305,8 +313,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
305
313
  - !ruby/object:Gem::Version
306
314
  version: '0'
307
315
  requirements: []
308
- rubygems_version: 3.2.32
309
- signing_key:
316
+ rubygems_version: 3.3.7
317
+ signing_key:
310
318
  specification_version: 4
311
319
  summary: Core library for the Waylon bot framework
312
320
  test_files: []