elk 0.0.13 → 0.5.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 +4 -4
- data/README.MD +38 -12
- data/lib/elk.rb +31 -75
- data/lib/elk/client.rb +77 -0
- data/lib/elk/error.rb +16 -0
- data/lib/elk/number.rb +42 -18
- data/lib/elk/sms.rb +49 -24
- data/lib/elk/util.rb +13 -3
- data/lib/elk/version.rb +1 -1
- data/spec/fixtures/sends_a_sms_to_multiple_recipients.txt +1 -1
- data/spec/fixtures/sends_a_sms_with_long_sender.txt +2 -2
- data/spec/integration/number_spec.rb +191 -0
- data/spec/integration/sms_spec.rb +241 -0
- data/spec/spec.opts +1 -1
- data/spec/spec_helper.rb +9 -3
- data/spec/unit/client_spec.rb +69 -0
- data/spec/unit/elk_spec.rb +70 -0
- data/spec/unit/number_spec.rb +93 -0
- data/spec/unit/sms_spec.rb +66 -0
- data/spec/unit/utils_spec.rb +50 -0
- metadata +27 -35
- data/spec/elk/number_spec.rb +0 -117
- data/spec/elk/sms_spec.rb +0 -168
- data/spec/elk_spec.rb +0 -58
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e3184044f09e7d64a7822c28eaa6e3de56978fc9
|
4
|
+
data.tar.gz: db5a2368596d235da746132e3dae9e03dd56adf2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d0ced3eef3b56b1225c8c1d92acf8a8a6f428f5105aa2e4a33e666a37c0db058d0bb0fc4348eea2d28232d4960944563aa1bc028ce1bb4e51f8c0cb60bdb4620
|
7
|
+
data.tar.gz: eeeec30f922cc461df8d750621b6c34a62097286848e7477bbef10e490e5af5cedad303355984529971a008a0fb866e72488eaa550da379deec663c4c7ca38c7
|
data/README.MD
CHANGED
@@ -1,12 +1,14 @@
|
|
1
1
|
# Elk - 46elks API-client
|
2
2
|
|
3
|
+
[](https://travis-ci.org/jage/elk)
|
4
|
+
[](https://codeclimate.com/github/jage/elk)
|
5
|
+
|
3
6
|
Ruby client for 46elks "Voice, SMS & MMS" service. http://46elks.com/
|
4
7
|
At the moment the API only supports sending SMS messages.
|
5
8
|
|
6
9
|
## Requirements
|
7
10
|
|
8
|
-
|
9
|
-
|
11
|
+
* Modern Ruby: >= 1.9
|
10
12
|
* API account at 46elks.com
|
11
13
|
|
12
14
|
## Install
|
@@ -21,7 +23,11 @@ The source for Elk is available on Github:
|
|
21
23
|
|
22
24
|
https://github.com/jage/elk
|
23
25
|
|
24
|
-
|
26
|
+
Elk uses rspec and webmock for testing, do a `bundle install` for all the development requirements.
|
27
|
+
|
28
|
+
Test specs with:
|
29
|
+
|
30
|
+
bundle exec rake spec
|
25
31
|
|
26
32
|
## Usage
|
27
33
|
|
@@ -32,12 +38,32 @@ elk can be used to allocate a phone numbers, manage the numbers and send/recieve
|
|
32
38
|
First thing when using elk is to set the authentication parameters
|
33
39
|
|
34
40
|
```Ruby
|
35
|
-
require
|
41
|
+
require "elk"
|
36
42
|
|
37
43
|
Elk.configure do |config|
|
38
|
-
config.username =
|
39
|
-
config.password =
|
44
|
+
config.username = "USERNAME"
|
45
|
+
config.password = "PASSWORD"
|
46
|
+
end
|
47
|
+
```
|
48
|
+
|
49
|
+
It is possible to avoid the singleton configuration:
|
50
|
+
|
51
|
+
```Ruby
|
52
|
+
require "elk"
|
53
|
+
|
54
|
+
client = Elk::Client.new
|
55
|
+
client.configure do |config|
|
56
|
+
config.username = "USERNAME"
|
57
|
+
config.password = "PASSWORD"
|
40
58
|
end
|
59
|
+
|
60
|
+
# Then pass client to the class methods
|
61
|
+
numbers = Elk::Number.all(client: client)
|
62
|
+
# => [#<Elk::Number ...>, #<Elk::Number ...>]
|
63
|
+
|
64
|
+
|
65
|
+
Elk::SMS.send(client: client, from: "MyService", to: "+46704508449", message: "Your order #171 has now been sent!")
|
66
|
+
# => #<Elk::SMS:0x0000010179d7e8 @client=... @from="MyService", @to="+46704508449", @message="Your order #171 has now been sent!", @message_id="sdc39a7926d37159b6985283e32f43251", @created_at=2011-07-17 16:21:13 +0200, @loaded_at=2011-07-17 16:21:13 +0200>
|
41
67
|
```
|
42
68
|
|
43
69
|
### Numbers
|
@@ -45,7 +71,7 @@ end
|
|
45
71
|
To be able to send and recieve messages, a number is needed. Several numbers can be allocated.
|
46
72
|
|
47
73
|
```Ruby
|
48
|
-
number = Elk::Number.allocate(:
|
74
|
+
number = Elk::Number.allocate(sms_url: "http://myservice.se/callback/newsms.php", country: "se")
|
49
75
|
# => #<Elk::Number:0x0000010282aa70 @country="se", @sms_url="http://myservice.se/callback/newsms.php", @status="yes", @number_id="n03e7db70cc06c1ff85e09a2b3f86dd62", @number="+46766861034", @capabilities=[:sms], @loaded_at=2011-07-17 15:23:55 +0200>
|
50
76
|
```
|
51
77
|
|
@@ -59,7 +85,7 @@ numbers = Elk::Number.all
|
|
59
85
|
Change number settings
|
60
86
|
|
61
87
|
```Ruby
|
62
|
-
number.sms_url =
|
88
|
+
number.sms_url = "http://myservice.se/callback/newsms.php"
|
63
89
|
number.save
|
64
90
|
# => true
|
65
91
|
```
|
@@ -79,7 +105,7 @@ number.status
|
|
79
105
|
Send SMS. Messages can be sent from one of the allocated numbers or an arbitrary alphanumeric string of at most 11 characters.
|
80
106
|
|
81
107
|
```Ruby
|
82
|
-
Elk::SMS.send(:
|
108
|
+
Elk::SMS.send(from: "MyService", to: "+46704508449", message: "Your order #171 has now been sent!")
|
83
109
|
# => #<Elk::SMS:0x0000010179d7e8 @from="MyService", @to="+46704508449", @message="Your order #171 has now been sent!", @message_id="sdc39a7926d37159b6985283e32f43251", @created_at=2011-07-17 16:21:13 +0200, @loaded_at=2011-07-17 16:21:13 +0200>
|
84
110
|
```
|
85
111
|
|
@@ -87,8 +113,8 @@ Receiving SMS does not require Elk, but should be of interest anyway.
|
|
87
113
|
Example with Sinatra:
|
88
114
|
|
89
115
|
```Ruby
|
90
|
-
post
|
91
|
-
if request.params[
|
116
|
+
post "/receive" do
|
117
|
+
if request.params["message"] == "Hello"
|
92
118
|
# Sends a return SMS with message "world!"
|
93
119
|
"world!"
|
94
120
|
end
|
@@ -104,4 +130,4 @@ Elk::SMS.all
|
|
104
130
|
|
105
131
|
## Copyright
|
106
132
|
|
107
|
-
Copyright (c) 2011 Johan Eckerström. See LICENSE for details.
|
133
|
+
Copyright (c) 2011 Johan Eckerström. See [MIT-LICENSE](MIT-LICENSE) for details.
|
data/lib/elk.rb
CHANGED
@@ -1,93 +1,49 @@
|
|
1
|
-
|
2
|
-
require 'multi_json'
|
3
|
-
require 'open-uri'
|
4
|
-
require 'rest_client'
|
5
|
-
require 'time'
|
1
|
+
require "forwardable"
|
6
2
|
|
7
3
|
# Base module
|
8
4
|
# Used for to configure username and password through Elk.configure
|
9
5
|
module Elk
|
10
|
-
# Base domain for 46elks API
|
11
|
-
BASE_DOMAIN = 'api.46elks.com'
|
12
|
-
# API version supported
|
13
|
-
API_VERSION = 'a1'
|
14
|
-
|
15
|
-
# When the authentication can't be done
|
16
|
-
class AuthError < RuntimeError; end
|
17
|
-
# Raised when the API server isn't working
|
18
|
-
class ServerError < RuntimeError; end
|
19
|
-
# Generic exception when 46elks API gives a response Elk can't parse
|
20
|
-
class BadResponse < RuntimeError; end
|
21
|
-
# Generic exception when Elk calls 46elk API the wrong way
|
22
|
-
class BadRequest < RuntimeError; end
|
23
|
-
# Raised when required paremeters are omitted
|
24
|
-
class MissingParameter < RuntimeError; end
|
25
|
-
|
26
6
|
class << self
|
27
|
-
|
28
|
-
|
29
|
-
#
|
30
|
-
|
31
|
-
|
32
|
-
|
7
|
+
extend Forwardable
|
8
|
+
|
9
|
+
# Delegate methods to client
|
10
|
+
delegated_methods = [
|
11
|
+
:username,
|
12
|
+
:username=,
|
13
|
+
:password,
|
14
|
+
:password=,
|
15
|
+
:base_domain,
|
16
|
+
:base_url,
|
17
|
+
:get,
|
18
|
+
:post,
|
19
|
+
:execute,
|
20
|
+
]
|
21
|
+
|
22
|
+
delegated_methods.each do |method|
|
23
|
+
def_delegator :client, method
|
24
|
+
end
|
33
25
|
|
34
26
|
# Set up authentication credentials, has to be done before using Elk::Number and Elk::SMS
|
35
27
|
#
|
36
28
|
# Elk.configure do |config|
|
37
|
-
# config.username =
|
38
|
-
# config.password =
|
29
|
+
# config.username = "USERNAME"
|
30
|
+
# config.password = "PASSWORD"
|
39
31
|
# end
|
40
32
|
def configure
|
41
|
-
yield
|
42
|
-
end
|
43
|
-
|
44
|
-
# Base URL used for calling 46elks API
|
45
|
-
def base_url
|
46
|
-
if not username or not password
|
47
|
-
raise AuthError, "API username and password required"
|
48
|
-
end
|
49
|
-
|
50
|
-
"https://#{username}:#{password}@#{(base_domain || BASE_DOMAIN)}/#{API_VERSION}"
|
51
|
-
end
|
52
|
-
|
53
|
-
# Wrapper for Elk.execute(:get)
|
54
|
-
def get(path, parameters = {})
|
55
|
-
execute(:get, path, parameters)
|
56
|
-
end
|
57
|
-
|
58
|
-
# Wrapper for Elk::execute(:post)
|
59
|
-
def post(path, parameters = {})
|
60
|
-
execute(:post, path, parameters)
|
61
|
-
end
|
62
|
-
|
63
|
-
# Wrapper around RestClient::RestClient.execute
|
64
|
-
#
|
65
|
-
# * Sets accept header to json
|
66
|
-
# * Handles some exceptions
|
67
|
-
#
|
68
|
-
def execute(method, path, parameters, headers={:accept => :json}, &block)
|
69
|
-
payload = {}.merge(parameters)
|
70
|
-
url = base_url + path
|
71
|
-
RestClient::Request.execute(:method => method, :url => url, :payload => payload, :headers => headers, &block)
|
72
|
-
rescue RestClient::Unauthorized
|
73
|
-
raise AuthError, "Authentication failed"
|
74
|
-
rescue RestClient::InternalServerError
|
75
|
-
raise ServerError, "Server error"
|
76
|
-
rescue RestClient::Forbidden => e
|
77
|
-
raise BadRequest, e.http_body
|
33
|
+
yield client
|
78
34
|
end
|
79
35
|
|
80
|
-
#
|
81
|
-
def
|
82
|
-
|
83
|
-
rescue MultiJson::DecodeError
|
84
|
-
raise BadResponse, "Can't parse JSON"
|
36
|
+
# Not thread safe
|
37
|
+
def client
|
38
|
+
@client ||= Client.new
|
85
39
|
end
|
86
40
|
end
|
87
41
|
end
|
88
42
|
|
89
43
|
# Internal
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
44
|
+
require_relative "elk/util"
|
45
|
+
require_relative "elk/error"
|
46
|
+
require_relative "elk/version"
|
47
|
+
require_relative "elk/client"
|
48
|
+
require_relative "elk/number"
|
49
|
+
require_relative "elk/sms"
|
data/lib/elk/client.rb
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
require "rest_client"
|
2
|
+
|
3
|
+
module Elk
|
4
|
+
class Client
|
5
|
+
# Base domain for 46elks API
|
6
|
+
BASE_DOMAIN = "api.46elks.com"
|
7
|
+
# API version supported
|
8
|
+
API_VERSION = "a1"
|
9
|
+
|
10
|
+
# API Username from 46elks.com
|
11
|
+
attr_accessor :username
|
12
|
+
# API Password from 46elks.com
|
13
|
+
attr_accessor :password
|
14
|
+
# Used to overrid Elk::BASE_DOMAIN (in tests)
|
15
|
+
attr_accessor :base_domain
|
16
|
+
|
17
|
+
def initialize(parameters = {})
|
18
|
+
@username = parameters[:username]
|
19
|
+
@password = parameters[:password]
|
20
|
+
end
|
21
|
+
|
22
|
+
# Set authentication credentials
|
23
|
+
#
|
24
|
+
# client = Elk::Client.new
|
25
|
+
# client.configure do |config|
|
26
|
+
# config.username = "USERNAME"
|
27
|
+
# config.password = "PASSWORD"
|
28
|
+
# end
|
29
|
+
def configure
|
30
|
+
yield self
|
31
|
+
end
|
32
|
+
|
33
|
+
# Base URL used for calling 46elks API
|
34
|
+
def base_url
|
35
|
+
unless username && password
|
36
|
+
raise AuthError, "API username and password required"
|
37
|
+
end
|
38
|
+
|
39
|
+
"https://#{username}:#{password}@#{(base_domain || BASE_DOMAIN)}/#{API_VERSION}"
|
40
|
+
end
|
41
|
+
|
42
|
+
# Wrapper for Elk.execute(:get)
|
43
|
+
def get(path, parameters = {})
|
44
|
+
execute(:get, path, parameters)
|
45
|
+
end
|
46
|
+
|
47
|
+
# Wrapper for Elk::execute(:post)
|
48
|
+
def post(path, parameters = {})
|
49
|
+
execute(:post, path, parameters)
|
50
|
+
end
|
51
|
+
|
52
|
+
# Wrapper around RestClient::RestClient.execute
|
53
|
+
#
|
54
|
+
# * Sets accept header to json
|
55
|
+
# * Handles some exceptions
|
56
|
+
#
|
57
|
+
def execute(method, path, parameters, headers = { accept: :json }, &block)
|
58
|
+
payload = {}.merge(parameters)
|
59
|
+
url = base_url + path
|
60
|
+
|
61
|
+
request_arguments = {
|
62
|
+
method: method,
|
63
|
+
url: url,
|
64
|
+
payload: payload,
|
65
|
+
headers: headers
|
66
|
+
}
|
67
|
+
|
68
|
+
RestClient::Request.execute(request_arguments, &block)
|
69
|
+
rescue RestClient::Unauthorized
|
70
|
+
raise AuthError, "Authentication failed"
|
71
|
+
rescue RestClient::InternalServerError
|
72
|
+
raise ServerError, "Server error"
|
73
|
+
rescue RestClient::Forbidden => e
|
74
|
+
raise BadRequest, e.http_body
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
data/lib/elk/error.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
module Elk
|
2
|
+
# When the authentication can't be done
|
3
|
+
class AuthError < RuntimeError; end
|
4
|
+
|
5
|
+
# Raised when the API server isn't working
|
6
|
+
class ServerError < RuntimeError; end
|
7
|
+
|
8
|
+
# Generic exception when 46elks API gives a response Elk can't parse
|
9
|
+
class BadResponse < RuntimeError; end
|
10
|
+
|
11
|
+
# Generic exception when Elk calls 46elk API the wrong way
|
12
|
+
class BadRequest < RuntimeError; end
|
13
|
+
|
14
|
+
# Raised when required paremeters are omitted
|
15
|
+
class MissingParameter < RuntimeError; end
|
16
|
+
end
|
data/lib/elk/number.rb
CHANGED
@@ -1,7 +1,9 @@
|
|
1
|
+
require "time"
|
2
|
+
|
1
3
|
module Elk
|
2
4
|
# Allocate and manage numbers used for SMS/MMS/Voice
|
3
5
|
class Number
|
4
|
-
attr_reader :number_id, :number, :capabilities, :loaded_at #:nodoc:
|
6
|
+
attr_reader :number_id, :number, :capabilities, :loaded_at, :client #:nodoc:
|
5
7
|
attr_accessor :country, :sms_url, :voice_start_url #:nodoc:
|
6
8
|
|
7
9
|
def initialize(parameters) #:nodoc:
|
@@ -15,16 +17,17 @@ module Elk
|
|
15
17
|
@status = parameters[:active]
|
16
18
|
@number_id = parameters[:id]
|
17
19
|
@number = parameters[:number]
|
18
|
-
@capabilities = parameters[:capabilities].
|
20
|
+
@capabilities = Array(parameters[:capabilities]).map(&:to_sym)
|
19
21
|
@loaded_at = Time.now
|
22
|
+
@client = parameters.fetch(:client) { Elk.client }
|
20
23
|
end
|
21
24
|
|
22
25
|
# Status of a number, if it's :active or :deallocated
|
23
26
|
def status
|
24
27
|
case @status
|
25
|
-
when
|
28
|
+
when "yes"
|
26
29
|
:active
|
27
|
-
when
|
30
|
+
when "no"
|
28
31
|
:deallocated
|
29
32
|
else
|
30
33
|
nil
|
@@ -33,26 +36,30 @@ module Elk
|
|
33
36
|
|
34
37
|
# Reloads a number from the API server
|
35
38
|
def reload
|
36
|
-
response =
|
37
|
-
self.set_paramaters(Elk.parse_json(response.body))
|
39
|
+
response = @client.get("/Numbers/#{self.number_id}")
|
40
|
+
self.set_paramaters(Elk::Util.parse_json(response.body))
|
38
41
|
response.code == 200
|
39
42
|
end
|
40
43
|
|
41
44
|
# Updates or allocates a number
|
42
45
|
def save
|
43
|
-
attributes = {
|
46
|
+
attributes = {
|
47
|
+
sms_url: self.sms_url,
|
48
|
+
voice_start: self.voice_start_url
|
49
|
+
}
|
50
|
+
|
44
51
|
# If new URL, send country, otherwise not
|
45
|
-
|
52
|
+
unless self.number_id
|
46
53
|
attributes[:country] = self.country
|
47
54
|
end
|
48
|
-
response =
|
55
|
+
response = @client.post("/Numbers/#{self.number_id}", attributes)
|
49
56
|
response.code == 200
|
50
57
|
end
|
51
58
|
|
52
59
|
# Deallocates a number, once allocated, a number cannot be used again, ever!
|
53
60
|
def deallocate!
|
54
|
-
response =
|
55
|
-
self.set_paramaters(Elk.parse_json(response.body))
|
61
|
+
response = @client.post("/Numbers/#{self.number_id}", { active: "no" })
|
62
|
+
self.set_paramaters(Elk::Util.parse_json(response.body))
|
56
63
|
response.code == 200
|
57
64
|
end
|
58
65
|
|
@@ -62,19 +69,36 @@ module Elk
|
|
62
69
|
# Allocates a phone number
|
63
70
|
#
|
64
71
|
# * Required parameters: :country
|
65
|
-
# * Optional parameters: :sms_url, :voice_start_url
|
72
|
+
# * Optional parameters: :sms_url, :voice_start_url, :client
|
66
73
|
def allocate(parameters)
|
67
74
|
verify_parameters(parameters, [:country])
|
68
|
-
|
69
|
-
|
75
|
+
|
76
|
+
client = parameters.fetch(:client) { Elk.client }
|
77
|
+
|
78
|
+
allowed_arguments = [:country, :sms_url, :voice_start_url]
|
79
|
+
arguments = parameters.dup.select do |key, _|
|
80
|
+
allowed_arguments.include?(key)
|
81
|
+
end
|
82
|
+
|
83
|
+
response = client.post('/Numbers', arguments)
|
84
|
+
self.new(Elk::Util.parse_json(response.body))
|
70
85
|
end
|
71
86
|
|
72
87
|
# Returns all Elk::Numbers, regardless of status (allocated/deallocated)
|
73
|
-
|
74
|
-
|
88
|
+
#
|
89
|
+
# Optional parameters
|
90
|
+
#
|
91
|
+
# * :client - Elk::Client instance
|
92
|
+
#
|
93
|
+
def all(parameters = {})
|
94
|
+
client = parameters.fetch(:client) { Elk.client }
|
95
|
+
|
96
|
+
response = client.get('/Numbers')
|
75
97
|
|
76
|
-
Elk.parse_json(response.body)
|
77
|
-
|
98
|
+
numbers = Elk::Util.parse_json(response.body).fetch(:data)
|
99
|
+
numbers.map do |number|
|
100
|
+
number[:client] = client
|
101
|
+
self.new(number)
|
78
102
|
end
|
79
103
|
end
|
80
104
|
end
|