fine_print 0.1.1 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (156) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +74 -45
  3. data/Rakefile +9 -9
  4. data/app/assets/javascripts/application.js~ +16 -0
  5. data/app/assets/javascripts/fine_print/application.js +8 -2
  6. data/app/controllers/fine_print/application_controller.rb +9 -7
  7. data/app/controllers/fine_print/application_controller.rb~ +9 -7
  8. data/app/controllers/fine_print/contracts_controller.rb +79 -0
  9. data/app/controllers/fine_print/contracts_controller.rb~ +79 -0
  10. data/app/controllers/fine_print/home_controller.rb +1 -11
  11. data/app/controllers/fine_print/home_controller.rb~ +2 -11
  12. data/app/controllers/fine_print/signatures_controller.rb +14 -0
  13. data/app/controllers/fine_print/signatures_controller.rb~ +14 -0
  14. data/app/helpers/fine_print/application_helper.rb +7 -0
  15. data/app/helpers/fine_print/application_helper.rb~ +7 -0
  16. data/app/helpers/fine_print/contracts_helper.rb~ +7 -0
  17. data/app/models/fine_print/contract.rb +96 -0
  18. data/app/models/fine_print/contract.rb~ +100 -0
  19. data/app/models/fine_print/signature.rb +25 -0
  20. data/app/models/fine_print/signature.rb~ +25 -0
  21. data/app/views/fine_print/contracts/_form.html.erb +35 -0
  22. data/app/views/fine_print/contracts/_form.html.erb~ +35 -0
  23. data/app/views/fine_print/contracts/edit.html.erb +10 -0
  24. data/app/views/fine_print/contracts/index.html.erb +43 -0
  25. data/app/views/fine_print/contracts/index.html.erb~ +43 -0
  26. data/app/views/fine_print/contracts/new.html.erb +9 -0
  27. data/app/views/fine_print/contracts/new_version.html.erb +9 -0
  28. data/app/views/fine_print/contracts/show.html.erb +33 -0
  29. data/app/views/fine_print/contracts/show.html.erb~ +35 -0
  30. data/app/views/fine_print/home/index.html.erb +15 -6
  31. data/app/views/fine_print/home/index.html.erb~ +12 -4
  32. data/app/views/fine_print/signatures/index.html.erb +36 -0
  33. data/app/views/fine_print/signatures/index.html.erb~ +32 -0
  34. data/app/views/layouts/fine_print/application.html.erb +6 -0
  35. data/app/views/layouts/fine_print/application.html.erb~ +20 -0
  36. data/config/initializers/fine_print.rb +27 -44
  37. data/config/initializers/fine_print.rb~ +23 -40
  38. data/config/routes.rb +9 -3
  39. data/config/routes.rb~ +9 -4
  40. data/db/migrate/0_install_fine_print.rb +26 -0
  41. data/db/migrate/0_install_fine_print.rb~ +26 -0
  42. data/lib/fine_print/controller_additions.rb +69 -0
  43. data/lib/fine_print/controller_additions.rb~ +69 -0
  44. data/lib/fine_print/engine.rb +8 -0
  45. data/lib/fine_print/security_transgression.rb +1 -2
  46. data/lib/fine_print/utilities.rb~ +26 -0
  47. data/lib/fine_print/version.rb +1 -1
  48. data/lib/fine_print.rb +89 -42
  49. data/lib/fine_print.rb~ +89 -41
  50. data/lib/tasks/fine_print_tasks.rake +11 -8
  51. data/spec/controllers/contracts_controller_spec.rb +222 -0
  52. data/spec/controllers/contracts_controller_spec.rb~ +224 -0
  53. data/spec/controllers/home_controller_spec.rb +25 -0
  54. data/spec/controllers/home_controller_spec.rb~ +25 -0
  55. data/spec/controllers/signatures_controller_spec.rb +46 -0
  56. data/spec/controllers/signatures_controller_spec.rb~ +46 -0
  57. data/spec/dummy/README.md +1 -1
  58. data/spec/dummy/app/controllers/dummy_models_controller.rb +2 -0
  59. data/spec/dummy/app/controllers/dummy_models_controller.rb~ +29 -0
  60. data/spec/dummy/app/helpers/application_helper.rb +13 -0
  61. data/spec/dummy/app/models/dummy_user.rb +3 -0
  62. data/spec/dummy/app/models/dummy_user.rb~ +4 -0
  63. data/spec/dummy/app/models/user.rb~ +78 -0
  64. data/spec/dummy/config/application.rb +2 -2
  65. data/spec/dummy/config/application.rb~ +60 -0
  66. data/spec/dummy/config/initializers/fine_print.rb +36 -0
  67. data/spec/dummy/config/initializers/fine_print.rb~ +36 -0
  68. data/spec/dummy/config/initializers/session_store.rb +1 -1
  69. data/spec/dummy/config/initializers/session_store.rb~ +8 -0
  70. data/spec/dummy/config/initializers/wrap_parameters.rb +1 -1
  71. data/spec/dummy/config/initializers/wrap_parameters.rb~ +14 -0
  72. data/spec/dummy/config/routes.rb +1 -2
  73. data/spec/dummy/config/routes.rb~ +4 -0
  74. data/spec/dummy/db/development.sqlite3 +0 -0
  75. data/spec/dummy/db/migrate/1_create_dummy_users.rb +9 -0
  76. data/spec/dummy/db/migrate/1_create_dummy_users.rb~ +8 -0
  77. data/spec/dummy/db/schema.rb +20 -12
  78. data/spec/dummy/db/test.sqlite3 +0 -0
  79. data/spec/dummy/log/development.log +1635 -0
  80. data/spec/dummy/log/test.log +46188 -0
  81. data/spec/factories/contract.rb +25 -0
  82. data/spec/factories/contract.rb~ +26 -0
  83. data/spec/factories/dummy_user.rb +4 -0
  84. data/spec/factories/dummy_user.rb~ +6 -0
  85. data/spec/factories/signature.rb +6 -0
  86. data/spec/factories/signature.rb~ +8 -0
  87. data/spec/factories/user.rb~ +6 -0
  88. data/spec/fine_print_spec.rb~ +15 -4
  89. data/spec/lib/fine_print/controller_additions_spec.rb +20 -0
  90. data/spec/lib/fine_print/controller_additions_spec.rb~ +20 -0
  91. data/spec/lib/fine_print_spec.rb +47 -0
  92. data/spec/lib/fine_print_spec.rb~ +47 -0
  93. data/spec/models/contract_spec.rb +79 -0
  94. data/spec/models/contract_spec.rb~ +80 -0
  95. data/spec/models/signature_spec.rb +28 -0
  96. data/spec/models/signature_spec.rb~ +28 -0
  97. data/spec/spec_helper.rb +31 -0
  98. data/spec/spec_helper.rb~ +32 -0
  99. data/spec/test_helper.rb~ +15 -0
  100. metadata +153 -91
  101. data/app/assets/javascripts/fine_print/agreements.js +0 -19
  102. data/app/assets/javascripts/fine_print/agreements.js~ +0 -19
  103. data/app/assets/javascripts/fine_print/application.js~ +0 -5
  104. data/app/assets/javascripts/fine_print/dialog.js +0 -2
  105. data/app/assets/javascripts/fine_print/dialog.js~ +0 -2
  106. data/app/assets/javascripts/fine_print/user_agreements.js +0 -20
  107. data/app/assets/javascripts/fine_print/user_agreements.js~ +0 -20
  108. data/app/assets/stylesheets/fine_print/agreements.css +0 -11
  109. data/app/assets/stylesheets/fine_print/agreements.css~ +0 -11
  110. data/app/assets/stylesheets/fine_print/application.css~ +0 -60
  111. data/app/assets/stylesheets/fine_print/user_agreements.css~ +0 -3
  112. data/app/assets/stylesheets/scaffold.css~ +0 -56
  113. data/app/controllers/fine_print/agreements_controller.rb +0 -114
  114. data/app/controllers/fine_print/agreements_controller.rb~ +0 -113
  115. data/app/controllers/fine_print/user_agreements_controller.rb +0 -63
  116. data/app/controllers/fine_print/user_agreements_controller.rb~ +0 -63
  117. data/app/models/fine_print/agreement.rb +0 -50
  118. data/app/models/fine_print/agreement.rb~ +0 -50
  119. data/app/models/fine_print/user_agreement.rb +0 -19
  120. data/app/models/fine_print/user_agreement.rb~ +0 -21
  121. data/app/views/fine_print/agreements/_agreement.html.erb +0 -77
  122. data/app/views/fine_print/agreements/_agreement.html.erb~ +0 -77
  123. data/app/views/fine_print/agreements/_dialog.html.erb +0 -27
  124. data/app/views/fine_print/agreements/_dialog.html.erb~ +0 -27
  125. data/app/views/fine_print/agreements/_form.html.erb +0 -51
  126. data/app/views/fine_print/agreements/_form.html.erb~ +0 -51
  127. data/app/views/fine_print/agreements/edit.html.erb +0 -8
  128. data/app/views/fine_print/agreements/edit.html.erb~ +0 -8
  129. data/app/views/fine_print/agreements/index.html.erb +0 -32
  130. data/app/views/fine_print/agreements/index.html.erb~ +0 -32
  131. data/app/views/fine_print/agreements/new.html.erb +0 -7
  132. data/app/views/fine_print/agreements/new.html.erb~ +0 -7
  133. data/app/views/fine_print/agreements/new_version.html.erb +0 -7
  134. data/app/views/fine_print/agreements/new_version.html.erb~ +0 -7
  135. data/app/views/fine_print/agreements/show.html.erb +0 -15
  136. data/app/views/fine_print/agreements/show.html.erb~ +0 -14
  137. data/app/views/fine_print/user_agreements/cancel.js.erb +0 -1
  138. data/app/views/fine_print/user_agreements/cancel.js.erb~ +0 -2
  139. data/app/views/fine_print/user_agreements/create.js.erb +0 -2
  140. data/app/views/fine_print/user_agreements/create.js.erb~ +0 -2
  141. data/app/views/fine_print/user_agreements/index.html.erb +0 -25
  142. data/app/views/fine_print/user_agreements/index.html.erb~ +0 -25
  143. data/db/migrate/0_create_fine_print_agreements.rb~ +0 -22
  144. data/db/migrate/0_install.rb +0 -28
  145. data/db/migrate/0_install.rb~ +0 -28
  146. data/lib/fine_print/agreements_helper.rb +0 -13
  147. data/lib/fine_print/agreements_helper.rb~ +0 -11
  148. data/lib/fine_print/fine_print_agreement.rb +0 -26
  149. data/lib/fine_print/fine_print_agreement.rb~ +0 -26
  150. data/lib/fine_print/require_agreement.rb~ +0 -22
  151. data/lib/fine_print/security_transgression.rb~ +0 -3
  152. data/lib/fine_print/version.rb~ +0 -3
  153. data/lib/tasks/fine_print_tasks.rake~ +0 -42
  154. data/spec/dummy/README.md~ +0 -3
  155. data/spec/fine_print_spec.rb +0 -7
  156. data/spec/minitest_helper.rb +0 -12
