sms77 0.0.1 → 0.4.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.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -2
  3. data/README.md +26 -6
  4. data/lib/sms77.rb +0 -1
  5. data/lib/sms77/client.rb +18 -87
  6. data/lib/sms77/{contacts_action.rb → contacts.rb} +2 -2
  7. data/lib/sms77/endpoint.rb +12 -12
  8. data/lib/sms77/hooks.rb +64 -0
  9. data/lib/sms77/journal.rb +38 -0
  10. data/lib/sms77/{lookup_type.rb → lookup.rb} +2 -2
  11. data/lib/sms77/resource.rb +93 -0
  12. data/lib/sms77/resources/analytics.rb +16 -0
  13. data/lib/sms77/resources/balance.rb +16 -0
  14. data/lib/sms77/resources/contacts.rb +26 -0
  15. data/lib/sms77/resources/hooks.rb +30 -0
  16. data/lib/sms77/resources/journal.rb +16 -0
  17. data/lib/sms77/resources/lookup.rb +30 -0
  18. data/lib/sms77/resources/pricing.rb +16 -0
  19. data/lib/sms77/resources/sms.rb +16 -0
  20. data/lib/sms77/resources/status.rb +16 -0
  21. data/lib/sms77/resources/validate_for_voice.rb +16 -0
  22. data/lib/sms77/resources/voice.rb +16 -0
  23. data/lib/sms77/sms.rb +8 -0
  24. data/lib/sms77/util.rb +68 -0
  25. data/lib/sms77/version.rb +1 -1
  26. data/release.sh +8 -0
  27. data/sms77.gemspec +13 -16
  28. data/spec/EnvKeyStore.rb +15 -0
  29. data/spec/matchers.rb +23 -0
  30. data/spec/sms77/balance_spec.rb +4 -7
  31. data/spec/sms77/client_spec.rb +15 -0
  32. data/spec/sms77/contacts_spec.rb +22 -24
  33. data/spec/sms77/hooks_spec.rb +106 -0
  34. data/spec/sms77/instance_spec.rb +20 -0
  35. data/spec/sms77/journal_spec.rb +86 -0
  36. data/spec/sms77/lookup_spec.rb +73 -82
  37. data/spec/sms77/pricing_spec.rb +25 -29
  38. data/spec/sms77/sms_spec.rb +20 -20
  39. data/spec/sms77/validate_for_voice_spec.rb +6 -6
  40. data/spec/sms77/voice_spec.rb +11 -8
  41. data/spec/sms77_spec.rb +0 -8
  42. data/spec/spec_helper.rb +31 -34
  43. metadata +60 -25
  44. data/lib/sms77/header.rb +0 -7
  45. data/spec/sms77/http_spec.rb +0 -40
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fe2489e8f42e261bf888d5d5d86805caba5e7a293dae1020399069b37ba26e2a
4
- data.tar.gz: cbb1faa8e91e0c29df20fa27ed31c8baa8a8655582fa180b64d45b24b27545a1
3
+ metadata.gz: 5dcd3acfda05ed3752e5d11fdd3218268ff39a9637373548fc7652845738c24c
4
+ data.tar.gz: f4a42f418594d53610fd89b2494c83555c654cc4401a1ebabf97d1e20feee5a6
5
5
  SHA512:
6
- metadata.gz: f0db040721b53efa7b02a8dc48af77d7ca6d43f0e5a8f0cdbae8700fef7abd856dd52fa149d68f3e61740a25761b37336274d0f65b3fa7d82071814be65cd824
7
- data.tar.gz: b22a80577d8b440de469a221f6013bf3fff1daa7ca9f3a8f8df9e9e59f7cfe94aef6ab79bf76c07b0cff800315acd1ac9c91e0b3f1f62a6dd29f01478cb85756
6
+ metadata.gz: 310757899c3eb52bbd50122271aada73242b984cbc83fc63361ae183e13ac410c6c9701214ddfc6124e1cb179ca5f2b2b1d075d533066b36b3ef814c015e3393
7
+ data.tar.gz: f4788dbac05a014e4ba53be45036e7db02f80d78d99fa7b0078779ac34b9349b6185f7c65db929e413f798e374746fe9f4384ce124afe953a36452bad68619eb
data/.gitignore CHANGED
@@ -1,4 +1,4 @@
1
- /.idea
2
- sms77.gem
1
+ build/
2
+ *.gem
3
3
  Gemfile.lock
