assently 1.0.0.beta1

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 +7 -0
  2. data/.gitignore +20 -0
  3. data/.rspec +3 -0
  4. data/.ruby-version +1 -0
  5. data/.travis.yml +15 -0
  6. data/Gemfile +10 -0
  7. data/LICENSE.txt +22 -0
  8. data/README.md +124 -0
  9. data/Rakefile +1 -0
  10. data/assently.gemspec +31 -0
  11. data/lib/assently/api_mappers/case_event_subscription_mapper.rb +12 -0
  12. data/lib/assently/api_mappers/case_mapper.rb +23 -0
  13. data/lib/assently/api_mappers/case_options_mapper.rb +74 -0
  14. data/lib/assently/api_mappers/document_mapper.rb +19 -0
  15. data/lib/assently/api_mappers/form_field_mapper.rb +12 -0
  16. data/lib/assently/api_mappers/party_mapper.rb +13 -0
  17. data/lib/assently/case.rb +50 -0
  18. data/lib/assently/case_event_subscription.rb +29 -0
  19. data/lib/assently/client.rb +129 -0
  20. data/lib/assently/document.rb +64 -0
  21. data/lib/assently/form_field.rb +3 -0
  22. data/lib/assently/id_generator.rb +10 -0
  23. data/lib/assently/party.rb +21 -0
  24. data/lib/assently/serializers/case_serializer.rb +15 -0
  25. data/lib/assently/version.rb +3 -0
  26. data/lib/assently.rb +14 -0
  27. data/spec/assently/api_mappers/case_event_subscription_mapper_spec.rb +23 -0
  28. data/spec/assently/api_mappers/case_mapper_spec.rb +34 -0
  29. data/spec/assently/api_mappers/case_options_mapper_spec.rb +92 -0
  30. data/spec/assently/api_mappers/document_mapper_spec.rb +35 -0
  31. data/spec/assently/api_mappers/form_field_mapper_spec.rb +19 -0
  32. data/spec/assently/api_mappers/party_mapper_spec.rb +24 -0
  33. data/spec/assently/case_event_subscription_spec.rb +18 -0
  34. data/spec/assently/case_spec.rb +68 -0
  35. data/spec/assently/client/create_case_spec.rb +55 -0
  36. data/spec/assently/client/get_case_spec.rb +84 -0
  37. data/spec/assently/client_spec.rb +207 -0
  38. data/spec/assently/document_spec.rb +126 -0
  39. data/spec/assently/form_field_spec.rb +18 -0
  40. data/spec/assently/id_generator_spec.rb +13 -0
  41. data/spec/assently/party_spec.rb +35 -0
  42. data/spec/assently/serializers/case_serializer_spec.rb +39 -0
  43. data/spec/assently_spec.rb +17 -0
  44. data/spec/fixtures/agreement.pdf +0 -0
  45. data/spec/fixtures/cassettes/Assently_Client/_create_case/valid_case.yml +75 -0
  46. data/spec/fixtures/cassettes/Assently_Client/_get_case/case_exists.yml +107 -0
  47. data/spec/fixtures/cassettes/Assently_Client/_get_case/case_missing.yml +43 -0
  48. data/spec/spec_helper.rb +38 -0
  49. metadata +225 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 933080f44f336e051125aa02137fbb9ce032f19b