@@ -1,53 +1,36 @@
1
1
  # Change the settings below to suit your needs
2
2
  # All settings are initially set to their default values
3
3
  FinePrint.configure do |config|
4
-
5
- # Engine Options (initializer only)
4
+ # Engine Configuration
6
5
 
7
6
  # Name of the ApplicationController helper method that returns the current user
8
- # Default: "current_user"
9
- config.current_user_method = "current_user"
7
+ # Default: 'current_user'
8
+ config.current_user_method = 'current_user'
10
9
 
11
10
  # Proc called with user as argument that should return true if and only if the user is an admin
12
11
  # Admins can create and edit agreements and terminate accepted agreements
13
12
  # Default: lambda { |user| false } (no admins)
14
13
  config.user_admin_proc = lambda { |user| false }
15
14
 
16
- # Path to redirect users to when an error occurs (e.g. permission denied on admin pages)
17
- # Default: "/"
18
- config.redirect_path = "/"
19
-
20
- # Path to link users to if they need to sign in
21
- # Set to nil to disable the link
22
- # Default: "/"
23
- config.sign_in_path = "/"
24
-
25
-
26
-
27
- # Agreement Options (initializer or inline)
15
+ # Proc that returns true if and only if the provided user is logged in
16
+ # In many systems, a non-logged-in user is represented by nil
17
+ # However, some systems use something like an AnonymousUser class to represent this state
18
+ # This proc is mostly used to help the developer realize that they should only be asking
19
+ # signed in users to sign contracts; without this, developers would get a cryptic SQL error
20
+ # Default: lambda { |user| !user.nil? }
21
+ config.user_signed_in_proc = lambda { |user| !user.nil? }
28
22
 