4
4
  .ruby-gemset
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
- ![](https://www.sms77.io/wp-content/uploads/2019/07/sms77-Logo-400x79.png "Sms77.io Logo")
1
+ ![Sms77.io Logo](https://www.sms77.io/wp-content/uploads/2019/07/sms77-Logo-400x79.png "Sms77.io Logo")
2
2
 
3
- # Sms77.io SMS Gateway API Client
3
+ # Ruby Client for the Sms77.io SMS Gateway API
4
4
 
5
5
  ## Installation
6
6
 
@@ -9,7 +9,27 @@
9
9
  ### Usage
10
10
 
11
11
  ```ruby
12
- client = Sms77::Client.new(api_key: ENV['SMS77_API_KEY'])
13
- balance = client.get(url: '/api/balance')
14
- puts balance.inspect
15
- ```
12
+ require 'sms77'
13
+
14
+ puts Sms77::Client.new(Sms77::Resource(ENV['SMS77_API_KEY'])).Balance.retrieve
15
+ # or
16
+ puts Sms77::Resources::Balance.new(ENV['SMS77_API_KEY']).retrieve
17
+ ```
18
+
19
+ #### Testing
20
+
21
+ ```shell
22
+ SMS77_API_KEY=MySms77ApiKey bundle exec rspec
23
+ ```
24
+
25
+ *Optional environment variables*
26
+
27
+ Setting ```SMS77_DEBUG=1``` prints details to stdout.
28
+
29
+ Setting ```SMS77_TEST_HTTP=1``` enables live testing with actual API requests.
30
+
31
+ ##### Support
32
+
33
+ Need help? Feel free to [contact us](https://www.sms77.io/en/company/contact/).
34
+
35
+ [![MIT](https://img.shields.io/badge/License-MIT-teal.svg)](./LICENSE)
data/lib/sms77.rb CHANGED
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'sms77/version'
4
- require 'sms77/client'
5
4
 
6
5
  module Sms77
7
6
  end
data/lib/sms77/client.rb CHANGED
@@ -1,98 +1,29 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'cgi'
4
- require 'json'
5
- require 'faraday'
6
- require 'sms77/endpoint'
7
- require 'sms77/contacts_action'
8
- require 'sms77/header'
3
+ require 'sms77/resources/analytics'
4
+ require 'sms77/resources/balance'
5
+ require 'sms77/resources/contacts'
6
+ require 'sms77/resources/hooks'
7
+ require 'sms77/resources/journal'
8
+ require 'sms77/resources/lookup'
9
+ require 'sms77/resources/pricing'
10
+ require 'sms77/resources/sms'
11
+ require 'sms77/resources/status'
12
+ require 'sms77/resources/validate_for_voice'
13
+ require 'sms77/resources/voice'
14
+ require 'sms77/util'
9
15
 
10
16
  module Sms77
11
17
  class Client
12
- def initialize(api_key, conn, sent_with = 'ruby')
13
- @api_key = api_key
14
- @conn = conn
15
- @sent_with = sent_with
18
+ # @param resource [Sms77::Resource]
19
+ def initialize(resource)
20
+ Sms77::Util::get_namespace_classes(Sms77::Resources).each do |cls|
21
+ name = cls.name.split('::').last
16
22
 
17
- raise 'missing api_key in config' if !@api_key || @api_key.empty?
18
- raise 'missing conn in config' unless @conn
23
+ instance_variable_set("@#{name}", cls.new(resource))
19
24
 
20
- @conn.headers['sentWith'] = @sent_with
21
- @conn.authorization :Bearer, @api_key
22
- end
23
-
24
- BASE_URI = 'https://gateway.sms77.io'
25
- API_SUFFIX = '/api/'
26
- API_URI = "#{BASE_URI}#{API_SUFFIX}"
27
-
28
- def analytics(params = {})
29
- get(Sms77::Endpoint::ANALYTICS, params)
30
- end
31
-
32
- def balance
33
- get(Sms77::Endpoint::BALANCE)
34
- end
35
-
36
- def contacts(params)
37
- method(params['action'] == ContactsAction::READ ? 'get' : 'post').call(Sms77::Endpoint::CONTACTS, params)
38
- end
39
-
40
- def lookup(params)
41
- get(Sms77::Endpoint::LOOKUP, params)
42
- end
43
-
44
- def pricing(params = {})
45
- get(Sms77::Endpoint::PRICING, params)
46
- end
47
-
48
- def sms(params)
49
- post(Sms77::Endpoint::SMS, params)
50
- end
51
-
52
- def status(params)
53
- get(Sms77::Endpoint::STATUS, params)
54
- end
55
-
56
- def validate_for_voice(params)
57
- get(Sms77::Endpoint::VALIDATE_FOR_VOICE, params)
58
- end
59
-
60
- def voice(params)
61
- post(Sms77::Endpoint::VOICE, params)
62
- end
63
-
64
- private
65
-
66
- def get(endpoint, params = {})
67
- request(endpoint, 'get', params)
68
- end
69
-
70
- def post(endpoint, params)
71
- request(endpoint, 'post', params)
72
- end
73
-
74
- def request(endpoint, method, params)
75
- url = "#{API_SUFFIX}#{endpoint}"
76
-
77
- if ENV['SMS77_DEBUG']
78
- puts "requesting url: #{url}"
79
- puts "headers: #{@conn.headers.inspect}"
25
+ singleton_class.instance_eval("attr_reader :#{name}")
80
26
  end
81
-
82
- response = if method == 'get'
83
- @conn.get(url, params)
84
- else
85
- @conn.post do |req|
86
- req.path = url
87
- req.params = params
88
- end
89
- end
90
-
91
- raise "Error requesting (#{self.class.name}) with code: #{response.status}" if response.status != 200
92
-
93
- puts "received body: #{response.body}" if ENV['SMS77_DEBUG']
94
-
95
- response
96
27
  end
97
28
  end
98
29
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Sms77
4
- module ContactsAction
3
+ module Sms77::Contacts
4
+ module Action
5
5
  DEL = 'del'
6
6
  READ = 'read'
7
7
  WRITE = 'write'
@@ -1,15 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Sms77
4
- module Endpoint
5
- ANALYTICS = 'analytics'
6
- BALANCE = 'balance'
7
- CONTACTS = 'contacts'
8
- LOOKUP = 'lookup'
9
- PRICING = 'pricing'
10
- SMS = 'sms'
11
- STATUS = 'status'
12
- VALIDATE_FOR_VOICE = 'validate_for_voice'
13
- VOICE = 'voice'
14
- end
3
+ module Sms77::Endpoint
4
+ ANALYTICS = 'analytics'
5
+ BALANCE = 'balance'
6
+ CONTACTS = 'contacts'
7
+ HOOKS = 'hooks'
8
+ JOURNAL = 'journal'
9
+ LOOKUP = 'lookup'
10
+ PRICING = 'pricing'
11
+ SMS = 'sms'
12
+ STATUS = 'status'
13
+ VALIDATE_FOR_VOICE = 'validate_for_voice'
14
+ VOICE = 'voice'
15
15
  end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sms77::Hooks
4
+ module Action
5
+ READ = 'read'
6
+ SUBSCRIBE = 'subscribe'
7
+ UNSUBSCRIBE = 'unsubscribe'
8
+ end
9
+
10
+ module EventType
11
+ ALL = 'all'
12
+ NEW_INBOUND_SMS = 'sms_mo'
13
+ SMS_STATUS_UPDATE = 'dlr'
14
+ VOICE_STATUS_UPDATE = 'voice_status'
15
+ end
16
+
17
+ module RequestMethod
18
+ GET = 'GET'
19
+ JSON = 'JSON'
20
+ POST = 'POST'
21
+ end
22
+
23
+ module Validator
24
+ def self.validate(params)
25
+ action = params[:action]
26
+
27
+ raise "Unknown action #{action}" unless Sms77::Hooks::Validator::is_action?(action)
28
+
29
+ if Sms77::Hooks::Action::SUBSCRIBE == action
30
+ raise 'Parameter validation failed' unless Sms77::Hooks::Validator::subscribe(params)
31
+ elsif Sms77::Hooks::Action::UNSUBSCRIBE == action
32
+ raise 'ID must be a positive integer' unless Sms77::Hooks::Validator::unsubscribe(params)
33
+ end
34
+ end
35
+
36
+ def self.subscribe(params)
37
+ { :request_method => Sms77::Hooks::RequestMethod::POST }.merge!(params)
38
+
39
+ self.event_type?(params[:event_type]) &&
40
+ self.request_method?(params[:request_method]) &&
41
+ self.target_url?(params[:target_url])
42
+ end
43
+
44
+ def self.unsubscribe(params)
45
+ Sms77::Util::is_positive_integer?(params[:id])
46
+ end
47
+
48
+ def self.is_action?(str)
49
+ Sms77::Util::in_module_constants?(str, Sms77::Hooks::Action)
50
+ end
51
+
52
+ def self.event_type?(str)
53
+ Sms77::Util::in_module_constants?(str, Sms77::Hooks::EventType)
54
+ end
55
+
56
+ def self.request_method?(str)
57
+ Sms77::Util::in_module_constants?(str, Sms77::Hooks::RequestMethod)
58
+ end
59
+
60
+ def self.target_url?(str)
61
+ Sms77::Util::is_valid_url?(str)
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sms77::Journal
4
+ module Type
5
+ INBOUND = 'inbound'
6
+ OUTBOUND = 'outbound'
7
+ REPLIES = 'replies'
8
+ VOICE = 'voice'
9
+ end
10
+
11
+ module Validator
12
+ def self.validate(params)
13
+ type = params[:type]
14
+ date_from = params[:date_from]
15
+ date_to = params[:date_to]
16
+
17
+ raise "Unknown type #{type}" unless Sms77::Journal::Validator::is_type?(type)
18
+ raise "Wrong date_from #{date_from}" unless Sms77::Journal::Validator::is_date?(date_from)
19
+ raise "Wrong date_to #{date_to}" unless Sms77::Journal::Validator::is_date?(date_to)
20
+ end
21
+
22
+ def self.subscribe(params)
23
+ { :request_method => Sms77::Hooks::RequestMethod::POST }.merge!(params)
24
+
25
+ self.event_type?(params[:event_type]) &&
26
+ self.request_method?(params[:request_method]) &&
27
+ self.target_url?(params[:target_url])
28
+ end
29
+
30
+ def self.is_type?(str)
31
+ Sms77::Util::in_module_constants?(str, Sms77::Journal::Type)
32
+ end
33
+
34
+ def self.is_date?(date)
35
+ date.is_a?(NilClass) || date.match(/[\d]{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][\d]|3[0-1])/)
36
+ end
37
+ end
38
+ end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Sms77
4
- module LookupType
3
+ module Sms77::Lookup
4
+ module Type
5
5
  CNAM = 'cnam'
6
6
  FORMAT = 'format'
7
7
  HLR = 'hlr'
@@ -0,0 +1,93 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'cgi'
4
+ require 'json'
5
+ require 'faraday'
6
+ require 'sms77/endpoint'
7
+
8
+ module Sms77
9
+ class Resource
10
+ attr_reader :api_key, :endpoint, :sent_with, :http_methods, :request_methods, :builder, :conn
11
+
12
+ BASE_PATH = '/api/'
13
+
14
+ def initialize(api_key, sent_with = 'ruby')
15
+ raise 'missing api_key in config' if api_key.to_s.empty?
16
+ raise 'missing sent_with in config' if sent_with.to_s.empty?
17
+
18
+ @api_key = api_key
19
+ @sent_with = sent_with
20
+ @endpoint = self.class.get_endpoint
21
+ @http_methods = self.class.get_http_methods
22
+ @conn = Faraday.new("https://gateway.sms77.io#{BASE_PATH}")
23
+ end
24
+
25
+ protected
26
+
27
+ def request(payload = {}, query = {})
28
+ path = @endpoint
29
+ http_method = @http_methods[caller_locations.first.label.to_sym]
30
+
31
+ if :get == http_method
32
+ query = payload
33
+
34
+ payload = {}
35
+ end
36
+
37
+ query.each do |key, val|
38
+ query.store(key, Sms77::Util::to_numbered_bool(val))
39
+ end
40
+
41
+ payload.each do |key, val|
42
+ payload.store(key, Sms77::Util::to_numbered_bool(val))
43
+ end
44
+
45
+ unless query.empty?
46
+ path = "#{path}?#{URI.encode_www_form(query)}"
47
+ end
48
+
49
+ headers = Hash[
50
+ Faraday::Request::Authorization::KEY, "Bearer #{@api_key}",
51
+ 'sentWith', @sent_with
52
+ ]
53
+
54
+ res = @conn.run_request(http_method, path, payload, headers)
55
+
56
+ puts JSON.pretty_generate(res.to_hash.merge({
57
+ :method => http_method,
58
+ :path => path,
59
+ :payload => payload,
60
+ :req_headers => headers,
61
+ :query => query,
62
+ }).compact) if ENV['SMS77_DEBUG']
63
+
64
+ raise "Error requesting (#{self.class.name}) with code #{res.status}" unless 200 == res.status
65
+
66
+ raise 'Unexpected response' unless res.is_a?(Faraday::Response)
67
+
68
+ body = res.body
69
+
70
+ if body.is_a?(String)
71
+ begin
72
+ body = JSON.parse(body, :symbolize_names => true)
73
+ rescue StandardError
74
+ # Ignored
75
+ end
76
+ end
77
+
78
+ body.map! { |hash| hash.transform_keys(&:to_sym) } if body.is_a?(Array)
79
+
80
+ body
81
+ end
82
+
83
+ class << self
84
+ def get_http_methods
85
+ @http_methods
86
+ end
87
+
88
+ def get_endpoint
89
+ @endpoint
90
+ end
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'sms77/resource'
4
+
5
+ module Sms77::Resources
6
+ class Analytics < Sms77::Resource
7
+ @endpoint = Sms77::Endpoint::ANALYTICS
8
+ @http_methods = {
9
+ :retrieve => :get,
10
+ }
11
+
12
+ def retrieve(params = {})
13
+ request(params)
14
+ end
15
+ end
16
+ end