erp_tech_svcs 3.0.12 → 3.1.0
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.
- data/app/controllers/erp_tech_svcs/session_controller.rb +1 -1
- data/app/models/attribute_type.rb +2 -0
- data/app/models/attribute_value.rb +2 -0
- data/app/models/audit_log.rb +4 -1
- data/app/models/audit_log_item.rb +2 -0
- data/app/models/audit_log_item_type.rb +2 -0
- data/app/models/audit_log_type.rb +2 -0
- data/app/models/capability.rb +2 -1
- data/app/models/capability_type.rb +2 -0
- data/app/models/extensions/category.rb +3 -0
- data/app/models/extensions/compass_ae_instance.rb +3 -0
- data/app/models/file_asset.rb +3 -1
- data/app/models/group.rb +5 -18
- data/app/models/scope_type.rb +1 -0
- data/app/models/security_role.rb +2 -0
- data/app/models/user.rb +29 -42
- data/app/views/user_mailer/activation_needed_email.html.erb +1 -1
- data/app/views/user_mailer/reset_password_email.html.erb +1 -1
- data/config/initializers/erp_tech_svcs.rb +2 -0
- data/db/data_migrations/20121130212146_note_capabilities.rb +2 -2
- data/db/migrate/20080805000010_base_tech_services.rb +3 -3
- data/lib/erp_tech_svcs/config.rb +4 -0
- data/lib/erp_tech_svcs/extensions/active_record/acts_as_versioned.rb +105 -106
- data/lib/erp_tech_svcs/extensions/active_record/has_capability_accessors.rb +4 -10
- data/lib/erp_tech_svcs/extensions/active_record/has_security_roles.rb +2 -0
- data/lib/erp_tech_svcs/extensions/active_record/protected_with_capabilities.rb +28 -53
- data/lib/erp_tech_svcs/extensions/railties/action_view/base.rb +8 -0
- data/lib/erp_tech_svcs/extensions/railties/action_view/helpers/include_helper.rb +28 -0
- data/lib/erp_tech_svcs/extensions.rb +3 -0
- data/lib/erp_tech_svcs/file_support/railties/s3_resolver.rb +1 -1
- data/lib/erp_tech_svcs/sms_wrapper/clickatell.rb +3 -3
- data/lib/erp_tech_svcs/utils/compass_access_negotiator.rb +4 -6
- data/lib/erp_tech_svcs/version.rb +2 -2
- data/lib/erp_tech_svcs.rb +2 -1
- data/spec/dummy/config/application.rb +6 -0
- data/spec/dummy/config/environments/spec.rb +3 -0
- data/spec/dummy/config/s3.yml +23 -0
- data/spec/dummy/db/data_migrations/20120109173616_create_download_capability_type.erp_tech_svcs.rb +14 -0
- data/spec/dummy/db/migrate/{20130105133955_base_erp_services.erp_base_erp_svcs.rb → 20130107214445_base_erp_services.erp_base_erp_svcs.rb} +0 -0
- data/spec/dummy/db/migrate/{20130105133956_base_tech_services.erp_tech_svcs.rb → 20130107214446_base_tech_services.erp_tech_svcs.rb} +0 -0
- data/spec/dummy/db/migrate/{20130105133957_create_has_attribute_tables.erp_tech_svcs.rb → 20130107214447_create_has_attribute_tables.erp_tech_svcs.rb} +0 -0
- data/spec/dummy/db/migrate/{20130105133958_create_groups.erp_tech_svcs.rb → 20130107214448_create_groups.erp_tech_svcs.rb} +0 -0
- data/spec/dummy/db/migrate/{20130105133959_upgrade_security.erp_tech_svcs.rb → 20130107214449_upgrade_security.erp_tech_svcs.rb} +0 -0
- data/spec/dummy/db/migrate/{20130105133960_upgrade_security2.erp_tech_svcs.rb → 20130107214450_upgrade_security2.erp_tech_svcs.rb} +0 -0
- data/spec/dummy/db/schema.rb +1 -1
- data/spec/dummy/db/spec.sqlite3 +0 -0
- data/spec/dummy/log/spec.log +15314 -121571
- data/spec/dummy/move_test_tmp/file_asset_spec_text.txt +1 -0
- data/spec/lib/erp_tech_svcs/extensions/active_record/has_roles_spec.rb +6 -6
- data/spec/lib/file_support/s3_manager_spec.rb +1 -0
- data/spec/models/audit_log_spec.rb +1 -1
- data/spec/models/file_asset_spec.rb +14 -5
- data/spec/models/group_spec.rb +41 -0
- data/spec/models/security_role_spec.rb +26 -0
- data/spec/models/user_spec.rb +12 -2
- data/spec/spec_helper.rb +12 -7
- metadata +65 -48
- data/db/data_migrations/upgrade/20120727152144_set_image_dimensions_on_file_assets.rb +0 -13
- data/db/migrate/upgrade/20111109161549_add_capabilites.rb +0 -56
- data/db/migrate/upgrade/20111109161550_update_roles.rb +0 -35
- data/db/migrate/upgrade/20111109161551_update_user.rb +0 -88
- data/db/migrate/upgrade/20120329161641_add_file_asset_indexes.rb +0 -22
- data/db/migrate/upgrade/20120517203052_add_queue_to_delayed_jobs.rb +0 -13
- data/db/migrate/upgrade/20120725205131_add_image_dimension_columns_to_file_asset.rb +0 -15
- data/lib/erp_tech_svcs/application_installer.rb +0 -102
- data/lib/erp_tech_svcs/utils/attachment_fu_patch.rb +0 -15
- data/lib/erp_tech_svcs/utils/compass_pdf.rb +0 -72
- data/lib/erp_tech_svcs/utils/pdf_processor.rb +0 -106
- data/spec/dummy/log/adam.log +0 -1
- data/spec/factories/role.rb +0 -5
- data/spec/models/role_spec.rb +0 -17
- data/spec/models/secured_model_spec.rb +0 -22
data/app/models/audit_log.rb
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
class AuditLog < ActiveRecord::Base
|
|
2
|
+
attr_protected :created_at, :updated_at
|
|
3
|
+
|
|
4
|
+
attr_protected :created_at, :updated_at
|
|
2
5
|
|
|
3
6
|
validates :party_id, :presence => {:message => 'cannot be blank'}
|
|
4
7
|
validates :description, :presence => {:message => 'cannot be blank'}
|
|
@@ -18,7 +21,7 @@ class AuditLog < ActiveRecord::Base
|
|
|
18
21
|
end
|
|
19
22
|
|
|
20
23
|
#allow items to be looked up by method calls
|
|
21
|
-
def respond_to?(m)
|
|
24
|
+
def respond_to?(m, include_private_methods = false)
|
|
22
25
|
(super ? true : get_item_by_item_type_internal_identifier(m.to_s)) rescue super
|
|
23
26
|
end
|
|
24
27
|
|
data/app/models/capability.rb
CHANGED
data/app/models/file_asset.rb
CHANGED
|
@@ -28,6 +28,8 @@ Paperclip.interpolates(:file_url){|data, style|
|
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
class FileAsset < ActiveRecord::Base
|
|
31
|
+
attr_protected :created_at, :updated_at
|
|
32
|
+
|
|
31
33
|
if respond_to?(:class_attribute)
|
|
32
34
|
class_attribute :file_type
|
|
33
35
|
class_attribute :valid_extensions
|
|
@@ -272,7 +274,7 @@ class Pdf < TextFile
|
|
|
272
274
|
self.valid_extensions = %w(.pdf .PDF)
|
|
273
275
|
end
|
|
274
276
|
|
|
275
|
-
class Swf <
|
|
277
|
+
class Swf < FileAsset
|
|
276
278
|
self.file_type = :swf
|
|
277
279
|
self.content_type = 'application/x-shockwave-flash'
|
|
278
280
|
self.valid_extensions = %w(.swf .SWF)
|
data/app/models/group.rb
CHANGED
|
@@ -8,6 +8,7 @@ class Group < ActiveRecord::Base
|
|
|
8
8
|
|
|
9
9
|
has_one :party, :as => :business_party
|
|
10
10
|
|
|
11
|
+
attr_accessible :description
|
|
11
12
|
validates_uniqueness_of :description, :case_sensitive => false
|
|
12
13
|
|
|
13
14
|
def self.add(description)
|
|
@@ -26,7 +27,7 @@ class Group < ActiveRecord::Base
|
|
|
26
27
|
|
|
27
28
|
def has_role?(role)
|
|
28
29
|
role = role.is_a?(SecurityRole) ? role : SecurityRole.find_by_internal_identifier(role.to_s)
|
|
29
|
-
|
|
30
|
+
roles.include?(role)
|
|
30
31
|
end
|
|
31
32
|
|
|
32
33
|
def add_role(role)
|
|
@@ -139,29 +140,15 @@ class Group < ActiveRecord::Base
|
|
|
139
140
|
end
|
|
140
141
|
|
|
141
142
|
def role_class_capabilities
|
|
142
|
-
|
|
143
|
-
Capability.joins(:capability_type).joins(:capability_accessors).
|
|
144
|
-
where(:capability_accessors => { :capability_accessor_record_type => "SecurityRole" }).
|
|
145
|
-
where("capability_accessor_record_id IN (#{roles.select('security_roles.id').to_sql})").
|
|
146
|
-
where(:scope_type_id => scope_type.id)
|
|
143
|
+
roles.collect{|r| r.class_capabilities }.flatten.uniq.compact
|
|
147
144
|
end
|
|
148
145
|
|
|
149
146
|
def all_class_capabilities
|
|
150
|
-
|
|
151
|
-
Capability.joins(:capability_type).joins(:capability_accessors).
|
|
152
|
-
where("(capability_accessors.capability_accessor_record_type = 'Group' AND
|
|
153
|
-
capability_accessor_record_id = (#{self.id})) OR
|
|
154
|
-
(capability_accessors.capability_accessor_record_type = 'SecurityRole' AND
|
|
155
|
-
capability_accessor_record_id IN (#{roles.select('security_roles.id').to_sql}))").
|
|
156
|
-
where(:scope_type_id => scope_type.id)
|
|
157
|
-
end
|
|
158
|
-
|
|
159
|
-
def all_uniq_class_capabilities
|
|
160
|
-
all_class_capabilities.all.uniq
|
|
147
|
+
(role_class_capabilities + class_capabilities).uniq
|
|
161
148
|
end
|
|
162
149
|
|
|
163
150
|
def class_capabilities_to_hash
|
|
164
|
-
|
|
151
|
+
all_class_capabilities.map {|capability|
|
|
165
152
|
{ :capability_type_iid => capability.capability_type.internal_identifier,
|
|
166
153
|
:capability_resource_type => capability.capability_resource_type
|
|
167
154
|
}
|
data/app/models/scope_type.rb
CHANGED
data/app/models/security_role.rb
CHANGED
|
@@ -8,6 +8,8 @@ class SecurityRole < ActiveRecord::Base
|
|
|
8
8
|
validates_uniqueness_of :internal_identifier, :case_sensitive => false
|
|
9
9
|
validates_length_of :internal_identifier, :within => 3..100
|
|
10
10
|
|
|
11
|
+
attr_accessible :description, :internal_identifier
|
|
12
|
+
|
|
11
13
|
def to_xml(options = {})
|
|
12
14
|
default_only = []
|
|
13
15
|
options[:only] = (options[:only] || []) + default_only
|
data/app/models/user.rb
CHANGED
|
@@ -41,15 +41,32 @@ class User < ActiveRecord::Base
|
|
|
41
41
|
party.security_roles
|
|
42
42
|
end
|
|
43
43
|
|
|
44
|
-
def has_role?(
|
|
45
|
-
|
|
46
|
-
|
|
44
|
+
def has_role?(*passed_roles)
|
|
45
|
+
result = false
|
|
46
|
+
passed_roles.flatten!
|
|
47
|
+
passed_roles.each do |role|
|
|
48
|
+
role_iid = role.is_a?(SecurityRole) ? role.internal_identifier : role.to_s
|
|
49
|
+
all_roles.each do |this_role|
|
|
50
|
+
result = true if (this_role.internal_identifier == role_iid)
|
|
51
|
+
break if result
|
|
52
|
+
end
|
|
53
|
+
break if result
|
|
54
|
+
end
|
|
55
|
+
result
|
|
47
56
|
end
|
|
48
57
|
|
|
49
58
|
def add_role(role)
|
|
50
59
|
party.add_role(role)
|
|
51
60
|
end
|
|
52
61
|
|
|
62
|
+
def add_roles(*passed_roles)
|
|
63
|
+
party.add_roles(*passed_roles)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def remove_roles(*passed_roles)
|
|
67
|
+
party.remove_roles(*passed_roles)
|
|
68
|
+
end
|
|
69
|
+
|
|
53
70
|
def remove_role(role)
|
|
54
71
|
party.remove_role(role)
|
|
55
72
|
end
|
|
@@ -86,70 +103,40 @@ class User < ActiveRecord::Base
|
|
|
86
103
|
|
|
87
104
|
# roles assigned to the groups this user belongs to
|
|
88
105
|
def group_roles
|
|
89
|
-
|
|
90
|
-
where(:parties => {:business_party_type => 'Group'}).
|
|
91
|
-
where("parties.business_party_id IN (#{groups.select('groups.id').to_sql})")
|
|
106
|
+
groups.collect{|g| g.roles }.flatten.uniq
|
|
92
107
|
end
|
|
93
108
|
|
|
94
109
|
# composite roles for this user
|
|
95
110
|
def all_roles
|
|
96
|
-
|
|
97
|
-
where("(parties.business_party_type='Group' AND
|
|
98
|
-
parties.business_party_id IN (#{groups.select('groups.id').to_sql})) OR
|
|
99
|
-
(users.id=#{self.id})")
|
|
100
|
-
end
|
|
101
|
-
|
|
102
|
-
def all_uniq_roles
|
|
103
|
-
all_roles.all.uniq
|
|
111
|
+
(group_roles + roles).uniq
|
|
104
112
|
end
|
|
105
113
|
|
|
106
114
|
def group_capabilities
|
|
107
|
-
|
|
108
|
-
where(:capability_accessors => { :capability_accessor_record_type => "Group" }).
|
|
109
|
-
where("capability_accessor_record_id IN (#{groups.select('groups.id').to_sql})")
|
|
115
|
+
groups.collect{|r| r.capabilities }.flatten.uniq.compact
|
|
110
116
|
end
|
|
111
117
|
|
|
112
118
|
def role_capabilities
|
|
113
|
-
|
|
114
|
-
where(:capability_accessors => { :capability_accessor_record_type => "SecurityRole" }).
|
|
115
|
-
where("capability_accessor_record_id IN (#{all_roles.select('security_roles.id').to_sql})")
|
|
119
|
+
all_roles.collect{|r| r.capabilities }.flatten.compact
|
|
116
120
|
end
|
|
117
121
|
|
|
118
122
|
def all_capabilities
|
|
119
|
-
|
|
120
|
-
where("(capability_accessors.capability_accessor_record_type = 'Group' AND
|
|
121
|
-
capability_accessor_record_id IN (#{groups.select('groups.id').to_sql})) OR
|
|
122
|
-
(capability_accessors.capability_accessor_record_type = 'SecurityRole' AND
|
|
123
|
-
capability_accessor_record_id IN (#{all_roles.select('security_roles.id').to_sql})) OR
|
|
124
|
-
(capability_accessors.capability_accessor_record_type = 'User' AND
|
|
125
|
-
capability_accessor_record_id = #{self.id})")
|
|
126
|
-
end
|
|
127
|
-
|
|
128
|
-
def all_uniq_capabilities
|
|
129
|
-
all_capabilities.all.uniq
|
|
123
|
+
(role_capabilities + group_capabilities + capabilities).uniq
|
|
130
124
|
end
|
|
131
125
|
|
|
132
126
|
def group_class_capabilities
|
|
133
|
-
|
|
134
|
-
group_capabilities.where(:scope_type_id => scope_type.id)
|
|
127
|
+
groups.collect{|g| g.class_capabilities }.flatten.uniq.compact
|
|
135
128
|
end
|
|
136
129
|
|
|
137
130
|
def role_class_capabilities
|
|
138
|
-
|
|
139
|
-
role_capabilities.where(:scope_type_id => scope_type.id)
|
|
131
|
+
all_roles.collect{|r| r.class_capabilities }.flatten.uniq.compact
|
|
140
132
|
end
|
|
141
133
|
|
|
142
134
|
def all_class_capabilities
|
|
143
|
-
|
|
144
|
-
all_capabilities.where(:scope_type_id => scope_type.id)
|
|
145
|
-
end
|
|
146
|
-
|
|
147
|
-
def all_uniq_class_capabilities
|
|
148
|
-
all_class_capabilities.all.uniq
|
|
135
|
+
(role_class_capabilities + group_class_capabilities + class_capabilities).uniq
|
|
149
136
|
end
|
|
150
137
|
|
|
151
138
|
def class_capabilities_to_hash
|
|
152
|
-
|
|
139
|
+
all_class_capabilities.map {|capability|
|
|
153
140
|
{ :capability_type_iid => capability.capability_type.internal_identifier,
|
|
154
141
|
:capability_resource_type => capability.capability_resource_type
|
|
155
142
|
}
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
<body>
|
|
7
7
|
<h1>Welcome <%= @user.username %></h1>
|
|
8
8
|
<p>
|
|
9
|
-
You have successfully registered, to activate your account follow this link: <a href="<%= @url %>"><%= @url %></a
|
|
9
|
+
You have successfully registered, to activate your account follow this link: <a href="<%= @url %>"><%= @url %></a>
|
|
10
10
|
</p>
|
|
11
11
|
<p>Your username is <%=@user.username%>, use the password you set during registration to login.</p>
|
|
12
12
|
<p>Thanks for joining and have a great day!!</p>
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
<h1>We have reset the password for, <%= @user.username %></h1>
|
|
8
8
|
<p>
|
|
9
9
|
The new password is <%= @user.password_confirmation %>.
|
|
10
|
-
To login and update your password follow this link: <a href="<%= @url %>"><%= @url %></a
|
|
10
|
+
To login and update your password follow this link: <a href="<%= @url %>"><%= @url %></a>
|
|
11
11
|
</p>
|
|
12
12
|
<p>Thanks for being a member and have a great day!</p>
|
|
13
13
|
</body>
|
|
@@ -2,7 +2,9 @@ Rails.application.config.erp_tech_svcs.configure do |config|
|
|
|
2
2
|
config.installation_domain = 'localhost:3000'
|
|
3
3
|
config.login_url = '/erp_app/login'
|
|
4
4
|
config.email_notifications_from = 'notifications@noreply.com'
|
|
5
|
+
config.email_regex = "^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,6}$"
|
|
5
6
|
config.max_file_size_in_mb = 5
|
|
7
|
+
config.file_upload_types = 'txt,pdf,zip,tgz,gz,rar,jpg,jpeg,gif,png,tif,tiff,bmp,csv,xls,xlsx,doc,docx,ppt,pptx,psd,ai,css,js,mp3,mp4,m4a,m4v,mov,wav,wmv'
|
|
6
8
|
config.file_assets_location = 'file_assets' # relative to Rails.root/
|
|
7
9
|
config.s3_url_expires_in_seconds = 60
|
|
8
10
|
config.s3_protocol = 'https' # Can be either 'http' or 'https'
|
|
@@ -2,8 +2,8 @@ class NoteCapabilities
|
|
|
2
2
|
|
|
3
3
|
def self.up
|
|
4
4
|
#insert data here
|
|
5
|
-
admin = SecurityRole.
|
|
6
|
-
employee = SecurityRole.
|
|
5
|
+
admin = SecurityRole.find_or_create_by_description_and_internal_identifier(:description => 'Admin', :internal_identifier => 'admin')
|
|
6
|
+
employee = SecurityRole.find_or_create_by_description_and_internal_identifier(:description => 'Employee', :internal_identifier => 'employee')
|
|
7
7
|
|
|
8
8
|
admin.add_capability('create', 'Note')
|
|
9
9
|
admin.add_capability('delete', 'Note')
|
|
@@ -258,9 +258,9 @@ class BaseTechServices < ActiveRecord::Migration
|
|
|
258
258
|
# check that each table exists before trying to delete it.
|
|
259
259
|
[ :groups,
|
|
260
260
|
:audit_logs, :sessions, :simple_captcha_data,
|
|
261
|
-
:
|
|
262
|
-
:
|
|
263
|
-
:users, :
|
|
261
|
+
:capability_accessors, :capability_types, :capabilities,:scope_types,
|
|
262
|
+
:parties_security_roles, :roles, :audit_log_items, :audit_log_item_types,
|
|
263
|
+
:users, :file_assets, :delayed_jobs
|
|
264
264
|
].each do |tbl|
|
|
265
265
|
if table_exists?(tbl)
|
|
266
266
|
drop_table tbl
|
data/lib/erp_tech_svcs/config.rb
CHANGED
|
@@ -3,9 +3,11 @@ module ErpTechSvcs
|
|
|
3
3
|
class << self
|
|
4
4
|
|
|
5
5
|
attr_accessor :max_file_size_in_mb,
|
|
6
|
+
:file_upload_types,
|
|
6
7
|
:installation_domain,
|
|
7
8
|
:login_url,
|
|
8
9
|
:email_notifications_from,
|
|
10
|
+
:email_regex,
|
|
9
11
|
:file_assets_location,
|
|
10
12
|
:s3_url_expires_in_seconds,
|
|
11
13
|
:s3_protocol,
|
|
@@ -17,9 +19,11 @@ module ErpTechSvcs
|
|
|
17
19
|
def init!
|
|
18
20
|
@defaults = {
|
|
19
21
|
:@max_file_size_in_mb => 5,
|
|
22
|
+
:@file_upload_types => 'txt,pdf,zip,tgz,gz,rar,jpg,jpeg,gif,png,tif,tiff,bmp,csv,xls,xlsx,doc,docx,ppt,pptx,psd,ai,css,js,mp3,mp4,m4a,m4v,mov,wav,wmv',
|
|
20
23
|
:@installation_domain => 'localhost:3000',
|
|
21
24
|
:@login_url => '/erp_app/login',
|
|
22
25
|
:@email_notifications_from => 'notifications@noreply.com',
|
|
26
|
+
:@email_regex => "^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,6}$",
|
|
23
27
|
:@file_assets_location => 'file_assets', # relative to Rails.root/
|
|
24
28
|
:@s3_url_expires_in_seconds => 60,
|
|
25
29
|
:@s3_protocol => 'https', # Can be either 'http' or 'https'
|
|
@@ -249,7 +249,7 @@ module ActiveRecord #:nodoc:
|
|
|
249
249
|
|
|
250
250
|
versioned_class.cattr_accessor :original_class
|
|
251
251
|
versioned_class.original_class = self
|
|
252
|
-
versioned_class.
|
|
252
|
+
versioned_class.table_name = versioned_table_name
|
|
253
253
|
versioned_class.belongs_to self.to_s.demodulize.underscore.to_sym,
|
|
254
254
|
:class_name => "::#{self.to_s}",
|
|
255
255
|
:foreign_key => versioned_foreign_key
|
|
@@ -268,134 +268,133 @@ module ActiveRecord #:nodoc:
|
|
|
268
268
|
after_save :clear_old_versions
|
|
269
269
|
end
|
|
270
270
|
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
end
|
|
271
|
+
# INSTANCE METHODS
|
|
272
|
+
# Saves a version of the model in the versioned table. This is called in the after_save callback by default
|
|
273
|
+
def save_version
|
|
274
|
+
if @saving_version
|
|
275
|
+
@saving_version = nil
|
|
276
|
+
rev = self.class.versioned_class.new
|
|
277
|
+
clone_versioned_model(self, rev)
|
|
278
|
+
rev.send("#{self.class.version_column}=", send(self.class.version_column))
|
|
279
|
+
rev.send("#{self.class.versioned_foreign_key}=", id)
|
|
280
|
+
rev.save
|
|
282
281
|
end
|
|
282
|
+
end
|
|
283
283
|
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
end
|
|
284
|
+
# Clears old revisions if a limit is set with the :limit option in <tt>acts_as_versioned</tt>.
|
|
285
|
+
# Override this method to set your own criteria for clearing old versions.
|
|
286
|
+
def clear_old_versions
|
|
287
|
+
return if self.class.max_version_limit == 0
|
|
288
|
+
excess_baggage = send(self.class.version_column).to_i - self.class.max_version_limit
|
|
289
|
+
if excess_baggage > 0
|
|
290
|
+
self.class.versioned_class.delete_all ["#{self.class.version_column} <= ? and #{self.class.versioned_foreign_key} = ?", excess_baggage, id]
|
|
292
291
|
end
|
|
292
|
+
end
|
|
293
293
|
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
end
|
|
301
|
-
self.clone_versioned_model(version, self)
|
|
302
|
-
send("#{self.class.version_column}=", version.send(self.class.version_column))
|
|
303
|
-
true
|
|
294
|
+
# Reverts a model to a given version. Takes either a version number or an instance of the versioned model
|
|
295
|
+
def revert_to(version)
|
|
296
|
+
if version.is_a?(self.class.versioned_class)
|
|
297
|
+
return false unless version.send(self.class.versioned_foreign_key) == id and !version.new_record?
|
|
298
|
+
else
|
|
299
|
+
return false unless version = versions.where(self.class.version_column => version).first
|
|
304
300
|
end
|
|
301
|
+
self.clone_versioned_model(version, self)
|
|
302
|
+
send("#{self.class.version_column}=", version.send(self.class.version_column))
|
|
303
|
+
true
|
|
304
|
+
end
|
|
305
305
|
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
306
|
+
# Reverts a model to a given version and saves the model.
|
|
307
|
+
# Takes either a version number or an instance of the versioned model
|
|
308
|
+
def revert_to!(version)
|
|
309
|
+
revert_to(version) ? save_without_revision : false
|
|
310
|
+
end
|
|
311
311
|
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
312
|
+
# Temporarily turns off Optimistic Locking while saving. Used when reverting so that a new version is not created.
|
|
313
|
+
def save_without_revision
|
|
314
|
+
save_without_revision!
|
|
315
|
+
true
|
|
316
|
+
rescue
|
|
317
|
+
false
|
|
318
|
+
end
|
|
319
319
|
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
end
|
|
320
|
+
def save_without_revision!
|
|
321
|
+
without_locking do
|
|
322
|
+
without_revision do
|
|
323
|
+
save!
|
|
325
324
|
end
|
|
326
325
|
end
|
|
326
|
+
end
|
|
327
327
|
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
# Clones a model. Used when saving a new version or reverting a model's version.
|
|
333
|
-
def clone_versioned_model(orig_model, new_model)
|
|
334
|
-
self.class.versioned_columns.each do |col|
|
|
335
|
-
new_model[col.name] = orig_model.send(col.name) if orig_model.has_attribute?(col.name)
|
|
336
|
-
end
|
|
328
|
+
def altered?
|
|
329
|
+
track_altered_attributes ? (version_if_changed - changed).length < version_if_changed.length : changed?
|
|
330
|
+
end
|
|
337
331
|
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
end
|
|
332
|
+
# Clones a model. Used when saving a new version or reverting a model's version.
|
|
333
|
+
def clone_versioned_model(orig_model, new_model)
|
|
334
|
+
self.class.versioned_columns.each do |col|
|
|
335
|
+
new_model[col.name] = orig_model.send(col.name) if orig_model.has_attribute?(col.name)
|
|
343
336
|
end
|
|
344
337
|
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
338
|
+
if orig_model.is_a?(self.class.versioned_class)
|
|
339
|
+
new_model[new_model.class.inheritance_column] = orig_model[self.class.versioned_inheritance_column]
|
|
340
|
+
elsif new_model.is_a?(self.class.versioned_class)
|
|
341
|
+
new_model[self.class.versioned_inheritance_column] = orig_model[orig_model.class.inheritance_column]
|
|
348
342
|
end
|
|
343
|
+
end
|
|
349
344
|
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
when version_condition.is_a?(Symbol)
|
|
355
|
-
send(version_condition)
|
|
356
|
-
when version_condition.respond_to?(:call) && (version_condition.arity == 1 || version_condition.arity == -1)
|
|
357
|
-
version_condition.call(self)
|
|
358
|
-
else
|
|
359
|
-
version_condition
|
|
360
|
-
end
|
|
361
|
-
end
|
|
345
|
+
# Checks whether a new version shall be saved or not. Calls <tt>version_condition_met?</tt> and <tt>changed?</tt>.
|
|
346
|
+
def save_version?
|
|
347
|
+
version_condition_met? && altered?
|
|
348
|
+
end
|
|
362
349
|
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
350
|
+
# Checks condition set in the :if option to check whether a revision should be created or not. Override this for
|
|
351
|
+
# custom version condition checking.
|
|
352
|
+
def version_condition_met?
|
|
353
|
+
case
|
|
354
|
+
when version_condition.is_a?(Symbol)
|
|
355
|
+
send(version_condition)
|
|
356
|
+
when version_condition.respond_to?(:call) && (version_condition.arity == 1 || version_condition.arity == -1)
|
|
357
|
+
version_condition.call(self)
|
|
358
|
+
else
|
|
359
|
+
version_condition
|
|
371
360
|
end
|
|
361
|
+
end
|
|
372
362
|
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
363
|
+
# Executes the block with the versioning callbacks disabled.
|
|
364
|
+
#
|
|
365
|
+
# @foo.without_revision do
|
|
366
|
+
# @foo.save
|
|
367
|
+
# end
|
|
368
|
+
#
|
|
369
|
+
def without_revision(&block)
|
|
370
|
+
self.class.without_revision(&block)
|
|
371
|
+
end
|
|
382
372
|
|
|
383
|
-
|
|
384
|
-
|
|
373
|
+
# Turns off optimistic locking for the duration of the block
|
|
374
|
+
#
|
|
375
|
+
# @foo.without_locking do
|
|
376
|
+
# @foo.save
|
|
377
|
+
# end
|
|
378
|
+
#
|
|
379
|
+
def without_locking(&block)
|
|
380
|
+
self.class.without_locking(&block)
|
|
381
|
+
end
|
|
385
382
|
|
|
386
|
-
|
|
383
|
+
def empty_callback()
|
|
384
|
+
end
|
|
387
385
|
|
|
388
|
-
|
|
389
|
-
# sets the new version before saving, unless you're using optimistic locking. In that case, let it take care of the version.
|
|
390
|
-
def set_new_version
|
|
391
|
-
@saving_version = new_record? || save_version?
|
|
392
|
-
self.send("#{self.class.version_column}=", next_version) if new_record? || (!locking_enabled? && save_version?)
|
|
393
|
-
end
|
|
386
|
+
#:nodoc:
|
|
394
387
|
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
388
|
+
protected
|
|
389
|
+
# sets the new version before saving, unless you're using optimistic locking. In that case, let it take care of the version.
|
|
390
|
+
def set_new_version
|
|
391
|
+
@saving_version = new_record? || save_version?
|
|
392
|
+
self.send("#{self.class.version_column}=", next_version) if new_record? || (!locking_enabled? && save_version?)
|
|
393
|
+
end
|
|
394
|
+
|
|
395
|
+
# Gets the next available version for the current record, or 1 for a new record
|
|
396
|
+
def next_version
|
|
397
|
+
(new_record? ? 0 : versions.calculate(:maximum, version_column).to_i) + 1
|
|
399
398
|
end
|
|
400
399
|
|
|
401
400
|
module ClassMethods
|