29
- # Message to be displayed to the user explaining that they need to accept an agreement
30
- # Set to nil to disable
31
- # Default: "You must accept the following agreement to proceed."
32
- config.agreement_notice = "You must accept the following agreement to proceed."
33
-
34
- # Path to redirect users to when an agreement is accepted and referer information is unavailable
35
- # Default: "/"
36
- config.accept_path = "/"
37
-
38
- # Path to redirect users to when an agreement is not accepted and referer information is unavailable
39
- # Default: "/"
40
- config.cancel_path = "/"
41
-
42
- # Whether to use referer information to redirect users after (not) accepting an agreement
43
- # Default: true
44
- config.use_referers = true
45
-
46
- # If set to true, modal jQuery UI dialogs will be used instead of redirecting the user to the agreement page
47
- # Note: users with javascript disabled will not even see the agreement and will be able to proceed without accepting it
48
- # if users are not supposed to ever see or interact with a certain page without accepting the agreement,
49
- # disable this option for that particular controller action
50
- # Default: false
51
- config.use_modal_dialogs = false
52
-
23
+ # Path to redirect users to when an error occurs (e.g. permission denied on admin pages)
24
+ # Default: '/'
25
+ config.redirect_path = '/'
26
+
27
+ # Signature (fine_print_get_signatures) Configuration
28
+
29
+ # Path to redirect users to when they need to agree to contract(s)
30
+ # A list of contract names that must be agreed to will be available in the 'contracts' parameter
31
+ # Your code doesn't have to deal with all of them at once, e.g. you can get
32
+ # the user to agree to the first one and then they'll just eventually be
33
+ # redirected back to this page with the remaining contract names
34
+ # Default: '/'
35
+ config.pose_contracts_path = '/'
53
36
  end
