xednese 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +2 -1
  3. data/README.md +22 -3
  4. data/Rakefile +8 -2
  5. data/bin/xednese +16 -0
  6. data/lib/xednese.rb +36 -9
  7. data/lib/xednese/account.rb +37 -0
  8. data/lib/xednese/account/dispatcher.rb +30 -0
  9. data/lib/xednese/account/messages.rb +47 -0
  10. data/lib/xednese/accounts.rb +14 -6
  11. data/lib/xednese/batch.rb +68 -0
  12. data/lib/xednese/batches.rb +33 -0
  13. data/lib/xednese/client.rb +46 -0
  14. data/lib/xednese/messages.rb +24 -0
  15. data/lib/xednese/requests/account.rb +17 -0
  16. data/lib/xednese/requests/batch.rb +17 -0
  17. data/lib/xednese/requests/messages.rb +1 -1
  18. data/lib/xednese/responses/batch.rb +20 -0
  19. data/lib/xednese/responses/batches.rb +15 -0
  20. data/lib/xednese/responses/status.rb +22 -0
  21. data/lib/xednese/users.rb +3 -8
  22. data/lib/xednese/version.rb +1 -1
  23. data/scenarios/accounts/getting_all_accounts.rb +37 -0
  24. data/scenarios/accounts/getting_an_account.rb +29 -0
  25. data/scenarios/helper.rb +113 -0
  26. data/spec/helper.rb +3 -3
  27. data/spec/xednese/{dispatcher_spec.rb → account/dispatcher_spec.rb} +5 -4
  28. data/spec/xednese/account/messages_spec.rb +56 -0
  29. data/spec/xednese/account_spec.rb +93 -0
  30. data/spec/xednese/accounts_spec.rb +19 -14
  31. data/spec/xednese/batch_spec.rb +121 -0
  32. data/spec/xednese/batches_spec.rb +70 -0
  33. data/spec/xednese/client_spec.rb +76 -2
  34. data/spec/xednese/messages_spec.rb +25 -1
  35. data/spec/xednese/requests/account_spec.rb +20 -0
  36. data/spec/xednese/requests/batch_spec.rb +20 -0
  37. data/spec/xednese/requests/messages_spec.rb +1 -1
  38. data/spec/xednese/responses/account_spec.rb +1 -1
  39. data/spec/xednese/responses/accounts_spec.rb +1 -1
  40. data/spec/xednese/responses/batch_spec.rb +83 -0
  41. data/spec/xednese/responses/batches_spec.rb +95 -0
  42. data/spec/xednese/responses/message_dispatcher_headers_spec.rb +1 -1
  43. data/spec/xednese/responses/message_header_spec.rb +1 -1
  44. data/spec/xednese/responses/message_headers_spec.rb +1 -1
  45. data/spec/xednese/responses/status_spec.rb +55 -0
  46. data/spec/xednese/users_spec.rb +1 -12
  47. data/spec/xednese_spec.rb +52 -12
  48. metadata +58 -8
  49. data/lib/xednese/dispatcher.rb +0 -20
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 381d98d8d9e52c8f4ad3136d50780e79eca43d75
4
- data.tar.gz: a3e8b964f56061bafe0ce6bc8401f92d3f557f58
3
+ metadata.gz: 847dade493b0ea06b341f02631f96df1fb5b9ba8
4
+ data.tar.gz: b5993ebab4f9baf48c75d71bf78599d8ad65dc27
5
5
  SHA512:
6
- metadata.gz: efb4d2396b366aa322791529f947d6b2409ea1c98323b8cbdb138dadc368f962c0b029a871e572ef6540d387a245891c771ddc833c842887f69c6876be73650f
7
- data.tar.gz: 87d1652e6ed3033da2e2ba1df223d3e82ed52b7259d3fefa73a97b98ca4bf0625ffa03e7a18eef58174452df8e989f5f7138be7caa24adc158bea47d4866d1df
6
+ metadata.gz: 3b92a2320ed4c2fe49c93df492ecdbb00b72fc483c82a6eaf2d6b569a1fbf43e6bd659443510d62ed18c29492b6c99bd8e390a86a98ec4da1caa8125d0cd8395
7
+ data.tar.gz: 5cb5ade70cee76dcb0d52074f75d52607490fb4b6ce4519972d790c1622d6a6677c0d2ab2c16c52defe5a29261323c7aad67cee9cf5abc4b96d3d593aaa07f72
data/Gemfile CHANGED
@@ -1,9 +1,10 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
3
  gem 'seq', '~> 0.2.0'
