rita 0.1.0 → 5.0.0.alpha.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +19 -0
- data/.rubocop.yml +51 -0
- data/.ruby-version +1 -0
- data/.travis.yml +16 -0
- data/CONTRIBUTING.md +18 -0
- data/Gemfile +5 -0
- data/{LICENSE.txt → LICENSE} +1 -3
- data/README.md +17 -24
- data/Rakefile +5 -5
- data/bin/lita +7 -0
- data/lib/lita/adapter.rb +147 -0
- data/lib/lita/adapters/shell.rb +126 -0
- data/lib/lita/adapters/test.rb +62 -0
- data/lib/lita/authorization.rb +112 -0
- data/lib/lita/callback.rb +39 -0
- data/lib/lita/cli.rb +218 -0
- data/lib/lita/configurable.rb +47 -0
- data/lib/lita/configuration_builder.rb +247 -0
- data/lib/lita/configuration_validator.rb +95 -0
- data/lib/lita/default_configuration.rb +122 -0
- data/lib/lita/errors.rb +25 -0
- data/lib/lita/handler/chat_router.rb +141 -0
- data/lib/lita/handler/common.rb +208 -0
- data/lib/lita/handler/event_router.rb +84 -0
- data/lib/lita/handler/http_router.rb +31 -0
- data/lib/lita/handler.rb +15 -0
- data/lib/lita/handlers/authorization.rb +129 -0
- data/lib/lita/handlers/help.rb +171 -0
- data/lib/lita/handlers/info.rb +66 -0
- data/lib/lita/handlers/room.rb +36 -0
- data/lib/lita/handlers/users.rb +37 -0
- data/lib/lita/http_callback.rb +46 -0
- data/lib/lita/http_route.rb +83 -0
- data/lib/lita/logger.rb +43 -0
- data/lib/lita/message.rb +124 -0
- data/lib/lita/middleware_registry.rb +39 -0
- data/lib/lita/namespace.rb +29 -0
- data/lib/lita/plugin_builder.rb +43 -0
- data/lib/lita/rack_app.rb +100 -0
- data/lib/lita/registry.rb +164 -0
- data/lib/lita/response.rb +65 -0
- data/lib/lita/robot.rb +273 -0
- data/lib/lita/room.rb +119 -0
- data/lib/lita/route_validator.rb +82 -0
- data/lib/lita/rspec/handler.rb +127 -0
- data/lib/lita/rspec/matchers/chat_route_matcher.rb +53 -0
- data/lib/lita/rspec/matchers/event_route_matcher.rb +29 -0
- data/lib/lita/rspec/matchers/http_route_matcher.rb +34 -0
- data/lib/lita/rspec.rb +48 -0
- data/lib/lita/source.rb +81 -0
- data/lib/lita/store.rb +23 -0
- data/lib/lita/target.rb +3 -0
- data/lib/lita/template.rb +71 -0
- data/lib/lita/template_resolver.rb +52 -0
- data/lib/lita/timer.rb +49 -0
- data/lib/lita/user.rb +157 -0
- data/lib/lita/util.rb +31 -0
- data/lib/lita/version.rb +6 -0
- data/lib/lita.rb +166 -0
- data/rita.gemspec +50 -0
- data/spec/lita/adapter_spec.rb +54 -0
- data/spec/lita/adapters/shell_spec.rb +99 -0
- data/spec/lita/authorization_spec.rb +122 -0
- data/spec/lita/configuration_builder_spec.rb +247 -0
- data/spec/lita/configuration_validator_spec.rb +114 -0
- data/spec/lita/default_configuration_spec.rb +242 -0
- data/spec/lita/handler/chat_router_spec.rb +236 -0
- data/spec/lita/handler/common_spec.rb +289 -0
- data/spec/lita/handler/event_router_spec.rb +121 -0
- data/spec/lita/handler/http_router_spec.rb +155 -0
- data/spec/lita/handler_spec.rb +62 -0
- data/spec/lita/handlers/authorization_spec.rb +111 -0
- data/spec/lita/handlers/help_spec.rb +124 -0
- data/spec/lita/handlers/info_spec.rb +67 -0
- data/spec/lita/handlers/room_spec.rb +24 -0
- data/spec/lita/handlers/users_spec.rb +35 -0
- data/spec/lita/logger_spec.rb +28 -0
- data/spec/lita/message_spec.rb +178 -0
- data/spec/lita/plugin_builder_spec.rb +41 -0
- data/spec/lita/response_spec.rb +62 -0
- data/spec/lita/robot_spec.rb +285 -0
- data/spec/lita/room_spec.rb +136 -0
- data/spec/lita/rspec/handler_spec.rb +33 -0
- data/spec/lita/rspec_spec.rb +162 -0
- data/spec/lita/source_spec.rb +68 -0
- data/spec/lita/store_spec.rb +23 -0
- data/spec/lita/template_resolver_spec.rb +42 -0
- data/spec/lita/template_spec.rb +52 -0
- data/spec/lita/timer_spec.rb +32 -0
- data/spec/lita/user_spec.rb +167 -0
- data/spec/lita/util_spec.rb +18 -0
- data/spec/lita_spec.rb +227 -0
- data/spec/spec_helper.rb +35 -0
- data/spec/templates/basic.erb +1 -0
- data/spec/templates/basic.irc.erb +1 -0
- data/spec/templates/helpers.erb +1 -0
- data/spec/templates/interpolated.erb +1 -0
- data/templates/locales/en.yml +137 -0
- data/templates/plugin/Gemfile +5 -0
- data/templates/plugin/README.tt +29 -0
- data/templates/plugin/Rakefile +8 -0
- data/templates/plugin/gemspec.tt +27 -0
- data/templates/plugin/gitignore +18 -0
- data/templates/plugin/lib/lita/plugin_type/plugin.tt +19 -0
- data/templates/plugin/lib/plugin.tt +16 -0
- data/templates/plugin/locales/en.yml.tt +4 -0
- data/templates/plugin/spec/lita/plugin_type/plugin_spec.tt +6 -0
- data/templates/plugin/spec/spec_helper.tt +8 -0
- data/templates/plugin/templates/gitkeep +0 -0
- data/templates/robot/Gemfile +5 -0
- data/templates/robot/lita_config.rb +28 -0
- metadata +386 -21
- data/.standard.yml +0 -3
- data/CHANGELOG.md +0 -5
- data/CODE_OF_CONDUCT.md +0 -132
- data/lib/rita/version.rb +0 -5
- data/lib/rita.rb +0 -8
- data/sig/rita.rbs +0 -4
@@ -0,0 +1,129 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Lita
|
4
|
+
# A namespace to hold all subclasses of {Handler}.
|
5
|
+
module Handlers
|
6
|
+
# Provides a chat interface for administering authorization groups.
|
7
|
+
class Authorization
|
8
|
+
extend Handler::ChatRouter
|
9
|
+
|
10
|
+
route(
|
11
|
+
/^auth\s+add/,
|
12
|
+
:add,
|
13
|
+
command: true,
|
14
|
+
restrict_to: :admins,
|
15
|
+
help: { t("help.add_key") => t("help.add_value") }
|
16
|
+
)
|
17
|
+
route(
|
18
|
+
/^auth\s+remove/,
|
19
|
+
:remove,
|
20
|
+
command: true,
|
21
|
+
restrict_to: :admins,
|
22
|
+
help: { t("help.remove_key") => t("help.remove_value") }
|
23
|
+
)
|
24
|
+
route(/^auth\s+list/, :list, command: true, restrict_to: :admins, help: {
|
25
|
+
t("help.list_key") => t("help.list_value")
|
26
|
+
})
|
27
|
+
|
28
|
+
# Adds a user to an authorization group.
|
29
|
+
# @param response [Response] The response object.
|
30
|
+
# @return [void]
|
31
|
+
def add(response)
|
32
|
+
toggle_membership(response, :add_user_to_group, "user_added", "user_already_in")
|
33
|
+
end
|
34
|
+
|
35
|
+
# Removes a user from an authorization group.
|
36
|
+
# @param response [Response] The response object.
|
37
|
+
# @return [void]
|
38
|
+
def remove(response)
|
39
|
+
toggle_membership(response, :remove_user_from_group, "user_removed", "user_not_in")
|
40
|
+
end
|
41
|
+
|
42
|
+
# Lists all authorization groups (or only the specified group) and the
|
43
|
+
# names of their members.
|
44
|
+
# @param response [Response] The response object.
|
45
|
+
# @return [void]
|
46
|
+
def list(response)
|
47
|
+
requested_group = response.args[1]
|
48
|
+
output = get_groups_list(response.args[1])
|
49
|
+
if output.empty?
|
50
|
+
response.reply(empty_state_for_list(requested_group))
|
51
|
+
else
|
52
|
+
response.reply(output.join("\n"))
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def empty_state_for_list(requested_group)
|
59
|
+
if requested_group
|
60
|
+
t("empty_state_group", group: requested_group)
|
61
|
+
else
|
62
|
+
t("empty_state")
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def get_groups_list(requested_group)
|
67
|
+
groups_with_users = robot.auth.groups_with_users
|
68
|
+
if requested_group
|
69
|
+
requested_group = requested_group.downcase.strip.to_sym
|
70
|
+
groups_with_users.select! { |group, _| group == requested_group }
|
71
|
+
end
|
72
|
+
groups_with_users.map do |group, users|
|
73
|
+
user_names = users.map(&:name).join(", ")
|
74
|
+
"#{group}: #{user_names}"
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def toggle_membership(response, method_name, success_key, failure_key)
|
79
|
+
return unless valid_message?(response)
|
80
|
+
|
81
|
+
if robot.auth.public_send(method_name, response.user, @user, @group)
|
82
|
+
response.reply t(success_key, user: @user.name, group: @group)
|
83
|
+
else
|
84
|
+
response.reply t(failure_key, user: @user.name, group: @group)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def valid_group?(response, identifier)
|
89
|
+
unless identifier && @group
|
90
|
+
response.reply "#{t("format")}: #{robot.name} auth add USER GROUP"
|
91
|
+
return false
|
92
|
+
end
|
93
|
+
|
94
|
+
if @group.downcase.strip == "admins"
|
95
|
+
response.reply t("admin_management")
|
96
|
+
return false
|
97
|
+
end
|
98
|
+
|
99
|
+
true
|
100
|
+
end
|
101
|
+
|
102
|
+
# Validates that incoming messages have the right format and a valid user.
|
103
|
+
# Also assigns the user and group to instance variables for the main
|
104
|
+
# methods to use later.
|
105
|
+
def valid_message?(response)
|
106
|
+
_command, identifier, @group = response.args
|
107
|
+
|
108
|
+
return unless valid_group?(response, identifier)
|
109
|
+
|
110
|
+
return unless valid_user?(response, identifier)
|
111
|
+
|
112
|
+
true
|
113
|
+
end
|
114
|
+
|
115
|
+
def valid_user?(response, identifier)
|
116
|
+
@user = User.fuzzy_find(identifier)
|
117
|
+
|
118
|
+
if @user
|
119
|
+
true
|
120
|
+
else
|
121
|
+
response.reply t("no_user_found", identifier: identifier)
|
122
|
+
false
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
Lita.register_handler(Authorization)
|
128
|
+
end
|
129
|
+
end
|
@@ -0,0 +1,171 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Lita
|
4
|
+
# A namespace to hold all subclasses of {Handler}.
|
5
|
+
module Handlers
|
6
|
+
# Provides online help about Lita commands for users.
|
7
|
+
class Help
|
8
|
+
extend Handler::ChatRouter
|
9
|
+
|
10
|
+
route(/^help\s*(?<query>.+)?/i, :help, command: true, help: {
|
11
|
+
"help" => t("help.help_value"),
|
12
|
+
t("help.help_query_key") => t("help.help_query_value")
|
13
|
+
})
|
14
|
+
|
15
|
+
# Outputs help information about Lita commands.
|
16
|
+
# @param response [Response] The response object.
|
17
|
+
# @return [void]
|
18
|
+
def help(response)
|
19
|
+
query = response.match_data["query"]
|
20
|
+
|
21
|
+
if query.nil?
|
22
|
+
return response.reply_privately(
|
23
|
+
"#{t("info", address: address)}\n\n#{list_handlers.join("\n")}"
|
24
|
+
)
|
25
|
+
end
|
26
|
+
|
27
|
+
handlers = matching_handlers(query)
|
28
|
+
handlers_to_messages = map_handlers_to_messages(response, handlers)
|
29
|
+
messages = matching_messages(response, query, handlers_to_messages)
|
30
|
+
response.reply_privately(format_reply(handlers_to_messages, messages, query))
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
# Checks if the user is authorized to at least one of the given groups.
|
36
|
+
def authorized?(user, required_groups)
|
37
|
+
required_groups.nil? || required_groups.any? do |group|
|
38
|
+
robot.auth.user_in_group?(user, group)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# Creates an alphabetically-sorted array containing the names of all
|
43
|
+
# installed handlers.
|
44
|
+
def list_handlers
|
45
|
+
robot.handlers.flat_map do |handler|
|
46
|
+
handler.namespace if handler.respond_to?(:routes)
|
47
|
+
end.compact.uniq.sort
|
48
|
+
end
|
49
|
+
|
50
|
+
# Creates an array of handlers matching the given query.
|
51
|
+
def matching_handlers(query)
|
52
|
+
name = query.downcase.strip
|
53
|
+
|
54
|
+
return [] unless list_handlers.include?(name)
|
55
|
+
|
56
|
+
robot.handlers.select { |handler| handler.namespace == name }
|
57
|
+
end
|
58
|
+
|
59
|
+
# Creates a hash of handler namespaces and their associated help messages.
|
60
|
+
def map_handlers_to_messages(response, handlers)
|
61
|
+
handlers_to_messages = {}
|
62
|
+
handlers.each do |handler|
|
63
|
+
messages = if handler.respond_to?(:routes)
|
64
|
+
handler.routes.map do |route|
|
65
|
+
route.help.map do |command, description|
|
66
|
+
help_command(response, route, command, description)
|
67
|
+
end
|
68
|
+
end.flatten
|
69
|
+
else
|
70
|
+
[]
|
71
|
+
end
|
72
|
+
|
73
|
+
(handlers_to_messages[handler.namespace] ||= []).push(*messages)
|
74
|
+
end
|
75
|
+
|
76
|
+
handlers_to_messages
|
77
|
+
end
|
78
|
+
|
79
|
+
# Creates an array of help messages for all registered routes.
|
80
|
+
def all_help_messages(response)
|
81
|
+
robot.handlers.map do |handler|
|
82
|
+
next unless handler.respond_to?(:routes)
|
83
|
+
|
84
|
+
handler.routes.map do |route|
|
85
|
+
route.help.map do |command, description|
|
86
|
+
help_command(response, route, command, description)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end.flatten.compact
|
90
|
+
end
|
91
|
+
|
92
|
+
# Creates an array consisting of all help messages that match the given
|
93
|
+
# query.
|
94
|
+
def all_matching_messages(response, query)
|
95
|
+
filter_messages(all_help_messages(response), query)
|
96
|
+
end
|
97
|
+
|
98
|
+
# Removes matching help messages that are already present in the
|
99
|
+
# comprehensive array of help messages defined by the requested
|
100
|
+
# handler(s).
|
101
|
+
def dedup_messages(handlers_to_messages, messages)
|
102
|
+
all_handler_messages = handlers_to_messages.values.flatten
|
103
|
+
messages.reject { |m| all_handler_messages.include?(m) }
|
104
|
+
end
|
105
|
+
|
106
|
+
# Creates an array of help messages matching the given query, minus
|
107
|
+
# duplicates.
|
108
|
+
def matching_messages(response, query, handlers_to_messages)
|
109
|
+
dedup_messages(handlers_to_messages, all_matching_messages(response, query))
|
110
|
+
end
|
111
|
+
|
112
|
+
# Filters help messages matching a query.
|
113
|
+
def filter_messages(messages, query)
|
114
|
+
messages.select do |line|
|
115
|
+
/(?:@?#{Regexp.escape(address)})?#{Regexp.escape(query)}/i.match?(line)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
# Formats a block of text associating a handler namespace with the help
|
120
|
+
# messages it defines.
|
121
|
+
def format_handler_messages(handler, messages)
|
122
|
+
unless messages.empty?
|
123
|
+
"#{t("handler_contains", handler: handler)}:\n\n" + messages.join("\n")
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
# Formats a block of text for message patterns or descriptions that directly match the user's
|
128
|
+
# query.
|
129
|
+
def format_messages(messages, query)
|
130
|
+
if messages.empty?
|
131
|
+
messages
|
132
|
+
else
|
133
|
+
["#{t("pattern_or_description_contains", query: query)}:\n"] + messages
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
# Formats the message to be sent in response to a help command.
|
138
|
+
def format_reply(handlers_to_messages, messages, query)
|
139
|
+
return t("no_help_found") if handlers_to_messages.empty? && messages.empty?
|
140
|
+
|
141
|
+
handler_messages = handlers_to_messages.keys.map do |handler|
|
142
|
+
format_handler_messages(handler, handlers_to_messages[handler])
|
143
|
+
end.compact
|
144
|
+
separator = handler_messages.empty? || messages.empty? ? "" : "\n\n"
|
145
|
+
[handler_messages, format_messages(messages, query)].map do |m|
|
146
|
+
m.join("\n")
|
147
|
+
end.join(separator)
|
148
|
+
end
|
149
|
+
|
150
|
+
# Formats an individual command's help message.
|
151
|
+
def help_command(response, route, command, description)
|
152
|
+
command = "#{address}#{command}" if route.command?
|
153
|
+
message = "#{command} - #{description}"
|
154
|
+
message << t("unauthorized") unless authorized?(response.user, route.required_groups)
|
155
|
+
message
|
156
|
+
end
|
157
|
+
|
158
|
+
# The way the bot should be addressed in order to trigger a command.
|
159
|
+
def address
|
160
|
+
robot.config.robot.alias || "#{name}: "
|
161
|
+
end
|
162
|
+
|
163
|
+
# Fallback in case no alias is defined.
|
164
|
+
def name
|
165
|
+
robot.config.robot.mention_name || robot.config.robot.name
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
Lita.register_handler(Help)
|
170
|
+
end
|
171
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "json"
|
4
|
+
|
5
|
+
module Lita
|
6
|
+
# A namespace to hold all subclasses of {Handler}.
|
7
|
+
module Handlers
|
8
|
+
# Provides information about the currently running robot.
|
9
|
+
class Info
|
10
|
+
extend Handler::ChatRouter
|
11
|
+
extend Handler::HTTPRouter
|
12
|
+
|
13
|
+
route(/^info$/i, :chat, command: true, help: {
|
14
|
+
"info" => t("help.info_value")
|
15
|
+
})
|
16
|
+
|
17
|
+
http.get "/lita/info", :web
|
18
|
+
|
19
|
+
# Replies with the current version of Lita, the current version of Redis,
|
20
|
+
# and Redis memory usage.
|
21
|
+
# @param response [Response] The response object.
|
22
|
+
# @return [void]
|
23
|
+
# @since 3.0.0
|
24
|
+
def chat(response)
|
25
|
+
response.reply(
|
26
|
+
%(Lita #{Lita::VERSION} - https://www.lita.io/),
|
27
|
+
%(Redis #{redis_version} - Memory used: #{redis_memory_usage})
|
28
|
+
)
|
29
|
+
end
|
30
|
+
|
31
|
+
# Returns JSON with basic information about the robot.
|
32
|
+
# @param _request [Rack::Request] The HTTP request.
|
33
|
+
# @param response [Rack::Response] The HTTP response.
|
34
|
+
# @return [void]
|
35
|
+
def web(_request, response)
|
36
|
+
response.headers["Content-Type"] = "application/json"
|
37
|
+
json = JSON.dump(
|
38
|
+
adapter: robot.config.robot.adapter,
|
39
|
+
lita_version: Lita::VERSION,
|
40
|
+
redis_memory_usage: redis_memory_usage,
|
41
|
+
redis_version: redis_version,
|
42
|
+
robot_mention_name: robot.mention_name,
|
43
|
+
robot_name: robot.name
|
44
|
+
)
|
45
|
+
response.write(json)
|
46
|
+
end
|
47
|
+
|
48
|
+
# A hash of information about Redis.
|
49
|
+
def redis_info
|
50
|
+
@redis_info ||= Lita.redis.redis.info
|
51
|
+
end
|
52
|
+
|
53
|
+
# The current version of Redis.
|
54
|
+
def redis_version
|
55
|
+
redis_info["redis_version"]
|
56
|
+
end
|
57
|
+
|
58
|
+
# The amount of memory Redis is using.
|
59
|
+
def redis_memory_usage
|
60
|
+
redis_info["used_memory_human"]
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
Lita.register_handler(Info)
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Lita
|
4
|
+
# A namespace to hold all subclasses of {Handler}.
|
5
|
+
module Handlers
|
6
|
+
# Allows administrators to make Lita join and part from rooms.
|
7
|
+
# @since 3.0.0
|
8
|
+
class Room
|
9
|
+
extend Handler::ChatRouter
|
10
|
+
|
11
|
+
route(/^join\s+(.+)$/i, :join, command: true, restrict_to: :admins, help: {
|
12
|
+
t("help.join_key") => t("help.join_value")
|
13
|
+
})
|
14
|
+
|
15
|
+
route(/^part\s+(.+)$/i, :part, command: true, restrict_to: :admins, help: {
|
16
|
+
t("help.part_key") => t("help.part_value")
|
17
|
+
})
|
18
|
+
|
19
|
+
# Joins the room with the specified ID.
|
20
|
+
# @param response [Response] The response object.
|
21
|
+
# @return [void]
|
22
|
+
def join(response)
|
23
|
+
robot.join(response.args[0])
|
24
|
+
end
|
25
|
+
|
26
|
+
# Parts from the room with the specified ID.
|
27
|
+
# @param response [Response] The response object.
|
28
|
+
# @return [void]
|
29
|
+
def part(response)
|
30
|
+
robot.part(response.args[0])
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
Lita.register_handler(Room)
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Lita
|
4
|
+
module Handlers
|
5
|
+
# Provides information on Lita users.
|
6
|
+
# @since 4.1.0
|
7
|
+
class Users
|
8
|
+
extend Handler::ChatRouter
|
9
|
+
|
10
|
+
route(/^users\s+find\s+(.+)/i, :find, command: true, help: {
|
11
|
+
t("help.find_key") => t("help.find_value")
|
12
|
+
})
|
13
|
+
|
14
|
+
# Outputs the name, ID, and mention name of a user matching the search query.
|
15
|
+
# @param response [Response] The response object.
|
16
|
+
# @return [void]
|
17
|
+
def find(response)
|
18
|
+
user = User.fuzzy_find(response.args[1])
|
19
|
+
|
20
|
+
if user
|
21
|
+
response.reply(formatted_user(user))
|
22
|
+
else
|
23
|
+
response.reply(t("find_empty_state"))
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
# Extract and label the relevant user information.
|
30
|
+
def formatted_user(user)
|
31
|
+
"#{user.name} (ID: #{user.id}, Mention name: #{user.mention_name})"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
Lita.register_handler(Users)
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rack"
|
4
|
+
|
5
|
+
module Lita
|
6
|
+
# A wrapper around a handler's HTTP route callbacks that sets up the request and response.
|
7
|
+
# @api private
|
8
|
+
# @since 4.0.0
|
9
|
+
class HTTPCallback
|
10
|
+
# @param handler_class [Handler] The handler defining the callback.
|
11
|
+
# @param callback [Proc] The callback.
|
12
|
+
def initialize(handler_class, callback)
|
13
|
+
@handler_class = handler_class
|
14
|
+
@callback = callback
|
15
|
+
end
|
16
|
+
|
17
|
+
# Call the Rack endpoint with a standard environment hash.
|
18
|
+
def call(env)
|
19
|
+
request = Rack::Request.new(env)
|
20
|
+
response = Rack::Response.new
|
21
|
+
|
22
|
+
if request.head?
|
23
|
+
response.status = 204
|
24
|
+
else
|
25
|
+
begin
|
26
|
+
handler = @handler_class.new(env["lita.robot"])
|
27
|
+
|
28
|
+
@callback.call(handler, request, response)
|
29
|
+
rescue StandardError => e
|
30
|
+
robot = env["lita.robot"]
|
31
|
+
error_handler = robot.config.robot.error_handler
|
32
|
+
|
33
|
+
if error_handler.arity == 2
|
34
|
+
error_handler.call(e, rack_env: env, robot: robot)
|
35
|
+
else
|
36
|
+
error_handler.call(e)
|
37
|
+
end
|
38
|
+
|
39
|
+
raise
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
response.finish
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "http_router"
|
4
|
+
|
5
|
+
require_relative "callback"
|
6
|
+
require_relative "http_callback"
|
7
|
+
|
8
|
+
module Lita
|
9
|
+
# Handlers use this class to define HTTP routes for the built-in web
|
10
|
+
# server.
|
11
|
+
class HTTPRoute
|
12
|
+
# An +HttpRouter::Route+ class used for dispatch.
|
13
|
+
# @since 3.0.0
|
14
|
+
ExtendedRoute = Class.new(HttpRouter::Route) do
|
15
|
+
include HttpRouter::RouteHelper
|
16
|
+
include HttpRouter::GenerationHelper
|
17
|
+
end
|
18
|
+
|
19
|
+
# The handler registering the route.
|
20
|
+
# @return [Handler] The handler.
|
21
|
+
attr_reader :handler_class
|
22
|
+
|
23
|
+
# @param handler_class [Handler] The handler registering the route.
|
24
|
+
def initialize(handler_class)
|
25
|
+
@handler_class = handler_class
|
26
|
+
end
|
27
|
+
|
28
|
+
class << self
|
29
|
+
private
|
30
|
+
|
31
|
+
# @!macro define_http_method
|
32
|
+
# @overload $1(path, method_name, options = {})
|
33
|
+
# Defines a new route with the "$1" HTTP method.
|
34
|
+
# @param path [String] The URL path component that will trigger the route.
|
35
|
+
# @param method_name [Symbol, String] The name of the instance method in
|
36
|
+
# the handler to call for the route.
|
37
|
+
# @param options [Hash] Various options for controlling the behavior of the route.
|
38
|
+
# @return [void]
|
39
|
+
# @overload $1(path, options = {})
|
40
|
+
# Defines a new route with the "$1" HTTP method.
|
41
|
+
# @param path [String] The URL path component that will trigger the route.
|
42
|
+
# @param options [Hash] Various options for controlling the behavior of the route.
|
43
|
+
# @yield The body of the route's callback.
|
44
|
+
# @return [void]
|
45
|
+
# @since 4.0.0
|
46
|
+
def define_http_method(http_method)
|
47
|
+
define_method(http_method) do |path, method_name = nil, options = {}, &block|
|
48
|
+
register_route(http_method.to_s.upcase, path, Callback.new(method_name || block), options)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
define_http_method :head
|
54
|
+
define_http_method :get
|
55
|
+
define_http_method :post
|
56
|
+
define_http_method :put
|
57
|
+
define_http_method :patch
|
58
|
+
define_http_method :delete
|
59
|
+
define_http_method :options
|
60
|
+
define_http_method :link
|
61
|
+
define_http_method :unlink
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
# Adds a new HTTP route for the handler.
|
66
|
+
def register_route(http_method, path, callback, options)
|
67
|
+
route = new_route(http_method, path, callback, options)
|
68
|
+
route.to(HTTPCallback.new(handler_class, callback))
|
69
|
+
handler_class.http_routes << route
|
70
|
+
end
|
71
|
+
|
72
|
+
# Creates and configures a new HTTP route.
|
73
|
+
def new_route(http_method, path, callback, options)
|
74
|
+
route = ExtendedRoute.new
|
75
|
+
route.path = path
|
76
|
+
route.name = callback.method_name
|
77
|
+
route.add_match_with(options)
|
78
|
+
route.add_request_method(http_method)
|
79
|
+
route.add_request_method("HEAD") if http_method == "GET"
|
80
|
+
route
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
data/lib/lita/logger.rb
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "logger"
|
4
|
+
|
5
|
+
require_relative "default_configuration"
|
6
|
+
|
7
|
+
module Lita
|
8
|
+
# Creates a Logger with the proper configuration.
|
9
|
+
# @api private
|
10
|
+
module Logger
|
11
|
+
class << self
|
12
|
+
# Creates a new {::Logger} outputting to standard error with the given
|
13
|
+
# severity level and a custom format.
|
14
|
+
# @param level [Symbol, String] The name of the log level to use.
|
15
|
+
# @param formatter [Proc] A proc to produce a custom log message format.
|
16
|
+
# @param io [String, IO] Where to write the logs. When this value is a +String+, logs will be
|
17
|
+
# written to the named file. When this value is an +IO+, logs will be written to the +IO+.
|
18
|
+
# @return [::Logger] The {::Logger} object.
|
19
|
+
def get_logger(level, formatter: DefaultConfiguration::DEFAULT_LOG_FORMATTER, io: $stderr)
|
20
|
+
logger = ::Logger.new(io)
|
21
|
+
logger.progname = "lita"
|
22
|
+
logger.level = get_level_constant(level)
|
23
|
+
logger.formatter = formatter if formatter
|
24
|
+
logger
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
# Gets the Logger constant for the given severity level.
|
30
|
+
def get_level_constant(level)
|
31
|
+
if level
|
32
|
+
begin
|
33
|
+
::Logger.const_get(level.to_s.upcase)
|
34
|
+
rescue NameError
|
35
|
+
::Logger::INFO
|
36
|
+
end
|
37
|
+
else
|
38
|
+
::Logger::INFO
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|