data/config/routes.rb CHANGED
@@ -1,7 +1,13 @@
1
1
  FinePrint::Engine.routes.draw do
2
- resources :agreements do
3
- get :new_version
2
+ resources :contracts do
3
+ member do
4
+ get :new_version
5
+ put :publish
6
+ put :unpublish
7
+ end
4
8
  end
5
- resources :user_agreements, :only => [:index, :create, :destroy]
9
+
10
+ resources :signatures, :only => [:index, :destroy]
11
+
6
12
  root :to => 'home#index'
7
13
  end
data/config/routes.rb~ CHANGED
@@ -1,7 +1,12 @@
1
1
  FinePrint::Engine.routes.draw do
2
- resources :agreements do
3
- get :new_version
2
+ resources :contracts do
3
+ member do
4
+ get :new_version, :on => :member
5
+ put :publish, :on => :member
6
+ put :unpublish, :on => :member
4
7
  end
5
- resources :user_agreements, :only => [:index, :create, :destroy]
6
- root :to => 'agreements#index'
8
+
9
+ resources :signatures, :only => [:index, :destroy]
10
+
11
+ root :to => 'home#index'
7
12
  end
@@ -0,0 +1,26 @@
1
+ class InstallFinePrint < ActiveRecord::Migration
2
+ def change
3
+ create_table :fine_print_contracts do |t|
4
+ t.string :name, :null => false
5
+ t.integer :version
6
+ t.string :title, :null => false
7
+ t.text :content, :null => false
8
+
9
+ t.timestamps
10
+ end
11
+
12
+ add_index :fine_print_contracts, [:name, :version], :unique => true
13
+
14
+ create_table :fine_print_signatures do |t|
15
+ t.belongs_to :contract, :null => false
16
+ t.belongs_to :user, :polymorphic => true, :null => false
17
+
18
+ t.timestamps
19
+ end
20
+
21
+ add_index :fine_print_signatures, :contract_id
22
+ add_index :fine_print_signatures, [:user_id, :user_type, :contract_id],
23
+ :name => 'index_fine_print_s_on_u_id_and_u_type_and_c_id',
24
+ :unique => true
25
+ end
26
+ end
@@ -0,0 +1,26 @@
1
+ class InstallFinePrint < ActiveRecord::Migration
2
+ def change
3
+ create_table :fine_print_contracts do |t|
4
+ t.string :name, :null => false
5
+ t.integer :version
6
+ t.string :title, :null => false, :default => ''
7
+ t.text :content, :null => false, :default => ''
8
+
9
+ t.timestamps
10
+ end
11
+
12
+ add_index :fine_print_contracts, [:name, :version], :unique => true
13
+
14
+ create_table :fine_print_signatures do |t|
15
+ t.belongs_to :contract, :null => false
16
+ t.belongs_to :user, :polymorphic => true, :null => false
17
+
18
+ t.timestamps
19
+ end
20
+
21
+ add_index :fine_print_signatures, :contract_id
22
+ add_index :fine_print_signatures, [:user_id, :user_type, :contract_id],
23
+ :name => 'index_fine_print_s_on_u_id_and_u_type_and_c_id',
24
+ :unique => true
25
+ end
26
+ end
@@ -0,0 +1,69 @@
1
+ module FinePrint
2
+ module ControllerAdditions
3
+ #
4
+ # Internally these methods think of contract names as strings, not symbols.
5
+ # Any names passed in as symbols are converted to strings.
6
+ #
7
+ def self.included(base)
8
+ base.extend(ClassMethods)
9
+ end
10
+
11
+ def fine_print_skipped_contract_names
12
+ @fine_print_skipped_contract_names ||= []
13
+ end
14
+
15
+ # See the README
16
+ def fine_print_return
17
+ redirect_to session.delete(:fine_print_return_to) || root_path
18
+ end
19
+
20
+ module ClassMethods
21
+ # See the README
22
+ def fine_print_get_signatures(*args)
23
+ options = args.last.is_a?(Hash) ? args.pop : {}
24
+
25
+ filter_options = options.except(*FinePrint::SIGNATURE_OPTIONS)
26
+ fine_print_options = options.slice(*FinePrint::SIGNATURE_OPTIONS)
27
+
28
+ # Convert all names to string
29
+ names = args.collect{|n| n.to_s}
30
+
31
+ class_eval do
32
+ before_filter(filter_options) do |controller|
33
+ names_to_check = names - fine_print_skipped_contract_names
34
+
35
+ # Bail if nothing to do
36
+ return true if names_to_check.blank?
37
+
38
+ user = send FinePrint.current_user_method
39
+ FinePrint.raise_unless_signed_in(user)
40
+
41
+ unsigned_contract_names =
42
+ FinePrint.get_unsigned_contract_names(names_to_check, user)
43
+ return true if unsigned_contract_names.empty?
44
+
45
+ # http://stackoverflow.com/a/2165727/1664216
46
+ session[:fine_print_return_to] = "#{request.protocol}#{request.host_with_port}#{request.fullpath}"
47
+ # http://stackoverflow.com/a/6561953
48
+ path = fine_print_options[:pose_contracts_path] || FinePrint.pose_contracts_path
49
+ redirect_to path + (path.include?('?') ? '&' : '?') + {:terms => unsigned_contract_names}.to_query
50
+ end
51
+ end
52
+ end
53
+
54
+ # See the README
55
+ def fine_print_skip_signatures(*args)
56
+ options = args.last.is_a?(Hash) ? args.pop : {}
57
+ names = args.collect{|arg| arg.to_s}
58
+
59
+ class_eval do
60
+ prepend_before_filter(options) do |controller|
61
+ fine_print_skipped_contract_names.push(*names)
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
68
+
69
+ ActionController::Base.send :include, FinePrint::ControllerAdditions
@@ -0,0 +1,69 @@
1
+ module FinePrint
2
+ module ControllerAdditions
3
+ #
4
+ # Internally these methods think of contract names as strings, not symbols.
5
+ # Any names passed in as symbols are converted to strings.
6
+ #
7
+ def self.included(base)
8
+ base.extend(ClassMethods)
9
+ end
10
+
11
+ def fine_print_skipped_contract_names
12
+ @fine_print_skipped_contract_names ||= []
13
+ end
14
+
15
+ # See the README
16
+ def fine_print_return
17
+ redirect_to root_path
18
+ end
19
+
20
+ module ClassMethods
21
+ # See the README
22
+ def fine_print_get_signatures(*args)
23
+ options = args.last.is_a?(Hash) ? args.pop : {}
24
+
25
+ filter_options = options.except(*FinePrint::SIGNATURE_OPTIONS)
26
+ fine_print_options = options.slice(*FinePrint::SIGNATURE_OPTIONS)
27
+
28
+ # Convert all names to string
29
+ names = args.collect{|n| n.to_s}
30
+
31
+ class_eval do
32
+ before_filter(filter_options) do |controller|
33
+ names_to_check = names - fine_print_skipped_contract_names
34
+
35
+ # Bail if nothing to do
36
+ return true if names_to_check.blank?
37
+
38
+ user = send FinePrint.current_user_method
39
+ FinePrint.raise_unless_signed_in(user)
40
+
41
+ unsigned_contract_names =
42
+ FinePrint.get_unsigned_contract_names(names_to_check, user)
43
+ return true if unsigned_contract_names.empty?
44
+
45
+ # http://stackoverflow.com/a/2165727/1664216
46
+ session[:fine_print_return_to] = "#{request.protocol}#{request.host_with_port}#{request.fullpath}"
47
+ # http://stackoverflow.com/a/6561953
48
+ path = fine_print_options[:pose_contracts_path] || FinePrint.pose_contracts_path
49
+ redirect_to path + (path.include?('?') ? '&' : '?') + {:terms => unsigned_contract_names}.to_query
50
+ end
51
+ end
52
+ end
53
+
54
+ # See the README
55
+ def fine_print_skip_signatures(*args)
56
+ options = args.last.is_a?(Hash) ? args.pop : {}
57
+ names = args.collect{|arg| arg.to_s}
58
+
59
+ class_eval do
60
+ prepend_before_filter(options) do |controller|
61
+ fine_print_skipped_contract_names.push(*names)
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
68
+
69
+ ActionController::Base.send :include, FinePrint::ControllerAdditions
@@ -1,5 +1,13 @@
1
1
  module FinePrint