4
- gem 'serialisable', '~> 0.0.0'
4
+ gem 'serialisable', '~> 0.1.0'
5
5
  gem 'nokogiri', '~> 1.6'
6
6
 
7
7
  gem 'rake', '~> 10.1'
8
8
  gem 'minitest', '~> 5.2'
9
9
  gem 'mocha', '~> 1.0'
10
+ gem 'webmock', '~> 1.17'
data/README.md CHANGED
@@ -3,11 +3,30 @@
3
3
  ``` ruby
4
4
  require 'xednese'
5
5
 
6
- esendex = Esendex.new('me@company.com', 'password', 'account reference')
7
- p esendex.messages.sent.first.body
6
+ esendex = Esendex.new('me@company.com', 'password')
7
+ p esendex.messages.sent.first.summary
8
8
  #=> "..."
9
9
 
10
- response = esendex.dispatcher.send('Hey guys', '445275XXX')
10
+ account = esendex.account("EX0000")
11
+ response = account.dispatcher.send('Hey guys', '445275XXX')
11
12
  p response.message_headers.map(&:id)
12
13
  #=> ["..."]
13
14
  ```
15
+
16
+ Xednese is a client library for interacting with the
17
+ [Esendex REST API][exapi]. It is currently under active development and should
18
+ not be considered stable enough for general use.
19
+
20
+
21
+ ## Running locally
22
+
23
+ Clone the repo, then to get the run the tests:
24
+
25
+ ``` bash
26
+ $ gen install bundler
27
+ $ bundle install
28
+ $ bundle exec rake
29
+ ...
30
+ ```
31
+
32
+ [exapi]: developers.esendex.com/APIs/REST-API/
data/Rakefile CHANGED
@@ -1,9 +1,15 @@
1
1
  require 'rake/testtask'
2
2
 
3
- Rake::TestTask.new(:test) do |t|
3
+ Rake::TestTask.new(:spec) do |t|
4
4
  t.libs << 'lib' << 'spec'
5
5
  t.pattern = 'spec/**/*_spec.rb'
6
6
  t.verbose = true
7
7
  end
8
8
 
9
- task :default => :test
9
+ Rake::TestTask.new(:acceptance) do |t|
10
+ t.libs << 'lib' << 'scenarios'
11
+ t.pattern = 'scenarios/*/*.rb'
12
+ t.verbose = true
13
+ end
14
+
15
+ task :default => [:spec, :acceptance]
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'xednese'
4
+ require 'pry'
5
+
6
+ if ARGV.size != 2
7
+ abort "Usage: xednese <username> <password>"
8
+ end
9
+
10
+ esendex = Esendex.new(ARGV.first, ARGV.last)
11
+
12
+ puts <<EOS
13
+ xednese: Call methods on 'esendex'; CTRL-D to exit.
14
+ EOS
15
+
16
+ binding.pry quiet: true, prompt: Pry::SIMPLE_PROMPT
@@ -1,3 +1,4 @@
1
+ require 'forwardable'
1
2
  require 'net/http'
2
3
  require 'nokogiri'
3
4
  require 'seq/paged'
@@ -7,39 +8,65 @@ require 'time'
7
8
  require_relative 'xednese/version'
8
9
  require_relative 'xednese/client'
9
10
 
11
+ require_relative 'xednese/requests/account'
12
+ require_relative 'xednese/requests/batch'
10
13
  require_relative 'xednese/requests/messages'
11
14
 
12
15
  require_relative 'xednese/responses/parser'
13
16
  require_relative 'xednese/responses/account'
14
17
  require_relative 'xednese/responses/accounts'
18
+ require_relative 'xednese/responses/status'
19
+ require_relative 'xednese/responses/batch'
20
+ require_relative 'xednese/responses/batches'
15
21
  require_relative 'xednese/responses/message_dispatcher_headers'
16
22
  require_relative 'xednese/responses/message_header'
17
23
  require_relative 'xednese/responses/message_headers'
18
24
 
