stealth-messagebird 1.0.0

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: a1228659f9b45371d5a9ccf1abaf8e6a6df5f3a4fff7a3a49ec7412e28459870
4
+ data.tar.gz: d10bcc20c96acf5aa4950ba62aaab8ebba6c0b39030d549144f6252f70416626
5
+ SHA512:
6
+ metadata.gz: 520c7678bc8d73f64c487e1badad84438e58dae307782f09305ca3bc74df92ad58bfe07c2fc8670b67d56b5975f5f7720251ec524200a46e07951057d6300bf1
7
+ data.tar.gz: c9eaeae10966f14f6eb943511fe5b865414a96e549c21fd5dbf84858d1eedd189d07e27ceb8235fdf4993dcee95c93eb797b67016d9189df04be9209e11777a3
@@ -0,0 +1,60 @@
1
+ # Ruby CircleCI 2.0 configuration file
2
+ #
3
+ # Check https://circleci.com/docs/2.0/language-ruby/ for more details
4
+ #
5
+ version: 2
6
+ jobs:
7
+ build:
8
+ docker:
9
+ # specify the version you desire here
10
+ - image: circleci/ruby:2.4.1-node-browsers
11
+ environment:
12
+ STEALTH_ENV: test
13
+
14
+ # Specify service dependencies here if necessary
15
+ # CircleCI maintains a library of pre-built images
16
+ # documented at https://circleci.com/docs/2.0/circleci-images/
17
+ # - image: circleci/postgres:9.4
18
+
19
+ working_directory: ~/repo
20
+
21
+ steps:
22
+ - checkout
23
+
24
+ # Download and cache dependencies
25
+ - restore_cache:
26
+ keys:
27
+ - v1-dependencies-{{ checksum "Gemfile.lock" }}
28
+ # fallback to using the latest cache if no exact match is found
29
+ - v1-dependencies-
30
+
31
+ - run:
32
+ name: install dependencies
33
+ command: |
34
+ bundle install --jobs=4 --retry=3 --path vendor/bundle
35
+
36
+ - save_cache:
37
+ paths:
38
+ - ./vendor/bundle
39
+ key: v1-dependencies-{{ checksum "Gemfile.lock" }}
40
+
41
+ # run tests!
42
+ - run:
43
+ name: run tests
44
+ command: |
45
+ mkdir /tmp/test-results
46
+ TEST_FILES="$(circleci tests glob "spec/**/*_spec.rb" | circleci tests split --split-by=timings)"
47
+
48
+ bundle exec rspec --format progress \
49
+ --format RspecJunitFormatter \
50
+ --out /tmp/test-results/rspec.xml \
51
+ --format progress \
52
+ -- \
53
+ $TEST_FILES
54
+
55
+ # collect reports
56
+ - store_test_results:
57
+ path: /tmp/test-results
58
+ - store_artifacts:
59
+ path: /tmp/test-results
60
+ destination: test-results
data/.gitignore ADDED
@@ -0,0 +1,13 @@
1
+ # please add general patterns to your global ignore list
2
+ # see https://github.com/github/gitignore#readme
3
+ .DS_STORE
4
+ *.swp
5
+ *.rbc
6
+ *.sass-cache
7
+ /pkg
8
+ /doc/api
9
+ /coverage
10
+ .yardoc
11
+ doc/
12
+ *.gem
13
+ Gemfile.lock
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'stealth', '>= 2.0.0.beta'
4
+
5
+ gemspec
6
+
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2021 Emilie Morissette
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,77 @@
1
+ # Messagebird WhatsApp Driver for Stealth
2
+
3
+ The [Stealth](https://github.com/hellostealth/stealth) WhatsApp driver adds the ability to build your bot using [Messagebird](https://www.messagebird.com/en/solutions/whatsapp-api) service.
4
+
5
+ Messagebird allow you to use your [own mobile number](https://support.messagebird.com/hc/en-us/articles/360000244558-How-to-pick-a-number-for-WhatsApp-Business) for WhatsApp. So no geographic restrictions compare to virtual mobile numbers (VMNs).
6
+
7
+ First thing first, create a Messagebird account and install your [WhatsApp Business channel](https://support.messagebird.com/hc/en-us/articles/360000258437-WhatsApp-Business-step-by-step-onboarding). This gem is not supporting the Messagebird Sandbox, since their Sandbox has limitations.
8
+
9
+ ## WhatsApp Supported Reply Types
10
+
11
+ * Text
12
+ * Image
13
+ * Audio
14
+ * Video/GIF (receive only)
15
+ * File
16
+ * Delay
17
+
18
+ * Location
19
+
20
+ In your replies files
21
+ ```
22
+ - reply_type: location
23
+ latitude: 41.69352000000001
24
+ longitude: 44.801473999999985
25
+ ```
26
+
27
+ More info here: https://developers.messagebird.com/quickstarts/whatsapp-deepdive/
28
+
29
+ ## Configure Messagebird with your Stealth bot
30
+ Once your WhatsApp Business Channel is active, you will receive a `channel_id`.
31
+ To visualize your channel_id, go to `Channels` in the sidebar of your Messagebird Dashboard.
32
+ You will need your Live API Key as well, go to `Developers` in the sidebar of your Messagebird Dashboard.
33
+
34
+ In `services.yml`
35
+ ```
36
+ messagebird:
37
+ access_key: <%= ENV['MESSAGEBIRD_ACCESS_KEY'] %>
38
+ channel_id: <%= ENV['MESSAGEBIRD_CHANNEL_ID'] %>
39
+ ```
40
+
41
+ ## Setup your Webhook
42
+ Create your webhook so that Messagebird can communicate with your app when receiving a message from a user.
43
+ Subscribe to `message.created` event only.
44
+
45
+ ```
46
+ curl -X POST "https://conversations.messagebird.com/v1/webhooks/" \
47
+ -H "Authorization: AccessKey YOUR_ACCESS_KEY" \
48
+ -H "Content-Type: application/json" \
49
+ -d '{
50
+ "events": ["message.created"],
51
+ "channelId": "YOUR_CHANNEL_ID",
52
+ "url": "https://1cfd8wc098r0.ngrok.io/incoming/messagebird"
53
+ }'
54
+ ```
55
+ When you provide your local ngrok URL to a messaging service, you will have to add /incoming/messagebird. More infos on [Stealth Repo](https://github.com/hellostealth/stealth/wiki/Local-Development).
56
+
57
+ For more infos on webhooks, follow the [Messagebird instructions](https://developers.messagebird.com/api/conversations/#create-webhook).
58
+
59
+ ## current_message
60
+ When calling the `current_message` method in your Stealth bot, you can retrieve the following informations:
61
+ ```
62
+ #<Stealth::Services::Messagebird::MessagebirdServiceMessage:0x00009ceg7cef4cd3
63
+ @attachments=[],
64
+ @conversation_id="1cdeee16bd432a987c167f67b611056f",
65
+ @display_name="Emilie",
66
+ @first_name="",
67
+ @last_name="",
68
+ @location={},
69
+ @message="Yo",
70
+ @messagebird_id="9881a12f6hhe4g41b9935hh4d299c01f",
71
+ @platform="whatsapp",
72
+ @read={},
73
+ @sender_id="33320110909",
74
+ @service="messagebird",
75
+ @target_id="098882ge-b745-1f12-a02f-4c1239da7d01",
76
+ @timestamp="2021-04-13T12:23:16Z">
77
+ ```
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 1.0.0
@@ -0,0 +1,4 @@
1
+ require 'pry'
2
+ require 'json'
3
+ require 'stealth/services/messagebird/version'
4
+ require 'stealth/services/messagebird/client'
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+ require 'messagebird'
3
+ require 'stealth/services/messagebird/message_handler'
4
+ require 'stealth/services/messagebird/messagebird_service_message'
5
+ require 'stealth/services/messagebird/reply_handler'
6
+ require 'stealth/services/messagebird/setup'
7
+
8
+ module Stealth
9
+ module Services
10
+ module Messagebird
11
+ class Client < Stealth::Services::BaseClient
12
+ attr_reader :messagebird_client, :reply
13
+
14
+ def initialize(reply:)
15
+ @reply = reply
16
+ access_key = Stealth.config.messagebird.access_key
17
+ @messagebird_client = MessageBird::Client.new(access_key)
18
+ end
19
+
20
+ def transmit
21
+ # Don't transmit anything for delays
22
+ return true if reply.blank?
23
+
24
+ response = messagebird_client.send_conversation_message(reply[:from], reply[:to], reply)
25
+
26
+ if response.status == "failed" || response.status == "rejected"
27
+ case response.error.code
28
+ when 301 # Message failed to send
29
+ raise Stealth::Errors::UserOptOut
30
+ when 302 # Contact is not registered on WhatsApp
31
+ raise Stealth::Errors::UserOptOut
32
+ when 470 # Outside the support window for freeform messages
33
+ raise Stealth::Errors::UserOptOut
34
+ when 2 # Request not allowed
35
+ raise Stealth::Errors::UserOptOut
36
+ when 25 # Not enough balance
37
+ raise Stealth::Errors::UserOptOut
38
+ else
39
+ raise
40
+ end
41
+ end
42
+
43
+ message = "Transmitting. Response: #{response.status}: "
44
+ if response.status == "failed" || response.status == "rejected"
45
+ message += response.error.description
46
+ end
47
+ Stealth::Logger.l(topic: "messagebird", message: message)
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+ module Stealth
3
+ module Services
4
+ module Messagebird
5
+ class MessageHandler < Stealth::Services::BaseMessageHandler
6
+ attr_reader :service_message, :params, :headers
7
+
8
+ def initialize(params:, headers:)
9
+ @params = params
10
+ @headers = headers
11
+ end
12
+
13
+ def coordinate
14
+ if params.dig('message', 'direction') == 'received'
15
+ Stealth::Services::HandleMessageJob.perform_async(
16
+ 'messagebird',
17
+ params,
18
+ headers
19
+ )
20
+ end
21
+ # Relay our acceptance
22
+ [200, 'OK']
23
+ end
24
+
25
+ def process
26
+ @service_message = MessagebirdServiceMessage.new(service: 'messagebird')
27
+ service_message.sender_id = params['contact']['msisdn'].to_s
28
+ service_message.target_id = params['message']['channelId']
29
+ service_message.timestamp = params['message']['createdDatetime']
30
+ service_message.message = params['message']['content']['text']
31
+ service_message.conversation_id = params['message']['conversationId']
32
+ service_message.messagebird_id = params['contact']['id']
33
+ service_message.display_name = params['contact']['displayName']
34
+ service_message.first_name = params['contact']['firstName']
35
+ service_message.last_name = params['contact']['lastName']
36
+ service_message.platform = params['message']['platform']
37
+
38
+ if params['message']['type'] == 'image'
39
+ service_message.attachments = [{
40
+ type: params['message']['type'],
41
+ url: params['message']['content']['image']['url']
42
+ }]
43
+ elsif params['message']['type'] == 'video'
44
+ service_message.attachments = [{
45
+ type: params['message']['type'],
46
+ url: params['message']['content']['video']['url']
47
+ }]
48
+ elsif params['message']['type'] == 'audio'
49
+ service_message.attachments = [{
50
+ type: params['message']['type'],
51
+ url: params['message']['content']['audio']['url']
52
+ }]
53
+ elsif params['message']['type'] == 'file'
54
+ service_message.attachments = [{
55
+ type: params['message']['type'],
56
+ location: params['message']['content']['file']['url']
57
+ }]
58
+ elsif params['message']['type'] == 'location'
59
+ service_message.location = [{
60
+ type: params['message']['type'],
61
+ location: params['message']['content']['location']
62
+ }]
63
+ end
64
+
65
+ service_message
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,15 @@
1
+ module Stealth
2
+ module Services
3
+ module Messagebird
4
+ class MessagebirdServiceMessage < Stealth::ServiceMessage
5
+ attr_accessor :conversation_id,
6
+ :messagebird_id,
7
+ :platform,
8
+ :display_name,
9
+ :first_name,
10
+ :last_name
11
+
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,138 @@
1
+ # frozen_string_literal: true
2
+ module Stealth
3
+ module Services
4
+ module Messagebird
5
+ class ReplyHandler < Stealth::Services::BaseReplyHandler
6
+
7
+ attr_reader :recipient_id, :reply
8
+
9
+ def initialize(recipient_id: nil, reply: nil)
10
+ @recipient_id = recipient_id
11
+ @reply = reply
12
+ end
13
+
14
+ def text
15
+ check_text_length
16
+
17
+ translated_reply = reply['text']
18
+
19
+ suggestions = generate_suggestions(suggestions: reply['suggestions'])
20
+ buttons = generate_buttons(buttons: reply['buttons'])
21
+
22
+ if suggestions.present?
23
+ translated_reply = [
24
+ translated_reply,
25
+ I18n.t(
26
+ "stealth.messagebird.respond_with_a_number",
27
+ default: "Respond with a number:"
28
+ )
29
+ ].join("\n\n")
30
+
31
+ suggestions.each_with_index do |suggestion, i|
32
+ translated_reply = [
33
+ translated_reply,
34
+ I18n.t(
35
+ "stealth.messagebird.number_option",
36
+ number: i + 1,
37
+ suggestion: suggestion,
38
+ default: "%{number} for %{suggestion}"
39
+ )
40
+ ].join("\n")
41
+ end
42
+ end
43
+
44
+ if buttons.present?
45
+ buttons.each do |button|
46
+ translated_reply = [
47
+ translated_reply,
48
+ button
49
+ ].join("\n\n")
50
+ end
51
+ end
52
+
53
+ # format_response({ body: translated_reply })
54
+ format_response(type: 'text', content: { text: translated_reply })
55
+ end
56
+
57
+ def image
58
+ check_text_length
59
+ format_response(type: 'image', content: { image: { caption: reply['text'], url: reply['image_url'] } })
60
+ end
61
+
62
+ def audio
63
+ check_text_length
64
+
65
+ format_response(type: 'audio', content: { audio: { caption: reply['text'], url: reply['audio_url'] } })
66
+ end
67
+
68
+ def video
69
+ check_text_length
70
+
71
+ format_response(type: 'video', content: { video: { caption: reply['text'], url: reply['video_url'] } })
72
+ end
73
+
74
+ def file
75
+ check_text_length
76
+
77
+ format_response(type: 'file', content: { file: { caption: reply['text'], url: reply['file_url'] } })
78
+ end
79
+
80
+ def location
81
+ check_text_length
82
+
83
+ format_response(type: 'location', content: { location: { latitude: reply['latitude'], longitude: reply['longitude'] } })
84
+ end
85
+
86
+ def delay
87
+
88
+ end
89
+
90
+ private
91
+
92
+ def check_text_length
93
+ if reply['text'].present? && reply['text'].size > 1600
94
+ raise(ArgumentError, "Text messages must be 1600 characters or less.")
95
+ end
96
+ end
97
+
98
+ def format_response(response)
99
+ sender_info = {
100
+ from: Stealth.config.messagebird.channel_id.to_s,
101
+ to: recipient_id.to_s
102
+ }
103
+ response.merge(sender_info)
104
+ end
105
+
106
+ def generate_suggestions(suggestions:)
107
+ return if suggestions.blank?
108
+
109
+ mf = suggestions.collect do |suggestion|
110
+ suggestion['text']
111
+ end.compact
112
+ end
113
+
114
+ def generate_buttons(buttons:)
115
+ return if buttons.blank?
116
+
117
+ sms_buttons = buttons.map do |button|
118
+ case button['type']
119
+ when 'url'
120
+ "#{button['text']}: #{button['url']}"
121
+ when 'payload'
122
+ I18n.t(
123
+ "stealth.messagebird.text_option",
124
+ text: button['text'],
125
+ option: button['payload'],
126
+ default: "For %{text}: Text %{option}"
127
+ )
128
+ when 'call'
129
+ "#{button['text']}: #{button['phone_number']}"
130
+ end
131
+ end.compact
132
+
133
+ sms_buttons
134
+ end
135
+ end
136
+ end
137
+ end
138
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+ require 'stealth/services/messagebird/client'
3
+
4
+ module Stealth
5
+ module Services
6
+ module Messagebird
7
+
8
+ class Setup
9
+
10
+ class << self
11
+ def trigger
12
+ Stealth::Logger.l(topic: "messagebird", message: "There is no setup needed!")
13
+ end
14
+ end
15
+
16
+ end
17
+
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Stealth
4
+ module Services
5
+ module Messagebird
6
+ module Version
7
+ def self.version
8
+ File.read(File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'VERSION')).strip
9
+ end
10
+ end
11
+
12
+ VERSION = Version.version
13
+ end
14
+ end
15
+ end
@@ -0,0 +1 @@
1
+ require 'stealth/messagebird'
@@ -0,0 +1,14 @@
1
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
3
+ require 'rspec'
4
+
5
+ require 'stealth'
6
+ require 'stealth-messagebird'
7
+
8
+ # Requires supporting files with custom matchers and macros, etc,
9
+ # in ./support/ and its subdirectories.
10
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
11
+
12
+ RSpec.configure do |config|
13
+
14
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
4
+
5
+ describe "Stealth::Services::Messagebird::Version" do
6
+
7
+ let(:version_in_file) { File.read(File.join(File.dirname(__FILE__), '..', 'VERSION')).strip }
8
+
9
+ it "should return the current gem version" do
10
+ expect(Stealth::Services::Messagebird::Version.version).to eq version_in_file
11
+ end
12
+
13
+ it "should return the current gem version via a constant" do
14
+ expect(Stealth::Services::Messagebird::VERSION).to eq version_in_file
15
+ end
16
+ end
@@ -0,0 +1,26 @@
1
+ $LOAD_PATH.push File.expand_path('../lib', __FILE__)
2
+
3
+ version = File.read(File.join(File.dirname(__FILE__), 'VERSION')).strip
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = 'stealth-messagebird'
7
+ s.summary = 'Stealth MessageBird Whatsapp driver'
8
+ s.description = 'MessageBird Whatsapp driver for Stealth.'
9
+ s.homepage = 'https://github.com/emorissettegregoire/stealth-messagebird'
10
+ s.licenses = ['MIT']
11
+ s.version = version
12
+ s.author = 'Emilie Morissette'
13
+ s.email = 'emorissettegregoire@gmail.com'
14
+
15
+ s.add_dependency 'stealth', '>= 2.0.0.beta'
16
+ s.add_dependency 'messagebird-rest', '1.4.2'
17
+
18
+ s.add_development_dependency 'rspec', '~> 3.6'
19
+ s.add_development_dependency 'rspec_junit_formatter', '~> 0.3'
20
+ s.add_development_dependency 'rack-test', '~> 1.1'
21
+
22
+ s.files = `git ls-files`.split("\n")
23
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
24
+ s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
25
+ s.require_paths = ['lib']
26
+ end
metadata ADDED
@@ -0,0 +1,131 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: stealth-messagebird
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Emilie Morissette
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2022-09-23 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: stealth
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 2.0.0.beta
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 2.0.0.beta
27
+ - !ruby/object:Gem::Dependency
28
+ name: messagebird-rest
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '='
32
+ - !ruby/object:Gem::Version
33
+ version: 1.4.2
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '='
39
+ - !ruby/object:Gem::Version
40
+ version: 1.4.2
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.6'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.6'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec_junit_formatter
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '0.3'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '0.3'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rack-test
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '1.1'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '1.1'
83
+ description: MessageBird Whatsapp driver for Stealth.
84
+ email: emorissettegregoire@gmail.com
85
+ executables: []
86
+ extensions: []
87
+ extra_rdoc_files: []
88
+ files:
89
+ - ".circleci/config.yml"
90
+ - ".gitignore"
91
+ - Gemfile
92
+ - LICENSE
93
+ - README.md
94
+ - VERSION
95
+ - lib/stealth-messagebird.rb
96
+ - lib/stealth/messagebird.rb
97
+ - lib/stealth/services/messagebird/client.rb
98
+ - lib/stealth/services/messagebird/message_handler.rb
99
+ - lib/stealth/services/messagebird/messagebird_service_message.rb
100
+ - lib/stealth/services/messagebird/reply_handler.rb
101
+ - lib/stealth/services/messagebird/setup.rb
102
+ - lib/stealth/services/messagebird/version.rb
103
+ - spec/spec_helper.rb
104
+ - spec/version_spec.rb
105
+ - stealth-messagebird.gemspec
106
+ homepage: https://github.com/emorissettegregoire/stealth-messagebird
107
+ licenses:
108
+ - MIT
109
+ metadata: {}
110
+ post_install_message:
111
+ rdoc_options: []
112
+ require_paths:
113
+ - lib
114
+ required_ruby_version: !ruby/object:Gem::Requirement
115
+ requirements:
116
+ - - ">="
117
+ - !ruby/object:Gem::Version
118
+ version: '0'
119
+ required_rubygems_version: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - ">="
122
+ - !ruby/object:Gem::Version
123
+ version: '0'
124
+ requirements: []
125
+ rubygems_version: 3.0.8
126
+ signing_key:
127
+ specification_version: 4
128
+ summary: Stealth MessageBird Whatsapp driver
129
+ test_files:
130
+ - spec/spec_helper.rb
131
+ - spec/version_spec.rb