4
+ data.tar.gz: 4ba7f86ccd3e8466e4926c10fa394f078f9cce25
5
+ SHA512:
6
+ metadata.gz: 3862f68bb0b1756e8bfc6934dc0d8a7e07d4a7593dbd1551a42899489b80a444e644bc811d35080fe13613e62585276ba4c1b07b0763a6e9106b294f66ddf0aa
7
+ data.tar.gz: f8e1f8e5d1ef32f5bf33c8ab6852f2131bfcecbfadf445f319e8140db471f9ef3e28f1ff3906cd5a0bd57f9826580b1e683838aed1e199a1340a74abd9312a80
data/.gitignore ADDED
@@ -0,0 +1,20 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ .env
7
+ Gemfile.lock
8
+ InstalledFiles
9
+ _yardoc
10
+ coverage
11
+ doc/
12
+ lib/bundler/man
13
+ pkg
14
+ rdoc
15
+ spec/reports
16
+ test/tmp
17
+ test/version_tmp
18
+ tmp
19
+ bin/
20
+ .DS_Store
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --color
2
+ --warnings
3
+ --require spec_helper
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ ruby-2.4.0
data/.travis.yml ADDED
@@ -0,0 +1,15 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.4.0
4
+ - 2.3.3
5
+ script: rspec spec
6
+ addons:
7
+ code_climate:
8
+ repo_token:
9
+ secure: MYIsQJ3/wQ6xBYaWCwgG1HRyrH7MH4vME+ACEbM9poMun6jgvFu7Unc0eGpjMxzytophN5o7j0LTc6xxNCMCz6UGFK8Y7RP9/fii6bLFdqROS7jrxYf6tFwKXO4bAhhOZdZjyuYEFiRxImNHPXka+ap4vOnP/QW3D8l94lrAyoM=
10
+ after_success:
11
+ - bundle exec codeclimate-test-reporter
12
+ env:
13
+ global:
14
+ - secure: NOH9DBJdldYSVadf2zAYPtP7Nke3k4rdrsXv2uBLelHwuZhmrRRprdgM2h3igheiq2j/OcbZSZeNgLMWY06A+RhxQzUOKUDBFcUs9QL23xgKFZcRi3YNqhhLC/LRXo4gmpL4J7OFJqMySTlaIWHRFqLJoFdoHTut3YKAChea4xE=
15
+ - secure: KQ/hQWZ1UTkbrfBUqy5qU/tw1YVpPSNtMnsNuammiBq9xJL2hkwIBiOwKmnC6rb48KhkCGCSmKU1CLvsqmAEncwF8vBXzrFPgQdg7JQN9Wn0gb2ESCnhfIP0rFfoKLZI9YVP3SB8YsfODlfNJwjKhAqsI6mCoQ/jN7yX8bvfnlM=
data/Gemfile ADDED
@@ -0,0 +1,10 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ group :test do
6
+ gem "simplecov"
7
+ gem "codeclimate-test-reporter", "~> 1.0.0"
8
+ gem "pry"
9
+ end
10
+
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Joel Junström
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,124 @@
1
+ [![Build Status](https://travis-ci.org/Oktavilla/egree-ruby.svg?branch=master)](https://travis-ci.org/Oktavilla/egree-ruby)
2
+ [![Code Climate](https://codeclimate.com/github/Oktavilla/egree-ruby/badges/gpa.svg)](https://codeclimate.com/github/Oktavilla/egree-ruby)
3
+ [![Test Coverage](https://codeclimate.com/github/Oktavilla/egree-ruby/badges/coverage.svg)](https://codeclimate.com/github/Oktavilla/egree-ruby)
4
+ [![Gem Version](https://badge.fury.io/rb/egree.svg)](http://badge.fury.io/rb/egree)
5
+
6
+ # Assently API Client
7
+
8
+ Ruby client for the [Assently API v2](https://assently.com/). Check out [the official API documentation here](https://app.assently.com/api/).
9
+
10
+ ### Supported API calls
11
+
12
+ | API call | Supported |
13
+ |----------|:-------------:|
14
+ | `createcase` | ✔️ |
15
+ | `sendcase` | ✔️|
16
+ | `getcase` | ✔️|
17
+ | `createcasefromtemplate ` | |
18
+ | `updatecase ` | |
19
+ | `remindcase ` | |
20
+ | `deletecase ` | |
21
+ | `recallcase ` | |
22
+ | `findcases ` | |
23
+ | `findtemplates ` | |
24
+ | `getdocumentdata ` | |
25
+ | `createagent ` | |
26
+ | `createssoticket ` | |
27
+
28
+ Missing something? Contributions are very welcome! 😘
29
+
30
+ ## Installation
31
+
32
+ Include the gem in your `Gemfile`:
33
+
34
+ ```ruby
35
+ gem "assently"
36
+ ```
37
+
38
+ ## Usage
39
+
40
+ ### Environment
41
+
42
+ When creating a client instance you can choose to use either Assently's `production` (default when not specified) or `test` environment. The host `app.assently.com` is used for production and `test.assently.com` is used for test when constructing the API commands. Test environment is specified like this:
43
+
44
+ ```ruby
45
+ Assently.client ENV["ASSENTLY_API_KEY"], ENV["ASSENTLY_API_SECRET"], :test
46
+ ```
47
+
48
+ ### Creating a case
49
+
50
+ ```ruby
51
+ assently = Assently.client assently_api_key, assently_api_secret
52
+
53
+ case_id = SecureRandom.uuid
54
+
55
+ signature_case = Assently::Case.new "Agreement", ["electronicid"], id: case_id
56
+ signature_case.add_party Assently::Party.new_with_attributes({
57
+ name: "First Last",
58
+ email: "name@example.com",
59
+ social_security_number: "1234567890"
60
+ })
61
+ signature_case.add_document Assently::Document.new "/some/path/file.pdf"
62
+
63
+ event_subscription = Assently::CaseEventSubscription.new ["finished", "expired"], "https://example.com/my-endpoint"
64
+
65
+ result = assently.create_case(signature_case, {
66
+ # Callback for document events
67
+ event_callback: event_subscription,
68
+ # User ends up here after finishing the signing process
69
+ continue: {
70
+ url: "http://example.com/user-endpoint",
71
+ auto: true
72
+ },
73
+ # User ends up here when cancelling, at the moment there is no cancel callback
74
+ cancel_url: "http://example.com/user-canceled"
75
+ })
76
+
77
+ if result.success?
78
+ puts "#{signature_case.id} was created."
79
+ else
80
+ puts "There was some issues with the case"
81
+ result.errors.each do |error|
82
+ puts error
83
+ end
84
+ end
85
+ ```
86
+
87
+ ### Making a case available for signing
88
+
89
+ ```ruby
90
+ assently = Assently.client API_KEY, API_SECRET
91
+ result = assently.get_case case_id
92
+
93
+ if result.success?
94
+ assently.send_case case_id
95
+
96
+ signing_case = assently.get_case case_id
97
+
98
+ puts "Sign it here: #{signing_case.response["Parties"].first["PartyUrl"]}"
99
+ else
100
+ puts "Could not get signature url"
101
+ result.errors.each do |error|
102
+ puts error
103
+ end
104
+ end
105
+ ```
106
+
107
+ ### Local development
108
+
109
+ Create a `.env` file in the root directory to run the integration tests against your Assently test environment.
110
+
111
+ ```sh
112
+ ASSENTLY_API_KEY=your-api-key
113
+ ASSENTLY_API_KEY=your-api-secret
114
+ ```
115
+
116
+
117
+ ## Contributing
118
+
119
+ Contributions is more than welcome!
120
+
121
+ Just create a fork and submit a pull request.
122
+
123
+ Please adhere to the coding standards used in the project and add tests.
124
+
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/assently.gemspec ADDED
@@ -0,0 +1,31 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'assently/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "assently"
8
+ spec.version = Assently::VERSION
9
+ spec.authors = ["Joel Junström"]
10
+ spec.email = ["joel.junstrom@oktavilla.se"]
11
+ spec.summary = %q{Client for the Assently APIv2}
12
+ spec.homepage = "https://github.com/Oktavilla/egree-ruby"
13
+ spec.license = "MIT"
14
+
15
+ spec.required_ruby_version = "~> 2.0"
16
+
17
+ spec.files = `git ls-files -z`.split("\x0")
18
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
19
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
20
+ spec.require_paths = ["lib"]
21
+
22
+ spec.add_dependency "http", "~> 2.2"
23
+
24
+ spec.add_development_dependency "bundler", "~> 1.14"
25
+ spec.add_development_dependency "dotenv", "~> 2.1"
26
+ spec.add_development_dependency "rake"
27
+ spec.add_development_dependency "rspec"
28
+ spec.add_development_dependency "webmock", "~> 2.3"
29
+ spec.add_development_dependency "vcr", "~> 3.0"
30
+ spec.add_development_dependency "luhn", "~> 1.0"
31
+ end
@@ -0,0 +1,12 @@
1
+ module Assently
2
+ module ApiMappers
3
+ module CaseEventSubscriptionMapper
4
+ def self.to_api case_event_subscription
5
+ {
6
+ "Events" => case_event_subscription.events,
7
+ "Url" => case_event_subscription.url
8
+ }
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,23 @@
1
+ require "json"
2
+ require "assently/api_mappers/party_mapper"
3
+ require "assently/api_mappers/document_mapper"
4
+
5
+ module Assently
6
+ module ApiMappers
7
+ module CaseMapper
8
+ def self.to_api signature_case
9
+ {
10
+ "Id" => signature_case.id,
11
+ "Name" => signature_case.name,
12
+ "Documents" => signature_case.documents.map { |document|
13
+ Assently::ApiMappers::DocumentMapper.to_api(document)
14
+ },
15
+ "Parties" => signature_case.parties.map { |party|
16
+ Assently::ApiMappers::PartyMapper.to_api(party)
17
+ },
18
+ "AllowedSignatureTypes" => signature_case.signature_types
19
+ }
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,74 @@
1
+ require "assently/api_mappers/case_event_subscription_mapper"
2
+
3
+ module Assently
4
+ class InvalidCaseOptionError < ArgumentError; end
5
+
6
+ module ApiMappers
7
+ module CaseOptionsMapper
8
+ def self.to_api options = {}, mappers = self.mappers
9
+ options.reduce({}) do |api_hash, (client_key, value)|
10
+ if mappers.key?(client_key)
11
+ api_hash.merge(self.map(client_key, value, mappers))
12
+ else
13
+ api_hash
14
+ end
15
+ end || {}
16
+ end
17
+
18
+ private
19
+
20
+ LOCALES = ->(locale) {
21
+ {
22
+ "sv" => "sv-SE",
23
+ "fi" => "fi-FI",
24
+ "en" => "en-US"
25
+ }.fetch(locale) { raise Assently::InvalidCaseOptionError.new("Unknown locale: #{locale}") }
26
+ }
27
+
28
+ def self.map client_key, value, mappers = self.mappers
29
+ mapper = mappers[client_key]
30
+
31
+ if mapper.respond_to?(:call)
32
+ mapper.call value
33
+ else
34
+ { mapper => value }
35
+ end
36
+ end
37
+
38
+ def self.mappers
39
+ {
40
+ name_alias: "NameAlias",
41
+ agent_username: "AgentUsername",
42
+ visibility: "Visibility",
43
+ description: "Description",
44
+ send_sign_request_email_to_parties: "SendSignRequestEmailToParties",
45
+ send_finish_email_to_creator: "SendFinishEmailToCreator",
46
+ send_finish_email_to_parties: "SendFinishEmailToParties",
47
+ send_recall_email_to_parties: "SendRecallEmailToParties",
48
+ cancel_url: "CancelUrl",
49
+ procedure: "Procedure",
50
+ locale: ->(value) {
51
+ { "Culture" => LOCALES.call(value) }
52
+ },
53
+ continue: ->(options) {
54
+ CaseOptionsMapper.to_api options, name: "ContinueName", url: "ContinueUrl", auto: "ContinueAuto"
55
+ },
56
+ sign_in_sequence: "SignInSequence",
57
+ identity_check: "IdentityCheck",
58
+ merge_on_send: "MergeOnSend",
59
+ expire_after_days: "ExpireAfterDays",
60
+ expire_on: ->(value) {
61
+ { "ExpireOn" => value.iso8601 }
62
+ },
63
+ remind_ander_days: "RemindAfterDays",
64
+ template_id: "TemplateId",
65
+ is_editable: "IsEditable",
66
+ event_callback: ->(value) {
67
+ { "EventCallback" => CaseEventSubscriptionMapper.to_api(value) }
68
+ },
69
+ meta_data: "MetaData"
70
+ }
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,19 @@
1
+ require "assently/api_mappers/form_field_mapper"
2
+
3
+ module Assently
4
+ module ApiMappers
5
+ module DocumentMapper
6
+ def self.to_api document
7
+ {
8
+ "Filename" => document.filename,
9
+ "Data" => document.data,
10
+ "ContentType" => document.content_type,
11
+ "Size" => document.size,
12
+ "FormFields" => document.form_fields.map { |form_field|
13
+ Assently::ApiMappers::FormFieldMapper.to_api(form_field)
14
+ }
15
+ }
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,12 @@
1
+ module Assently
2
+ module ApiMappers
3
+ module FormFieldMapper
4
+ def self.to_api form_field
5
+ {
6
+ "Name" => form_field.name,
7
+ "Value" => form_field.value
8
+ }
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,13 @@
1
+ module Assently
2
+ module ApiMappers
3
+ module PartyMapper
4
+ def self.to_api party
5
+ {
6
+ "Name" => party.name,
7
+ "EmailAddress" => party.email,
8
+ "SocialSecurityNumber" => party.social_security_number
9
+ }
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,50 @@
1
+ require "assently/id_generator"
2
+
3
+ module Assently
4
+ class Case
5
+ def self.signature_types
6
+ [ "sms", "electronicid", "touch", "quickintent", "signbyhand" ]
7
+ end
8
+
9
+ attr_reader :name, :signature_types, :id
10
+
11
+ def initialize name, signature_types, id: nil
12
+ @name = name
13
+ @id = id || IdGenerator.generate
14
+ self.signature_types = signature_types
15
+ end
16
+
17
+ def signature_types= signature_types
18
+ types = Array(signature_types)
19
+
20
+ unknown_types = types - Case.signature_types
21
+ if unknown_types.any?
22
+ raise unknown_signature_type_error(unknown_types)
23
+ end
24
+
25
+ @signature_types = types
26
+ end
27
+
28
+ def add_party party
29
+ self.parties << party
30
+ end
31
+
32
+ def parties
33
+ @parties ||= []
34
+ end
35
+
36
+ def add_document document
37
+ self.documents << document
38
+ end
39
+
40
+ def documents
41
+ @documents ||= []
42
+ end
43
+
44
+ private
45
+
46
+ def unknown_signature_type_error types
47
+ ArgumentError.new("Unknown signature types: #{types.join(", ")}. Valid types are: #{Case.signature_types.join(", ")}")
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,29 @@
1
+ module Assently
2
+ class CaseEventSubscription
3
+ attr_reader :events, :url
4
+
5
+ def self.events
6
+ [ "created", "sent", "recalled", "finished", "rejected", "expired", "deleted", "signatureadded", "approvalrequested", "reminded" ]
7
+ end
8
+
9
+ def initialize(events, url)
10
+ self.events = events
11
+ @url = url
12
+ end
13
+
14
+ def events= events
15
+ unknown_events = events - CaseEventSubscription.events
16
+ if unknown_events.any?
17
+ raise unknown_event_error(unknown_events)
18
+ end
19
+
20
+ @events = events
21
+ end
22
+
23
+ private
24
+
25
+ def unknown_event_error events
26
+ ArgumentError.new("Unknown events: #{events.join(", ")}. Valid events are: #{CaseEventSubscription.events.join(", ")}")
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,129 @@
1
+ require "json"
2
+ require "http"
3
+
4
+ require "assently/serializers/case_serializer"
5
+
6
+ module Assently
7
+ class Client
8
+ attr_reader :api_key, :api_secret
9
+
10
+ attr_accessor :environment
11
+
12
+ def initialize api_key, api_secret, environment = :production
13
+ @api_key = api_key
14
+ @api_secret = api_secret
15
+ self.environment = environment
16
+ end
17
+
18
+ def create_case signature_case, options = {}
19
+ signature_case_json = Assently::Serializers::CaseSerializer.serialize signature_case, options
20
+
21
+ post "/api/v2/createcase", signature_case_json
22
+ end
23
+
24
+ def send_case id
25
+ post "/api/v2/sendcase", JSON.pretty_generate({ id: id })
26
+ end
27
+
28
+ def get_case id
29
+ get "/api/v2/getcase", { id: id }
30
+ end
31
+
32
+ def post api_command, body = nil
33
+ make_response make_post(api_command, body)
34
+ end
35
+
36
+ def get api_command, parameters = {}
37
+ make_response make_get(api_command, parameters)
38
+ end
39
+
40
+ def host
41
+ hosts.fetch(self.environment, hosts[:production])
42
+ end
43
+
44
+ def connection
45
+ HTTP.
46
+ headers(accept: "application/json").
47
+ basic_auth(user: api_key, pass: api_secret)
48
+ end
49
+
50
+ def headers
51
+ connection.headers
52
+ end
53
+
54
+ private
55
+
56
+ def api_base_url
57
+ "https://#{host}"
58
+ end
59
+
60
+ def api_url path
61
+ URI.join(api_base_url, path)
62
+ end
63
+
64
+ def make_response response
65
+ if response.status.success?
66
+ SuccessResult.new response.body.to_s
67
+ else
68
+ ErrorResult.new response.body.to_s
69
+ end
70
+ end
71
+
72
+ def make_post path, body
73
+ connection.
74
+ headers(content_type: "application/json; charset=utf-8").
75
+ post api_url(path), body: body
76
+ end
77
+
78
+ def make_get path, parameters
79
+ connection.get api_url(path), params: parameters
80
+ end
81
+
82
+ def hosts
83
+ {
84
+ production: "app.assently.com",
85
+ test: "test.assently.com"
86
+ }
87
+ end
88
+
89
+ class SuccessResult
90
+ attr_reader :raw
91
+
92
+ def initialize response
93
+ @raw = response
94
+ end
95
+
96
+ def response
97
+ begin
98
+ JSON.parse raw
99
+ rescue JSON::ParserError
100
+ raw
101
+ end
102
+ end
103
+
104
+ def success?
105
+ true
106
+ end
107
+ end
108
+
109
+ class ErrorResult
110
+ attr_reader :raw
111
+
112
+ def initialize response
113
+ @raw = response
114
+ end
115
+
116
+ def errors
117
+ begin
118
+ Array(JSON.parse(raw)["error"].values.join(" "))
119
+ rescue JSON::ParserError
120
+ raw
121
+ end
122
+ end
123
+
124
+ def success?
125
+ false
126
+ end
127
+ end
128
+ end
129
+ end
@@ -0,0 +1,64 @@
1
+ require "open-uri"
2
+ require "base64"
3
+
4
+ module Assently
5
+ class CouldNotFetchDocumentError < StandardError
6
+ end
7
+
8
+ class Document
9
+ attr_reader :path, :username, :password
10
+
11
+ def initialize path, filename: nil, username: nil, password: nil
12
+ @path = path
13
+ @filename = filename
14
+ @username = username
15
+ @password = password
16
+ end
17
+
18
+ def filename
19
+ @filename || File.basename(path)
20
+ end
21
+
22
+ def size
23
+ file.size
24
+ end
25
+
26
+ def content_type
27
+ "application/pdf"
28
+ end
29
+
30
+ def data
31
+ Base64.encode64 file_contents
32
+ end
33
+
34
+ def add_form_field form_field
35
+ self.form_fields << form_field
36
+ end
37
+
38
+ def form_fields
39
+ @form_fields ||= []
40
+ end
41
+
42
+ private
43
+
44
+ def file_contents
45
+ file.read
46
+ end
47
+
48
+ def file
49
+ begin
50
+ open path, authentication_params
51
+ rescue OpenURI::HTTPError => error
52
+ raise Assently::CouldNotFetchDocumentError.new("Could not get url #{path} (#{error.message})")
53
+ end
54
+ end
55
+
56
+ def authentication_params
57
+ if username && password
58
+ { http_basic_authentication: [ username, password ] }
59
+ else
60
+ {}
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,3 @@
1
+ module Assently
2
+ FormField = Struct.new :name, :value
3
+ end