rightsignature-railstyle 1.1.9
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.
- checksums.yaml +7 -0
- data/.gitignore +8 -0
- data/CONTRIBUTING.md +26 -0
- data/Gemfile +2 -0
- data/README.md +443 -0
- data/Rakefile +2 -0
- data/lib/rightsignature.rb +15 -0
- data/lib/rightsignature/account.rb +37 -0
- data/lib/rightsignature/connection.rb +207 -0
- data/lib/rightsignature/connection/oauth_connection.rb +109 -0
- data/lib/rightsignature/connection/token_connection.rb +36 -0
- data/lib/rightsignature/document.rb +333 -0
- data/lib/rightsignature/errors.rb +51 -0
- data/lib/rightsignature/helpers/normalizing.rb +137 -0
- data/lib/rightsignature/helpers/refine_hash_to_indifferent_access.rb +23 -0
- data/lib/rightsignature/rails_style.rb +89 -0
- data/lib/rightsignature/template.rb +299 -0
- data/lib/rightsignature/version.rb +3 -0
- data/rightsignature-api.gemspec +26 -0
- data/spec/account_spec.rb +54 -0
- data/spec/api_token_connection_spec.rb +27 -0
- data/spec/configuration_spec.rb +98 -0
- data/spec/connection_spec.rb +224 -0
- data/spec/document_spec.rb +301 -0
- data/spec/errors_spec.rb +153 -0
- data/spec/normalizing_spec.rb +85 -0
- data/spec/oauth_connnection_spec.rb +143 -0
- data/spec/rails_style_spec.rb +331 -0
- data/spec/spec_helper.rb +12 -0
- data/spec/template_spec.rb +408 -0
- metadata +143 -0
@@ -0,0 +1,51 @@
|
|
1
|
+
module RightSignature
|
2
|
+
class ResponseError < Exception
|
3
|
+
attr_reader :response
|
4
|
+
|
5
|
+
# Creates new instance of RightSignature::ResponseError to make API calls
|
6
|
+
# * <b>response</b>: Net::HTTP response or HTTParty response
|
7
|
+
# * <b>message</b>: (Optional) Custom error message
|
8
|
+
#
|
9
|
+
def initialize(response, message=nil)
|
10
|
+
self.set_backtrace(caller[1..-1]) if self.backtrace.nil?
|
11
|
+
@response = response
|
12
|
+
super((message || @response.message))
|
13
|
+
end
|
14
|
+
|
15
|
+
# returns HTTP Code from response
|
16
|
+
def code
|
17
|
+
@response.code
|
18
|
+
end
|
19
|
+
|
20
|
+
# Suggestions on how to resolve a certain error
|
21
|
+
def common_solutions
|
22
|
+
if @response.code.to_i == 406
|
23
|
+
"Check the Content-Type and makes sure it's the correct type (usually application/json or application/xml), ensure url has .xml or .json at the end, check 'Accept' header to allow xml or json ('*/*' for anything)"
|
24
|
+
elsif @response.code.to_i == 401
|
25
|
+
"Check your credentials and make sure they are correct and not expired"
|
26
|
+
elsif @response.code.to_i >= 500 && @response.code.to_i < 600
|
27
|
+
"Check the format of your xml or json"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# Attempts to parse an error message from the response body
|
32
|
+
def detailed_message
|
33
|
+
if @response.is_a? Net::HTTPResponse
|
34
|
+
parsed_response = MultiXml.parse(@response.body)
|
35
|
+
|
36
|
+
parsed_response["error"]["message"] if parsed_response && parsed_response["error"]
|
37
|
+
else
|
38
|
+
if @response.parsed_response.is_a? Hash
|
39
|
+
@response.parsed_response["error"]["message"] if @response.parsed_response["error"]
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
class TokenResponseError < ResponseError # :nodoc:
|
48
|
+
end
|
49
|
+
class OAuthResponseError < ResponseError # :nodoc:
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,137 @@
|
|
1
|
+
require 'pry'
|
2
|
+
module RightSignature::Helpers #:nodoc:
|
3
|
+
module TagsHelper #:nodoc:
|
4
|
+
class <<self #:nodoc:
|
5
|
+
def array_and_metadata_to_string_array(array_of_tags, hash_of_metadata)
|
6
|
+
array_of_tags ||= []
|
7
|
+
hash_of_metadata ||= {}
|
8
|
+
if !(array_of_tags.is_a?(Array) && hash_of_metadata.is_a?(Hash))
|
9
|
+
return raise ArgumentError, "Objects must be an array and a hash"
|
10
|
+
end
|
11
|
+
|
12
|
+
tags_array =
|
13
|
+
array_of_tags.collect{|t| CGI.escape(t)} +
|
14
|
+
hash_of_metadata.collect{ |k,v|
|
15
|
+
"#{CGI.escape(k.to_s)}:#{CGI.escape(v.to_s)}" if ! v.to_s.strip.empty?
|
16
|
+
}.select{ |t|
|
17
|
+
! t.to_s.strip.empty?
|
18
|
+
}
|
19
|
+
|
20
|
+
tags_array.join ','
|
21
|
+
end
|
22
|
+
|
23
|
+
def tags_array_from_tags_string tags_string
|
24
|
+
tags_string ||= ""
|
25
|
+
|
26
|
+
if ! tags_string.is_a? String
|
27
|
+
return raise ArgumentError, "Object must be a string"
|
28
|
+
end
|
29
|
+
|
30
|
+
tags_string.split(',')
|
31
|
+
.select{|t| t !~ /:/}
|
32
|
+
.collect{|t| CGI.unescape(t)}
|
33
|
+
end
|
34
|
+
|
35
|
+
def metadata_hash_from_tags_string tags_string
|
36
|
+
tags_string ||= ""
|
37
|
+
|
38
|
+
if ! tags_string.is_a? String
|
39
|
+
return raise ArgumentError, "Object must be a string"
|
40
|
+
end
|
41
|
+
|
42
|
+
Hash[
|
43
|
+
tags_string.split(',')
|
44
|
+
.select{ |t| t =~ /:/}
|
45
|
+
.collect{ |t|
|
46
|
+
md = t.split(':')
|
47
|
+
[CGI.unescape(md[0]), CGI.unescape(md[1])]
|
48
|
+
}
|
49
|
+
]
|
50
|
+
end
|
51
|
+
|
52
|
+
def mixed_array_to_string_array(array_of_tags)
|
53
|
+
return array_of_tags unless array_of_tags.is_a?(Array)
|
54
|
+
|
55
|
+
tags = []
|
56
|
+
array_of_tags.each_with_index do |tag, idx|
|
57
|
+
if tag.is_a? Hash
|
58
|
+
tags << tag.collect{|k,v| "#{CGI.escape(k.to_s)}:#{CGI.escape(v.to_s)}"}
|
59
|
+
elsif tag.is_a? String
|
60
|
+
tags << CGI.escape(tag.to_s)
|
61
|
+
else
|
62
|
+
raise "Tags should be an array of Strings ('tag_name') or Hashes ({'tag_name' => 'value'})"
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
tags.join(',')
|
67
|
+
end
|
68
|
+
|
69
|
+
def array_to_xml_hash(tags_array)
|
70
|
+
tags_array.map do |t|
|
71
|
+
if t.is_a? Hash
|
72
|
+
name, value = t.first
|
73
|
+
{:tag => {:name => name.to_s, :value => value.to_s}}
|
74
|
+
else
|
75
|
+
{:tag => {:name => t.to_s}}
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
module RolesHelper #:nodoc:
|
84
|
+
class <<self #:nodoc:
|
85
|
+
# Converts [{"Role_ID" => {:name => "John", :email => "email@example.com"}}] to
|
86
|
+
# [{:role => {:name => "John", :email => "email@example.com", "@role_id" => "Role_ID"} }]
|
87
|
+
# Tries to guess if it's using Role ID or Role Name
|
88
|
+
def array_to_xml_hash(roles_array)
|
89
|
+
roles_hash_array = []
|
90
|
+
roles_array.each do |role_hash|
|
91
|
+
name, value = role_hash.first
|
92
|
+
raise "Hash '#{role_hash.inspect}' is malformed, should be something like {ROLE_NAME => {:name => \"a\", :email => \"a@a.com\"}}" unless value.is_a? Hash and (name.is_a? String or name.is_a? Symbol)
|
93
|
+
if name.match(/^signer_[A-Z]+$/) || name.match(/^cc_[A-Z]+$/)
|
94
|
+
roles_hash_array << {:role => value.merge({"@role_id" => name.to_s})}
|
95
|
+
else
|
96
|
+
roles_hash_array << {:role => value.merge({"@role_name" => name.to_s})}
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
roles_hash_array
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
|
107
|
+
module MergeFieldsHelper #:nodoc:
|
108
|
+
class <<self #:nodoc:
|
109
|
+
# Converts [{"Role Name" => {:name => "John", :email => "email@example.com"}}] to
|
110
|
+
# [{"role roles_name=\"Role Name\"" => {:role => {:name => "John", :email => "email@example.com"}} }]
|
111
|
+
def array_to_xml_hash(merge_fields_array, use_id=false)
|
112
|
+
merge_fields = []
|
113
|
+
merge_fields_array.each do |merge_field_hash|
|
114
|
+
name, value = merge_field_hash.first
|
115
|
+
if use_id
|
116
|
+
merge_fields << { :merge_field => {:value => value.to_s, "@merge_field_id" => name.to_s}}
|
117
|
+
else
|
118
|
+
merge_fields << { :merge_field => {:value => value.to_s, "@merge_field_name" => name.to_s}}
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
merge_fields
|
123
|
+
end
|
124
|
+
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
#:nodoc:
|
129
|
+
def array_to_acceptable_names_hash(acceptable_names)
|
130
|
+
converted_fields = []
|
131
|
+
acceptable_names.each do |name|
|
132
|
+
converted_fields << {:name => name}
|
133
|
+
end
|
134
|
+
|
135
|
+
converted_fields
|
136
|
+
end
|
137
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module RefineHashToIndifferentAccess
|
2
|
+
|
3
|
+
# Turn all hashes into "with indifferent access" hashes
|
4
|
+
refine Hash do
|
5
|
+
regular_indexing = instance_method(:[])
|
6
|
+
define_method(:[]) do |key|
|
7
|
+
if has_key? key.to_sym
|
8
|
+
regular_indexing.bind(self).(key.to_sym)
|
9
|
+
else
|
10
|
+
regular_indexing.bind(self).(key.to_s)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
regular_deletion = instance_method(:delete)
|
15
|
+
define_method(:delete) do |key|
|
16
|
+
if has_key? key.to_sym
|
17
|
+
regular_deletion.bind(self).(key.to_sym)
|
18
|
+
else
|
19
|
+
regular_deletion.bind(self).(key.to_s)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
using RefineHashToIndifferentAccess
|
2
|
+
|
3
|
+
module RightSignature
|
4
|
+
class RailsStyle < Connection
|
5
|
+
def prepackage_and_send guid, roles, options
|
6
|
+
# These conversions are basically from Rails-style structures to XML-style structures
|
7
|
+
|
8
|
+
# Convert hashes to array-of-hashes
|
9
|
+
# {k1: v1, k2: v2} => [{k1: v1}, {k2: v2}]
|
10
|
+
|
11
|
+
options[:merge_fields] = (options.delete(:merge_fields)||{}).collect{|k,v| {k => v}}
|
12
|
+
|
13
|
+
roles = roles.collect{|k,v| {k => v}}
|
14
|
+
|
15
|
+
options[:tags] =
|
16
|
+
(options[:tags]||[]) +
|
17
|
+
(options.delete(:metadata)||{}).collect{|k,v| {k => v} if v && ! v.to_s.strip.empty?}.select{|h| ! h.nil?}
|
18
|
+
|
19
|
+
# TODO: Resolve RS choking on anything a HashWithIndifferentAccess
|
20
|
+
super guid, roles, options
|
21
|
+
end
|
22
|
+
|
23
|
+
#TODO: Copy pasta
|
24
|
+
def template_details guid
|
25
|
+
doc = super(guid)[:template]
|
26
|
+
|
27
|
+
tags_string = doc.delete(:tags)
|
28
|
+
doc[:metadata] = TagsHelper.metadata_hash_from_tags_string tags_string
|
29
|
+
doc[:tags] = TagsHelper.tags_array_from_tags_string tags_string
|
30
|
+
|
31
|
+
# Convert a deeply nested array of objects into a normal hash
|
32
|
+
# Note: Must check if it's a deeply nested hash instead, since that is what occurs
|
33
|
+
# for single-item XLM "arrays"
|
34
|
+
# {..., recipients: {recipient: [{...},{...}]}} => {..., recipients: {...: {...}, ...:{...}}}
|
35
|
+
tmp = doc[:roles][:role].is_a?(Hash) ? [doc[:roles][:role]] : doc[:roles][:role]
|
36
|
+
doc[:roles] = tmp.reduce({}){|h, v| h[v[:document_role_id]] = v and h}
|
37
|
+
|
38
|
+
tmp = doc[:merge_fields][:merge_field].is_a?(Hash) ? [doc[:merge_fields][:merge_field]] : doc[:merge_fields][:merge_field]
|
39
|
+
doc[:merge_fields] = tmp.reduce({}){|h, v| h[v[:name]] = v and h}
|
40
|
+
|
41
|
+
# Extract a few fields from a deeply nested array
|
42
|
+
tmp = doc[:pages][:page].is_a?(Hash) ? doc[:pages][:page] : doc[:pages][:page].first
|
43
|
+
%i(original_template_guid original_template_filename).each do |sym|
|
44
|
+
doc[sym] = tmp[sym]
|
45
|
+
end
|
46
|
+
doc.delete(:pages)
|
47
|
+
|
48
|
+
%i(thumbnail_url).each do |sym|
|
49
|
+
doc[sym] = CGI.unescape doc[sym]
|
50
|
+
end
|
51
|
+
|
52
|
+
doc
|
53
|
+
end
|
54
|
+
|
55
|
+
def document_details guid
|
56
|
+
doc = super(guid)[:document]
|
57
|
+
|
58
|
+
tags_string = doc.delete(:tags)
|
59
|
+
doc[:metadata] = TagsHelper.metadata_hash_from_tags_string tags_string
|
60
|
+
doc[:tags] = TagsHelper.tags_array_from_tags_string tags_string
|
61
|
+
|
62
|
+
# Convert a deeply nested array of objects into a normal hash
|
63
|
+
# Note: Must check if it's a deeply nested hash instead, since that is what occurs
|
64
|
+
# for single-item XLM "arrays"
|
65
|
+
# {..., recipients: {recipient: [{...},{...}]}} => {..., recipients: {...: {...}, ...:{...}}}
|
66
|
+
tmp = doc[:recipients][:recipient].is_a?(Hash) ? [doc[:recipients][:recipient]] : doc[:recipients][:recipient]
|
67
|
+
doc[:recipients] = tmp.reduce({}){|h, v| h[v[:role_id]] = v and h}
|
68
|
+
|
69
|
+
tmp = doc[:audit_trails][:audit_trail].is_a?(Hash) ? [doc[:audit_trails][:audit_trail]] : doc[:audit_trails][:audit_trail]
|
70
|
+
doc[:audit_trails] = tmp.reduce({}){|h, v| h[v[:timestamp]] = v and h}
|
71
|
+
|
72
|
+
tmp = doc[:form_fields][:form_field].is_a?(Hash) ? [doc[:form_fields][:form_field]] : doc[:form_fields][:form_field]
|
73
|
+
doc[:form_fields] = tmp.reduce({}){|h, v| h[v[:name]] = v and h}
|
74
|
+
|
75
|
+
# Extract a few fields from a deeply nested array
|
76
|
+
tmp = doc[:pages][:page].is_a?(Hash) ? doc[:pages][:page] : doc[:pages][:page].first
|
77
|
+
%i(original_template_guid original_template_filename).each do |sym|
|
78
|
+
doc[sym] = tmp[sym]
|
79
|
+
end
|
80
|
+
doc.delete(:pages)
|
81
|
+
|
82
|
+
%i(original_url pdf_url thumbnail_url large_url signed_pdf_url).each do |sym|
|
83
|
+
doc[sym] = CGI.unescape doc[sym]
|
84
|
+
end
|
85
|
+
|
86
|
+
doc
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,299 @@
|
|
1
|
+
using RefineHashToIndifferentAccess
|
2
|
+
|
3
|
+
module RightSignature
|
4
|
+
module Template
|
5
|
+
include RightSignature::Helpers
|
6
|
+
# List Templates with optional filters
|
7
|
+
# * <b>Options</b>: (optional) Hash of filters to use
|
8
|
+
# * <b>page</b>: page number
|
9
|
+
# * <b>per_page</b>: number of templates to return per page.
|
10
|
+
# API only supports 10, 20, 30, 40, or 50. Default is 10.
|
11
|
+
# * <b>tags</b>: filter templates by given tags. Array of strings, for name/value tags colon (:) should separate name and value.
|
12
|
+
# Ex. "single_tag,tag_key:tag_value" would find templates with 'single_tag' and the name/value of 'tag_key' with value 'tag_value'.
|
13
|
+
# * <b>search</b>: term to search for in templates.
|
14
|
+
#
|
15
|
+
# Ex.
|
16
|
+
# options = {
|
17
|
+
# :state => ['completed', 'trashed'],
|
18
|
+
# :page => 1,
|
19
|
+
# :per_page => 20,
|
20
|
+
# :search => "me",
|
21
|
+
# :tags => ["single_tag", "key" => "with_value"]
|
22
|
+
# }
|
23
|
+
# @rs_connection.templates_list(options)
|
24
|
+
def templates_list(options={})
|
25
|
+
if options[:metadata]
|
26
|
+
options[:tags] = TagsHelper.array_and_metadata_to_string_array(options[:tags], options.delete(:metadata))
|
27
|
+
elsif options[:tags]
|
28
|
+
options[:tags] = TagsHelper.mixed_array_to_string_array(options[:tags])
|
29
|
+
end
|
30
|
+
get "/api/templates.xml", options
|
31
|
+
end
|
32
|
+
|
33
|
+
# Gets template details
|
34
|
+
# * <b>guid</b>: templates guid. Ex. a_1_zcfdidf8fi23
|
35
|
+
def template_details(guid)
|
36
|
+
get "/api/templates/#{guid}.xml", {}
|
37
|
+
end
|
38
|
+
|
39
|
+
# Clones a template so it can be used for sending. Always first step in sending a template.
|
40
|
+
# * <b>guid</b>: templates guid. Ex. a_1_zcfdidf8fi23
|
41
|
+
def prepackage(guid)
|
42
|
+
post "/api/templates/#{guid}/prepackage.xml", {}
|
43
|
+
end
|
44
|
+
|
45
|
+
# Prefills template. Should use a <b>prepackaged</b> template first.
|
46
|
+
# * <b>guid</b>: templates guid. Ex. a_1_zcfdidf8fi23
|
47
|
+
# * <b>subject</b>: subject of the document that'll appear in email
|
48
|
+
# * <b>roles</b>: Recipients of the document, should be an array of role names and emails in a hash with keys as role_names.
|
49
|
+
# Ex. [{"Employee" => {:name => "John Employee", :email => "john@employee.com"}}]
|
50
|
+
# is equivalent to
|
51
|
+
# <role role_name="Employee">
|
52
|
+
# <name>John Employee</name>
|
53
|
+
# <email>john@employee.com</email>
|
54
|
+
# </role>
|
55
|
+
# * <b>options</b>: other optional values
|
56
|
+
# * <b>description</b>: document description that'll appear in the email
|
57
|
+
# * <b>merge_fields</b>: document merge fields, should be an array of merge_field_values in a hash with the merge_field_name.
|
58
|
+
# Ex. [{"Salary" => "$1,000,000"}]
|
59
|
+
# is equivalent to
|
60
|
+
# <merge_field merge_field_name="Salary">
|
61
|
+
# <value>$1,000,000</value>
|
62
|
+
# </merge_field>
|
63
|
+
# * <b>expires_in</b>: number of days before expiring the document. API only allows 2,5,15, or 30.
|
64
|
+
# * <b>tags</b>: document tags, an array of string or hashes 'single_tag' (for simple tag) or {'tag_name' => 'tag_value'} (for tuples pairs)
|
65
|
+
# Ex. ['sent_from_api', {"user_id" => "32"}]
|
66
|
+
# * <b>callback_location</b>: A URI encoded URL that specifies the location for API to POST a callback notification to when the document has been created and signed.
|
67
|
+
# Ex. "http://yoursite/callback"
|
68
|
+
#
|
69
|
+
# Ex. call with all options used
|
70
|
+
# @rs_connection.prefill(
|
71
|
+
# "a_1_zcfdidf8fi23",
|
72
|
+
# "Your Employee Handbook",
|
73
|
+
# [{"employee" => {:name => "John Employee", :email => "john@employee.com"}}],
|
74
|
+
# {
|
75
|
+
# :description => "Please read over the handbook and sign it.",
|
76
|
+
# :merge_fields => [
|
77
|
+
# { "Department" => "Fun and games" },
|
78
|
+
# { "Salary" => "$1,000,000" }
|
79
|
+
# ],
|
80
|
+
# :expires_in => 5,
|
81
|
+
# :tags => [
|
82
|
+
# {:name => 'sent_from_api'},
|
83
|
+
# {:name => 'user_id', :value => '32'}
|
84
|
+
# ],
|
85
|
+
# :redirect_location => "http://yoursite/redirect",
|
86
|
+
# :callback_location => "http://yoursite/callback"
|
87
|
+
# })
|
88
|
+
def prefill(guid, subject, roles, options={})
|
89
|
+
use_merge_field_ids = options.delete(:use_merge_field_ids)
|
90
|
+
xml_hash = {
|
91
|
+
:template => {
|
92
|
+
:guid => guid,
|
93
|
+
:action => "prefill",
|
94
|
+
:subject => subject
|
95
|
+
}.merge(options)
|
96
|
+
}
|
97
|
+
|
98
|
+
xml_hash[:template][:roles] = RolesHelper.array_to_xml_hash(roles)
|
99
|
+
|
100
|
+
# Optional arguments
|
101
|
+
xml_hash[:template][:merge_fields] = MergeFieldsHelper.array_to_xml_hash(options[:merge_fields], use_merge_field_ids) if options[:merge_fields]
|
102
|
+
xml_hash[:template][:tags] = TagsHelper.array_to_xml_hash(options[:tags]) if options[:tags]
|
103
|
+
|
104
|
+
post "/api/templates.xml", xml_hash
|
105
|
+
end
|
106
|
+
|
107
|
+
# Prepackages and sends template.
|
108
|
+
# * <b>guid</b>: templates guid. Ex. a_1_zcfdidf8fi23
|
109
|
+
# * <b>roles</b>: Recipients of the document, should be an array of role names and emails in a hash with keys as role_names.
|
110
|
+
# Ex. [{"Employee" => {:name => "John Employee", :email => "john@employee.com"}}]
|
111
|
+
# is equivalent to
|
112
|
+
# <role role_name="Employee">
|
113
|
+
# <name>John Employee</name>
|
114
|
+
# <email>john@employee.com</email>
|
115
|
+
# </role>
|
116
|
+
# * <b>options</b>: other optional values
|
117
|
+
# * <b>subject</b>: subject of the document that'll appear in email. Defaults to template's subject
|
118
|
+
# * <b>description</b>: document description that'll appear in the email
|
119
|
+
# * <b>merge_fields</b>: document merge fields, should be an array of merge_field_values in a hash with the merge_field_name.
|
120
|
+
# Ex. [{"Salary" => "$1,000,000"}]
|
121
|
+
# is equivalent to
|
122
|
+
# <merge_field merge_field_name="Salary">
|
123
|
+
# <value>$1,000,000</value>
|
124
|
+
# </merge_field>
|
125
|
+
# * <b>expires_in</b>: number of days before expiring the document. API only allows 2,5,15, or 30.
|
126
|
+
# * <b>tags</b>: document tags, an array of {:name => 'tag_name'} (for simple tag) or {:name => 'tag_name', :value => 'value'} (for tuples pairs)
|
127
|
+
# Ex. [{:name => 'sent_from_api'}, {:name => "user_id", :value => "32"}]
|
128
|
+
# * <b>callback_location</b>: A URI encoded URL that specifies the location for API to POST a callback notification to when the document has been created and signed.
|
129
|
+
# Ex. "http://yoursite/callback"
|
130
|
+
#
|
131
|
+
# Ex. call with all options used
|
132
|
+
# @rs_connection.prepackage_and_send(
|
133
|
+
# "a_1_zcfdidf8fi23",
|
134
|
+
# "Your Employee Handbook",
|
135
|
+
# [{"employee" => {:name => "John Employee", :email => "john@employee.com"}}],
|
136
|
+
# {
|
137
|
+
# :description => "Please read over the handbook and sign it.",
|
138
|
+
# :merge_fields => [
|
139
|
+
# { "Department" => "Fun and games" },
|
140
|
+
# { "Salary" => "$1,000,000" }
|
141
|
+
# ],
|
142
|
+
# :expires_in => 5,
|
143
|
+
# :tags => [
|
144
|
+
# {:name => 'sent_from_api'},
|
145
|
+
# {:name => 'user_id', :value => '32'}
|
146
|
+
# ],
|
147
|
+
# :callback_location => "http://yoursite/callback"
|
148
|
+
# })
|
149
|
+
def prepackage_and_send(guid, roles, options={})
|
150
|
+
response = prepackage(guid)
|
151
|
+
new_guid = response["template"]["guid"]
|
152
|
+
send_template(new_guid, options.delete(:subject) || response["template"]["subject"], roles, options)
|
153
|
+
end
|
154
|
+
|
155
|
+
# Sends template. Should use a <b>prepackaged</b> template first. Easier to use <b>prepackage_and_send</b> for most cases.
|
156
|
+
# * <b>guid</b>: templates guid. Ex. a_1_zcfdidf8fi23
|
157
|
+
# * <b>subject</b>: subject of the document that'll appear in email
|
158
|
+
# * <b>roles</b>: Recipients of the document, should be an array of role names and emails in a hash with keys as role_names.
|
159
|
+
# Ex. [{"Employee" => {:name => "John Employee", :email => "john@employee.com"}}]
|
160
|
+
# is equivalent to
|
161
|
+
# <role role_name="Employee">
|
162
|
+
# <name>John Employee</name>
|
163
|
+
# <email>john@employee.com</email>
|
164
|
+
# </role>
|
165
|
+
# * <b>options</b>: other optional values
|
166
|
+
# * <b>description</b>: document description that'll appear in the email
|
167
|
+
# * <b>merge_fields</b>: document merge fields, should be an array of merge_field_values in a hash with the merge_field_name.
|
168
|
+
# Ex. [{"Salary" => "$1,000,000"}]
|
169
|
+
# is equivalent to
|
170
|
+
# <merge_field merge_field_name="Salary">
|
171
|
+
# <value>$1,000,000</value>
|
172
|
+
# </merge_field>
|
173
|
+
# * <b>expires_in</b>: number of days before expiring the document. API only allows 2,5,15, or 30.
|
174
|
+
# * <b>tags</b>: document tags, an array of {:name => 'tag_name'} (for simple tag) or {:name => 'tag_name', :value => 'value'} (for tuples pairs)
|
175
|
+
# Ex. [{:name => 'sent_from_api'}, {:name => "user_id", :value => "32"}]
|
176
|
+
# * <b>callback_location</b>: A URI encoded URL that specifies the location for API to POST a callback notification to when the document has been created and signed.
|
177
|
+
# Ex. "http://yoursite/callback"
|
178
|
+
#
|
179
|
+
# Ex. call with all options used
|
180
|
+
# @rs_connection.send_template(
|
181
|
+
# "a_1_zcfdidf8fi23",
|
182
|
+
# "Your Employee Handbook",
|
183
|
+
# [{"employee" => {:name => "John Employee", :email => "john@employee.com"}}],
|
184
|
+
# {
|
185
|
+
# :description => "Please read over the handbook and sign it.",
|
186
|
+
# :merge_fields => [
|
187
|
+
# { "Department" => "Fun and games" },
|
188
|
+
# { "Salary" => "$1,000,000" }
|
189
|
+
# ],
|
190
|
+
# :expires_in => 5,
|
191
|
+
# :tags => [
|
192
|
+
# {:name => 'sent_from_api'},
|
193
|
+
# {:name => 'user_id', :value => '32'}
|
194
|
+
# ],
|
195
|
+
# :callback_location => "http://yoursite/callback"
|
196
|
+
# })
|
197
|
+
def send_template(guid, subject, roles, options={})
|
198
|
+
prefill(guid, subject, roles, options.merge({:action => 'send'}))
|
199
|
+
end
|
200
|
+
|
201
|
+
# Creates a URL that give person ability to create a template in your account.
|
202
|
+
# * <b>options</b>: optional options for redirected person
|
203
|
+
# * <b>callback_location</b>: URI encoded URL that specifies the location we will POST a callback notification to when the template has been created.
|
204
|
+
# * <b>redirect_location</b>: A URI encoded URL that specifies the location we will redirect the user to, after they have created a template.
|
205
|
+
# * <b>tags</b>: tags to add to the template. an array of 'tag_name' (for simple tag) or {'tag_name' => 'value'} (for tuples pairs)
|
206
|
+
# Ex. ['created_from_api', {"user_id" => "123"}]
|
207
|
+
# * <b>acceptable_role_names</b>: The user creating the Template will be forced to select one of the values provided.
|
208
|
+
# There will be no free-form name entry when adding roles to the Template. An array of strings.
|
209
|
+
# Ex. ["Employee", "Employeer"]
|
210
|
+
# * <b>acceptable_merge_field_names</b>: The user creating the Template will be forced to select one of the values provided.
|
211
|
+
# There will be no free-form name entry when adding merge fields to the Template.
|
212
|
+
# Ex. ["Location", "Tax ID", "Company Name"]
|
213
|
+
def generate_build_url(options={})
|
214
|
+
xml_hash = {:template => options}
|
215
|
+
xml_hash[:template][:tags] = TagsHelper.array_to_xml_hash(options[:tags]) if options[:tags]
|
216
|
+
|
217
|
+
[:acceptable_merge_field_names, :acceptable_role_names].each do |option|
|
218
|
+
xml_hash[:template][option] = array_to_acceptable_names_hash(options[option]) if options[option]
|
219
|
+
end
|
220
|
+
|
221
|
+
response = post "/api/templates/generate_build_token.xml", xml_hash
|
222
|
+
|
223
|
+
redirect_token = response["token"]["redirect_token"]
|
224
|
+
|
225
|
+
"#{site}/builder/new?rt=#{redirect_token}"
|
226
|
+
end
|
227
|
+
|
228
|
+
# Sends template with all roles as embedded signers and returns an array of hashes with :name and :url for each signer link.
|
229
|
+
# * <b>guid</b>: templates guid. Ex. a_1_zcfdidf8fi23
|
230
|
+
# * <b>roles</b>: Recipients of the document, should be an array of role names in a hash with keys as role_names.
|
231
|
+
# Ex. [{"Employee" => {:name => "John Employee"}]
|
232
|
+
# is equivalent to
|
233
|
+
# <role role_name="Employee">
|
234
|
+
# <name>John Employee</name>
|
235
|
+
# <email>noemail@rightsignature.com</email>
|
236
|
+
# </role>
|
237
|
+
# * <b>options</b>: other optional values
|
238
|
+
# * <b>subject</b>: subject of the document that'll appear in email. Defaults to Template's subject
|
239
|
+
# * <b>description</b>: document description that'll appear in the email
|
240
|
+
# * <b>merge_fields</b>: document merge fields, should be an array of merge_field_values in a hash with the merge_field_name.
|
241
|
+
# Ex. [{"Salary" => "$1,000,000"}]
|
242
|
+
# is equivalent to
|
243
|
+
# <merge_field merge_field_name="Salary">
|
244
|
+
# <value>$1,000,000</value>
|
245
|
+
# </merge_field>
|
246
|
+
# * <b>expires_in</b>: number of days before expiring the document. API only allows 2,5,15, or 30.
|
247
|
+
# * <b>tags</b>: document tags, an array of {:name => 'tag_name'} (for simple tag) or {:name => 'tag_name', :value => 'value'} (for tuples pairs)
|
248
|
+
# Ex. [{:name => 'sent_from_api'}, {:name => "user_id", :value => "32"}]
|
249
|
+
# * <b>callback_location</b>: A URI encoded URL that specifies the location for API to POST a callback notification to when the document has been created and signed.
|
250
|
+
# Ex. "http://yoursite/callback"
|
251
|
+
# * <b>redirect_location</b>: A URI encoded URL that specifies the location for the signing widget to redirect the user to after it is signed.
|
252
|
+
# Ex. "http://yoursite/thanks_for_signing"
|
253
|
+
#
|
254
|
+
# Ex. call with all options used
|
255
|
+
# @rs_connection.send_as_embedded_signers(
|
256
|
+
# "a_1_zcfdidf8fi23",
|
257
|
+
# "Your Employee Handbook",
|
258
|
+
# [{"employee" => {:name => "John Employee", :email => "john@employee.com"}}],
|
259
|
+
# {
|
260
|
+
# :description => "Please read over the handbook and sign it.",
|
261
|
+
# :merge_fields => [
|
262
|
+
# { "Department" => "Fun and games" },
|
263
|
+
# { "Salary" => "$1,000,000" }
|
264
|
+
# ],
|
265
|
+
# :expires_in => 5,
|
266
|
+
# :tags => [
|
267
|
+
# {:name => 'sent_from_api'},
|
268
|
+
# {:name => 'user_id', :value => '32'}
|
269
|
+
# ],
|
270
|
+
# :redirect_location => "http://yoursite/redirect_from_signing"
|
271
|
+
# })
|
272
|
+
def send_as_embedded_signers(guid, recipients, options={})
|
273
|
+
redirect_location = options.delete(:redirect_location)
|
274
|
+
|
275
|
+
response = prepackage(guid)
|
276
|
+
template = response["template"]
|
277
|
+
|
278
|
+
recipients.each do |role_hash|
|
279
|
+
key, value = role_hash.first
|
280
|
+
role_hash[key][:email] = "noemail@rightsignature.com" unless role_hash[key]["email"] || role_hash[key][:email]
|
281
|
+
end
|
282
|
+
|
283
|
+
response = send_template(template["guid"], options[:subject] || template["subject"], recipients, options)
|
284
|
+
document_guid = response["document"]["guid"]
|
285
|
+
|
286
|
+
get_document_signer_links_for(document_guid, redirect_location)
|
287
|
+
end
|
288
|
+
|
289
|
+
# Deletes a template
|
290
|
+
# * <b>guid</b>: Document GUID
|
291
|
+
#
|
292
|
+
# Ex. Delete template GUID123
|
293
|
+
# @rs_connection.trash_template("GUID123")
|
294
|
+
#
|
295
|
+
def trash_template(guid)
|
296
|
+
delete "/api/templates/#{guid}.xml"
|
297
|
+
end
|
298
|
+
end
|
299
|
+
end
|