bot 0.0.1 → 0.0.16

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/bot/bot_controller.rb +23 -0
  3. data/lib/bot.rb +7 -1
  4. data/lib/bot/adapter.rb +8 -0
  5. data/lib/bot/adapters/base.rb +15 -0
  6. data/lib/bot/adapters/kik.rb +26 -0
  7. data/lib/bot/adapters/test.rb +19 -0
  8. data/lib/bot/configuration.rb +21 -0
  9. data/lib/bot/engine.rb +4 -0
  10. data/lib/bot/handler.rb +46 -0
  11. data/lib/bot/responder.rb +96 -0
  12. data/lib/bot/responder_chain.rb +15 -0
  13. data/lib/bot/route_extensions.rb +7 -0
  14. data/lib/bot/rspec.rb +23 -0
  15. data/lib/bot/rspec/fixnum_helper.rb +13 -0
  16. data/lib/bot/rspec/matchers.rb +41 -0
  17. data/lib/bot/rspec/syntax.rb +39 -0
  18. data/lib/bot/version.rb +1 -1
  19. data/lib/generators/bot/install/install_generator.rb +24 -0
  20. data/lib/generators/bot/install/templates/application_handler.rb +7 -0
  21. data/lib/generators/bot/install/templates/application_responder.rb +11 -0
  22. data/lib/generators/bot/install/templates/initializer.rb +3 -0
  23. data/lib/generators/bot/responder/responder_generator.rb +25 -0
  24. data/lib/generators/rspec/install_generator.rb +14 -0
  25. data/lib/generators/rspec/responder_generator.rb +14 -0
  26. data/lib/generators/rspec/templates/application_handler_spec.rb +5 -0
  27. data/lib/generators/rspec/templates/responder_spec.rb +17 -0
  28. data/test/dummy/app/bot/application_handler.rb +5 -0
  29. data/test/dummy/app/bot/application_responder.rb +2 -0
  30. data/test/dummy/app/bot/responders/multi.rb +11 -0
  31. data/test/dummy/app/bot/responders/scan.rb +11 -0
  32. data/test/dummy/app/bot/responders/test.rb +11 -0
  33. data/test/dummy/app/bot/responders/text.rb +9 -0
  34. data/test/dummy/config/environments/development.rb +2 -0
  35. data/test/dummy/config/initializers/bot.rb +3 -0
  36. data/test/dummy/config/routes.rb +1 -2
  37. data/test/dummy/db/development.sqlite3 +0 -0
  38. data/test/dummy/db/schema.rb +16 -0
  39. data/test/dummy/db/test.sqlite3 +0 -0
  40. data/test/dummy/log/development.log +4 -0
  41. data/test/dummy/log/test.log +2345 -0
  42. data/test/integration/navigation_test.rb +24 -1
  43. data/test/test_helper.rb +2 -0
  44. metadata +90 -8
  45. data/app/controllers/bot/kik_controller.rb +0 -8
  46. data/config/routes.rb +0 -3
  47. data/lib/bot/message_handler.rb +0 -26
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 73903dfd956f72bd8b5027f5fc0f426167781940
4
- data.tar.gz: 88d59d632dc0ec52bd5a1ebc5b4d1e8a1ed812e8
3
+ metadata.gz: 07f61d84f72deea7fe40bb6f1780276a64cd7460
4
+ data.tar.gz: 1c24da37fa185a9003c4b8bd8bd4fcc5c6667cca
5
5
  SHA512:
6
- metadata.gz: e917449bdf62fe2588fae9af8b625bc7ace0b2965fa27436db6c3f07bed00e3f2ed2f6f6d20476d81af048832b0f600e9d20bf60a58d902791bb0895a0baf7a1
7
- data.tar.gz: 21ca504f96bed73e007506cb00e5399c9522195d358e468513ecab73a8b1afea57bf8edc3946b7003b5c0a20062dcadadae7087f44c1dd6803acb18f74b7cfd2
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/message_handler"
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
@@ -0,0 +1,8 @@
1
+ require "bot/adapters/base"
2
+ require "bot/adapters/kik"
3
+ require "bot/adapters/test"
4
+
5
+ module Bot
6
+ module Adapter
7
+ end
8
+ end
@@ -0,0 +1,15 @@
1
+ module Bot
2
+ module Adapter
3
+ class Base
4
+ attr_reader :config
5
+
6
+ def initialize(config=nil)
7
+ @config = config
8
+ end
9
+
10
+ def send_messages(messages)
11
+ raise NotImplementedError
12
+ end
13
+ end
14
+ end
15
+ end
@@ -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
@@ -1,5 +1,9 @@
1
1
  module Bot
2
2
  class Engine < ::Rails::Engine
3
3
  isolate_namespace Bot
4
+
5
+ initializer 'bot.routes', after: 'action_dispatch.prepare_dispatcher' do |app|
6
+ ActionDispatch::Routing::Mapper.send :include, ::Bot::RouteExtensions
7
+ end
4
8
  end
5
9
  end
@@ -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
@@ -0,0 +1,15 @@
1
+ module Bot
2
+ class ResponderChain
3
+ def initialize
4
+ @responders = []
5
+ end
6
+
7
+ def add(responder)
8
+ @responders += Array.wrap(responder)
9
+ end
10
+
11
+ def responders
12
+ @responders.map {|r| r.to_s.constantize }
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,7 @@
1
+ module Bot
2
+ module RouteExtensions
3
+ def mount_bot(mount_point='/bot/notify', handler=ApplicationHandler)
4
+ post mount_point, to: 'bot/bot#notify', bot: handler
5
+ end
6
+ end
7
+ end
@@ -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,13 @@
1
+ module Bot
2
+ module Rspec
3
+ module FixnumHelper
4
+ def message
5
+ self
6
+ end
7
+
8
+ def messages
9
+ self
10
+ end
11
+ end
12
+ end
13
+ 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