25
+ require_relative 'xednese/account'
19
26
  require_relative 'xednese/accounts'
20
- require_relative 'xednese/dispatcher'
27
+ require_relative 'xednese/batch'
28
+ require_relative 'xednese/batches'
21
29
  require_relative 'xednese/messages'
22
30
  require_relative 'xednese/users'
23
31
 
32
+ require_relative 'xednese/account/dispatcher'
33
+ require_relative 'xednese/account/messages'
34
+
24
35
  class Esendex
25
- Credentials = Struct.new(:username, :password, :account_reference)
36
+ Credentials = Struct.new(:username, :password)
26
37
 
27
- def initialize(username, password, account_reference)
28
- @credentials = Credentials.new(username, password, account_reference)
38
+ # @param username [String]
39
+ # @param password [String]
40
+ def initialize(username, password)
41
+ @credentials = Credentials.new(username, password)
29
42
  end
30
43
 
31
- def account
32
- Accounts.new(@credentials)
44
+ # @param reference [String]
45
+ # @return [Account]
46
+ # @see http://developers.esendex.com/APIs/REST-API/accounts
47
+ def account(reference)
48
+ accounts.find {|a| a.reference == reference }
33
49
  end
34
50
 
35
- def dispatcher
36
- Dispatcher.new(@credentials)
51
+ # @return [Accounts]
52
+ # @see http://developers.esendex.com/APIs/REST-API/accounts
53
+ def accounts
54
+ Accounts.new(@credentials)
37
55
  end
38
56
 
39
- def user
57
+ # @return [Users]
58
+ def users
40
59
  Users.new(@credentials)
41
60
  end
42
61
 
62
+ # @return [Batches]
63
+ # @see http://developers.esendex.com/APIs/REST-API/messagebatches
64
+ def batches
65
+ Batches.new(@credentials)
66
+ end
67
+
68
+ # @return [Messages]
69
+ # @see http://developers.esendex.com/APIs/REST-API/messageheaders
43
70
  def messages
44
71
  Messages.new(@credentials)
45
72
  end
@@ -0,0 +1,37 @@
1
+ class Esendex
2
+
3
+ class Account
4
+ def initialize(credentials, response)
5
+ @credentials = credentials
6
+ @response = response
7
+ end
8
+
9
+ # @return [Dispatcher]
10
+ # @see http://developers.esendex.com/APIs/REST-API/messagedispatcher
11
+ def dispatcher
12
+ Dispatcher.new(@credentials, reference)
13
+ end
14
+
15
+ # @return [Messages]
16
+ def messages
17
+ Messages.new(@credentials, reference)
18
+ end
19
+
20
+ extend Forwardable
21
+
22
+ def_delegators :@response, :id, :reference, :address, :type,
23
+ :messages_remaining, :expires_on, :role
24
+
25
+ def label
26
+ @label || @response.label
27
+ end
28
+
29
+ def label=(value)
30
+ request = Requests::Account.new(label: value)
31
+
32
+ Client.put(@credentials, "v1.0/accounts/#{id}", request) do |code, body|
33
+ @label = value
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,30 @@
1
+ class Esendex
2
+ class Account
3
+ class Dispatcher
4
+
5
+ # @see Esendex::Account#dispatcher
6
+ # @api private
7
+ def initialize(credentials, reference)
8
+ @credentials = credentials
9
+ @reference = reference
10
+ end
11
+
12
+ # Sends a message to a single recipient.
13
+ # @param body [String] the message body
14
+ # @param to [String] the number to send to
15
+ # @return [Responses::MessageDispatcherHeaders]
16
+ def send(body, to)
17
+ args = {
18
+ account_reference: @reference,
19
+ messages: [{to: to, body: body}]
20
+ }
21
+
22
+ messages = Requests::Messages.new(args)
23
+
24
+ Client.post(@credentials, 'v1.0/messagedispatcher', messages) do |code, body|
25
+ Responses::MessageDispatcherHeaders.deserialise(body)
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,47 @@
1
+ class Esendex
2
+ class Account
3
+ class Messages
4
+ PAGE_COUNT = 25
5
+
6
+ # @see Esendex::Account#messages
7
+ # @api private
8
+ def initialize(credentials, reference)
9
+ @credentials = credentials
10
+ @reference = reference
11
+ end
12
+
13
+ # @return [Enumerable<Responses::MessageHeader>] an Enumerable that
14
+ # iterates over all sent messages. Requests are made for fixed size
15
+ # pages when required.
16
+ def sent
17
+ Seq::Paged.new do |page|
18
+ params = {
19
+ startIndex: PAGE_COUNT * page,
20
+ count: PAGE_COUNT,
21
+ accountReference: @reference
22
+ }
23
+
24
+ Client.get(@credentials, 'v1.0/messageheaders', params) do |status, data|
25
+ Responses::MessageHeaders.deserialise(data).message_headers
26
+ end
27
+ end
28
+ end
29
+
30
+ # @return [Enumerable<Responses::MessageHeader>] an Enumerable that
31
+ # iterates over all received messages. Requests are made for fixed size
32
+ # pages when required.
33
+ def received
34
+ Seq::Paged.new do |page|
35
+ params = {
36
+ startIndex: PAGE_COUNT * page,
37
+ count: PAGE_COUNT
38
+ }
39
+
40
+ Client.get(@credentials, "v1.0/inbox/#{@reference}/messages", params) do |status, data|
41
+ Responses::MessageHeaders.deserialise(data).message_headers
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -1,24 +1,32 @@
1
1
  class Esendex
