agree2 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +0 -0
- data/License.txt +20 -0
- data/README.rdoc +165 -0
- data/Rakefile +97 -0
- data/lib/agree2/agreement.rb +71 -0
- data/lib/agree2/base.rb +147 -0
- data/lib/agree2/client.rb +101 -0
- data/lib/agree2/party.rb +23 -0
- data/lib/agree2/proxy_collection.rb +76 -0
- data/lib/agree2/template.rb +100 -0
- data/lib/agree2/user.rb +73 -0
- data/lib/agree2.rb +34 -0
- data/spec/agreement_spec.rb +190 -0
- data/spec/client_spec.rb +49 -0
- data/spec/fixtures/agreement.json +50 -0
- data/spec/fixtures/party.json +15 -0
- data/spec/party_spec.rb +138 -0
- data/spec/proxy_collection_spec.rb +124 -0
- data/spec/spec_helper.rb +5 -0
- data/spec/template_spec.rb +89 -0
- data/spec/user_spec.rb +77 -0
- metadata +118 -0
data/History.txt
ADDED
File without changes
|
data/License.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2008 Extra Eagle LLC
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,165 @@
|
|
1
|
+
= Agree2 Client
|
2
|
+
|
3
|
+
Agree2 (https://agree2.com) is a site for creating and maintaining contracts.
|
4
|
+
|
5
|
+
This Client library will let you integrate Agree2 into your own web applications to create full legal contracts between you and your users or between your users.
|
6
|
+
|
7
|
+
== Install the Agree2 gem
|
8
|
+
|
9
|
+
The Agree2 client is installed as a ruby gem:
|
10
|
+
|
11
|
+
sudo gem install agree2
|
12
|
+
|
13
|
+
The source is available on github https://github.com/pelle/agree2-client/tree/master .
|
14
|
+
|
15
|
+
== Getting Started
|
16
|
+
|
17
|
+
First of all you need to signup with https://agree2.com.
|
18
|
+
|
19
|
+
Now go to the page http://agree2.dev/client_applications and register an application.
|
20
|
+
|
21
|
+
Find the snippet of code on your client application page called "Example using your own AccessToken". This provides you everything to get started creating agreements under you own account. It should something like this:
|
22
|
+
|
23
|
+
@client=Agree2::Client.new "DM0VybBbeTc6GfFSF1WbQ","aVmgGmQ1WOjsbbSZbrPcT4qet6IMa2tqJebaeyIBs"
|
24
|
+
@user=@client.user "zEHUnKDNuLGXQuicFWZRpQ","0VM3ESRl3rGtg95Wa2JsOFWmu4E78lNHfvMy1j4UtQ"
|
25
|
+
|
26
|
+
If you wanted to list all the agreements you've got in your account you would do the following:
|
27
|
+
|
28
|
+
@user.agreements
|
29
|
+
|
30
|
+
Creating a new agreement:
|
31
|
+
|
32
|
+
@agreement=@user.agreements.create(:title=>"User Agreement",:body=>"This is the body of the agreement")
|
33
|
+
@agreement.to_url # Returns the agreement's url
|
34
|
+
redirect_to @agreement.to_url # Redirect to agreements url in Rails
|
35
|
+
|
36
|
+
Invite a party:
|
37
|
+
|
38
|
+
@party=@agreement.parties.create :role=>"client",:first_name=>"Joe",:last_name=>"Bloggs",:email=>"joe@blogs.inv",:organization_name=>"Big Inc"
|
39
|
+
redirect_to @party.present # Redirect user in an authenticated way to agreement
|
40
|
+
|
41
|
+
List the parties to an agreement:
|
42
|
+
|
43
|
+
@agreement.parties
|
44
|
+
|
45
|
+
By default new agreements are in draft mode, ready for further customization. For the parties to be able to accept the agreement you must finalize it:
|
46
|
+
|
47
|
+
@agreement.finalize!
|
48
|
+
|
49
|
+
== Using Templates
|
50
|
+
|
51
|
+
In most day to day use you will probably be using templates to create agreements. You can create your own templates or use our growing library of public templates (https://agree2.com/masters/public).
|
52
|
+
|
53
|
+
As an example lets use this "Confidentiality Agreement for access to source code" (https://agree2.com/masters/b4f9a904efaab5ad71f695824c997c332b955876).
|
54
|
+
|
55
|
+
You could instantiate the template using the long code that comes at the end of the url:
|
56
|
+
|
57
|
+
@template=@agree2_user.templates.find "b4f9a904efaab5ad71f695824c997c332b955876"
|
58
|
+
|
59
|
+
We have actually made it even easier though. Each template has it's own Ruby version that you can download. If you click on "Tools" and then "Instant Ruby API" you will find it customized for your own use. In our example you can find it at:
|
60
|
+
|
61
|
+
https://agree2.com/masters/b4f9a904efaab5ad71f695824c997c332b955876.rb
|
62
|
+
|
63
|
+
Save this file and require it into your application. This will also provide you with an instance of the template in @template.
|
64
|
+
|
65
|
+
=== Preparing an Agreement from a Template
|
66
|
+
|
67
|
+
To create an agreement with no customizations simply do:
|
68
|
+
|
69
|
+
@agreement=@template.prepare
|
70
|
+
|
71
|
+
Templates have user defined fields that can be filled out by the application. This is where it gets interesting:
|
72
|
+
|
73
|
+
@agreement=@template.prepare :holder => "John Doe",
|
74
|
+
:holder_info => "john@gmail.inv",
|
75
|
+
:coder => "Phil Armonic",
|
76
|
+
:coder_info => "phil@gmail.inv",
|
77
|
+
:project => "Spoogle.com",
|
78
|
+
:svn => "http://svnhost.inv/spoogle"
|
79
|
+
|
80
|
+
Each of the custom fields from the template is now directly available in the agreement:
|
81
|
+
|
82
|
+
puts @agreement.holder
|
83
|
+
> "John Doe"
|
84
|
+
|
85
|
+
You can also get the full list of fields using:
|
86
|
+
|
87
|
+
@agreement.fields
|
88
|
+
|
89
|
+
=== Preparing Agreement from a Template and adding Parties
|
90
|
+
|
91
|
+
To reduce the amount of network activity between your servers and ours you can create an agreement from a template and add parties in one step.
|
92
|
+
|
93
|
+
@agreement=@template.prepare {
|
94
|
+
:holder => "John Doe",
|
95
|
+
:holder_info => "john@gmail.inv",
|
96
|
+
:coder => "Phil Armonic",
|
97
|
+
:coder_info => "phil@gmail.inv",
|
98
|
+
:project => "Spoogle.com",
|
99
|
+
:svn => "http://svnhost.inv/spoogle"
|
100
|
+
},{
|
101
|
+
:coder=>{
|
102
|
+
:first_name=>"Phil",
|
103
|
+
:last_name=>"Armonic",
|
104
|
+
:email=>"phil@gmail.inv"
|
105
|
+
},
|
106
|
+
:holder=>{
|
107
|
+
:first_name=>"John",
|
108
|
+
:last_name=>"Doe",
|
109
|
+
:email=>"john@gmail.inv",
|
110
|
+
:organization_name=>"Spoogle Inc"
|
111
|
+
}
|
112
|
+
}
|
113
|
+
|
114
|
+
The above creates the agreement, adds the 2 parties and sends emails to them.
|
115
|
+
|
116
|
+
You can also add your applications user in agree2 as a party without having to repeat all the information:
|
117
|
+
|
118
|
+
@agreement=@template.prepare {
|
119
|
+
:holder => "John Doe",
|
120
|
+
:holder_info => "john@gmail.inv",
|
121
|
+
:coder => "Phil Armonic",
|
122
|
+
:coder_info => "phil@gmail.inv",
|
123
|
+
:project => "Spoogle.com",
|
124
|
+
:svn => "http://svnhost.inv/spoogle"
|
125
|
+
},{
|
126
|
+
:coder=>{
|
127
|
+
:first_name=>"Phil",
|
128
|
+
:last_name=>"Armonic",
|
129
|
+
:email=>"phil@gmail.inv"
|
130
|
+
}
|
131
|
+
},"holder"
|
132
|
+
|
133
|
+
This does the same as the first example except "holder" will have the details from your user account.
|
134
|
+
|
135
|
+
=== Preparing and signing an agreeement from the API
|
136
|
+
|
137
|
+
Lets say you want to create an agreement, add the parties and sign it so your user can go straight to it to accept it. Agree2 offers the possibility of signing an agreement during the creation process. Not all accounts have access to this feature.
|
138
|
+
|
139
|
+
The signing process is done using the OAuth protocol we use for authentication. We also only allow you to sign on behalf of the application's user.
|
140
|
+
|
141
|
+
@agreement=@template.prepare_and_sign {
|
142
|
+
:holder => "John Doe",
|
143
|
+
:holder_info => "john@gmail.inv",
|
144
|
+
:coder => "Phil Armonic",
|
145
|
+
:coder_info => "phil@gmail.inv",
|
146
|
+
:project => "Spoogle.com",
|
147
|
+
:svn => "http://svnhost.inv/spoogle"
|
148
|
+
},{
|
149
|
+
:coder=>{
|
150
|
+
:first_name=>"Phil",
|
151
|
+
:last_name=>"Armonic",
|
152
|
+
:email=>"phil@gmail.inv"
|
153
|
+
}
|
154
|
+
},"holder"
|
155
|
+
|
156
|
+
The final parameter "holder" is optional. It will add you as a party with the role "application" by default.
|
157
|
+
|
158
|
+
== About Agree2 Client
|
159
|
+
|
160
|
+
Author:: Pelle Braendgaard (http://stakeventures.com)
|
161
|
+
Copyright:: Copyright (c) 2008 Extra Eagle LLC
|
162
|
+
License:: MIT
|
163
|
+
Git:: https://github.com/pelle/agree2-client/tree/master
|
164
|
+
|
165
|
+
This client library allows you to integrate Agree2 into your application.
|
data/Rakefile
ADDED
@@ -0,0 +1,97 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
require 'rake/rdoctask'
|
4
|
+
require 'rake/testtask'
|
5
|
+
require 'spec/rake/spectask'
|
6
|
+
require 'rake/gempackagetask'
|
7
|
+
require 'yaml'
|
8
|
+
namespace :rdoc do |ns|
|
9
|
+
Rake::RDocTask.new(:doc) do |rd|
|
10
|
+
rd.main = "README.rdoc"
|
11
|
+
rd.rdoc_dir = 'doc'
|
12
|
+
rd.rdoc_files.include("README.rdoc", "lib/**/*.rb")
|
13
|
+
rd.options << "-t Agree2"
|
14
|
+
end
|
15
|
+
|
16
|
+
desc 'Publish RDoc to RubyForge.'
|
17
|
+
task :publish_docs => [:doc] do
|
18
|
+
config = YAML.load(File.read(File.expand_path("~/.rubyforge/user-config.yml")))
|
19
|
+
host = "#{config["username"]}@rubyforge.org"
|
20
|
+
|
21
|
+
remote_dir = "/var/www/gforge-projects/agree2"
|
22
|
+
local_dir = 'doc'
|
23
|
+
|
24
|
+
sh %{rsync -av --delete #{local_dir}/ #{host}:#{remote_dir}}
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
namespace :spec do |ns|
|
30
|
+
desc "Run all examples"
|
31
|
+
Spec::Rake::SpecTask.new('spec') do |t|
|
32
|
+
t.spec_files = FileList['spec/*.rb']
|
33
|
+
end
|
34
|
+
|
35
|
+
desc "Run rcov"
|
36
|
+
Spec::Rake::SpecTask.new('rcov') do |t|
|
37
|
+
t.spec_files = FileList['spec/*.rb']
|
38
|
+
t.rcov = true
|
39
|
+
t.rcov_opts = ['--exclude','gems,spec']
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
namespace :gem do |gem|
|
44
|
+
File.open( 'agree2.gemspec') do |f|
|
45
|
+
@gem=eval(f.read)
|
46
|
+
@version=@gem.version.to_s
|
47
|
+
end
|
48
|
+
|
49
|
+
Rake::GemPackageTask.new @gem do |pkg|
|
50
|
+
pkg.need_tar = true
|
51
|
+
pkg.need_zip = true
|
52
|
+
end
|
53
|
+
|
54
|
+
desc 'Install the package as a gem.'
|
55
|
+
task :install => [:clean, :package] do
|
56
|
+
gem = Dir['pkg/*.gem'].first
|
57
|
+
sh "sudo gem install --local #{gem}"
|
58
|
+
end
|
59
|
+
|
60
|
+
|
61
|
+
desc 'Package and upload the release to rubyforge.'
|
62
|
+
task :release => [:clean, :package] do |t|
|
63
|
+
pkg = "pkg/#{name}-#{@version}"
|
64
|
+
|
65
|
+
if $DEBUG then
|
66
|
+
puts "release_id = rf.add_release #{rubyforge_name.inspect}, #{name.inspect}, #{@version.inspect}, \"#{pkg}.tgz\""
|
67
|
+
puts "rf.add_file #{rubyforge_name.inspect}, #{name.inspect}, release_id, \"#{pkg}.gem\""
|
68
|
+
end
|
69
|
+
|
70
|
+
rf = RubyForge.new.configure
|
71
|
+
puts "Logging in"
|
72
|
+
rf.login
|
73
|
+
|
74
|
+
# c = rf.userconfig
|
75
|
+
# c["release_notes"] = description if description
|
76
|
+
# c["release_changes"] = changes if changes
|
77
|
+
# c["preformatted"] = true
|
78
|
+
|
79
|
+
files = ["#{pkg}.tgz",
|
80
|
+
"#{pkg}.zip",
|
81
|
+
"#{pkg}.gem"].compact
|
82
|
+
|
83
|
+
puts "Releasing #{name} v. #{@version}"
|
84
|
+
rf.add_release rubyforge_name, name, @version, *files
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
88
|
+
|
89
|
+
desc "Clean up all dirt"
|
90
|
+
task :clean => [ "rdoc:clobber_doc", "gem:clobber_package" ] do
|
91
|
+
%w(diff diff.txt email.txt ri *.gem *~ **/*~ *.rbc **/*.rbc coverage).each do |pattern|
|
92
|
+
files = Dir[pattern]
|
93
|
+
rm_rf files, :verbose => true unless files.empty?
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
task :default=>[:spec]
|
@@ -0,0 +1,71 @@
|
|
1
|
+
module Agree2
|
2
|
+
class Agreement<Base
|
3
|
+
attr_serializable :permalink,:title,:body,:created_at,:updated_at,:smart_fields,:state,:active_version,
|
4
|
+
:version,:digest,:finalized_at,:finalized_at,:terminated_at,:activated_at,:valid_to
|
5
|
+
|
6
|
+
alias_method :fields,:smart_fields
|
7
|
+
# Returns the parties to the agreement
|
8
|
+
def parties
|
9
|
+
@parties||=Agree2::ProxyCollection.new self,"#{self.path}/parties",'Party'
|
10
|
+
end
|
11
|
+
|
12
|
+
def parties=(values)
|
13
|
+
@parties=Agree2::ProxyCollection.new self,"#{self.path}/parties",'Party',values
|
14
|
+
end
|
15
|
+
|
16
|
+
def to_param #:nodoc:
|
17
|
+
permalink
|
18
|
+
end
|
19
|
+
|
20
|
+
def respond_to?(symbol, include_priv = false) #:nodoc:
|
21
|
+
return true if super symbol,include_priv
|
22
|
+
return false if fields.nil?||fields.empty?
|
23
|
+
method=symbol.to_s
|
24
|
+
if method=~/(.+)=$/
|
25
|
+
field=$1
|
26
|
+
setter=true
|
27
|
+
else
|
28
|
+
field=method
|
29
|
+
setter=false
|
30
|
+
end
|
31
|
+
fields.has_key?(field)
|
32
|
+
end
|
33
|
+
|
34
|
+
# Finalize marks a draft agreement as being ready to accept
|
35
|
+
def finalize!
|
36
|
+
user.post(path+"/finalize")==" "
|
37
|
+
end
|
38
|
+
|
39
|
+
protected
|
40
|
+
|
41
|
+
def attributes_for_save #:nodoc:
|
42
|
+
if new_record?
|
43
|
+
{self.class.singular_name=>attributes}
|
44
|
+
else
|
45
|
+
{"fields"=>fields}
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def method_missing(method, *args, &block) #:nodoc:
|
50
|
+
return super(method, *args, &block) if fields.nil?||fields.empty?
|
51
|
+
method=method.to_s
|
52
|
+
if method=~/(.+)=$/
|
53
|
+
field=$1
|
54
|
+
setter=true
|
55
|
+
else
|
56
|
+
field=method
|
57
|
+
setter=false
|
58
|
+
end
|
59
|
+
if fields.has_key?(field)
|
60
|
+
if setter
|
61
|
+
fields[field]=args.first
|
62
|
+
else
|
63
|
+
fields[field]
|
64
|
+
end
|
65
|
+
else
|
66
|
+
super method, *args, &block
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
end
|
data/lib/agree2/base.rb
ADDED
@@ -0,0 +1,147 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'set'
|
3
|
+
module Agree2
|
4
|
+
# The superclass of all Agree2 Resource objects.
|
5
|
+
class Base
|
6
|
+
class<<self
|
7
|
+
|
8
|
+
def attr_serializable(*attributes) #:nodoc:
|
9
|
+
attributes.map!{|a|a.to_sym}
|
10
|
+
write_inheritable_attribute("serializable_attributes",
|
11
|
+
Set.new(attributes) +
|
12
|
+
(serializable_attributes || []))
|
13
|
+
attr_accessor *attributes
|
14
|
+
end
|
15
|
+
|
16
|
+
# Returns an array of all the attributes that have been made accessible to mass-assignment.
|
17
|
+
def serializable_attributes # :nodoc:
|
18
|
+
read_inheritable_attribute("serializable_attributes")
|
19
|
+
end
|
20
|
+
|
21
|
+
def collection_path #:nodoc:
|
22
|
+
"/#{collection_name}"
|
23
|
+
end
|
24
|
+
|
25
|
+
def instance_path(id) #:nodoc:
|
26
|
+
"#{collection_path}/#{id}"
|
27
|
+
end
|
28
|
+
|
29
|
+
def collection_name #:nodoc:
|
30
|
+
self.to_s.demodulize.tableize
|
31
|
+
end
|
32
|
+
|
33
|
+
def singular_name #:nodoc:
|
34
|
+
self.to_s.demodulize.underscore.singularize
|
35
|
+
end
|
36
|
+
|
37
|
+
# Gets an instance of a resource
|
38
|
+
def get(container,id)
|
39
|
+
user=(container.is_a?(User) ? container : container.user)
|
40
|
+
new( container, user.get(container.path+instance_path(id)))
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
attr_accessor :user,:container
|
46
|
+
|
47
|
+
def initialize(container,fields={})#:nodoc:
|
48
|
+
@container=container
|
49
|
+
@user=(container.is_a?(User) ? container : container.user)
|
50
|
+
if fields.is_a?(Hash)
|
51
|
+
load_attributes(fields)
|
52
|
+
else
|
53
|
+
load_json(fields)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# Has this record been saved to the server yet?
|
58
|
+
def new_record?
|
59
|
+
@from_wire!=true
|
60
|
+
end
|
61
|
+
|
62
|
+
# Reloads the object from Agree2's servers
|
63
|
+
def reload
|
64
|
+
load_json(user.get(path))
|
65
|
+
end
|
66
|
+
|
67
|
+
# Destroys the object from Agree2's servers
|
68
|
+
def destroy
|
69
|
+
user.delete(path)
|
70
|
+
end
|
71
|
+
|
72
|
+
# Returns the full URL for the object
|
73
|
+
def to_url
|
74
|
+
"#{AGREE2_URL}#{path}"
|
75
|
+
end
|
76
|
+
|
77
|
+
# Returns the relative path to the object
|
78
|
+
def path #:nodoc:
|
79
|
+
self.container.path+self.class.instance_path(to_param)
|
80
|
+
end
|
81
|
+
|
82
|
+
# The primary key of the object
|
83
|
+
def to_param #:nodoc:
|
84
|
+
id
|
85
|
+
end
|
86
|
+
|
87
|
+
# Saves the record to the server
|
88
|
+
def save
|
89
|
+
if new_record?
|
90
|
+
load_json(@user.post("#{self.container.path}/#{self.class.collection_name}",attributes_for_save))
|
91
|
+
else
|
92
|
+
load_json(@user.put("#{path}",attributes_for_save))
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
# Get the primary attributes of an object as a hash
|
97
|
+
def attributes
|
98
|
+
self.class.serializable_attributes.inject({}) do |h,field|
|
99
|
+
value=self.send(field)
|
100
|
+
h[field]=value if value
|
101
|
+
h
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
protected
|
106
|
+
|
107
|
+
def attributes_for_save #:nodoc:
|
108
|
+
{self.class.singular_name=>attributes}
|
109
|
+
end
|
110
|
+
|
111
|
+
def decode(element) #:nodoc:
|
112
|
+
for field in self.class.serializable_attributes
|
113
|
+
method_name="#{field.to_s}=".to_sym
|
114
|
+
self.send(method_name, (element/field.to_sym).innerHTML) if self.respond_to?(method_name)
|
115
|
+
end
|
116
|
+
self
|
117
|
+
end
|
118
|
+
|
119
|
+
def load_attributes(attributes) #:nodoc:
|
120
|
+
@attributes=attributes
|
121
|
+
attributes.each_pair do |key,value|
|
122
|
+
method_name="#{key.to_s}=".to_sym
|
123
|
+
self.send(method_name,value) if self.respond_to?(method_name)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
def load_json(json) #:nodoc:
|
128
|
+
@from_wire=true
|
129
|
+
load_attributes(JSON.parse(json))
|
130
|
+
end
|
131
|
+
# private
|
132
|
+
#
|
133
|
+
# def method_missing(method_symbol, *arguments) #:nodoc:
|
134
|
+
# method_name = method_symbol.to_s
|
135
|
+
#
|
136
|
+
# case method_name.last
|
137
|
+
# when "="
|
138
|
+
# self.attributes[method_name.first(-1)] = arguments.first
|
139
|
+
# when "?"
|
140
|
+
# self.attributes[method_name.first(-1)]
|
141
|
+
# else
|
142
|
+
# self.attributes.has_key?(method_name) ? self.attributes[method_name] : super
|
143
|
+
# end
|
144
|
+
# end
|
145
|
+
#
|
146
|
+
end
|
147
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
require 'oauth/consumer'
|
2
|
+
|
3
|
+
module Agree2
|
4
|
+
# If you haven't done so already register your application at https://agree2.com/client_applications
|
5
|
+
#
|
6
|
+
# The full authorization process works like this over 2 controller actions (This example is in Rails):
|
7
|
+
#
|
8
|
+
# def request_token
|
9
|
+
# @client = Agree2::Client.new "key","secret"
|
10
|
+
# @request_token = @client.get_request_token
|
11
|
+
#
|
12
|
+
# # Store the token in a model in your applications mapping it to your user
|
13
|
+
# Agree2RequestToken.create :user=>current_user,:token=>@request_token.token,:secret=>@request_token.secret
|
14
|
+
# redirect_to @request_token.authorize_url
|
15
|
+
# end
|
16
|
+
#
|
17
|
+
# # The user authorizes the token on the Agree2 web site and is redirected to the authorize_url you setup when you registered your application at:
|
18
|
+
# # https://agree2.com/client_applications
|
19
|
+
# def authorize
|
20
|
+
# @client = Agree2::Client.new "key","secret"
|
21
|
+
#
|
22
|
+
# # Load the request token from your Agree2RequestToken through your user model
|
23
|
+
# @request_token = current_user.agree2_request_token.request_token
|
24
|
+
#
|
25
|
+
# # Exchange the authorized request token for a more permanent User token on the Agree2 site
|
26
|
+
# @user_client=@client.user_from_request_token(@request_token)
|
27
|
+
#
|
28
|
+
# # Store the Agree2 user data in your own model
|
29
|
+
# @agree2_user=Agree2User.create :user=>current_user,:token=>@user_client.token,:secret=>@user_client.secret
|
30
|
+
# end
|
31
|
+
#
|
32
|
+
|
33
|
+
class Client
|
34
|
+
attr_accessor :consumer
|
35
|
+
|
36
|
+
# Initialize the Agree2 Client
|
37
|
+
#
|
38
|
+
# === Required Fields
|
39
|
+
#
|
40
|
+
# * <tt>key</tt> - The Consumer Key
|
41
|
+
# * <tt>secret</tt> - The Consumer Secret
|
42
|
+
#
|
43
|
+
# To get these register your application at: https://agree2.com/client_applications
|
44
|
+
def initialize(key,secret)
|
45
|
+
@consumer=OAuth::Consumer.new(key,secret,{:site=>AGREE2_URL})
|
46
|
+
end
|
47
|
+
|
48
|
+
# initialize a new user object with the given token and secret. The user object is what you use to do most of the work.
|
49
|
+
# Use this method when you need to create a user object from a token and secret you have stored in your applications database.
|
50
|
+
#
|
51
|
+
# === Required Fields
|
52
|
+
#
|
53
|
+
# * <tt>token</tt> - This is the authorized Token
|
54
|
+
# * <tt>secret</tt> - This is the authorized Token Secret
|
55
|
+
#
|
56
|
+
def user(token,token_secret)
|
57
|
+
User.new(self,token,token_secret)
|
58
|
+
end
|
59
|
+
|
60
|
+
# Start the process of authorizing a token for an Agree2 user.
|
61
|
+
#
|
62
|
+
# Example:
|
63
|
+
# @request_token = @client.get_request_token
|
64
|
+
# redirect_to @request_token.authorize_url
|
65
|
+
#
|
66
|
+
def get_request_token
|
67
|
+
consumer.get_request_token
|
68
|
+
end
|
69
|
+
|
70
|
+
# Exchange an Authorized RequestToken for a working user object
|
71
|
+
#
|
72
|
+
# === Required Field
|
73
|
+
#
|
74
|
+
# * <tt>request_token</tt> The Request token created using get_request_token and authorized on Agree2 by your user
|
75
|
+
#
|
76
|
+
# Example:
|
77
|
+
#
|
78
|
+
# @user_client = @client.user_from_request_token(@request_token)
|
79
|
+
#
|
80
|
+
def user_from_request_token(request_token)
|
81
|
+
access_token=request_token.get_access_token
|
82
|
+
user(access_token.token,access_token.secret)
|
83
|
+
rescue Net::HTTPServerException=>e
|
84
|
+
if e.response.code=='401'
|
85
|
+
raise Agree2Exception,"The user has not authorized this request token",caller
|
86
|
+
else
|
87
|
+
raise
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
# Returns your consumer key
|
92
|
+
def key
|
93
|
+
@consumer.key
|
94
|
+
end
|
95
|
+
|
96
|
+
# Returns your consumer secret
|
97
|
+
def secret
|
98
|
+
@consumer.secret
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
data/lib/agree2/party.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
module Agree2
|
2
|
+
class Party<Base
|
3
|
+
attr_serializable :id,:role,:email,:first_name,:last_name,:created_at,:updated_at,:organization_name
|
4
|
+
alias_method :agreement,:container
|
5
|
+
|
6
|
+
# Creates a one time signed url to redirect your user to their acceptance page. This url is only valid once. Call again to
|
7
|
+
# redirect your user to the agreement again.
|
8
|
+
def present
|
9
|
+
path="/present/#{agreement.permalink}/to/#{email}"
|
10
|
+
AGREE2_URL+user.client.consumer.create_signed_request(:get,path,user.access_token,{:scheme=>:query_string}).path
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.validate_parties_hash(parties) #:nodoc:
|
14
|
+
parties&&parties.each{|r,p| validate_party_hash(p)}
|
15
|
+
true
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.validate_party_hash(p) #:nodoc:
|
19
|
+
raise ArgumentError,"Your parties are missing required fields" if [:first_name,:last_name,:email].find{|k| !p.include?(k)}
|
20
|
+
return true
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|