assently 1.0.0.beta1

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.
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
@@ -0,0 +1,10 @@
1
+ require "securerandom"
2
+
3
+ module Assently
4
+ class IdGenerator
5
+
6
+ def self.generate
7
+ SecureRandom.uuid
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,21 @@
1
+ module Assently
2
+ class Party
3
+ attr_accessor :name, :email
4
+ attr_reader :social_security_number
5
+
6
+ def self.new_with_attributes attributes = {}
7
+ party = self.new
8
+
9
+ attributes.each do |name, value|
10
+ assignment_method_name = "#{name}="
11
+ party.public_send(assignment_method_name, value) if party.respond_to?(assignment_method_name)
12
+ end
13
+
14
+ party
15
+ end
16
+
17
+ def social_security_number= social_security_number
18
+ @social_security_number = social_security_number.to_s.gsub(/\D/, "")
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,15 @@
1
+ require "json"
2
+ require "assently/api_mappers/case_mapper"
3
+ require "assently/api_mappers/case_options_mapper"
4
+
5
+ module Assently
6
+ module Serializers
7
+ module CaseSerializer
8
+ def self.serialize signature_case, options = {}
9
+ signature_case_api_hash = Assently::ApiMappers::CaseMapper.to_api signature_case
10
+ options_api_hash = Assently::ApiMappers::CaseOptionsMapper.to_api options
11
+ JSON.pretty_generate signature_case_api_hash.merge(options_api_hash)
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,3 @@
1
+ module Assently
2
+ VERSION = "1.0.0.beta1"
3
+ end
data/lib/assently.rb ADDED
@@ -0,0 +1,14 @@
1
+ require "assently/case"
2
+ require "assently/client"
3
+ require "assently/document"
4
+ require "assently/form_field"
5
+ require "assently/party"
6
+ require "assently/id_generator"
7
+ require "assently/version"
8
+ require "assently/case_event_subscription"
9
+
10
+ module Assently
11
+ def self.client api_key, api_secret, environment = :production
12
+ Client.new api_key, api_secret, environment
13
+ end
14
+ end
@@ -0,0 +1,23 @@
1
+ require "spec_helper"
2
+ require "assently/case_event_subscription"
3
+ require "assently/api_mappers/case_event_subscription_mapper"
4
+
5
+ module Assently
6
+ module ApiMappers
7
+ RSpec.describe CaseEventSubscriptionMapper do
8
+ describe ".to_api" do
9
+ it "creates a hash that matches the api's expected format" do
10
+ case_event_subscription = CaseEventSubscription.new(
11
+ ["created", "sent"],
12
+ "http://example.com"
13
+ )
14
+
15
+ expect(CaseEventSubscriptionMapper.to_api(case_event_subscription)).to eq({
16
+ "Events" => ["created", "sent"],
17
+ "Url" => "http://example.com"
18
+ })
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,34 @@
1
+ require "spec_helper"
2
+
3
+ require "assently/case"
4
+ require "assently/api_mappers/case_mapper"
5
+
6
+ module Assently
7
+ module ApiMappers
8
+ RSpec.describe CaseMapper do
9
+ describe "#to_api" do
10
+ it "maps the case into an has that complies with the expected format" do
11
+ party = double "Party"
12
+ document = double "Document"
13
+
14
+ signature_case = Assently::Case.new "Agreement", ["electronicid"]
15
+ signature_case.add_party party
16
+ signature_case.add_document document
17
+
18
+ expect(Assently::ApiMappers::PartyMapper).to receive(:to_api).with(party).and_return(party: "on")
19
+ expect(Assently::ApiMappers::DocumentMapper).to receive(:to_api).with(document).and_return(document: "on")
20
+
21
+ api_hash = CaseMapper.to_api signature_case
22
+
23
+ expect(api_hash).to eq({
24
+ "Id" => signature_case.id,
25
+ "Name" => "Agreement",
26
+ "Documents" => [{ document: "on" }],
27
+ "Parties" => [{ party: "on" }],
28
+ "AllowedSignatureTypes" => ["electronicid"]
29
+ })
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,92 @@
1
+ require "spec_helper"
2
+ require "assently/api_mappers/case_options_mapper"
3
+
4
+ module Assently
5
+ module ApiMappers
6
+ RSpec.describe CaseOptionsMapper do
7
+ describe "#to_api" do
8
+ it "translates event_callback to EventCallback object" do
9
+ event_callback = double "CaseEventSubscription", events: ["finished"], url: "http://example.com"
10
+ event_callback_representation = {
11
+ "EventCallback" => {
12
+ "Events" => ["finished"],
13
+ "Url" => "http://example.com"
14
+ }
15
+ }
16
+ expect(CaseOptionsMapper.to_api(event_callback: event_callback)).to eq(event_callback_representation)
17
+ end
18
+
19
+ it "translates cancel_url to CancelUrl" do
20
+ expect(CaseOptionsMapper.to_api(cancel_url: "http://example.com")).to eq({
21
+ "CancelUrl" => "http://example.com"
22
+ })
23
+ end
24
+
25
+ it "translates procedure to Procedure" do
26
+ expect(CaseOptionsMapper.to_api(procedure: "form")).to eq({
27
+ "Procedure" => "form"
28
+ })
29
+ end
30
+
31
+ describe "locale" do
32
+ it "translates locale to Culture allowing sv, fi and en" do
33
+ { "sv" => "sv-SE", "fi" => "fi-FI", "en" => "en-US" }.each do |key, locale|
34
+ expect(CaseOptionsMapper.to_api(locale: key)).to eq({
35
+ "Culture" => locale
36
+ })
37
+ end
38
+ end
39
+
40
+ it "raises an InvalidCaseOptionError for unkown locales" do
41
+ expect{ CaseOptionsMapper.to_api(locale: "unknown") }.to raise_error{
42
+ Assently::InvalidCaseOptionError
43
+ }
44
+ end
45
+ end
46
+
47
+ describe "continue" do
48
+ it "translates name" do
49
+ options = { continue: { name: "The label" } }
50
+
51
+ expect(CaseOptionsMapper.to_api(options)).to eq({
52
+ "ContinueName" => "The label"
53
+ })
54
+ end
55
+
56
+ it "translates url" do
57
+ options = { continue: { url: "http://example.com/where-to-go" } }
58
+
59
+ expect(CaseOptionsMapper.to_api(options)).to eq({
60
+ "ContinueUrl" => "http://example.com/where-to-go"
61
+ })
62
+ end
63
+
64
+ it "translates auto" do
65
+ options = { continue: { auto: true } }
66
+
67
+ expect(CaseOptionsMapper.to_api(options)).to eq({
68
+ "ContinueAuto" => true
69
+ })
70
+ end
71
+ end
72
+
73
+ it "ignores unknown keys" do
74
+ expect(CaseOptionsMapper.to_api({
75
+ locale: "sv",
76
+ unknown: "Some value"
77
+ })).to eq({
78
+ "Culture" => "sv-SE"
79
+ })
80
+ end
81
+ end
82
+
83
+ it "formats expire on date" do
84
+ expire_date = DateTime.new 2017,1,31
85
+
86
+ expect(CaseOptionsMapper.to_api({ expire_on: expire_date })).to eq({
87
+ "ExpireOn" => "2017-01-31T00:00:00+00:00"
88
+ })
89
+ end
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,35 @@
1
+ require "spec_helper"
2
+ require "assently/api_mappers/document_mapper"
3
+
4
+ module Assently
5
+ module ApiMappers
6
+ RSpec.describe DocumentMapper do
7
+ describe ".to_api" do
8
+ it "creates a hash that matches the api's expected format" do
9
+ form_field = double "FormField"
10
+
11
+ document = double("Document", {
12
+ filename: "agreement.pdf",
13
+ size: 123,
14
+ data: "encoded-data",
15
+ content_type: "application/pdf",
16
+ form_fields: [form_field]
17
+ })
18
+
19
+ expect(Assently::ApiMappers::FormFieldMapper).to receive(:to_api).with(form_field).and_return({
20
+ name: "FieldKey",
21
+ value: "FieldValue"
22
+ })
23
+
24
+ expect(DocumentMapper.to_api(document)).to eq({
25
+ "Filename" => "agreement.pdf",
26
+ "Data" => "encoded-data",
27
+ "ContentType" => "application/pdf",
28
+ "Size" => 123,
29
+ "FormFields" => [{ name: "FieldKey", value: "FieldValue" }]
30
+ })
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,19 @@
1
+ require "spec_helper"
2
+
3
+ require "assently/api_mappers/form_field_mapper"
4
+ require "assently/form_field"
5
+
6
+ module Assently
7
+ module ApiMappers
8
+ RSpec.describe FormFieldMapper do
9
+ specify ".to_api" do
10
+ form_field = Assently::FormField.new "The name", "The Value"
11
+
12
+ expect(FormFieldMapper.to_api(form_field)).to eq({
13
+ "Name" => "The name",
14
+ "Value" => "The Value"
15
+ })
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,24 @@
1
+ require "spec_helper"
2
+ require "assently/api_mappers/party_mapper"
3
+
4
+ module Assently
5
+ module ApiMappers
6
+ RSpec.describe PartyMapper do
7
+ describe ".to_api" do
8
+ it "creates a hash that matches the api's expected format" do
9
+ party = double("Party", {
10
+ name: "First Last",
11
+ email: "first-last@example.com",
12
+ social_security_number: "1234567890"
13
+ })
14
+
15
+ expect(PartyMapper.to_api(party)).to eq({
16
+ "Name" => "First Last",
17
+ "EmailAddress" => "first-last@example.com",
18
+ "SocialSecurityNumber" => "1234567890"
19
+ })
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,18 @@
1
+ require "spec_helper"
2
+ require "assently/case_event_subscription"
3
+
4
+ module Assently
5
+ RSpec.describe CaseEventSubscription do
6
+ describe "events" do
7
+ it "accepts a valid event" do
8
+ case_event_subscription = CaseEventSubscription.new([CaseEventSubscription.events.first], 'http://test.com')
9
+
10
+ expect(case_event_subscription.events.first).to eq(CaseEventSubscription.events.first)
11
+ end
12
+
13
+ it "throws an error if it is an unknown event" do |variable|
14
+ expect{ CaseEventSubscription.new(['invalid_event'], 'http://test.com') }.to raise_error(ArgumentError)
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,68 @@
1
+ require "spec_helper"
2
+ require "assently/case"
3
+
4
+ module Assently
5
+ RSpec.describe Case do
6
+ let :signature_case do
7
+ Case.new "Agreement", Case.signature_types
8
+ end
9
+
10
+ it "requires a name" do
11
+ expect(signature_case.name).to eq "Agreement"
12
+ end
13
+
14
+ describe "#id" do
15
+ it "creates a unique id" do
16
+ expect(Assently::IdGenerator).to receive(:generate).and_return "very-random"
17
+
18
+ expect(signature_case.id).to eq "very-random"
19
+ end
20
+
21
+ it "does not change the id after created" do
22
+ last_id = signature_case.id
23
+
24
+ expect(signature_case.id).to eq last_id
25
+ end
26
+
27
+ it "does not share id between instances" do
28
+ expect(signature_case.id).to_not eq Case.new("Agreement", Case.signature_types).id
29
+ end
30
+
31
+ it "can be overwritten on initialize" do
32
+ signature_case = Case.new "Agreement", Case.signature_types, id: "my-special-id"
33
+
34
+ expect(signature_case.id).to eq "my-special-id"
35
+ end
36
+ end
37
+
38
+ describe "signature types" do
39
+ it "requires at least one valid signature type" do
40
+ signature_case = Case.new "Agreement", Case.signature_types.first
41
+
42
+ expect(signature_case.signature_types).to eq [ Case.signature_types.first ]
43
+ end
44
+
45
+ it "throws an error if it is an unknown signature type" do
46
+ expect{ Case.new("Agreement", "unknown type") }.to raise_error(ArgumentError)
47
+ end
48
+ end
49
+
50
+ it "adds a party" do
51
+ signature_case = Case.new "Agreement", Case.signature_types
52
+
53
+ party = double "Party"
54
+ signature_case.add_party party
55
+
56
+ expect(signature_case.parties).to eq [party]
57
+ end
58
+
59
+ it "adds a document" do
60
+ signature_case = Case.new "Agreement", Case.signature_types
61
+
62
+ document = double "Document"
63
+ signature_case.add_document document
64
+
65
+ expect(signature_case.documents).to eq [document]
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,55 @@
1
+ require "luhn"
2
+ require "spec_helper"
3
+
4
+ require "assently/client"
5
+ require "assently/case"
6
+ require "assently/document"
7
+ require "assently/party"
8
+
9
+ module Assently
10
+ describe Assently::Client do
11
+ describe "#create_case" do
12
+ let :client do
13
+ Assently::Client.new ENV["ASSENTLY_API_KEY"], ENV["ASSENTLY_API_KEY"], :test
14
+ end
15
+
16
+ it "sends the create case command with a json representation of the case" do
17
+ allow(client).to receive :post
18
+
19
+ signature_case = double "Case"
20
+ options = { locale: "sv" }
21
+
22
+ expect(Assently::Serializers::CaseSerializer).to receive(:serialize).with(signature_case, options).and_return "case-json"
23
+
24
+ client.create_case signature_case, options
25
+
26
+ expect(client).to have_received(:post).with "/api/v2/createcase", "case-json"
27
+ end
28
+
29
+ describe "with a valid case", vcr: { cassette_name: "Assently_Client/_create_case/valid_case" } do
30
+ it "returns a successful result object" do
31
+ signature_case = Assently::Case.new "Agreement", ["touch"]
32
+ signature_case.add_party Assently::Party.new_with_attributes({
33
+ name: "First Last",
34
+ email: "name@example.com",
35
+ social_security_number: Luhn::CivicNumber.generate
36
+ })
37
+ signature_case.add_document Assently::Document.new(File.join(Dir.pwd, "spec/fixtures/agreement.pdf"))
38
+
39
+ result = client.create_case(signature_case, {
40
+ continue: {
41
+ name: "Back to the site",
42
+ url: "http://example.com/thanks",
43
+ auto: true
44
+ },
45
+ cancel_url: "http://example.com/sorry",
46
+ procedure: "form",
47
+ locale: "sv"
48
+ })
49
+
50
+ expect(result.success?).to be true
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,84 @@
1
+ require "luhn"
2
+ require "securerandom"
3
+ require "spec_helper"
4
+
5
+ require "assently/client"
6
+ require "assently/case"
7
+ require "assently/document"
8
+ require "assently/party"
9
+
10
+ module Assently
11
+ describe Assently::Client do
12
+ let :client do
13
+ Assently::Client.new ENV["ASSENTLY_API_KEY"], ENV["ASSENTLY_API_SECRET"], :test
14
+ end
15
+
16
+ describe "#get_case" do
17
+ describe "with a case_id as argument" do
18
+ it "sends the getcase query with the case id json" do
19
+ allow(client).to receive :get
20
+
21
+ case_id = SecureRandom.uuid
22
+
23
+ client.get_case case_id
24
+
25
+ expect(client).to have_received(:get).with "/api/v2/getcase", id: case_id
26
+ end
27
+ end
28
+
29
+ describe "when the case exists", vcr: { cassette_name: "Assently_Client/_get_case/case_exists" } do
30
+ let (:case_id) { "my-case-id" }
31
+
32
+ before do
33
+ create_case case_id
34
+ end
35
+
36
+ describe "result" do
37
+ it "is successful" do
38
+ result = client.get_case case_id
39
+
40
+ expect(result.success?).to be true
41
+ end
42
+
43
+ it "has the url" do
44
+ result = client.get_case case_id
45
+
46
+ expect(result).to be_a Assently::Client::SuccessResult
47
+ expect(result.response["Parties"].first["PartyUrl"]).to match(/\Ahttps:\/\/test.assently.com\/c\/.*\z/)
48
+ end
49
+ end
50
+ end
51
+
52
+ describe "when there is no matching case" do
53
+ describe "result", vcr: { cassette_name: "Assently_Client/_get_case/case_missing" } do
54
+ it "is not successfull" do
55
+ result = client.get_case "missing-case"
56
+
57
+ expect(result.success?).to be false
58
+ end
59
+
60
+ it "has the error" do
61
+ result = client.get_case "missing-case"
62
+
63
+ expect(result.errors[0]).to eq "EX404 Not Found Request parameters may not be well formed"
64
+ end
65
+ end
66
+ end
67
+ end
68
+
69
+ private
70
+
71
+ def create_case case_id = nil
72
+ signature_case = Assently::Case.new "Agreement", ["touch"], id: case_id
73
+ signature_case.add_party Assently::Party.new_with_attributes({
74
+ name: "First Last",
75
+ email: "name@example.com",
76
+ social_security_number: Luhn::CivicNumber.generate
77
+ })
78
+ signature_case.add_document Assently::Document.new(File.join(Dir.pwd, "spec/fixtures/agreement.pdf"))
79
+
80
+ client.create_case signature_case
81
+ end
82
+ end
83
+ end
84
+