2
2
  class Engine < ::Rails::Engine
3
3
  isolate_namespace FinePrint
4
+
5
+ # http://viget.com/extend/rails-engine-testing-with-rspec-capybara-and-factorygirl
6
+ config.generators do |g|
7
+ g.test_framework :rspec, :fixture => false
8
+ g.fixture_replacement :factory_girl, :dir => 'spec/factories'
9
+ g.assets false
10
+ g.helper false
11
+ end
4
12
  end
5
13
  end
@@ -1,4 +1,3 @@
1
1
  module FinePrint
2
- class SecurityTransgression < StandardError
3
- end
2
+ class SecurityTransgression < StandardError; end
4
3
  end
@@ -0,0 +1,26 @@
1
+ module FinePrint
2
+ module Utilities
3
+ # Returns true iff the given user has signed any version of the given contract.
4
+ # contract -- can be a Contract object, its ID, or its name as a String or Symbol
5
+ def self.any_signed_contract_version?(contract, user)
6
+ contract = FinePrint::get_contract(contract)
7
+ !user.nil? &&
8
+ !Signature.joins(:contract)
9
+ .where(:contract => {:name => contract.name},
10
+ :user_type => user.class.name,
11
+ :user_id => user.id).first.nil?
12
+ end
13
+
14
+ # Returns the latest version of the named contract (since contracts don't have
15
+ # versions until they are published this only returns published contracts).
16
+ # If no such contract exists, returns nil.
17
+ # name -- can be a String or a Symbol
18
+ def self.latest_contract_named(name)
19
+ name = name.to_s
20
+ contract = Contract.where(:name => name).published.first
21
+ raise IllegalState, "Published version of #{name} not found" \
22
+ if contract.nil?
23
+ contract
24
+ end
25
+ end
26
+ end
@@ -1,3 +1,3 @@
1
1
  module FinePrint
