bot 0.0.1 → 0.0.16
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.
- checksums.yaml +4 -4
- data/app/controllers/bot/bot_controller.rb +23 -0
- data/lib/bot.rb +7 -1
- data/lib/bot/adapter.rb +8 -0
- data/lib/bot/adapters/base.rb +15 -0
- data/lib/bot/adapters/kik.rb +26 -0
- data/lib/bot/adapters/test.rb +19 -0
- data/lib/bot/configuration.rb +21 -0
- data/lib/bot/engine.rb +4 -0
- data/lib/bot/handler.rb +46 -0
- data/lib/bot/responder.rb +96 -0
- data/lib/bot/responder_chain.rb +15 -0
- data/lib/bot/route_extensions.rb +7 -0
- data/lib/bot/rspec.rb +23 -0
- data/lib/bot/rspec/fixnum_helper.rb +13 -0
- data/lib/bot/rspec/matchers.rb +41 -0
- data/lib/bot/rspec/syntax.rb +39 -0
- data/lib/bot/version.rb +1 -1
- data/lib/generators/bot/install/install_generator.rb +24 -0
- data/lib/generators/bot/install/templates/application_handler.rb +7 -0
- data/lib/generators/bot/install/templates/application_responder.rb +11 -0
- data/lib/generators/bot/install/templates/initializer.rb +3 -0
- data/lib/generators/bot/responder/responder_generator.rb +25 -0
- data/lib/generators/rspec/install_generator.rb +14 -0
- data/lib/generators/rspec/responder_generator.rb +14 -0
- data/lib/generators/rspec/templates/application_handler_spec.rb +5 -0
- data/lib/generators/rspec/templates/responder_spec.rb +17 -0
- data/test/dummy/app/bot/application_handler.rb +5 -0
- data/test/dummy/app/bot/application_responder.rb +2 -0
- data/test/dummy/app/bot/responders/multi.rb +11 -0
- data/test/dummy/app/bot/responders/scan.rb +11 -0
- data/test/dummy/app/bot/responders/test.rb +11 -0
- data/test/dummy/app/bot/responders/text.rb +9 -0
- data/test/dummy/config/environments/development.rb +2 -0
- data/test/dummy/config/initializers/bot.rb +3 -0
- data/test/dummy/config/routes.rb +1 -2
- data/test/dummy/db/development.sqlite3 +0 -0
- data/test/dummy/db/schema.rb +16 -0
- data/test/dummy/db/test.sqlite3 +0 -0
- data/test/dummy/log/development.log +4 -0
- data/test/dummy/log/test.log +2345 -0
- data/test/integration/navigation_test.rb +24 -1
- data/test/test_helper.rb +2 -0
- metadata +90 -8
- data/app/controllers/bot/kik_controller.rb +0 -8
- data/config/routes.rb +0 -3
- data/lib/bot/message_handler.rb +0 -26
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 07f61d84f72deea7fe40bb6f1780276a64cd7460
|
4
|
+
data.tar.gz: 1c24da37fa185a9003c4b8bd8bd4fcc5c6667cca
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 518171c0bb723d1a2f5f427aae51ea30da0b8cab462ab533042e58e3672ca8af67d83e339af6cf00d9c942759823941cf4f97d800f142af4e452cc519a20a124
|
7
|
+
data.tar.gz: a8083b8140a65a80b628cad46e5f16f1c59bf0f0cea3002716d177dff7d2fb93b23a24914359358145518813d4d156874a1acc4aed1e60e0cf23b2cbc7b95f9a
|
@@ -0,0 +1,23 @@
|
|
1
|
+
class Bot::BotController < ActionController::Base
|
2
|
+
def notify
|
3
|
+
@responses = bot_handler.handle(messages).compact
|
4
|
+
|
5
|
+
adapter.send_messages(@responses) if @responses.present?
|
6
|
+
|
7
|
+
render json: []
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def messages
|
13
|
+
Array.wrap(params[:messages])
|
14
|
+
end
|
15
|
+
|
16
|
+
def adapter
|
17
|
+
Bot.configuration.adapter
|
18
|
+
end
|
19
|
+
|
20
|
+
def bot_handler
|
21
|
+
params[:bot]
|
22
|
+
end
|
23
|
+
end
|
data/lib/bot.rb
CHANGED
@@ -1,5 +1,11 @@
|
|
1
1
|
require "bot/engine"
|
2
|
-
require "bot/
|
2
|
+
require "bot/handler"
|
3
|
+
require "bot/responder"
|
4
|
+
require "bot/route_extensions"
|
5
|
+
require "bot/adapter"
|
6
|
+
require "bot/configuration"
|
7
|
+
require "bot/responder_chain"
|
8
|
+
require "bot/rspec.rb"
|
3
9
|
|
4
10
|
module Bot
|
5
11
|
end
|
data/lib/bot/adapter.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'rest-client'
|
2
|
+
|
3
|
+
module Bot
|
4
|
+
module Adapter
|
5
|
+
class Kik < Base
|
6
|
+
|
7
|
+
AUTH_URL = "https://auth.kik.com/verification/v1/check"
|
8
|
+
MESSAGING_URL = "https://engine.apikik.com/api/v1/message"
|
9
|
+
|
10
|
+
def send_messages(messages)
|
11
|
+
Rails.logger.error "\n\n\nSending:\n"
|
12
|
+
Rails.logger.error messages.to_json
|
13
|
+
Rails.logger.error "\n\n\n"
|
14
|
+
|
15
|
+
RestClient::Request.execute({
|
16
|
+
method: :post,
|
17
|
+
user: config[:bot_user],
|
18
|
+
password: config[:bot_token],
|
19
|
+
url: MESSAGING_URL,
|
20
|
+
payload: { messages: messages }.to_json,
|
21
|
+
headers: { content_type: :json }
|
22
|
+
})
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Bot
|
2
|
+
module Adapter
|
3
|
+
class Test < Base
|
4
|
+
@@sent_messages = []
|
5
|
+
|
6
|
+
def send_messages(messages)
|
7
|
+
@@sent_messages += Array.wrap(messages)
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.sent_messages
|
11
|
+
@@sent_messages
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.empty_messages
|
15
|
+
@@sent_messages = []
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Bot
|
2
|
+
@@configuration = nil
|
3
|
+
|
4
|
+
def self.configure
|
5
|
+
@@configuration = Configuration.new
|
6
|
+
|
7
|
+
if block_given?
|
8
|
+
yield configuration
|
9
|
+
end
|
10
|
+
|
11
|
+
configuration
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.configuration
|
15
|
+
@@configuration || configure
|
16
|
+
end
|
17
|
+
|
18
|
+
class Configuration
|
19
|
+
attr_accessor :adapter
|
20
|
+
end
|
21
|
+
end
|
data/lib/bot/engine.rb
CHANGED
data/lib/bot/handler.rb
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
module Bot
|
2
|
+
class Handler
|
3
|
+
@@responder_chain = nil
|
4
|
+
|
5
|
+
def self.use(responder)
|
6
|
+
responder_chain.add(responder)
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.handle(messages)
|
10
|
+
new.handle(messages)
|
11
|
+
end
|
12
|
+
|
13
|
+
def handle(messages)
|
14
|
+
messages.flat_map { |m| handle_message(m) }
|
15
|
+
end
|
16
|
+
|
17
|
+
def execute_chain(message, responses, user)
|
18
|
+
responder_chain.responders.each do |responder|
|
19
|
+
responder = responder.new(message, user, responses, self)
|
20
|
+
if responder.can_respond_to_type?(message['type']) && responder.can_handle?
|
21
|
+
responses << responder.handle
|
22
|
+
break
|
23
|
+
end
|
24
|
+
end
|
25
|
+
responses
|
26
|
+
end
|
27
|
+
|
28
|
+
def responder_chain
|
29
|
+
@@responder_chain ||= Bot::ResponderChain.new
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.responder_chain
|
33
|
+
@@responder_chain ||= Bot::ResponderChain.new
|
34
|
+
end
|
35
|
+
|
36
|
+
protected
|
37
|
+
|
38
|
+
def handle_message(message)
|
39
|
+
user = user_for(message)
|
40
|
+
execute_chain(message, [], user).flatten
|
41
|
+
end
|
42
|
+
|
43
|
+
def user_for(message)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
module Bot
|
2
|
+
class Responder
|
3
|
+
include ActionView::Helpers::TextHelper
|
4
|
+
include ActionView::Helpers::DateHelper
|
5
|
+
|
6
|
+
class_attribute :respond_to_types
|
7
|
+
|
8
|
+
attr_reader :message, :user, :responses, :handler
|
9
|
+
|
10
|
+
def self.respond_to(*types)
|
11
|
+
new_types = (respond_to_types || []).dup
|
12
|
+
types.each { |type| new_types << type.to_s }.uniq
|
13
|
+
self.respond_to_types = new_types.freeze
|
14
|
+
end
|
15
|
+
|
16
|
+
def initialize(message, user, responses, handler)
|
17
|
+
@message = message
|
18
|
+
@user = user
|
19
|
+
@responses = responses
|
20
|
+
@handler = handler
|
21
|
+
end
|
22
|
+
|
23
|
+
def can_respond_to_type?(type)
|
24
|
+
valid_message_types = self.class.respond_to_types || ['text']
|
25
|
+
valid_message_types.include?(type)
|
26
|
+
end
|
27
|
+
|
28
|
+
def can_handle?
|
29
|
+
!responses.count
|
30
|
+
end
|
31
|
+
|
32
|
+
def handle
|
33
|
+
raise NotImplementedError
|
34
|
+
end
|
35
|
+
|
36
|
+
protected
|
37
|
+
|
38
|
+
def text_response(message_text, suggested_responses=false)
|
39
|
+
text_response = {
|
40
|
+
'type' => 'text',
|
41
|
+
'to' => message['from'],
|
42
|
+
'body' => message_text,
|
43
|
+
'typeTime' => 0
|
44
|
+
}
|
45
|
+
text_response['suggestedResponses'] = suggested_responses if suggested_responses
|
46
|
+
text_response
|
47
|
+
end
|
48
|
+
|
49
|
+
def photo_response(photo_url, suggested_responses=false)
|
50
|
+
photo_response = {
|
51
|
+
'type' => 'gallery',
|
52
|
+
'to' => message['from'],
|
53
|
+
'picUrl' => photo_url
|
54
|
+
}
|
55
|
+
photo_response['suggestedResponses'] = suggested_responses if suggested_responses
|
56
|
+
photo_response
|
57
|
+
end
|
58
|
+
|
59
|
+
def video_response(video_id, suggested_responses=false)
|
60
|
+
video_response = {
|
61
|
+
'type' => 'video',
|
62
|
+
'to' => message['from'],
|
63
|
+
'videoId' => video_id,
|
64
|
+
'muted' => true,
|
65
|
+
'autoplay' => true
|
66
|
+
}
|
67
|
+
video_response['suggestedResponses'] = suggested_responses if suggested_responses
|
68
|
+
video_response
|
69
|
+
end
|
70
|
+
|
71
|
+
def delay(message, delay)
|
72
|
+
message['delay'] = delay
|
73
|
+
message
|
74
|
+
end
|
75
|
+
|
76
|
+
def match_message(match)
|
77
|
+
if match.is_a?(Regexp)
|
78
|
+
match.match(message['body'])
|
79
|
+
else
|
80
|
+
message['body'].upcase == match.upcase
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def no_responses?
|
85
|
+
responses.empty?
|
86
|
+
end
|
87
|
+
|
88
|
+
def reexecute_with(current_response, new_message=false)
|
89
|
+
handler.execute_chain(new_message || message, Array.wrap(current_response), user)
|
90
|
+
end
|
91
|
+
|
92
|
+
def scan_data
|
93
|
+
JSON.parse(message['data'])
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
data/lib/bot/rspec.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
require "bot/rspec/syntax.rb"
|
2
|
+
require "bot/rspec/matchers.rb"
|
3
|
+
require "bot/rspec/fixnum_helper.rb"
|
4
|
+
|
5
|
+
module Bot
|
6
|
+
module Rspec
|
7
|
+
include Syntax
|
8
|
+
include Matchers
|
9
|
+
|
10
|
+
Fixnum.send(:include, FixnumHelper)
|
11
|
+
|
12
|
+
def self.included(base)
|
13
|
+
if base.metadata[:type] == :responder
|
14
|
+
base.let(:username) { "user" } unless base.respond_to? :username
|
15
|
+
base.let(:user) { create(:user) } unless base.respond_to? :user
|
16
|
+
base.let(:message) { incoming_message(user.username) } unless base.respond_to? :message
|
17
|
+
base.let(:handler) { class_double("Handler") } unless base.respond_to? :handler
|
18
|
+
base.let(:responses) { [] } unless base.respond_to? :responses
|
19
|
+
base.let(:responder) { base.described_class.new(message, user, responses, handler) } unless base.respond_to? :responder
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'rspec/expectations'
|
2
|
+
|
3
|
+
module Bot
|
4
|
+
module Rspec
|
5
|
+
module Matchers
|
6
|
+
RSpec::Matchers.define :be_to do |to_user|
|
7
|
+
match do |sent_messages|
|
8
|
+
Array.wrap(sent_messages).flatten.any? { |msg| msg["to"] == to_user }
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
RSpec::Matchers.define :say do |body|
|
13
|
+
match do |sent_messages|
|
14
|
+
Array.wrap(sent_messages).flatten.any? { |msg| msg["body"] == body }
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
RSpec::Matchers.define :match_message do |body|
|
19
|
+
match do |sent_messages|
|
20
|
+
Array.wrap(sent_messages).flatten.any? { |msg| msg["body"].match(body).present? }
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
RSpec::Matchers.define :send_a_message_like do |expected_message|
|
25
|
+
match do |sent_messages|
|
26
|
+
Array.wrap(sent_messages).flatten.keep_if { |msg| matches_expected?(msg, expected_message) }.present?
|
27
|
+
end
|
28
|
+
|
29
|
+
def matches_expected?(sent, expected)
|
30
|
+
!expected.reject { |k, v| sent[k] == v }.present?
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
RSpec::Matchers.define :send do |expected_count|
|
35
|
+
match do |sent_messages|
|
36
|
+
Array.wrap(sent_messages).flatten.count == expected_count
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Bot
|
2
|
+
module Rspec
|
3
|
+
module Syntax
|
4
|
+
def incoming_message(from, options={})
|
5
|
+
{
|
6
|
+
"from" => from,
|
7
|
+
"body" => "No Message",
|
8
|
+
"readReceiptRequested" => true,
|
9
|
+
"timestamp" => Time.now.to_i * 1000,
|
10
|
+
"type" => "text",
|
11
|
+
"id" => "07c6eb77-e01c-439a-80e7-3583dd784de1"
|
12
|
+
}.merge(options.stringify_keys)
|
13
|
+
end
|
14
|
+
|
15
|
+
def incoming_scan(from, options={})
|
16
|
+
{
|
17
|
+
"from" => from,
|
18
|
+
"timestamp" => 1457449114952,
|
19
|
+
"data" => "{}",
|
20
|
+
"mention" => nil,
|
21
|
+
"participants" => [from],
|
22
|
+
"readReceiptRequested" => false,
|
23
|
+
"type" => "scan-data",
|
24
|
+
"id" => "e6303158-ca60-4332-a600-236c5de4fedb",
|
25
|
+
"chatId" => "d68a7ab10a1526ac9682b764e2784080bb1cb52fc82c8f9c10c7d0534741fc93"
|
26
|
+
}.merge(options.stringify_keys)
|
27
|
+
end
|
28
|
+
|
29
|
+
def outgoing_message(to, options={})
|
30
|
+
{
|
31
|
+
"to" => to,
|
32
|
+
"body" => "No Message",
|
33
|
+
"type" => "text",
|
34
|
+
"typeTime" => 0
|
35
|
+
}.merge(options.stringify_keys)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|