essential 0.9.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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 7fef856a4598b665b03c68baaf34c34eb79a8d8d
4
+ data.tar.gz: 81c1e44539dfbe8b6dc59dd7f61165640247a2a7
5
+ SHA512:
6
+ metadata.gz: 2f81a83c772e1190736131d8c99444538b1451b2ce609625e4528474584e992eb78f9d2cb45ab0067ddedb15e3a8dafede902da1c3233cba1db48b0c3233d803
7
+ data.tar.gz: 061610d3b785a2d8ee7d9dffa12605b93c9da1a59c6401b6668a170f420c534727a2480e3519b175450272160a3fe47d4f3c9e057003213572a11e5cd37da373
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "http://www.rubygems.org"
2
+
3
+ gemspec
@@ -0,0 +1,35 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ essential (0.1.0)
5
+ rest-client (~> 1.8)
6
+
7
+ GEM
8
+ remote: http://www.rubygems.org/
9
+ specs:
10
+ domain_name (0.5.20160128)
11
+ unf (>= 0.0.5, < 1.0.0)
12
+ http-cookie (1.0.2)
13
+ domain_name (~> 0.5)
14
+ mime-types (2.99.1)
15
+ minitest (5.8.4)
16
+ netrc (0.11.0)
17
+ rake (10.5.0)
18
+ rest-client (1.8.0)
19
+ http-cookie (>= 1.0.2, < 2.0)
20
+ mime-types (>= 1.16, < 3.0)
21
+ netrc (~> 0.7)
22
+ unf (0.1.4)
23
+ unf_ext
24
+ unf_ext (0.0.7.2)
25
+
26
+ PLATFORMS
27
+ ruby
28
+
29
+ DEPENDENCIES
30
+ essential!
31
+ minitest (~> 5.8.4)
32
+ rake
33
+
34
+ BUNDLED WITH
35
+ 1.11.2
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License
2
+
3
+ Copyright (c) 2016- Essential Platform Services, Inc. (https://essential.to)
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,107 @@
1
+ # essential-ruby
2
+
3
+ ## Quick Start
4
+
5
+ ```ruby
6
+ require 'essential'
7
+
8
+ Essential.sid = ENV['ESSENTIAL_SID']
9
+ Essential.token = ENV['ESSENTIAL_TOKEN']
10
+
11
+ default_channel = Essential::Messaging::Channel.list.first
12
+
13
+ message = default_channel.messages.create(
14
+ subscriber: '2065551212',
15
+ body: "Hello there."
16
+ )
17
+ puts message.sid
18
+
19
+ ```
20
+
21
+ ## Usage
22
+
23
+ ### Initial Setup
24
+
25
+ ```ruby
26
+ require 'essential'
27
+ # Essential.api_base = 'http://127.0.0.1:3000'
28
+ Essential.sid = ENV['ESSENTIAL_SID']
29
+ Essential.token = ENV['ESSENTIAL_TOKEN']
30
+
31
+ ```
32
+
33
+ ### Account
34
+
35
+ ```ruby
36
+ account = Essential::Account.retrieve
37
+ ```
38
+
39
+ ### Channels
40
+
41
+ ```ruby
42
+ account.channels.map{|ch| {ch.sid => ch.name}}.reduce(&:merge)
43
+ # => {"ch_p03Gjl8Uzn0RkZSpHXHnrw"=>"default", "ch_QsbrYCSo2m0sShMLOlZqtw"=>"yradnoces"}
44
+ channel = Essential::Messaging::Channel.retrieve('ch_p03Gjl8Uzn0RkZSpHXHnrw')
45
+ channel.update(name: 'default', onreceived_url: 'http:/api.example.com/hook')
46
+ ```
47
+
48
+ ### Subscribers
49
+
50
+ ```ruby
51
+ channel = Essential::Messaging::Channel.list.first
52
+
53
+ # create a subscriber
54
+ subscriber = channel.subscribers.create(phone_number: '2065551212')
55
+ puts subscriber.sid
56
+ # => sub_WfnIr-f-7FBMFr4nVKkMdg
57
+
58
+ # unsubscribe
59
+ subscriber.unsubscribe
60
+
61
+ # re-subscribe
62
+ subscriber = channel.subscribers.create(phone_number: '2065551212')
63
+ puts subscriber.sid
64
+ # => sub_WfnIr-f-7FBMFr4nVKkMdg
65
+ ```
66
+
67
+ ### Messages
68
+
69
+ ```ruby
70
+ # This example magically finds the correct channel
71
+ # by either using an existing subscriber, or falling
72
+ # back on the channel named 'default'.
73
+ message = Essential::Messaging::Message.create(
74
+ subscriber: '2065551212',
75
+ body: 'magic channel'
76
+ )
77
+
78
+ # Here we specify a subscriber explicitly
79
+ message = Essential::Messaging::Message.create(
80
+ subscriber: 'sub_pDTv7LSV-R-AzL7oEpBfoQ',
81
+ body: 'subscriber by sid'
82
+ )
83
+
84
+ # Here we specify a channel
85
+ message = Essential::Messaging::Message.create(
86
+ subscriber: '2065551212',
87
+ channel: 'yradnoces',
88
+ body: 'explicit channel'
89
+ )
90
+ ```
91
+
92
+ ### Properties
93
+
94
+ ```ruby
95
+ subscriber = channel.subscribers.create(phone_number: '2065551212')
96
+
97
+ # set new properties
98
+ subscriber.properties.create(name: 'external_id', value: 1234)
99
+ subscriber.properties.create(name: 'name', value: 'Brendan Ribera')
100
+ subscriber.properties.create(name: 'state', value: 'WA')
101
+
102
+ # print them
103
+ puts JSON.pretty_generate(subscriber.properties.as_json)
104
+
105
+ # update one
106
+ subscriber.properties.create(name: 'name', value: 'Nabnerb Arebir')
107
+ ```
@@ -0,0 +1,9 @@
1
+ require 'rake/testtask'
2
+
3
+ task :default => [:test]
4
+
5
+ Rake::TestTask.new do |t|
6
+ t.libs << 'lib'
7
+ t.libs << 'test'
8
+ t.pattern = "test/**/*_test.rb"
9
+ end
@@ -0,0 +1,26 @@
1
+ $:.unshift(File.join(File.dirname(__FILE__), 'lib'))
2
+
3
+ require 'essential/version'
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = 'essential'
7
+ s.version = Essential::VERSION
8
+ s.date = '2016-04-06'
9
+ s.summary = 'Essential Ruby Library'
10
+ s.description = 'A GEM for interacting with the Essential.to service.'
11
+ s.authors = ['Brendan Ribera']
12
+ s.email = 'brendan@madronavl.com'
13
+ s.homepage = 'http://github.com/madrona-labs/essential-ruby'
14
+ s.license = 'MIT'
15
+
16
+ s.add_dependency('rest-client', '~> 1.8')
17
+
18
+ s.add_development_dependency('rake', '~> 10.5')
19
+ s.add_development_dependency('minitest', '~> 5.8')
20
+
21
+ s.files = `git ls-files`.split("\n")
22
+ s.test_files = `git ls-files -- test/*`.split("\n")
23
+ # s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
24
+
25
+ s.require_paths = ['lib']
26
+ end
@@ -0,0 +1,32 @@
1
+ require 'json'
2
+ require 'rest-client'
3
+ require 'set'
4
+ require 'uri'
5
+
6
+ require 'essential/version'
7
+ require 'essential/client'
8
+
9
+ # Resources
10
+ require 'essential/resource'
11
+ require 'essential/resource/paginator_proxy'
12
+
13
+ # Top-level Resources
14
+ require 'essential/account'
15
+
16
+ # Messaging Resources
17
+ require 'essential/messaging/message'
18
+ require 'essential/messaging/property'
19
+ require 'essential/messaging/transport'
20
+ require 'essential/messaging/subscriber'
21
+ require 'essential/messaging/channel'
22
+
23
+ module Essential
24
+ @api_base = 'https://api.essential.to'
25
+ @utc_offset = nil
26
+
27
+ class << self
28
+ attr_accessor :api_base, :sid, :token, :utc_offset
29
+ end
30
+
31
+ include Client
32
+ end
@@ -0,0 +1,56 @@
1
+ module Essential
2
+ class Account < Resource
3
+ include Essential::Resource::Update
4
+
5
+ attr_property :name, :token, :unsubscribed_send_raises, :created_at, :updated_at
6
+ attr_schema created_at: Time, updated_at: Time
7
+
8
+ def self.retrieve(opts={}, headers: {})
9
+ me = self.new(headers: headers)
10
+ me.fetch
11
+ me
12
+ end
13
+
14
+ def self.url
15
+ "/v2/account"
16
+ end
17
+
18
+ def self.api_status(params: {}, headers: @headers)
19
+ # permitted:
20
+ # :start_date, :end_date
21
+ resp = self.request(
22
+ :get,
23
+ url: '/v2/account/analytics/api_status',
24
+ params: params,
25
+ headers: headers
26
+ )
27
+ JSON.parse(resp)
28
+ end
29
+
30
+ def initialize(sid: nil, headers: nil)
31
+ sid ||= Essential.sid
32
+
33
+ super(sid: sid, headers: headers)
34
+ end
35
+
36
+ def url
37
+ self.class.url
38
+ end
39
+
40
+ def channels
41
+ Essential::Resource::PaginatorProxy.new(Essential::Messaging::Channel, headers: @headers)
42
+ end
43
+
44
+ def subscribers
45
+ Essential::Resource::PaginatorProxy.new(Essential::Messaging::Subscriber, headers: @headers)
46
+ end
47
+
48
+ def transports
49
+ Essential::Resource::PaginatorProxy.new(Essential::Messaging::Transport, headers: @headers)
50
+ end
51
+
52
+ def messages
53
+ Essential::Resource::PaginatorProxy.new(Essential::Messaging::Message, headers: @headers)
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,65 @@
1
+ require 'essential/errors/api_error'
2
+
3
+ module Essential
4
+ module Client
5
+ module ClassMethods
6
+ def request(method, url, sid: nil, token: nil, params: {}, headers: {})
7
+ # GET -> :get, etc
8
+ method = method.to_s.downcase.to_sym
9
+
10
+ sid ||= self.sid
11
+ token ||= self.token
12
+
13
+ uri = URI.join(self. api_base, url)
14
+
15
+ headers = {
16
+ 'Content-Type' => 'application/json',
17
+ 'Accept' => 'application/json',
18
+ 'User-Agent' => user_agent(),
19
+ }.merge(headers || {})
20
+
21
+ case method
22
+ when :get, :delete
23
+ uri.query = URI.encode_www_form(params) if params && params.any?
24
+ else
25
+ payload = params.to_json
26
+ end
27
+
28
+ opts = {
29
+ method: method,
30
+ url: uri.to_s,
31
+ user: sid,
32
+ password: token,
33
+ timeout: 10, # TODO config
34
+ open_timeout: 10, # TODO: config
35
+ headers: headers,
36
+ payload: payload
37
+ }
38
+
39
+ if $debug
40
+ puts format('%s %s', method.to_s.upcase, uri)
41
+ puts format('opts: %s', JSON.pretty_generate(opts))
42
+ end
43
+
44
+ begin
45
+ response = RestClient::Request.execute(opts)
46
+ rescue StandardError => e
47
+ raise Essential::APIError.from_exception(e)
48
+ end
49
+
50
+ response
51
+ end
52
+
53
+ protected
54
+
55
+ def user_agent
56
+ format('Essential Ruby (%s)', Essential::VERSION)
57
+ end
58
+ end
59
+
60
+ def self.included(base)
61
+ base.extend(ClassMethods)
62
+ end
63
+
64
+ end
65
+ end
@@ -0,0 +1,54 @@
1
+ module Essential
2
+ class APIError < StandardError
3
+ private_class_method :new
4
+
5
+ attr_reader :http_status, :body
6
+ attr_reader :type, :message, :code, :params
7
+
8
+ def self.from_exception(e)
9
+ case e
10
+ # when SocketError
11
+ # when NoMethodError
12
+ when RestClient::ExceptionWithResponse
13
+ new(
14
+ http_status: e.http_code,
15
+ body: e.http_body
16
+ )
17
+ when RestClient::Exception
18
+ new(http_status: e.http_code)
19
+ # when Errno::ECONNREFUSED
20
+ else
21
+ raise e
22
+ end
23
+ end
24
+
25
+ def initialize(http_status: nil, body: nil)
26
+ @http_status = http_status
27
+
28
+ if body
29
+ begin
30
+ @body = JSON.parse(body)
31
+ if @body.key?('error')
32
+ error = @body['error']
33
+ @type = error['type']
34
+ @message = error['message']
35
+ @code = error['code']
36
+ @params = error['params']
37
+ end
38
+ rescue JSON::ParserError
39
+ @body = body
40
+ end
41
+ end
42
+ end
43
+
44
+ def to_s
45
+ parts = []
46
+ parts << format('<%s>', self.http_status)
47
+ parts << self.type
48
+ parts << self.message if self.message
49
+ parts << self.params.to_json if self.params
50
+ parts.join(' - ')
51
+ end
52
+
53
+ end
54
+ end
@@ -0,0 +1,36 @@
1
+ module Essential::Messaging
2
+ class Channel < Essential::Resource
3
+ extend Essential::Resource::List
4
+ include Essential::Resource::Update
5
+
6
+ attr_property :name, :onreceived_url, :created_at, :updated_at
7
+ attr_schema created_at: Time, updated_at: Time
8
+
9
+ attr_relation account_sid: 'Essential::Account'
10
+
11
+ def transports
12
+ Essential::Resource::PaginatorProxy.new(
13
+ Transport,
14
+ params: {channel: self.sid},
15
+ headers: @headers
16
+ )
17
+ end
18
+
19
+ def subscribers
20
+ Essential::Resource::PaginatorProxy.new(
21
+ Subscriber,
22
+ params: {channel: self.sid},
23
+ headers: @headers
24
+ )
25
+ end
26
+
27
+ def messages
28
+ Essential::Resource::PaginatorProxy.new(
29
+ Message,
30
+ params: {channel: self.sid},
31
+ headers: @headers
32
+ )
33
+ end
34
+
35
+ end
36
+ end