erp_tech_svcs 3.0.12 → 3.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|