2
- VERSION = "0.1.1"
2
+ VERSION = '1.0.0'
3
3
  end
data/lib/fine_print.rb CHANGED
@@ -1,69 +1,116 @@
1
- require "fine_print/engine"
2
- require "fine_print/fine_print_agreement"
1
+ require 'fine_print/engine'
2
+ require 'fine_print/security_transgression'
3
+ require 'fine_print/controller_additions'
3
4
 
4
5
  module FinePrint
5
- ASSET_FILES = %w(dialog.js)
6
-
7
6
  # Attributes
8
7
 
9
8
  # Can be set in initializer only
10
9
  ENGINE_OPTIONS = [
11
10
  :current_user_method,
12
11
  :user_admin_proc,
13
- :redirect_path,
14
- :sign_in_path
12
+ :user_signed_in_proc,
13
+ :pose_contracts_path,
14
+ :redirect_path
15
15
  ]
16
16
 
17
- # Can be set in initializer or passed as an option to fine_print_agreement
18
- AGREEMENT_OPTIONS = [
19
- :agreement_notice,
20
- :accept_path,
21
- :cancel_path,
22
- :use_referers,
23
- :use_modal_dialogs
17
+ # Can be set in initializer or passed as an option to fine_print_get_signatures
18
+ SIGNATURE_OPTIONS = [
19
+ :pose_contracts_path
24
20
  ]
25
21
 
26
- (ENGINE_OPTIONS + AGREEMENT_OPTIONS).each do |option|
22
+ (ENGINE_OPTIONS + SIGNATURE_OPTIONS).each do |option|
27
23
  mattr_accessor option
28
24
  end
29
-
30
- ActiveSupport.on_load(:before_initialize) do
31
- Rails.configuration.assets.precompile += ASSET_FILES
32
- end
33
25
 
34
26
  def self.configure
35
27
  yield self
36
28
  end
37
29
 
38
- def self.get_option(options, name)
39
- (!options.nil? && !options[name].nil?) ? options[name] : self.send(name)
30
+ # Gets a contract given either the contract's object, ID or name
31
+ # If given a name, it returns the latest published version of that contract
32
+ #
33
+ def self.get_contract(reference)
34
+ ref = Integer(reference) rescue reference
35
+ case ref
36
+ when Contract
37
+ ref
38
+ when Integer
39
+ Contract.find(ref)
40
+ when String
41
+ Contract.where(:name => ref).published.first
42
+ end
43
+ end
44
+
45
+ # Returns an array of names for the contracts whose latest published
46
+ # version the given user has not signed.
47
+ # - names -- an array of contract names
48
+ # - user -- the user in question
49
+ #
50
+ def self.get_unsigned_contract_names(names, user)
51
+ raise_unless_signed_in(user)
52
+ return [] if names.blank?
53
+ names_array = names.is_a?(Array) ? names.collect{|name| name.to_s} : [names.to_s]
54
+
55
+ signed_contracts = Contract
56
+ .joins(:signatures)
57
+ .where({:name => names_array,
58
+ :fine_print_signatures => {:user_id => user.id,
59
+ :user_type => user.class.name}}).latest
60
+ signed_contract_names = signed_contracts.collect{|c| c.name}
61
+
62
+ return names - signed_contract_names
40
63
  end
41
64
 
42
- def self.require_agreements(controller, names, options)
43
- user = controller.send current_user_method
44
- fine_print_dialog_agreements = []
45
- names.each do |name|
46
- agreement = Agreement.latest_ready(name)
47
- next if agreement.nil? || agreement.accepted_by?(user)
48
- if get_option(options, :use_modal_dialogs)
49
- fine_print_dialog_agreements << agreement
50
- else
51
- controller.session[:fine_print_accept_path] = options[:accept_path]
52
- controller.session[:fine_print_cancel_path] = options[:cancel_path]
53
- if get_option(options, :use_referers)
54
- controller.session[:fine_print_request_url] = controller.request.url
55
- controller.session[:fine_print_request_ref] = controller.request.referer
56
- end
57
- controller.redirect_to controller.fine_print.agreement_path(agreement),
58
- :notice => get_option(options, :agreement_notice)
59
- end
65
+ # Records that the given user has signed the given contract; the contract
66
+ # can be a Contract object, a contract ID, or a contract name (string)
67
+ #
68
+ def self.sign_contract(contract, user)
69
+ raise_unless_signed_in(user)
70
+ contract = get_contract(contract)
71
+ raise IllegalState, 'Contract not found' if contract.nil?
72
+
73
+ Signature.create do |signature|
74
+ signature.user = user
75
+ signature.contract = contract
60
76
  end
61
- controller.instance_variable_set(:@fine_print_dialog_agreements, fine_print_dialog_agreements)
62
- controller.instance_variable_set(:@fine_print_user, user)
63
- controller.instance_variable_set(:@fine_print_dialog_notice, get_option(options, :agreement_notice))
77
+ end
78
+
79
+ # Returns true iff the given user has signed the given contract; the contract
80
+ # can be a Contract object, a contract ID, or a contract name (string)
81
+ #
82
+ def self.signed_contract?(contract, user)
83
+ raise_unless_signed_in(user)
84
+ contract = get_contract(contract)
85
+
86
+ !contract.signatures.where(:user_id => user.id,
87
+ :user_type => user.class.name).first.nil?
88
+ end
89
+
90
+ # Returns true iff the given user has signed any version of the given contract.
91
+ # - contract -- can be a Contract object, its ID, or its name as a String or Symbol
92
+ def self.signed_any_contract_version?(contract, user)
93
+ raise_unless_signed_in(user)
94
+ contract = get_contract(contract)
95
+ !Signature.joins(:contract)
96
+ .where(:fine_print_contracts => {:name => contract.name},
97
+ :user_type => user.class.name,
98
+ :user_id => user.id).first.nil?
99
+ end
100
+
101
+ def self.is_signed_in?(user)
102
+ user_signed_in_proc.call(user)
64
103
  end
65
104
 
66
105
  def self.is_admin?(user)
67
- !user.nil? && user_admin_proc.call(user)
106
+ is_signed_in?(user) && user_admin_proc.call(user)
107
+ end
108
+
109
+ def self.raise_unless_signed_in(user)
110
+ raise IllegalState, 'User not signed in' unless is_signed_in?(user)
111
+ end
112
+
113
+ def self.raise_unless_admin(user)
114
+ raise SecurityTransgression unless is_admin?(user)
68
115
  end
69
116
  end