signnow-ruby 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,74 @@
1
+ module Signnow
2
+ module Request
3
+ class Connection
4
+ include Helpers
5
+ attr_reader :https
6
+
7
+ def initialize(request_info)
8
+ @info = request_info
9
+ end
10
+
11
+ def setup_https
12
+ @https = Net::HTTP.new(api_url, Net::HTTP.https_default_port)
13
+ @https.use_ssl = true
14
+ @https.verify_mode = OpenSSL::SSL::VERIFY_NONE
15
+ end
16
+
17
+ def request
18
+ https.start do |connection|
19
+ https.request(https_request)
20
+ end
21
+ end
22
+
23
+ protected
24
+
25
+ def authentication
26
+ return {} unless @info.authentication[:type]
27
+ case @info.authentication[:type]
28
+ when :basic
29
+ raise AuthenticationError unless Signnow.encoded_app_credentials
30
+ {'Authorization' => "Basic #{Signnow.encoded_app_credentials}"}
31
+ when :user_token
32
+ raise AuthenticationError unless @info.authentication[:token]
33
+ {'Authorization' => "Bearer #{@info.authentication[:token]}"}
34
+ else
35
+ {}
36
+ end
37
+ end
38
+
39
+ def https_request
40
+ https_request = case @info.http_method
41
+ when :post
42
+ Net::HTTP::Post.new(@info.url, authentication)
43
+ when :put
44
+ Net::HTTP::Put.new(@info.url, authentication)
45
+ when :delete
46
+ Net::HTTP::Delete.new(@info.url, authentication)
47
+ else
48
+ Net::HTTP::Get.new(@info.path_with_params(@info.url, @info.data), authentication)
49
+ end
50
+
51
+ if [:post, :put].include?(@info.http_method)
52
+ if @info.use_form_data?
53
+ https_request.set_form_data(@info.data)
54
+ else
55
+ https_request.body = JSON.generate(normalize_params(@info.data))
56
+ end
57
+ end
58
+
59
+ https_request
60
+ end
61
+
62
+ # Returns the api url foir this request or default
63
+ def api_url
64
+ domain + '.' + API_BASE
65
+ end
66
+
67
+ # Returns the domain for the current request or the default one
68
+ def domain
69
+ return @info.subdomain if @info
70
+ DOMAIN_BASE
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,36 @@
1
+ module Signnow
2
+ module Request
3
+ module Helpers
4
+ def flatten_hash_keys(old_hash, new_hash={}, keys=nil)
5
+ old_hash.each do |key, value|
6
+ key = key.to_s
7
+ if value.is_a?(Hash)
8
+ all_keys_formatted = keys + "[#{key}]"
9
+ flatten_hash_keys(value, new_hash, all_keys_formatted)
10
+ else
11
+ new_hash[key] = value
12
+ end
13
+ end
14
+ new_hash
15
+ end
16
+
17
+ def normalize_params(params, key=nil)
18
+ params = flatten_hash_keys(params) if params.is_a?(Hash)
19
+ result = {}
20
+ params.each do |key, value|
21
+ case value
22
+ when Hash
23
+ result[key.to_s] = normalize_params(value)
24
+ when Array
25
+ value.each_with_index do |item_value, index|
26
+ result["#{key.to_s}[#{index}]"] = item_value.to_s
27
+ end
28
+ else
29
+ result[key.to_s] = value.to_s
30
+ end
31
+ end
32
+ result
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,50 @@
1
+ module Signnow
2
+ module Request
3
+ class Info
4
+ attr_accessor :http_method, :api_url, :data, :subdomain, :authentication, :base_path, :options
5
+
6
+ def initialize(http_method, subdomain, api_url, data, options={})
7
+ @http_method = http_method
8
+ @subdomain = subdomain || Signnow.domain
9
+ @api_url = api_url
10
+ @data = data
11
+ @base_path = Signnow.base_path
12
+ @authentication = {}
13
+ @authentication[:type] = options.delete(:auth_type)
14
+ @authentication[:token] = options.delete(:auth_token)
15
+ @options = options
16
+ end
17
+
18
+ def url
19
+ url = ''
20
+ url += "/#{base_path}" if base_path
21
+ url += "/#{api_url}"
22
+ if has_id?
23
+ url += "/#{data[:id]}"
24
+ data.delete(:id)
25
+ end
26
+
27
+ url
28
+ end
29
+
30
+ def path_with_params(path, params)
31
+ unless params.empty?
32
+ encoded_params = URI.encode_www_form(params)
33
+ [path, encoded_params].join("?")
34
+ else
35
+ path
36
+ end
37
+ end
38
+
39
+ def use_form_data?
40
+ options.fetch(:use_form_data, false)
41
+ end
42
+
43
+ protected
44
+
45
+ def has_id?
46
+ !data[:id].nil?
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,52 @@
1
+ module Signnow
2
+ module Request
3
+ class Validator
4
+ attr_reader :info
5
+ attr_accessor :response
6
+
7
+ def initialize(info)
8
+ @info = info
9
+ end
10
+
11
+ def validated_data_for(incoming_response)
12
+ self.response = incoming_response
13
+ verify_response_code
14
+ info.data = JSON.parse(response.body)
15
+ validate_response_data
16
+ info.data
17
+ end
18
+
19
+ protected
20
+
21
+ def verify_response_code
22
+ raise AuthenticationError if response.code.to_i == 401
23
+ raise NotFound if response.code.to_i == 404
24
+ raise APIError if response.code.to_i >= 500
25
+ end
26
+
27
+ def validate_response_data(body=nil)
28
+ body ||= info.data
29
+ if body.is_a?(Hash)
30
+ if body['404']
31
+ fail NotFound.new(body['404'])
32
+ elsif body['error']
33
+ handle_api_error(body['code'], body['error'])
34
+ elsif body['errors']
35
+ body['errors'].each do |error|
36
+ handle_api_error(error['code'], error['message'])
37
+ end
38
+ end
39
+ end
40
+ end
41
+
42
+ def handle_api_error(code, message)
43
+ error = case code
44
+ when 1539 then InvalidToken.new(message)
45
+ when 65536 then EmptyDocuments.new(message)
46
+ else APIError.new(message)
47
+ end
48
+ fail error
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,31 @@
1
+ module Signnow
2
+ class User < Base
3
+ include Signnow::Operations::Show
4
+
5
+ attr_accessor :id, :email, :first_name, :last_name, :attributes, :active,
6
+ :type, :pro, :created, :emails, :identity, :subscriptions, :credits,
7
+ :has_atticus_access, :is_logged_in, :teams
8
+
9
+ # Initializes the object using the given attributes
10
+ #
11
+ # @param [Hash] attributes The attributes to use for initialization
12
+ def initialize(attributes = {})
13
+ super(attributes)
14
+ parse_booleans
15
+ end
16
+
17
+ def email
18
+ return @email if @email
19
+ return unless emails
20
+ emails.first
21
+ end
22
+
23
+ # Parses Boolean fileds.
24
+ def parse_booleans
25
+ @active = ( active == '1' ) if active and active.is_a? String
26
+ @pro = ( pro == 1 ) if pro and pro.is_a? Integer
27
+ end
28
+ protected :parse_booleans
29
+
30
+ end
31
+ end
@@ -0,0 +1,3 @@
1
+ module Signnow
2
+ VERSION = '0.0.2'
3
+ end
@@ -0,0 +1,22 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "signnow/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "signnow-ruby"
7
+ s.version = Signnow::VERSION
8
+ s.authors = ["Andres Bravo"]
9
+ s.email = ["hola@andresbravo.com"]
10
+ s.homepage = "https://github.com/andresbravog/signnow-ruby"
11
+ s.summary = %q{API wrapper for Signnow.}
12
+ s.description = %q{API wrapper for Signnow.}
13
+
14
+ s.files = `git ls-files`.split("\n")
15
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
16
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
17
+ s.require_paths = ["lib"]
18
+
19
+ s.add_dependency "json"
20
+ s.add_development_dependency "rspec"
21
+ s.add_development_dependency "pry"
22
+ end
@@ -0,0 +1,12 @@
1
+ require "spec_helper"
2
+
3
+ describe Signnow::Base do
4
+ describe "#parse_timestamps" do
5
+ context "given #created is present" do
6
+ it "creates a Time object" do
7
+ base = Signnow::Base.new(created: 1358300444)
8
+ base.created.class.should eql(Time)
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,53 @@
1
+ require "spec_helper"
2
+
3
+ describe Signnow::Client do
4
+ let(:valid_attributes) do
5
+ JSON.parse %{
6
+ {
7
+ "id": "23f2f9dc10e0f12883f78e91296207640dede6d1",
8
+ "first_name": "Test",
9
+ "last_name": "User",
10
+ "active": "1",
11
+ "type": 1,
12
+ "pro": 0,
13
+ "created": "1358945328",
14
+ "emails": ["hola+test@andresbravo.com"],
15
+ "identity": {
16
+ "Identified": "No",
17
+ "Status": "First attempt",
18
+ "OKToRetry": true
19
+ },
20
+ "subscriptions": [],
21
+ "credits": 0,
22
+ "has_atticus_access": false,
23
+ "is_logged_in": true,
24
+ "teams": []
25
+ }
26
+ }
27
+ end
28
+
29
+ let (:client) do
30
+ Signnow::Client.new(user_access_token)
31
+ end
32
+
33
+ let(:user_access_token) { '_user_access_token_' }
34
+
35
+ describe "#initialize" do
36
+ it 'initializes attributes correctly' do
37
+ client.access_token.should eql(user_access_token)
38
+ end
39
+ end
40
+
41
+ describe "#perform!" do
42
+ before :each do
43
+ allow(Signnow).to receive(:request).and_return(valid_attributes)
44
+ end
45
+ it "executes requests inside the block" do
46
+ expect(Signnow).to receive(:request).with(:get, nil, "user", {}, { auth_type: :user_token, auth_token: user_access_token })
47
+ client.perform! do |token|
48
+ Signnow::User.show(access_token: token)
49
+ end
50
+ end
51
+ end
52
+
53
+ end
@@ -0,0 +1,188 @@
1
+ require "spec_helper"
2
+
3
+ describe Signnow::Document do
4
+ let(:valid_attributes) do
5
+ JSON.parse %{
6
+ {
7
+ "id": "9e30bb3094e00abc291016a7a597ba1840a6d6ec",
8
+ "user_id": "adb16da39e5ecc448e2aa4aec8a34a8158fa137a",
9
+ "document_name": "sample.pdf",
10
+ "page_count": "1",
11
+ "created": "1358300444",
12
+ "updated": "1358300444",
13
+ "original_filename": "sample.pdf",
14
+ "thumbnail": {
15
+ "small": "https:\/\/api.signnow.com\/document\/9e30bb3094e00abc291016a7a597ba1840a6d6ec\/thumbnail?size=small",
16
+ "medium": "https:\/\/api.signnow.com\/document\/9e30bb3094e00abc291016a7a597ba1840a6d6ec\/thumbnail?size=medium",
17
+ "large": "https:\/\/api.signnow.com\/document\/9e30bb3094e00abc291016a7a597ba1840a6d6ec\/thumbnail?size=large"
18
+ },
19
+ "signatures": [],
20
+ "seals": [],
21
+ "texts": [],
22
+ "inserts": [],
23
+ "tags": [],
24
+ "fields": [],
25
+ "requests": [],
26
+ "notary_invites": [],
27
+ "version_time": "1358300444"
28
+ }
29
+ }
30
+ end
31
+
32
+ let(:valid_all_response) do
33
+ JSON.parse %{
34
+ [{
35
+ "id": "9e30bb3094e00abc291016a7a597ba1840a6d6ec",
36
+ "user_id": "adb16da39e5ecc448e2aa4aec8a34a8158fa137a",
37
+ "document_name": "sample.pdf",
38
+ "page_count": "1",
39
+ "created": "1358300444",
40
+ "updated": "1358300444",
41
+ "original_filename": "sample.pdf",
42
+ "thumbnail": {
43
+ "small": "https:\/\/api.signnow.com\/document\/9e30bb3094e00abc291016a7a597ba1840a6d6ec\/thumbnail?size=small",
44
+ "medium": "https:\/\/api.signnow.com\/document\/9e30bb3094e00abc291016a7a597ba1840a6d6ec\/thumbnail?size=medium",
45
+ "large": "https:\/\/api.signnow.com\/document\/9e30bb3094e00abc291016a7a597ba1840a6d6ec\/thumbnail?size=large"
46
+ },
47
+ "signatures": [],
48
+ "seals": [],
49
+ "texts": [],
50
+ "inserts": [],
51
+ "tags": [],
52
+ "fields": [],
53
+ "requests": [],
54
+ "notary_invites": [],
55
+ "version_time": "1358300444"
56
+ }, {
57
+ "id": "321e1c74ada708f442bf3f9529ed0d44b3628796",
58
+ "user_id": "adb16da39e5ecc448e2aa4aec8a34a8158fa137a",
59
+ "document_name": "sample.pdf",
60
+ "page_count": "1",
61
+ "created": "1341248871",
62
+ "updated": "1341248871",
63
+ "original_filename": "sample.pdf",
64
+ "thumbnail": {
65
+ "small": "https:\/\/api.signnow.com\/document\/321e1c74ada708f442bf3f9529ed0d44b3628796\/thumbnail?size=small",
66
+ "medium": "https:\/\/api.signnow.com\/document\/321e1c74ada708f442bf3f9529ed0d44b3628796\/thumbnail?size=medium",
67
+ "large": "https:\/\/api.signnow.com\/document\/321e1c74ada708f442bf3f9529ed0d44b3628796\/thumbnail?size=large"
68
+ },
69
+ "signatures": [],
70
+ "seals": [],
71
+ "texts": [],
72
+ "inserts": [],
73
+ "tags": [],
74
+ "fields": [],
75
+ "requests": [{
76
+ "unique_id": "1cb9d8e6b26d6ececc4f4c9d08aaaa28e10fa80f",
77
+ "id": "1cb9d8e6b26d6ececc4f4c9d08aaaa28e10fa80f",
78
+ "user_id": "adb16da39e5ecc448e2aa4aec8a34a8158fa137a",
79
+ "created": "1349903957",
80
+ "originator_email": "user@test.com",
81
+ "signer_email": "signer@test.com"
82
+ }],
83
+ "notary_invites": [],
84
+ "version_time": "1341248871"
85
+ }, {
86
+ "id": "1db4c6ba33332f655cb2eda468743c1d040ae079",
87
+ "user_id": "adb16da39e5ecc448e2aa4aec8a34a8158fa137a",
88
+ "document_name": "sample.pdf",
89
+ "page_count": "1",
90
+ "created": "1335819071",
91
+ "updated": "1335819071",
92
+ "original_filename": "sample.pdf",
93
+ "thumbnail": {
94
+ "small": "https:\/\/api.signnow.com\/document\/1db4c6ba33332f655cb2eda468743c1d040ae079\/thumbnail?size=small",
95
+ "medium": "https:\/\/api.signnow.com\/document\/1db4c6ba33332f655cb2eda468743c1d040ae079\/thumbnail?size=medium",
96
+ "large": "https:\/\/api.signnow.com\/document\/1db4c6ba33332f655cb2eda468743c1d040ae079\/thumbnail?size=large"
97
+ },
98
+ "signatures": [],
99
+ "seals": [],
100
+ "texts": [],
101
+ "inserts": [],
102
+ "tags": [],
103
+ "fields": [],
104
+ "requests": [{
105
+ "unique_id": "5d8ce45d8e27c7ed717d7d23117200c72442ee3e",
106
+ "id": "5d8ce45d8e27c7ed717d7d23117200c72442ee3e",
107
+ "user_id": "adb16da39e5ecc448e2aa4aec8a34a8158fa137a",
108
+ "created": "1335819085",
109
+ "originator_email": "jane@test.com",
110
+ "signer_email": "signer@test.com"
111
+ }],
112
+ "notary_invites": [],
113
+ "version_time": "1335819071"
114
+ }]
115
+ }
116
+ end
117
+
118
+ let (:document) do
119
+ Signnow::Document.new(valid_attributes)
120
+ end
121
+
122
+ let(:user_access_token) { '_user_access_token_' }
123
+
124
+ describe "#initialize" do
125
+ it 'initializes all attributes correctly' do
126
+ document.id.should eql('9e30bb3094e00abc291016a7a597ba1840a6d6ec')
127
+ document.user_id.should eql('adb16da39e5ecc448e2aa4aec8a34a8158fa137a')
128
+ document.document_name.should eql('sample.pdf')
129
+ document.page_count.should eql('1')
130
+ document.original_filename.should eql('sample.pdf')
131
+ end
132
+ end
133
+
134
+ describe ".show" do
135
+ let(:document_show) { Signnow::Document.show(access_token: user_access_token, id: document.id ) }
136
+ before :each do
137
+ allow(Signnow).to receive(:request).and_return(valid_attributes)
138
+ end
139
+ it "makes a new GET request using the correct API endpoint to receive a specific user" do
140
+ expect(Signnow).to receive(:request).with(:get, nil, "document/#{document.id}", {}, { auth_type: :user_token, auth_token: user_access_token })
141
+ document_show
142
+ end
143
+ it 'returns a user with the correct id' do
144
+ expect(document_show.id).to eql('9e30bb3094e00abc291016a7a597ba1840a6d6ec')
145
+ end
146
+ it 'returns a user with the correct document_name' do
147
+ expect(document_show.document_name).to eql('sample.pdf')
148
+ end
149
+ it 'returns a user with the correct original_filename' do
150
+ expect(document_show.original_filename).to eql('sample.pdf')
151
+ end
152
+ end
153
+
154
+ describe ".download_link" do
155
+ let(:document_download_link) { Signnow::Document.download_link(access_token: user_access_token, id: document.id ) }
156
+ let(:valid_link_attributes) do
157
+ JSON.parse %{
158
+ {
159
+ "link": "https://signnow.com/dispatch?route=onetimedownload&document_download_id=67de624701a70cdfe208b5c537f61fefa48b410a"
160
+ }
161
+ }
162
+ end
163
+ before :each do
164
+ allow(Signnow).to receive(:request).and_return(valid_link_attributes)
165
+ end
166
+ it "makes a new GET request using the correct API endpoint to receive a specific user" do
167
+ expect(Signnow).to receive(:request).with(:post, nil, "document/#{document.id}/download/link", {}, { auth_type: :user_token, auth_token: user_access_token })
168
+ document_download_link
169
+ end
170
+ it 'returns a user with the correct link' do
171
+ expect(document_download_link).to eql('https://signnow.com/dispatch?route=onetimedownload&document_download_id=67de624701a70cdfe208b5c537f61fefa48b410a')
172
+ end
173
+ end
174
+
175
+ describe ".all" do
176
+ let(:document_all) { Signnow::Document.all(access_token: user_access_token) }
177
+ before :each do
178
+ allow(Signnow).to receive(:request).and_return(valid_all_response)
179
+ end
180
+ it "makes a new POST request using the correct API endpoint" do
181
+ expect(Signnow).to receive(:request).with(:get, nil, "user/documentsv2", {}, { auth_type: :user_token, auth_token: user_access_token })
182
+ document_all
183
+ end
184
+ it 'returns a user with the correct id' do
185
+ expect(document_all.first.id).to eql('9e30bb3094e00abc291016a7a597ba1840a6d6ec')
186
+ end
187
+ end
188
+ end