2
+
3
+ # Provides methods for working with Accounts. An Accounts instance is an
4
+ # Enumerable, and will only make requests when needed.
2
5
  class Accounts
6
+
7
+ # @see Esendex#accounts
8
+ # @api private
3
9
  def initialize(credentials)
4
10
  @credentials = credentials
5
11
  end
6
12
 
7
- def reference
8
- @credentials.account_reference
9
- end
10
-
13
+ # @yield [Account] Calls the provided block with each account the user has
14
+ # access to
11
15
  def each(&block)
12
16
  Client.get(@credentials, 'v1.0/accounts') {|status, data|
13
- Responses::Accounts.deserialise(data).accounts
17
+ Responses::Accounts.deserialise(data).accounts.map do |account|
18
+ Account.new(@credentials, account)
19
+ end
14
20
  }.each(&block)
15
21
  end
16
22
 
17
23
  include Enumerable
18
24
 
25
+ # @param id [String] the id of the account to return
26
+ # @return [Account] Returns the account with the given id.
19
27
  def get(id)
20
28
  Client.get(@credentials, "v1.0/accounts/#{id}") do |status, data|
21
- Responses::Account.deserialise(data)
29
+ Account.new @credentials, Responses::Account.deserialise(data)
22
30
  end
23
31
  end
24
32
  end
@@ -0,0 +1,68 @@
1
+ class Esendex
2
+ class Batch
3
+ PAGE_COUNT = 25
4
+
5
+ # @see Esendex#batches
6
+ # @api private
7
+ def initialize(credentials, response)
8
+ @credentials = credentials
9
+ @response = response
10
+ end
11
+
12
+ extend Forwardable
13
+
14
+ def_delegators :@response, :id, :created_at, :batch_size,
15
+ :persisted_batch_size, :account_reference, :created_by
16
+
17
+ def status
18
+ s = @response.status
19
+
20
+ [:acknowledged,
21
+ :authorisation_failed,
22
+ :connecting,
23
+ :delivered,
24
+ :failed,
25
+ :partially_delivered,
26
+ :rejected,
27
+ :scheduled,
28
+ :sent,
29
+ :submitted,
30
+ :validity_period_expired,
31
+ :cancelled].find do |type|
32
+ s.send(type) == 1
33
+ end
34
+ end
35
+
36
+ def name
37
+ @name || @response.name
38
+ end
39
+
40
+ def name=(value)
41
+ request = Requests::Batch.new(name: value)
42
+
43
+ Client.put(@credentials, "v1.1/messagebatches/#{id}", request) do |status, data|
44
+ @name = value
45
+ end
46
+ end
47
+
48
+ def cancel!
49
+ Client.delete(@credentials, "v1.1/messagebatches/#{id}/schedule")
50
+ end
51
+
52
+ # @return [Enumerable<Responses::MessageHeader>] an Enumerable that iterates
53
+ # over all messages in the batch. Requests are made for fixed size pages
54
+ # when required.
55
+ def messages
56
+ Seq::Paged.new do |page|
57
+ params = {
58
+ startIndex: PAGE_COUNT * page,
59
+ count: PAGE_COUNT
60
+ }
61
+
62
+ Client.get(@credentials, "v1.0/messagebatches/#{id}/messages", params) do |status, data|
63
+ Responses::MessageHeaders.deserialise(data).message_headers
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,33 @@
1
+ class Esendex
2
+
3
+ # Provides methods for working with message batches. A Batches instance is
4
+ # Enumerable, and will only make requests when needed.
5
+ class Batches
6
+
7
+ # @see Esendex#batches
8
+ # @api private
9
+ def initialize(credentials)
10
+ @credentials = credentials
11
+ end
12
+
13
+ # @yield [Batch] Calls the provided block with each batch the user has
14
+ # access to
15
+ def each(&block)
16
+ Client.get(@credentials, 'v1.1/messagebatches') {|status, data|
17
+ Responses::Batches.deserialise(data).batches.map do |batch|
18
+ Batch.new(@credentials, batch)
19
+ end
20
+ }.each(&block)
21
+ end
22
+
23
+ include Enumerable
24
+
25
+ # @param id [String] the id of the batch to return
26
+ # @return [Batch] Returns the batch with the given id.
27
+ def get(id)
28
+ Client.get(@credentials, "v1.1/messagebatches/#{id}") do |status, data|
29
+ Batch.new @credentials, Responses::Batch.deserialise(data)
30
+ end
31
+ end
32
+ end
33
+ end
@@ -1,9 +1,18 @@
1
1
  class Esendex
