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
@@ -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
+