lita 1.1.2 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +202 -45
- data/lib/lita.rb +45 -24
- data/lib/lita/adapter.rb +35 -0
- data/lib/lita/adapters/shell.rb +14 -3
- data/lib/lita/authorization.rb +24 -0
- data/lib/lita/cli.rb +1 -0
- data/lib/lita/config.rb +52 -19
- data/lib/lita/handler.rb +100 -36
- data/lib/lita/handlers/authorization.rb +38 -27
- data/lib/lita/handlers/help.rb +25 -22
- data/lib/lita/handlers/web.rb +25 -0
- data/lib/lita/http_route.rb +64 -0
- data/lib/lita/logger.rb +34 -0
- data/lib/lita/message.rb +41 -7
- data/lib/lita/rack_app_builder.rb +110 -0
- data/lib/lita/response.rb +30 -0
- data/lib/lita/robot.rb +56 -1
- data/lib/lita/rspec.rb +23 -50
- data/lib/lita/rspec/handler.rb +168 -0
- data/lib/lita/source.rb +19 -1
- data/lib/lita/user.rb +37 -1
- data/lib/lita/util.rb +26 -0
- data/lib/lita/version.rb +2 -1
- data/lita.gemspec +5 -0
- data/spec/lita/adapters/shell_spec.rb +12 -4
- data/spec/lita/config_spec.rb +18 -2
- data/spec/lita/handler_spec.rb +43 -46
- data/spec/lita/handlers/authorization_spec.rb +24 -31
- data/spec/lita/handlers/help_spec.rb +10 -8
- data/spec/lita/handlers/web_spec.rb +19 -0
- data/spec/lita/logger_spec.rb +26 -0
- data/spec/lita/message_spec.rb +16 -11
- data/spec/lita/robot_spec.rb +25 -2
- data/spec/lita/rspec_spec.rb +32 -20
- data/spec/lita/util_spec.rb +9 -0
- data/spec/lita_spec.rb +0 -51
- data/spec/spec_helper.rb +2 -1
- metadata +85 -3
- data/CHANGELOG.md +0 -21
data/lib/lita/adapter.rb
CHANGED
@@ -1,10 +1,18 @@
|
|
1
1
|
module Lita
|
2
|
+
# Adapters are the glue between Lita's API and a chat service.
|
2
3
|
class Adapter
|
4
|
+
# The instance of {Lita::Robot}.
|
5
|
+
# @return [Lita::Robot]
|
3
6
|
attr_reader :robot
|
4
7
|
|
5
8
|
class << self
|
9
|
+
# A list of configuration keys that are required for the adapter to boot.
|
10
|
+
# @return [Array]
|
6
11
|
attr_reader :required_configs
|
7
12
|
|
13
|
+
# Defines configuration keys that are requried for the adapter to boot.
|
14
|
+
# @param keys [String, Symbol] The required keys.
|
15
|
+
# @return [void]
|
8
16
|
def require_config(*keys)
|
9
17
|
@required_configs ||= []
|
10
18
|
@required_configs.concat(keys.flatten.map(&:to_sym))
|
@@ -13,11 +21,37 @@ module Lita
|
|
13
21
|
alias_method :require_configs, :require_config
|
14
22
|
end
|
15
23
|
|
24
|
+
# @param robot [Lita::Robot] The currently running robot.
|
16
25
|
def initialize(robot)
|
17
26
|
@robot = robot
|
18
27
|
ensure_required_configs
|
19
28
|
end
|
20
29
|
|
30
|
+
# @!method run
|
31
|
+
# The main loop. Should connect to the chat service, listen for incoming
|
32
|
+
# messages, create {Lita::Message} objects from them, and dispatch them to
|
33
|
+
# the robot by calling {Lita::Robot#receive}.
|
34
|
+
# @return [void]
|
35
|
+
# @abstract This should be implemented by the adapter.
|
36
|
+
|
37
|
+
# @!method send_messages(target, strings)
|
38
|
+
# Sends one or more messages to a user or room.
|
39
|
+
# @param target [Lita::Source] The user or room to send messages to.
|
40
|
+
# @param strings [Array<String>] An array of messages to send.
|
41
|
+
# @return [void]
|
42
|
+
# @abstract This should be implemented by the adapter.
|
43
|
+
|
44
|
+
# @!method set_topic(target, topic)
|
45
|
+
# Sets the topic for a room.
|
46
|
+
# @param target [Lita::Source] The room to change the topic for.
|
47
|
+
# @param topic [String] The new topic.
|
48
|
+
# @return [void]
|
49
|
+
# @abstract This should be implemented by the adapter.
|
50
|
+
|
51
|
+
# @!method shut_down
|
52
|
+
# Performs any clean up necessary when disconnecting from the chat service.
|
53
|
+
# @return [void]
|
54
|
+
# @abstract This should be implemented by the adapter.
|
21
55
|
[:run, :send_messages, :set_topic, :shut_down].each do |method|
|
22
56
|
define_method(method) do |*args|
|
23
57
|
Lita.logger.warn("This adapter has not implemented ##{method}.")
|
@@ -26,6 +60,7 @@ module Lita
|
|
26
60
|
|
27
61
|
private
|
28
62
|
|
63
|
+
# Logs a fatal message and aborts if a required config key is not set.
|
29
64
|
def ensure_required_configs
|
30
65
|
required_configs = self.class.required_configs
|
31
66
|
return if required_configs.nil?
|
data/lib/lita/adapters/shell.rb
CHANGED
@@ -1,8 +1,12 @@
|
|
1
1
|
module Lita
|
2
2
|
module Adapters
|
3
|
+
# An adapter that runs Lita in a UNIX shell.
|
3
4
|
class Shell < Adapter
|
5
|
+
# Creates a "Shell User" and then loops a prompt and input, passing the
|
6
|
+
# incoming messages to the robot.
|
7
|
+
# @return [void]
|
4
8
|
def run
|
5
|
-
user = User.
|
9
|
+
user = User.create(1, name: "Shell User")
|
6
10
|
source = Source.new(user)
|
7
11
|
puts 'Type "exit" or "quit" to end the session.'
|
8
12
|
|
@@ -11,15 +15,22 @@ module Lita
|
|
11
15
|
input = $stdin.gets.chomp.strip
|
12
16
|
break if input == "exit" || input == "quit"
|
13
17
|
message = Message.new(robot, input, source)
|
14
|
-
|
18
|
+
message.command! if Lita.config.adapter.private_chat
|
19
|
+
robot.receive(message)
|
15
20
|
end
|
16
21
|
end
|
17
22
|
|
23
|
+
# Outputs outgoing messages to the shell.
|
24
|
+
# @param target [Lita::Source] Unused, since there is only one user in the
|
25
|
+
# shell environment.
|
26
|
+
# @param strings [Array<String>] An array of strings to output.
|
27
|
+
# @return [void]
|
18
28
|
def send_messages(target, strings)
|
19
|
-
puts
|
20
29
|
puts strings
|
21
30
|
end
|
22
31
|
|
32
|
+
# Adds a blank line for a nice looking exit.
|
33
|
+
# @return [void]
|
23
34
|
def shut_down
|
24
35
|
puts
|
25
36
|
end
|
data/lib/lita/authorization.rb
CHANGED
@@ -1,30 +1,54 @@
|
|
1
1
|
module Lita
|
2
|
+
# Methods for querying and manipulating authorization groups.
|
2
3
|
module Authorization
|
3
4
|
class << self
|
5
|
+
# Adds a user to an authorization group.
|
6
|
+
# @param requesting_user [Lita::User] The user who sent the command.
|
7
|
+
# @param user [Lita::User] The user to add to the group.
|
8
|
+
# @param group [Symbol, String] The name of the group.
|
9
|
+
# @return [Symbol] :unauthorized if the requesting user is not authorized.
|
10
|
+
# @return [Boolean] true if the user was added. false if the user was
|
11
|
+
# already in the group.
|
4
12
|
def add_user_to_group(requesting_user, user, group)
|
5
13
|
return :unauthorized unless user_is_admin?(requesting_user)
|
6
14
|
redis.sadd(normalize_group(group), user.id)
|
7
15
|
end
|
8
16
|
|
17
|
+
# Removes a user from an authorization group.
|
18
|
+
# @param requesting_user [Lita::User] The user who sent the command.
|
19
|
+
# @param user [Lita::User] The user to remove from the group.
|
20
|
+
# @param group [Symbol, String] The name of the group.
|
21
|
+
# @return [Symbol] :unauthorized if the requesting user is not authorized.
|
22
|
+
# @return [Boolean] true if the user was removed. false if the user was
|
23
|
+
# not in the group.
|
9
24
|
def remove_user_from_group(requesting_user, user, group)
|
10
25
|
return :unauthorized unless user_is_admin?(requesting_user)
|
11
26
|
redis.srem(normalize_group(group), user.id)
|
12
27
|
end
|
13
28
|
|
29
|
+
# Checks if a user is in an authorization group.
|
30
|
+
# @param user [Lita::User] The user.
|
31
|
+
# @param group [Symbol, String] The name of the group.
|
32
|
+
# @return [Boolean] Whether or not the user is in the group.
|
14
33
|
def user_in_group?(user, group)
|
15
34
|
redis.sismember(normalize_group(group), user.id)
|
16
35
|
end
|
17
36
|
|
37
|
+
# Checks if a user is an administrator.
|
38
|
+
# @param user [Lita::User] The user.
|
39
|
+
# @return [Boolean] Whether or not the user is an administrator.
|
18
40
|
def user_is_admin?(user)
|
19
41
|
Array(Lita.config.robot.admins).include?(user.id)
|
20
42
|
end
|
21
43
|
|
22
44
|
private
|
23
45
|
|
46
|
+
# Ensures that group names are stored consistently in Redis.
|
24
47
|
def normalize_group(group)
|
25
48
|
group.to_s.downcase.strip
|
26
49
|
end
|
27
50
|
|
51
|
+
# A Redis::Namespace for authorization data.
|
28
52
|
def redis
|
29
53
|
@redis ||= Redis::Namespace.new("auth", redis: Lita.redis)
|
30
54
|
end
|
data/lib/lita/cli.rb
CHANGED
data/lib/lita/config.rb
CHANGED
@@ -1,41 +1,74 @@
|
|
1
1
|
module Lita
|
2
|
+
# An object that stores various user settings that affect Lita's behavior.
|
2
3
|
class Config < Hash
|
3
|
-
|
4
|
-
new
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
4
|
+
class << self
|
5
|
+
# Initializes a new Config object with the default settings.
|
6
|
+
# @return [Lita::Config] The default configuration.
|
7
|
+
def default_config
|
8
|
+
config = new.tap do |c|
|
9
|
+
c.robot = new
|
10
|
+
c.robot.name = "Lita"
|
11
|
+
c.robot.adapter = :shell
|
12
|
+
c.robot.log_level = :info
|
13
|
+
c.robot.admins = nil
|
14
|
+
c.redis = new
|
15
|
+
c.http = new
|
16
|
+
c.http.port = 8080
|
17
|
+
c.http.debug = false
|
18
|
+
c.adapter = new
|
19
|
+
c.handlers = new
|
20
|
+
end
|
21
|
+
load_handler_configs(config)
|
22
|
+
config
|
13
23
|
end
|
14
|
-
end
|
15
24
|
|
16
|
-
|
17
|
-
config_path
|
25
|
+
# Loads configuration from a user configuration file.
|
26
|
+
# @param config_path [String] The path to the configuration file.
|
27
|
+
# @return [void]
|
28
|
+
def load_user_config(config_path = nil)
|
29
|
+
config_path = "lita_config.rb" unless config_path
|
18
30
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
31
|
+
begin
|
32
|
+
load(config_path)
|
33
|
+
rescue Exception => e
|
34
|
+
Lita.logger.fatal <<-MSG
|
23
35
|
Lita configuration file could not be processed. The exception was:
|
24
36
|
#{e.message}
|
25
37
|
#{e.backtrace.join("\n")}
|
26
38
|
MSG
|
27
|
-
|
28
|
-
|
39
|
+
abort
|
40
|
+
end if File.exist?(config_path)
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
# Adds and populates a Config object to Lita.config.handlers for every
|
46
|
+
# registered handler that implements self.default_config.
|
47
|
+
def load_handler_configs(config)
|
48
|
+
Lita.handlers.each do |handler|
|
49
|
+
next unless handler.respond_to?(:default_config)
|
50
|
+
handler_config = config.handlers[handler.namespace] = new
|
51
|
+
handler.default_config(handler_config)
|
52
|
+
end
|
53
|
+
end
|
29
54
|
end
|
30
55
|
|
56
|
+
# Sets a config key.
|
57
|
+
# @param key [Symbol, String] The key.
|
58
|
+
# @param value The value.
|
59
|
+
# @return The value.
|
31
60
|
def []=(key, value)
|
32
61
|
super(key.to_sym, value)
|
33
62
|
end
|
34
63
|
|
64
|
+
# Get a config key.
|
65
|
+
# @param key [Symbol, String] The key.
|
66
|
+
# @return The value.
|
35
67
|
def [](key)
|
36
68
|
super(key.to_sym)
|
37
69
|
end
|
38
70
|
|
71
|
+
# Allows keys to be read and written with struct-like syntax.
|
39
72
|
def method_missing(name, *args)
|
40
73
|
name_string = name.to_s
|
41
74
|
if name_string.chomp!("=")
|
data/lib/lita/handler.rb
CHANGED
@@ -1,77 +1,141 @@
|
|
1
1
|
module Lita
|
2
|
+
# Base class for objects that add new behavior to Lita.
|
2
3
|
class Handler
|
3
4
|
extend Forwardable
|
4
5
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
6
|
+
# A Redis::Namespace scoped to the handler.
|
7
|
+
# @return [Redis::Namespace]
|
8
|
+
attr_reader :redis
|
9
|
+
|
10
|
+
# The running {Lita::Robot} instance.
|
11
|
+
# @return [Lita::Robot]
|
12
|
+
attr_reader :robot
|
13
|
+
|
14
|
+
# A Struct representing a chat route defined by a handler.
|
15
|
+
class Route < Struct.new(
|
16
|
+
:pattern,
|
17
|
+
:method_name,
|
18
|
+
:command,
|
19
|
+
:required_groups,
|
20
|
+
:help
|
21
|
+
)
|
11
22
|
alias_method :command?, :command
|
12
23
|
end
|
13
24
|
|
14
25
|
class << self
|
15
|
-
|
26
|
+
# Creates a chat route.
|
27
|
+
# @param pattern [Regexp] A regular expression to match incoming messages
|
28
|
+
# against.
|
29
|
+
# @param method [Symbol, String] The name of the method to trigger.
|
30
|
+
# @param command [Boolean] Whether or not the message must be directed at
|
31
|
+
# the robot.
|
32
|
+
# @param restrict_to [Array<Symbol, String>, nil] A list of authorization
|
33
|
+
# groups the user must be in to trigger the route.
|
34
|
+
# @param help [Hash] A map of example invocations to descriptions.
|
35
|
+
# @return [void]
|
36
|
+
def route(pattern, method, command: false, restrict_to: nil, help: {})
|
37
|
+
groups = restrict_to.nil? ? nil : Array(restrict_to)
|
38
|
+
routes << Route.new(pattern, method, command, groups, help)
|
39
|
+
end
|
40
|
+
|
41
|
+
# A list of chat routes defined by the handler.
|
42
|
+
# @return [Array<Lita::Handler::Route>]
|
43
|
+
def routes
|
16
44
|
@routes ||= []
|
17
|
-
required_groups = restrict_to.nil? ? nil : Array(restrict_to)
|
18
|
-
@routes << Route.new(pattern, to, command, required_groups)
|
19
45
|
end
|
20
46
|
|
47
|
+
# The main entry point for the handler at runtime. Checks if the message
|
48
|
+
# matches any of the routes and invokes the route's method if it does.
|
49
|
+
# Called by {Lita::Robot#receive}.
|
50
|
+
# @param robot [Lita::Robot] The currently running robot.
|
51
|
+
# @param message [Lita::Message] The incoming message.
|
52
|
+
# @return [void]
|
21
53
|
def dispatch(robot, message)
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
54
|
+
routes.each do |route|
|
55
|
+
if route_applies?(route, message)
|
56
|
+
Lita.logger.debug <<-LOG.chomp
|
57
|
+
Dispatching message to #{self}##{route.method_name}.
|
58
|
+
LOG
|
59
|
+
new(robot).public_send(route.method_name, Response.new(
|
60
|
+
message,
|
61
|
+
matches: message.match(route.pattern)
|
62
|
+
))
|
30
63
|
end
|
31
|
-
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# Creates a new {Lita::HTTPRoute} which is used to define an HTTP route
|
68
|
+
# for the built-in web server.
|
69
|
+
# @see Lita::HTTPRoute
|
70
|
+
# @return [Lita::HTTPRoute] The new {Lita::HTTPRoute}.
|
71
|
+
def http
|
72
|
+
HTTPRoute.new(self)
|
73
|
+
end
|
74
|
+
|
75
|
+
# An array of all HTTP routes defined for the handler.
|
76
|
+
# @return [Array<Lita::HTTPRoute>] The array of routes.
|
77
|
+
def http_routes
|
78
|
+
@http_routes ||= []
|
79
|
+
end
|
80
|
+
|
81
|
+
# The namespace for the handler, used for its configuration object and
|
82
|
+
# Redis store. If the handler is an anonymous class, it must explicitly
|
83
|
+
# define +self.name+.
|
84
|
+
# @return [String] The handler's namespace.
|
85
|
+
# @raise [RuntimeError] If +self.name+ is not defined.
|
86
|
+
def namespace
|
87
|
+
if name
|
88
|
+
Util.underscore(name.split("::").last)
|
89
|
+
else
|
90
|
+
raise "Handlers that are anonymous classes must define self.name."
|
91
|
+
end
|
32
92
|
end
|
33
93
|
|
34
94
|
private
|
35
95
|
|
36
|
-
|
96
|
+
# Determines whether or not an incoming messages should trigger a route.
|
97
|
+
def route_applies?(route, message)
|
37
98
|
# Message must match the pattern
|
38
|
-
return unless route.pattern ===
|
99
|
+
return unless route.pattern === message.body
|
39
100
|
|
40
101
|
# Message must be a command if the route requires a command
|
41
|
-
return if route.command? && !
|
102
|
+
return if route.command? && !message.command?
|
42
103
|
|
43
104
|
# User must be in auth group if route is restricted
|
44
105
|
return if route.required_groups && route.required_groups.none? do |group|
|
45
|
-
Authorization.user_in_group?(
|
106
|
+
Authorization.user_in_group?(message.user, group)
|
46
107
|
end
|
47
108
|
|
48
109
|
true
|
49
110
|
end
|
50
|
-
|
51
|
-
def matches_for_route(route, instance)
|
52
|
-
instance.scan(route.pattern)
|
53
|
-
end
|
54
111
|
end
|
55
112
|
|
56
|
-
|
113
|
+
# @param robot [Lita::Robot] The currently running robot.
|
114
|
+
def initialize(robot)
|
57
115
|
@robot = robot
|
58
|
-
@message = message
|
59
116
|
@redis = Redis::Namespace.new(redis_namespace, redis: Lita.redis)
|
60
117
|
end
|
61
118
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
def
|
67
|
-
|
119
|
+
# Creates a new +Faraday::Connection+ for making HTTP requests.
|
120
|
+
# @param options [Hash] A set of options passed on to Faraday.
|
121
|
+
# @yield [builder] A Faraday builder object for adding middleware.
|
122
|
+
# @return [Faraday::Connection] The new connection object.
|
123
|
+
def http(options = {}, &block)
|
124
|
+
options = default_faraday_options.merge(options)
|
125
|
+
Faraday::Connection.new(nil, options, &block)
|
68
126
|
end
|
69
127
|
|
70
128
|
private
|
71
129
|
|
130
|
+
# Default options for new Faraday connections. Sets the user agent to the
|
131
|
+
# current version of Lita.
|
132
|
+
def default_faraday_options
|
133
|
+
{ headers: { "User-Agent" => "Lita v#{VERSION}" } }
|
134
|
+
end
|
135
|
+
|
136
|
+
# The handler's namespace for Redis.
|
72
137
|
def redis_namespace
|
73
|
-
|
74
|
-
"handlers:#{name}"
|
138
|
+
"handlers:#{self.class.namespace}"
|
75
139
|
end
|
76
140
|
end
|
77
141
|
end
|
@@ -1,51 +1,60 @@
|
|
1
1
|
module Lita
|
2
2
|
module Handlers
|
3
|
+
# Provides a chat interface for administering authorization groups.
|
3
4
|
class Authorization < Handler
|
4
|
-
route(/^auth\s+add/,
|
5
|
-
|
5
|
+
route(/^auth\s+add/, :add, command: true, help: {
|
6
|
+
"auth add USER GROUP" => "Add USER to authorization group GROUP. Requires admin privileges."
|
7
|
+
})
|
8
|
+
route(/^auth\s+remove/, :remove, command: true, help: {
|
9
|
+
"auth remove USER GROUP" => "Remove USER from authorization group GROUP. Requires admin privileges."
|
10
|
+
})
|
6
11
|
|
7
|
-
|
8
|
-
|
12
|
+
# Adds a user to an authorization group.
|
13
|
+
# @param response [Lita::Response] The response object.
|
14
|
+
# @return [void]
|
15
|
+
def add(response)
|
16
|
+
return unless valid_message?(response)
|
9
17
|
|
10
|
-
|
11
|
-
"#{robot_name}: auth add USER GROUP" => "Add USER to authorization group GROUP. Requires admin privileges.",
|
12
|
-
"#{robot_name}: auth remove USER GROUP" => "Remove USER from authorization group GROUP. Requires admin privileges."
|
13
|
-
}
|
14
|
-
end
|
15
|
-
|
16
|
-
def add(matches)
|
17
|
-
return unless valid_message?
|
18
|
-
|
19
|
-
case Lita::Authorization.add_user_to_group(user, @user, @group)
|
18
|
+
case Lita::Authorization.add_user_to_group(response.user, @user, @group)
|
20
19
|
when :unauthorized
|
21
|
-
reply "Only administrators can add users to groups."
|
20
|
+
response.reply "Only administrators can add users to groups."
|
22
21
|
when true
|
23
|
-
reply "#{@user.name} was added to #{@group}."
|
22
|
+
response.reply "#{@user.name} was added to #{@group}."
|
24
23
|
else
|
25
|
-
reply "#{@user.name} was already in #{@group}."
|
24
|
+
response.reply "#{@user.name} was already in #{@group}."
|
26
25
|
end
|
27
26
|
end
|
28
27
|
|
29
|
-
|
30
|
-
|
28
|
+
# Removes a user from an authorization group.
|
29
|
+
# @param response [Lita::Response] The response object.
|
30
|
+
# @return [void]
|
31
|
+
def remove(response)
|
32
|
+
return unless valid_message?(response)
|
31
33
|
|
32
|
-
case Lita::Authorization.remove_user_from_group(
|
34
|
+
case Lita::Authorization.remove_user_from_group(
|
35
|
+
response.user,
|
36
|
+
@user,
|
37
|
+
@group
|
38
|
+
)
|
33
39
|
when :unauthorized
|
34
|
-
reply "Only administrators can remove users from groups."
|
40
|
+
response.reply "Only administrators can remove users from groups."
|
35
41
|
when true
|
36
|
-
reply "#{@user.name} was removed from #{@group}."
|
42
|
+
response.reply "#{@user.name} was removed from #{@group}."
|
37
43
|
else
|
38
|
-
reply "#{@user.name} was not in #{@group}."
|
44
|
+
response.reply "#{@user.name} was not in #{@group}."
|
39
45
|
end
|
40
46
|
end
|
41
47
|
|
42
48
|
private
|
43
49
|
|
44
|
-
|
45
|
-
|
50
|
+
# Validates that incoming messages have the right format and a valid user.
|
51
|
+
# Also assigns the user and group to instance variables for the main
|
52
|
+
# methods to use later.
|
53
|
+
def valid_message?(response)
|
54
|
+
command, identifier, @group = response.args
|
46
55
|
|
47
56
|
unless identifier && @group
|
48
|
-
reply "Format: #{robot.name} auth add USER GROUP"
|
57
|
+
response.reply "Format: #{robot.name} auth add USER GROUP"
|
49
58
|
return
|
50
59
|
end
|
51
60
|
|
@@ -53,7 +62,9 @@ module Lita
|
|
53
62
|
@user = User.find_by_name(identifier) unless @user
|
54
63
|
|
55
64
|
unless @user
|
56
|
-
reply
|
65
|
+
response.reply <<-REPLY.chomp
|
66
|
+
No user was found with the identifier "#{identifier}".
|
67
|
+
REPLY
|
57
68
|
return
|
58
69
|
end
|
59
70
|
|