2
+
3
+ # Client is a wrapper for Net::HTTP for calling through to the Esendex REST
4
+ # API.
2
5
  class Client
3
6
  ROOT = URI('https://api.esendex.com/')
4
7
  USER_AGENT = "ruby/xednese-#{VERSION}"
5
8
  CONTENT_TYPE = "application/xml"
6
9
 
10
+ # @param credentials [Credentials]
11
+ # @param path [String] Path to GET (after the api.esendex.com/ part)
12
+ # @param args [Hash] An optional hash of query parameters to be appended to
13
+ # the url.
14
+ #
15
+ # @return [Integer, String] Returns the status code and the response body.
7
16
  def self.get(credentials, path, args={})
8
17
  uri = url(path)
9
18
  uri.query = URI.encode_www_form(args)
@@ -14,6 +23,26 @@ class Esendex
14
23
  block_given? ? yield(code, body) : [code, body]
15
24
  end
16
25
 
26
+ # @param credentials [Credentials]
27
+ # @param path [String] Path to DELETE
28
+ #
29
+ # @return [Integer, String] Returns the status code and the response body.
30
+ def self.delete(credentials, path)
31
+ uri = url(path)
32
+ request = Net::HTTP::Delete.new(uri)
33
+
34
+ code, body = execute(credentials, request)
35
+
36
+ block_given? ? yield(code, body) : [code, body]
37
+ end
38
+
39
+ # @param credentials [Credentials]
40
+ # @param path [String] Path to POST to
41
+ # @param object [#serialise] The object that represents the content to be
42
+ # posted. This must be an object with a method #serialise that returns a
43
+ # string of xml.
44
+ #
45
+ # @return [Integer, String] Returns the status code and the response body.
17
46
  def self.post(credentials, path, object)
18
47
  request = Net::HTTP::Post.new(url(path))
19
48
  request.body = object.serialise
@@ -24,6 +53,23 @@ class Esendex
24
53
  block_given? ? yield(code, body) : [code, body]
25
54
  end
26
55
 
56
+ # @param credentials [Credentials]
57
+ # @param path [String] Path to PUT to
58
+ # @param object [#serialise] The object that represents the content to be
59
+ # posted. This must be an object with a method #serialise that returns a
60
+ # string of xml.
61
+ #
62
+ # @return [Integer, String] Returns the status code and the response body.
63
+ def self.put(credentials, path, object)
64
+ request = Net::HTTP::Put.new(url(path))
65
+ request.body = object.serialise
66
+ request.content_type = CONTENT_TYPE
67
+
68
+ code, body = execute(credentials, request)
69
+
70
+ block_given? ? yield(code, body) : [code, body]
71
+ end
72
+
27
73
  private
28
74
 
29
75
  def self.url(path)