rightsignature-railstyle 1.1.9
Sign up to get free protection for your applications and to get access to all the features.
- 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
|