waylon-core 0.1.1 → 0.1.4

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