portatext 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 50ede6f538968f483c1cbb537ac84e9f88745f41
4
+ data.tar.gz: a24b867a6f1d19153295d2882b4c3f9ef5751bad
5
+ SHA512:
6
+ metadata.gz: 2a0dda3ef83a228e9d14ca5a906b6ad1c4a5f9ca33bede9aa88512579af405aca5f11b3b95a99e47dd2a909e1513cd6960778f4628fc8a578bb73a082eb7b831
7
+ data.tar.gz: 77ccb360a42737f6c13a46ef897c4f4cb5b54182cb14dfdcaae064c2e00b9aed9e0f1780cad64a5975402a2db7fef7e3d5684d3438b151e2e90586bc13f349ab
data/.codeclimate.yml ADDED
@@ -0,0 +1,25 @@
1
+ ---
2
+ engines:
3
+ bundler-audit:
4
+ enabled: false
5
+ duplication:
6
+ enabled: true
7
+ config:
8
+ languages:
9
+ - ruby
10
+ fixme:
11
+ enabled: false
12
+ rubocop:
13
+ enabled: true
14
+ ratings:
15
+ paths:
16
+ - Gemfile.lock
17
+ - "**.inc"
18
+ - "**.js"
19
+ - "**.jsx"
20
+ - "**.module"
21
+ - "**.php"
22
+ - "**.py"
23
+ - "**.rb"
24
+ exclude_paths:
25
+ - test/**/*
data/.gitignore ADDED
@@ -0,0 +1,3 @@
1
+ Gemfile.lock
2
+ coverage
3
+ *.gem
data/.rubocop.yml ADDED
@@ -0,0 +1,7 @@
1
+ AllCops:
2
+ Include:
3
+ - '**/Rakefile'
4
+ - 'src/**/*'
5
+ Exclude:
6
+ - 'test/**/*'
7
+
data/.travis.yml ADDED
@@ -0,0 +1,9 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.0.0
4
+ - 2.1.0
5
+ - 2.2.0
6
+ before_install: gem install bundler -v 1.10.6
7
+ addons:
8
+ code_climate:
9
+ repo_token: 2949b385b49f033864d017ee2a530cb3a1ff12b332be2433fb16abe4b794425e
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,178 @@
1
+
2
+ Apache License
3
+ Version 2.0, January 2004
4
+ http://www.apache.org/licenses/
5
+
6
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7
+
8
+ 1. Definitions.
9
+
10
+ "License" shall mean the terms and conditions for use, reproduction,
11
+ and distribution as defined by Sections 1 through 9 of this document.
12
+
13
+ "Licensor" shall mean the copyright owner or entity authorized by
14
+ the copyright owner that is granting the License.
15
+
16
+ "Legal Entity" shall mean the union of the acting entity and all
17
+ other entities that control, are controlled by, or are under common
18
+ control with that entity. For the purposes of this definition,
19
+ "control" means (i) the power, direct or indirect, to cause the
20
+ direction or management of such entity, whether by contract or
21
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
22
+ outstanding shares, or (iii) beneficial ownership of such entity.
23
+
24
+ "You" (or "Your") shall mean an individual or Legal Entity
25
+ exercising permissions granted by this License.
26
+
27
+ "Source" form shall mean the preferred form for making modifications,
28
+ including but not limited to software source code, documentation
29
+ source, and configuration files.
30
+
31
+ "Object" form shall mean any form resulting from mechanical
32
+ transformation or translation of a Source form, including but
33
+ not limited to compiled object code, generated documentation,
34
+ and conversions to other media types.
35
+
36
+ "Work" shall mean the work of authorship, whether in Source or
37
+ Object form, made available under the License, as indicated by a
38
+ copyright notice that is included in or attached to the work
39
+ (an example is provided in the Appendix below).
40
+
41
+ "Derivative Works" shall mean any work, whether in Source or Object
42
+ form, that is based on (or derived from) the Work and for which the
43
+ editorial revisions, annotations, elaborations, or other modifications
44
+ represent, as a whole, an original work of authorship. For the purposes
45
+ of this License, Derivative Works shall not include works that remain
46
+ separable from, or merely link (or bind by name) to the interfaces of,
47
+ the Work and Derivative Works thereof.
48
+
49
+ "Contribution" shall mean any work of authorship, including
50
+ the original version of the Work and any modifications or additions
51
+ to that Work or Derivative Works thereof, that is intentionally
52
+ submitted to Licensor for inclusion in the Work by the copyright owner
53
+ or by an individual or Legal Entity authorized to submit on behalf of
54
+ the copyright owner. For the purposes of this definition, "submitted"
55
+ means any form of electronic, verbal, or written communication sent
56
+ to the Licensor or its representatives, including but not limited to
57
+ communication on electronic mailing lists, source code control systems,
58
+ and issue tracking systems that are managed by, or on behalf of, the
59
+ Licensor for the purpose of discussing and improving the Work, but
60
+ excluding communication that is conspicuously marked or otherwise
61
+ designated in writing by the copyright owner as "Not a Contribution."
62
+
63
+ "Contributor" shall mean Licensor and any individual or Legal Entity
64
+ on behalf of whom a Contribution has been received by Licensor and
65
+ subsequently incorporated within the Work.
66
+
67
+ 2. Grant of Copyright License. Subject to the terms and conditions of
68
+ this License, each Contributor hereby grants to You a perpetual,
69
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70
+ copyright license to reproduce, prepare Derivative Works of,
71
+ publicly display, publicly perform, sublicense, and distribute the
72
+ Work and such Derivative Works in Source or Object form.
73
+
74
+ 3. Grant of Patent License. Subject to the terms and conditions of
75
+ this License, each Contributor hereby grants to You a perpetual,
76
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77
+ (except as stated in this section) patent license to make, have made,
78
+ use, offer to sell, sell, import, and otherwise transfer the Work,
79
+ where such license applies only to those patent claims licensable
80
+ by such Contributor that are necessarily infringed by their
81
+ Contribution(s) alone or by combination of their Contribution(s)
82
+ with the Work to which such Contribution(s) was submitted. If You
83
+ institute patent litigation against any entity (including a
84
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
85
+ or a Contribution incorporated within the Work constitutes direct
86
+ or contributory patent infringement, then any patent licenses
87
+ granted to You under this License for that Work shall terminate
88
+ as of the date such litigation is filed.
89
+
90
+ 4. Redistribution. You may reproduce and distribute copies of the
91
+ Work or Derivative Works thereof in any medium, with or without
92
+ modifications, and in Source or Object form, provided that You
93
+ meet the following conditions:
94
+
95
+ (a) You must give any other recipients of the Work or
96
+ Derivative Works a copy of this License; and
97
+
98
+ (b) You must cause any modified files to carry prominent notices
99
+ stating that You changed the files; and
100
+
101
+ (c) You must retain, in the Source form of any Derivative Works
102
+ that You distribute, all copyright, patent, trademark, and
103
+ attribution notices from the Source form of the Work,
104
+ excluding those notices that do not pertain to any part of
105
+ the Derivative Works; and
106
+
107
+ (d) If the Work includes a "NOTICE" text file as part of its
108
+ distribution, then any Derivative Works that You distribute must
109
+ include a readable copy of the attribution notices contained
110
+ within such NOTICE file, excluding those notices that do not
111
+ pertain to any part of the Derivative Works, in at least one
112
+ of the following places: within a NOTICE text file distributed
113
+ as part of the Derivative Works; within the Source form or
114
+ documentation, if provided along with the Derivative Works; or,
115
+ within a display generated by the Derivative Works, if and
116
+ wherever such third-party notices normally appear. The contents
117
+ of the NOTICE file are for informational purposes only and
118
+ do not modify the License. You may add Your own attribution
119
+ notices within Derivative Works that You distribute, alongside
120
+ or as an addendum to the NOTICE text from the Work, provided
121
+ that such additional attribution notices cannot be construed
122
+ as modifying the License.
123
+
124
+ You may add Your own copyright statement to Your modifications and
125
+ may provide additional or different license terms and conditions
126
+ for use, reproduction, or distribution of Your modifications, or
127
+ for any such Derivative Works as a whole, provided Your use,
128
+ reproduction, and distribution of the Work otherwise complies with
129
+ the conditions stated in this License.
130
+
131
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
132
+ any Contribution intentionally submitted for inclusion in the Work
133
+ by You to the Licensor shall be under the terms and conditions of
134
+ this License, without any additional terms or conditions.
135
+ Notwithstanding the above, nothing herein shall supersede or modify
136
+ the terms of any separate license agreement you may have executed
137
+ with Licensor regarding such Contributions.
138
+
139
+ 6. Trademarks. This License does not grant permission to use the trade
140
+ names, trademarks, service marks, or product names of the Licensor,
141
+ except as required for reasonable and customary use in describing the
142
+ origin of the Work and reproducing the content of the NOTICE file.
143
+
144
+ 7. Disclaimer of Warranty. Unless required by applicable law or
145
+ agreed to in writing, Licensor provides the Work (and each
146
+ Contributor provides its Contributions) on an "AS IS" BASIS,
147
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148
+ implied, including, without limitation, any warranties or conditions
149
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150
+ PARTICULAR PURPOSE. You are solely responsible for determining the
151
+ appropriateness of using or redistributing the Work and assume any
152
+ risks associated with Your exercise of permissions under this License.
153
+
154
+ 8. Limitation of Liability. In no event and under no legal theory,
155
+ whether in tort (including negligence), contract, or otherwise,
156
+ unless required by applicable law (such as deliberate and grossly
157
+ negligent acts) or agreed to in writing, shall any Contributor be
158
+ liable to You for damages, including any direct, indirect, special,
159
+ incidental, or consequential damages of any character arising as a
160
+ result of this License or out of the use or inability to use the
161
+ Work (including but not limited to damages for loss of goodwill,
162
+ work stoppage, computer failure or malfunction, or any and all
163
+ other commercial damages or losses), even if such Contributor
164
+ has been advised of the possibility of such damages.
165
+
166
+ 9. Accepting Warranty or Additional Liability. While redistributing
167
+ the Work or Derivative Works thereof, You may choose to offer,
168
+ and charge a fee for, acceptance of support, warranty, indemnity,
169
+ or other liability obligations and/or rights consistent with this
170
+ License. However, in accepting such obligations, You may act only
171
+ on Your own behalf and on Your sole responsibility, not on behalf
172
+ of any other Contributor, and only if You agree to indemnify,
173
+ defend, and hold each Contributor harmless for any liability
174
+ incurred by, or claims asserted against, such Contributor by reason
175
+ of your accepting any such warranty or additional liability.
176
+
177
+ END OF TERMS AND CONDITIONS
178
+
data/README.md ADDED
@@ -0,0 +1,150 @@
1
+ [![License](http://img.shields.io/badge/license-APACHE2-blue.svg)](http://img.shields.io/badge/license-APACHE2-blue.svg)
2
+ [![Gem Version](https://badge.fury.io/rb/portatext.svg)](https://badge.fury.io/rb/portatext)
3
+ [![Yard Docs](http://img.shields.io/badge/yard-docs-blue.svg)](http://rubydoc.info/github/portatext/ruby-sdk/master/frames)
4
+
5
+ [![Build Status](https://travis-ci.org/PortaText/ruby-sdk.svg)](https://travis-ci.org/PortaText/ruby-sdk)
6
+ [![Coverage Status](https://coveralls.io/repos/PortaText/ruby-sdk/badge.svg?branch=master&service=github)](https://coveralls.io/github/PortaText/ruby-sdk?branch=master)
7
+ [![Code Climate](https://codeclimate.com/github/PortaText/ruby-sdk/badges/gpa.svg)](https://codeclimate.com/github/PortaText/ruby-sdk)
8
+ [![Issue Count](https://codeclimate.com/github/PortaText/ruby-sdk/badges/issue_count.svg)](https://codeclimate.com/github/PortaText/ruby-sdk)
9
+ [![Inline docs](http://inch-ci.org/github/portatext/ruby-sdk.svg?branch=master)](http://inch-ci.org/github/portatext/ruby-sdk)
10
+ [![Yard Docs](http://img.shields.io/badge/yard-docs-blue.svg)](http://rubydoc.info/github/remote-exec/command-designer/master/frames)
11
+ # ruby-sdk
12
+ Official Ruby Client for the [PortaText](https://www.portatext.com/) API.
13
+
14
+ # Documentation
15
+
16
+ * The [endpoint tests](https://github.com/PortaText/ruby-sdk/tree/master/test/endpoints) should also serve as good doucmentation on how to use the API.
17
+ * General PortaText documentation (including the REST API) can be found at the [PortaText wiki](https://github.com/PortaText/docs/wiki).
18
+
19
+ # Installing
20
+ Add this library to your [Gemfile](http://bundler.io/gemfile.html).
21
+ ```ruby
22
+ gem 'portatext'
23
+ ```
24
+
25
+ # Basic use
26
+
27
+ ## Getting a client instance
28
+ The first thing is to get a [Client](https://github.com/PortaText/ruby-sdk/blob/master/lib/portatext/client/base_client.rb) instance, for example
29
+ the [Net::HTTP](https://github.com/PortaText/ruby-sdk/blob/master/lib/portatext/client/http_client.rb) implementation:
30
+
31
+ ```ruby
32
+ require 'portatext'
33
+ client = PortaText::Client::HttpClient.new
34
+ ```
35
+
36
+ ## (Optional) Set your logger
37
+ You can optionally set a [Logger](http://ruby-doc.org/stdlib-2.2.0/libdoc/logger/rdoc/Logger.html) compatible logger:
38
+ ```ruby
39
+ client.logger = my_logger
40
+ ```
41
+
42
+ By default, the client will use a logger pointing to `/dev/null`
43
+
44
+ ## Authenticating
45
+ You can authenticate to the endpoints by using your [API key](https://github.com/PortaText/docs/wiki/REST-API#auth_api) or your username/password. This translates to
46
+ either doing this:
47
+
48
+ ```ruby
49
+ client.api_key = api_key
50
+ ```
51
+
52
+ Or this:
53
+
54
+ ```ruby
55
+ client.credentials = [username, password]
56
+ ```
57
+
58
+ When you specify a [username and password](https://github.com/PortaText/docs/wiki/REST-API#auth_basic) instead of an api key, the sdk will
59
+ automatically login and get a [session token](https://github.com/PortaText/docs/wiki/REST-API#auth_session) when needed.
60
+
61
+ # Using the endpoints
62
+ All the API commands can be found in the [command/api](https://github.com/PortaText/ruby-sdk/tree/master/lib/portatext/command/api)
63
+ directory. The client offers a way to instantiate them by just calling them by their name.
64
+
65
+ ## Quick example
66
+ As an example, to create a template, you would do:
67
+
68
+ ```ruby
69
+ result = client
70
+ .templates # Get an instance of the Templates endpoint.
71
+ .text('The text of my template')
72
+ .description('My first template')
73
+ .name('template1')
74
+ .post # Call the Templates endpoint with a POST.
75
+ ```
76
+
77
+ To get a template by id:
78
+
79
+ ```ruby
80
+ result = client.templates.id(45).get
81
+ ```
82
+
83
+ Or, to get all the templates:
84
+
85
+ ```ruby
86
+ result = client.templates.get
87
+ ```
88
+
89
+ ## The result
90
+ After calling an endpoint, one of two things can happen:
91
+ * A [PortaText Exception](https://github.com/PortaText/ruby-sdk/tree/master/lib/portatext/exception) is raised.
92
+ * A [Result](https://github.com/PortaText/ruby-sdk/blob/master/lib/portatext/command/result.rb) instance is returned.
93
+
94
+ Also, when possible, your PortaText exception will contain a `Result` object that
95
+ can be retrieved by using the `result` accessor on the exception. This is usually useful for the
96
+ [ClientError](https://github.com/PortaText/ruby-sdk/blob/master/lib/portatext/exception/client_error.rb) exception, where
97
+ you will be able to see if a field was missing or different than what was expected.
98
+
99
+ ### Testing for success
100
+ ```ruby
101
+ if result.success?
102
+ ...
103
+ end
104
+ ```
105
+
106
+ ### Getting error strings back from the server
107
+ ```ruby
108
+ if !result.errors.nil?
109
+ result.errors.each do |e|
110
+ puts e
111
+ end
112
+ end
113
+ ```
114
+
115
+ ### Getting data back from the server
116
+ ```ruby
117
+ if result.success
118
+ data = result.data
119
+ end
120
+ ```
121
+
122
+ # Developers
123
+ This project uses [rake](https://github.com/ruby/rake). Current tasks include:
124
+ * test: Runs [MiniTest](https://github.com/seattlerb/minitest)s.
125
+ * rubocop: Runs [RuboCop](https://github.com/bbatsov/rubocop).
126
+ * default: This is the default task, and will run all the other tasks.
127
+
128
+ ## Running a rake task
129
+ To run a task, just do:
130
+
131
+ ```sh
132
+ rake test
133
+ ```
134
+
135
+ ## Contributing
136
+ To contribute:
137
+ * Make sure you open a **concise** and **short** pull request.
138
+ * Throw in any needed unit tests to accomodate the new code or the
139
+ changes involved.
140
+ * Run `rake` and make sure everything is ok before submitting the pull
141
+ request (make rubocop happy).
142
+ * Your code must comply with [the GitHub ruby style](https://github.com/styleguide/ruby).
143
+ * If your code is accepted, it will belong to PortaText and will be published
144
+ under the Apache2 License.
145
+
146
+ # License
147
+ The source code is released under Apache 2 License.
148
+
149
+ Check [LICENSE](https://github.com/PortaText/ruby-sdk/blob/master/LICENSE) file for more information.
150
+
data/Rakefile ADDED
@@ -0,0 +1,13 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rake/testtask'
3
+ require 'rubocop/rake_task'
4
+
5
+ RuboCop::RakeTask.new
6
+
7
+ Rake::TestTask.new(:test) do |t|
8
+ t.libs << 'test'
9
+ t.libs << 'lib'
10
+ t.test_files = FileList['test/**/*_test.rb']
11
+ end
12
+
13
+ task default: [:rubocop, :test]
@@ -0,0 +1,114 @@
1
+ require 'logger'
2
+ require 'base64'
3
+
4
+ module PortaText
5
+ module Client
6
+ # A generic PortaText client.
7
+ #
8
+ # Author:: Marcelo Gornstein (mailto:marcelog@portatext.com)
9
+ # Copyright:: Copyright (c) 2015 PortaText
10
+ # License:: Apache-2.0
11
+ class BaseClient
12
+ attr_writer :endpoint
13
+ attr_writer :api_key
14
+ attr_writer :credentials
15
+ attr_writer :executor
16
+ attr_writer :logger
17
+
18
+ def method_missing(method, *_arguments, &_block)
19
+ method = method.to_s.split('_').map(&:capitalize)
20
+ name = "PortaText::Command::Api::#{method.join('')}"
21
+ class_name = Object.const_get name
22
+ class_name.new self
23
+ end
24
+
25
+ # rubocop:disable Metrics/MethodLength
26
+ # rubocop:disable Metrics/AbcSize
27
+ def run(endpoint, method, content_type, body, auth = nil)
28
+ true_endpoint = "#{@endpoint}/#{endpoint}"
29
+ auth ||= auth_method(auth)
30
+ headers = form_headers content_type, auth
31
+ @logger.debug "Calling #{method} #{true_endpoint} with #{auth}"
32
+ descriptor = PortaText::Command::Descriptor.new(
33
+ true_endpoint, method, headers, body
34
+ )
35
+ ret_code, ret_headers, ret_body = @executor.execute descriptor
36
+ result = PortaText::Command::Result.new(
37
+ ret_code, ret_headers, JSON.parse(ret_body)
38
+ )
39
+ if ret_code.eql?(401) && auth.eql?(:session_token)
40
+ login!
41
+ result = run endpoint, method, content_type, body
42
+ end
43
+ assert_result descriptor, result
44
+ end
45
+ # rubocop:enable Metrics/MethodLength
46
+ # rubocop:enable Metrics/AbcSize
47
+
48
+ def initialize
49
+ @logger = Logger.new nil
50
+ @endpoint = DEFAULT_ENDPOINT
51
+ @api_key = nil
52
+ @credentials = nil
53
+ @session_token = nil
54
+ @executor = self
55
+ end
56
+
57
+ private
58
+
59
+ def login!
60
+ result = run 'login', :post, 'application/json', '', :basic
61
+ @session_token = result.data['token']
62
+ end
63
+
64
+ def assert_result(descriptor, result)
65
+ error = error_for result.code
66
+ return result if error.nil?
67
+ fail error, [descriptor, result]
68
+ end
69
+
70
+ def auth_method(auth_suggested)
71
+ return auth_suggested unless auth_suggested.nil?
72
+ return :session_token unless @session_token.nil?
73
+ return :api_key unless @api_key.nil?
74
+ login!
75
+ :session_token
76
+ end
77
+
78
+ # rubocop:disable Metrics/MethodLength
79
+ def error_for(code)
80
+ errors = {
81
+ 400 => PortaText::Exception::ClientError,
82
+ 401 => PortaText::Exception::InvalidCredentials,
83
+ 402 => PortaText::Exception::PaymentRequired,
84
+ 403 => PortaText::Exception::Forbidden,
85
+ 404 => PortaText::Exception::NotFound,
86
+ 405 => PortaText::Exception::InvalidMethod,
87
+ 415 => PortaText::Exception::InvalidMedia,
88
+ 429 => PortaText::Exception::RateLimited,
89
+ 500 => PortaText::Exception::ServerError
90
+ }
91
+ errors[code]
92
+ end
93
+
94
+ def form_headers(content_type, auth)
95
+ headers = {
96
+ 'Content-Type' => content_type,
97
+ 'Accept' => 'application/json'
98
+ }
99
+ case auth
100
+ when :session_token
101
+ headers['X-Session-Token'] = @session_token
102
+ when :basic
103
+ auth_string = Base64.encode64 "#{@credentials[0]}:#{@credentials[1]}"
104
+ headers['Authorization'] = "Basic #{auth_string}"
105
+ when :api_key
106
+ headers['X-Api-Key'] = @api_key
107
+ else
108
+ fail "Invalid auth type: #{auth}"
109
+ end
110
+ headers
111
+ end
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,55 @@
1
+ require 'net/http'
2
+ require 'uri'
3
+ require 'openssl'
4
+
5
+ module PortaText
6
+ module Client
7
+ # This class implements the client using Net::HTTP
8
+ #
9
+ # Author:: Marcelo Gornstein (mailto:marcelog@portatext.com)
10
+ # Copyright:: Copyright (c) 2015 PortaText
11
+ # License:: Apache-2.0
12
+ class HttpClient < BaseClient
13
+ def execute(descriptor)
14
+ uri = URI.parse descriptor.uri
15
+ http = create_http uri
16
+ request = create_request uri, descriptor.method, descriptor.body
17
+ begin
18
+ request! descriptor, http, request
19
+ rescue => e
20
+ raise ::PortaText::Exception::RequestError.new(
21
+ descriptor, nil, e.message, e
22
+ )
23
+ end
24
+ end
25
+
26
+ private
27
+
28
+ def create_http(uri)
29
+ http = Net::HTTP.new uri.host, uri.port
30
+ http.use_ssl = uri.scheme == 'https'
31
+ http.verify_mode = OpenSSL::SSL::VERIFY_PEER
32
+ http
33
+ end
34
+
35
+ def create_request(uri, method, body)
36
+ method = method.to_s.capitalize
37
+ request = Object.const_get("Net::HTTP::#{method}").new uri
38
+ request.body = body
39
+ request
40
+ end
41
+
42
+ def request!(descriptor, http, request)
43
+ descriptor.headers.each_pair do |k, v|
44
+ request[k] = v
45
+ end
46
+ result = http.request request
47
+ headers = result.to_hash.each_with_object({}) do |(k, v), acc|
48
+ acc[k.downcase] = v.shift
49
+ acc
50
+ end
51
+ [result.code.to_i, headers, result.body]
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,27 @@
1
+ module PortaText
2
+ module Command
3
+ module Api
4
+ # The me/acl endpoint.
5
+ # https://github.com/PortaText/docs/wiki/REST-API#api_acl
6
+ #
7
+ # Author:: Marcelo Gornstein (mailto:marcelog@portatext.com)
8
+ # Copyright:: Copyright (c) 2015 PortaText
9
+ # License:: Apache-2.0
10
+ class Acl < Base
11
+ def add(ip, netmask = 32, description = '')
12
+ key = "#{ip}#{netmask}"
13
+ set key, ip: ip, netmask: netmask, description: description
14
+ end
15
+
16
+ def body(method)
17
+ return super if method.eql? :get
18
+ { acl: @args.values }.to_json
19
+ end
20
+
21
+ def endpoint(_method)
22
+ 'me/acl'
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,43 @@
1
+ module PortaText
2
+ module Command
3
+ module Api
4
+ # The me/credit_cards/:id endpoint.
5
+ # https://github.com/PortaText/docs/wiki/REST-API#api_credit_cards
6
+ #
7
+ # Author:: Marcelo Gornstein (mailto:marcelog@portatext.com)
8
+ # Copyright:: Copyright (c) 2015 PortaText
9
+ # License:: Apache-2.0
10
+ class CreditCards < Base
11
+ def id(id)
12
+ set :id, id
13
+ end
14
+
15
+ def name_on_card(first, last)
16
+ set :first_name, first
17
+ set :last_name, last
18
+ end
19
+
20
+ def card_info(number, expiration_date, code)
21
+ set :card_number, number
22
+ set :card_expiration_date, expiration_date
23
+ set :card_code, code
24
+ end
25
+
26
+ def address(street_address, city, state, zip, country)
27
+ set :address, street_address
28
+ set :city, city
29
+ set :state, state
30
+ set :zip, zip
31
+ set :country, country
32
+ end
33
+
34
+ def endpoint(_method)
35
+ return 'me/credit_cards' if @args[:id].nil?
36
+ id = @args[:id]
37
+ @args.delete :id
38
+ "me/credit_cards/#{id}"
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,41 @@
1
+ module PortaText
2
+ module Command
3
+ module Api
4
+ # The me/dids/:did endpoint.
5
+ # https://github.com/PortaText/docs/wiki/REST-API#api_did_settings
6
+ #
7
+ # Author:: Marcelo Gornstein (mailto:marcelog@portatext.com)
8
+ # Copyright:: Copyright (c) 2015 PortaText
9
+ # License:: Apache-2.0
10
+ class DidSettings < Base
11
+ def for_number(number)
12
+ set :id, number
13
+ end
14
+
15
+ def disable_cnam
16
+ set :cnam_enabled, false
17
+ end
18
+
19
+ def enable_cnam
20
+ set :cnam_enabled, true
21
+ end
22
+
23
+ def dont_autorespond
24
+ set :autoresponder_enabled, false
25
+ end
26
+
27
+ def autorespond_with(text)
28
+ set :autoresponder_text, text
29
+ set :autoresponder_enabled, true
30
+ end
31
+
32
+ def endpoint(_method)
33
+ fail 'DID number cant be null' if @args[:id].nil?
34
+ id = @args[:id]
35
+ @args.delete :id
36
+ "me/dids/#{id}"
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,38 @@
1
+ module PortaText
2
+ module Command
3
+ module Api
4
+ # The me endpoint.
5
+ # https://github.com/PortaText/docs/wiki/REST-API#api_me
6
+ #
7
+ # Author:: Marcelo Gornstein (mailto:marcelog@portatext.com)
8
+ # Copyright:: Copyright (c) 2015 PortaText
9
+ # License:: Apache-2.0
10
+ class Me < Base
11
+ def name(first, last)
12
+ set :first_name, first
13
+ set :last_name, last
14
+ end
15
+
16
+ def company(company)
17
+ set :company, company
18
+ end
19
+
20
+ def email(email)
21
+ set :email, email
22
+ end
23
+
24
+ def callback_url(callback_url)
25
+ set :callback_url, callback_url
26
+ end
27
+
28
+ def timezone(timezone)
29
+ set :timezone, timezone
30
+ end
31
+
32
+ def endpoint(_method)
33
+ 'me'
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,45 @@
1
+ module PortaText
2
+ module Command
3
+ module Api
4
+ # The me/settings endpoint.
5
+ # https://github.com/PortaText/docs/wiki/REST-API#api_settings
6
+ #
7
+ # Author:: Marcelo Gornstein (mailto:marcelog@portatext.com)
8
+ # Copyright:: Copyright (c) 2015 PortaText
9
+ # License:: Apache-2.0
10
+ class Settings < Base
11
+ def dont_alert_on_low_credit
12
+ set :alert_when_credit_less_than, nil
13
+ end
14
+
15
+ def alert_when_credit_less_than(total)
16
+ set :alert_when_credit_less_than, total
17
+ end
18
+
19
+ def dont_send_inbound_by_email
20
+ set :email_on_inbound_sms, nil
21
+ end
22
+
23
+ def send_inbound_by_email(email)
24
+ set :email_on_inbound_sms, email
25
+ end
26
+
27
+ def enable_autorecharges(when_credit, card_id, plan_id, total)
28
+ set :autorecharge_enabled, true
29
+ set :autorecharge_plan_id, plan_id
30
+ set :autorecharge_card_id, card_id
31
+ set :autorecharge_total, total
32
+ set :autorecharge_when_credit, when_credit
33
+ end
34
+
35
+ def disable_autorecharges
36
+ set :autorecharge_enabled, false
37
+ end
38
+
39
+ def endpoint(_method)
40
+ 'me/settings'
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,24 @@
1
+ module PortaText
2
+ module Command
3
+ module Api
4
+ # The tariffs endpoint.
5
+ # https://github.com/PortaText/docs/wiki/REST-API#api_tariffs
6
+ #
7
+ # Author:: Marcelo Gornstein (mailto:marcelog@portatext.com)
8
+ # Copyright:: Copyright (c) 2015 PortaText
9
+ # License:: Apache-2.0
10
+ class Tariffs < Base
11
+ def for_country(country_iso)
12
+ set :country, country_iso
13
+ end
14
+
15
+ def endpoint(_method)
16
+ return 'tariffs' if @args[:country].nil?
17
+ country = @args[:country]
18
+ @args.delete :country
19
+ "tariffs/#{country}"
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,57 @@
1
+ require 'json'
2
+
3
+ module PortaText
4
+ module Command
5
+ # The base command class.
6
+ #
7
+ # Author:: Marcelo Gornstein (mailto:marcelog@portatext.com)
8
+ # Copyright:: Copyright (c) 2015 PortaText
9
+ # License:: Apache-2.0
10
+ class Base
11
+ def get
12
+ run :get
13
+ end
14
+
15
+ def post
16
+ run :post
17
+ end
18
+
19
+ def put
20
+ run :put
21
+ end
22
+
23
+ def patch
24
+ run :patch
25
+ end
26
+
27
+ def delete
28
+ run :delete
29
+ end
30
+
31
+ def set(key, value)
32
+ @args[key] = value
33
+ self
34
+ end
35
+
36
+ def content_type(_method)
37
+ 'application/json'
38
+ end
39
+
40
+ def body(_method)
41
+ return '' if @args.size.eql? 0
42
+ @args.to_json
43
+ end
44
+
45
+ def initialize(client)
46
+ @client = client
47
+ @args = {}
48
+ end
49
+
50
+ private
51
+
52
+ def run(method)
53
+ @client.run endpoint(method), method, content_type(method), body(method)
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,23 @@
1
+ module PortaText
2
+ module Command
3
+ # This class holds the descriptor with the needed information to call an
4
+ # endpoint.
5
+ #
6
+ # Author:: Marcelo Gornstein (mailto:marcelog@portatext.com)
7
+ # Copyright:: Copyright (c) 2015 PortaText
8
+ # License:: Apache-2.0
9
+ class Descriptor
10
+ attr_accessor :uri
11
+ attr_accessor :method
12
+ attr_accessor :headers
13
+ attr_accessor :body
14
+
15
+ def initialize(uri, method, headers, body)
16
+ @uri = uri
17
+ @method = method
18
+ @headers = headers
19
+ @body = body
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,22 @@
1
+ module PortaText
2
+ module Command
3
+ # This class holds the result of calling the endpoint.
4
+ #
5
+ # Author:: Marcelo Gornstein (mailto:marcelog@portatext.com)
6
+ # Copyright:: Copyright (c) 2015 PortaText
7
+ # License:: Apache-2.0
8
+ class Result
9
+ attr_accessor :code
10
+ attr_accessor :headers
11
+ attr_accessor :data
12
+ attr_reader :success
13
+
14
+ def initialize(code, headers, data)
15
+ @code = code
16
+ @headers = headers
17
+ @data = data
18
+ @success = code > 199 && code < 300 && data['success']
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,11 @@
1
+ module PortaText
2
+ module Exception
3
+ # Raised when the request issued was invalid, HTTP 400.
4
+ #
5
+ # Author:: Marcelo Gornstein (mailto:marcelog@portatext.com)
6
+ # Copyright:: Copyright (c) 2015 PortaText
7
+ # License:: Apache-2.0
8
+ class ClientError < RequestError
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module PortaText
2
+ module Exception
3
+ # Raised when access was denied to the resource, HTTP 403.
4
+ #
5
+ # Author:: Marcelo Gornstein (mailto:marcelog@portatext.com)
6
+ # Copyright:: Copyright (c) 2015 PortaText
7
+ # License:: Apache-2.0
8
+ class Forbidden < RequestError
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module PortaText
2
+ module Exception
3
+ # Raised when credentials were invalid HTTP 401.
4
+ #
5
+ # Author:: Marcelo Gornstein (mailto:marcelog@portatext.com)
6
+ # Copyright:: Copyright (c) 2015 PortaText
7
+ # License:: Apache-2.0
8
+ class InvalidCredentials < RequestError
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module PortaText
2
+ module Exception
3
+ # Raised on invalid content type for endpoint/method combination HTTP 415.
4
+ #
5
+ # Author:: Marcelo Gornstein (mailto:marcelog@portatext.com)
6
+ # Copyright:: Copyright (c) 2015 PortaText
7
+ # License:: Apache-2.0
8
+ class InvalidMedia < RequestError
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module PortaText
2
+ module Exception
3
+ # Raised on invalid endpoint/method combination HTTP 405.
4
+ #
5
+ # Author:: Marcelo Gornstein (mailto:marcelog@portatext.com)
6
+ # Copyright:: Copyright (c) 2015 PortaText
7
+ # License:: Apache-2.0
8
+ class InvalidMethod < RequestError
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module PortaText
2
+ module Exception
3
+ # Raised when the resource was not found HTTP 404.
4
+ #
5
+ # Author:: Marcelo Gornstein (mailto:marcelog@portatext.com)
6
+ # Copyright:: Copyright (c) 2015 PortaText
7
+ # License:: Apache-2.0
8
+ class NotFound < RequestError
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module PortaText
2
+ module Exception
3
+ # Raised when not enough funds, HTTP 402.
4
+ #
5
+ # Author:: Marcelo Gornstein (mailto:marcelog@portatext.com)
6
+ # Copyright:: Copyright (c) 2015 PortaText
7
+ # License:: Apache-2.0
8
+ class PaymentRequired < RequestError
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module PortaText
2
+ module Exception
3
+ # Raised on rate limited by the server, HTTP 429.
4
+ #
5
+ # Author:: Marcelo Gornstein (mailto:marcelog@portatext.com)
6
+ # Copyright:: Copyright (c) 2015 PortaText
7
+ # License:: Apache-2.0
8
+ class RateLimited < RequestError
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,21 @@
1
+ module PortaText
2
+ module Exception
3
+ # Generic endpoint request error
4
+ #
5
+ # Author:: Marcelo Gornstein (mailto:marcelog@portatext.com)
6
+ # Copyright:: Copyright (c) 2015 PortaText
7
+ # License:: Apache-2.0
8
+ class RequestError < ::Exception
9
+ attr_reader :descriptor
10
+ attr_reader :original
11
+ attr_reader :result
12
+
13
+ def initialize(descriptor, result = nil, message = nil, original = nil)
14
+ super message
15
+ @descriptor = descriptor
16
+ @original = original
17
+ @result = result
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,11 @@
1
+ module PortaText
2
+ module Exception
3
+ # Raised on server error, HTTP 500.
4
+ #
5
+ # Author:: Marcelo Gornstein (mailto:marcelog@portatext.com)
6
+ # Copyright:: Copyright (c) 2015 PortaText
7
+ # License:: Apache-2.0
8
+ class ServerError < RequestError
9
+ end
10
+ end
11
+ end
data/lib/portatext.rb ADDED
@@ -0,0 +1,30 @@
1
+ require_relative 'portatext/client/base_client'
2
+ require_relative 'portatext/client/http_client'
3
+ require_relative 'portatext/command/descriptor'
4
+ require_relative 'portatext/command/result'
5
+ require_relative 'portatext/command/base'
6
+ require_relative 'portatext/command/api/tariffs'
7
+ require_relative 'portatext/command/api/me'
8
+ require_relative 'portatext/command/api/acl'
9
+ require_relative 'portatext/command/api/settings'
10
+ require_relative 'portatext/command/api/did_settings'
11
+ require_relative 'portatext/command/api/credit_cards'
12
+ require_relative 'portatext/exception/request_error'
13
+ require_relative 'portatext/exception/server_error'
14
+ require_relative 'portatext/exception/rate_limited'
15
+ require_relative 'portatext/exception/invalid_media'
16
+ require_relative 'portatext/exception/invalid_method'
17
+ require_relative 'portatext/exception/not_found'
18
+ require_relative 'portatext/exception/forbidden'
19
+ require_relative 'portatext/exception/payment_required'
20
+ require_relative 'portatext/exception/invalid_credentials'
21
+ require_relative 'portatext/exception/client_error'
22
+
23
+ # The PortaText namespace.
24
+ #
25
+ # Author:: Marcelo Gornstein (mailto:marcelog@portatext.com)
26
+ # Copyright:: Copyright (c) 2015 PortaText
27
+ # License:: Apache-2.0
28
+ module PortaText
29
+ DEFAULT_ENDPOINT = 'https://rest.portatext.com'
30
+ end
data/portatext.gemspec ADDED
@@ -0,0 +1,20 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = 'portatext'
3
+ s.version = '0.0.2'
4
+ s.summary = 'Official PortaText API ruby client'
5
+ s.description = 'This is the official PortaText API ruby client'
6
+ s.authors = ['PortaText']
7
+ s.email = 'hello@portatext.com'
8
+ s.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
9
+ s.require_paths = ['lib']
10
+ s.homepage = 'http://rubygems.org/gems/portatext'
11
+ s.license = 'Apache-2.0'
12
+ s.add_development_dependency 'simplecov', '~> 0.11'
13
+ s.add_development_dependency 'coveralls', '~> 0.8'
14
+ s.add_development_dependency 'bundler', '~> 1.10'
15
+ s.add_development_dependency 'rake', '~> 10.0'
16
+ s.add_development_dependency 'minitest', '~> 5.8'
17
+ s.add_development_dependency 'rubocop', '~> 0.35'
18
+ s.add_development_dependency 'bundler-audit', '~> 0.4'
19
+ s.add_development_dependency 'codeclimate-test-reporter', '~> 0.4'
20
+ end
metadata ADDED
@@ -0,0 +1,186 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: portatext
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ platform: ruby
6
+ authors:
7
+ - PortaText
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-12-14 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: simplecov
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.11'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0.11'
27
+ - !ruby/object:Gem::Dependency
28
+ name: coveralls
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0.8'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0.8'
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.10'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.10'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '10.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '10.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: minitest
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '5.8'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '5.8'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rubocop
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '0.35'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '0.35'
97
+ - !ruby/object:Gem::Dependency
98
+ name: bundler-audit
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '0.4'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '0.4'
111
+ - !ruby/object:Gem::Dependency
112
+ name: codeclimate-test-reporter
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '0.4'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '0.4'
125
+ description: This is the official PortaText API ruby client
126
+ email: hello@portatext.com
127
+ executables: []
128
+ extensions: []
129
+ extra_rdoc_files: []
130
+ files:
131
+ - ".codeclimate.yml"
132
+ - ".gitignore"
133
+ - ".rubocop.yml"
134
+ - ".travis.yml"
135
+ - Gemfile
136
+ - LICENSE
137
+ - README.md
138
+ - Rakefile
139
+ - lib/portatext.rb
140
+ - lib/portatext/client/base_client.rb
141
+ - lib/portatext/client/http_client.rb
142
+ - lib/portatext/command/api/acl.rb
143
+ - lib/portatext/command/api/credit_cards.rb
144
+ - lib/portatext/command/api/did_settings.rb
145
+ - lib/portatext/command/api/me.rb
146
+ - lib/portatext/command/api/settings.rb
147
+ - lib/portatext/command/api/tariffs.rb
148
+ - lib/portatext/command/base.rb
149
+ - lib/portatext/command/descriptor.rb
150
+ - lib/portatext/command/result.rb
151
+ - lib/portatext/exception/client_error.rb
152
+ - lib/portatext/exception/forbidden.rb
153
+ - lib/portatext/exception/invalid_credentials.rb
154
+ - lib/portatext/exception/invalid_media.rb
155
+ - lib/portatext/exception/invalid_method.rb
156
+ - lib/portatext/exception/not_found.rb
157
+ - lib/portatext/exception/payment_required.rb
158
+ - lib/portatext/exception/rate_limited.rb
159
+ - lib/portatext/exception/request_error.rb
160
+ - lib/portatext/exception/server_error.rb
161
+ - portatext.gemspec
162
+ homepage: http://rubygems.org/gems/portatext
163
+ licenses:
164
+ - Apache-2.0
165
+ metadata: {}
166
+ post_install_message:
167
+ rdoc_options: []
168
+ require_paths:
169
+ - lib
170
+ required_ruby_version: !ruby/object:Gem::Requirement
171
+ requirements:
172
+ - - ">="
173
+ - !ruby/object:Gem::Version
174
+ version: '0'
175
+ required_rubygems_version: !ruby/object:Gem::Requirement
176
+ requirements:
177
+ - - ">="
178
+ - !ruby/object:Gem::Version
179
+ version: '0'
180
+ requirements: []
181
+ rubyforge_project:
182
+ rubygems_version: 2.4.8
183
+ signing_key:
184
+ specification_version: 4
185
+ summary: Official PortaText API ruby client
186
+ test_files: []