| 1 |
module Zena |
|---|
| 2 |
module Acts |
|---|
| 3 |
module Multiversioned |
|---|
| 4 |
|
|---|
| 5 |
def self.included(base) |
|---|
| 6 |
|
|---|
| 7 |
base.extend AddActsAsMethod |
|---|
| 8 |
end |
|---|
| 9 |
module AddActsAsMethod |
|---|
| 10 |
def acts_as_multiversioned |
|---|
| 11 |
validate :valid_redaction |
|---|
| 12 |
after_save :save_version |
|---|
| 13 |
after_save :after_all |
|---|
| 14 |
private |
|---|
| 15 |
has_many :versions, :order=>"number DESC", :dependent => :destroy |
|---|
| 16 |
has_many :editions, :class_name=>"Version", :conditions=>"publish_from <= now() AND status = #{Zena::Status[:pub]}", :order=>'lang' |
|---|
| 17 |
public |
|---|
| 18 |
class_eval <<-END |
|---|
| 19 |
include Zena::Acts::Multiversioned::InstanceMethods |
|---|
| 20 |
END |
|---|
| 21 |
end |
|---|
| 22 |
end |
|---|
| 23 |
|
|---|
| 24 |
|
|---|
| 25 |
module InstanceMethods |
|---|
| 26 |
def self.included(aClass) |
|---|
| 27 |
aClass.extend ClassMethods |
|---|
| 28 |
end |
|---|
| 29 |
|
|---|
| 30 |
|
|---|
| 31 |
|
|---|
| 32 |
|
|---|
| 33 |
def version=(v) |
|---|
| 34 |
if v.kind_of?(Version) |
|---|
| 35 |
@version = v |
|---|
| 36 |
end |
|---|
| 37 |
end |
|---|
| 38 |
|
|---|
| 39 |
def can_edit? |
|---|
| 40 |
can_edit_lang? |
|---|
| 41 |
end |
|---|
| 42 |
|
|---|
| 43 |
def can_edit_lang?(lang=nil) |
|---|
| 44 |
return false unless can_write? |
|---|
| 45 |
if lang |
|---|
| 46 |
|
|---|
| 47 |
v = versions.find(:first, :conditions=>["status >= #{Zena::Status[:red]} AND status < #{Zena::Status[:pub]} AND lang=?", lang]) |
|---|
| 48 |
v == nil |
|---|
| 49 |
else |
|---|
| 50 |
|
|---|
| 51 |
|
|---|
| 52 |
v = versions.find(:first, :conditions=>["status >= #{Zena::Status[:red]} AND status < #{Zena::Status[:pub]} AND lang=?", visitor.lang]) |
|---|
| 53 |
v == nil || (v.status == Zena::Status[:red] && v.user_id == visitor[:id]) |
|---|
| 54 |
end |
|---|
| 55 |
rescue ActiveRecord::RecordNotFound |
|---|
| 56 |
true |
|---|
| 57 |
end |
|---|
| 58 |
|
|---|
| 59 |
|
|---|
| 60 |
def edit!(lang = nil, publish_after_save = false) |
|---|
| 61 |
redaction(lang, publish_after_save) |
|---|
| 62 |
end |
|---|
| 63 |
|
|---|
| 64 |
def edit_content! |
|---|
| 65 |
redaction && redaction.redaction_content |
|---|
| 66 |
end |
|---|
| 67 |
|
|---|
| 68 |
|
|---|
| 69 |
def traductions(opts={}) |
|---|
| 70 |
if opts == {} |
|---|
| 71 |
trad = editions |
|---|
| 72 |
else |
|---|
| 73 |
trad = editions.find(:all, opts) |
|---|
| 74 |
end |
|---|
| 75 |
trad.map! do |t| |
|---|
| 76 |
t.node = self |
|---|
| 77 |
t |
|---|
| 78 |
end |
|---|
| 79 |
trad == [] ? nil : trad |
|---|
| 80 |
end |
|---|
| 81 |
|
|---|
| 82 |
|
|---|
| 83 |
def can_propose? |
|---|
| 84 |
can_apply?(:propose) |
|---|
| 85 |
end |
|---|
| 86 |
|
|---|
| 87 |
|
|---|
| 88 |
|
|---|
| 89 |
|
|---|
| 90 |
def can_publish? |
|---|
| 91 |
can_apply?(:publish) |
|---|
| 92 |
end |
|---|
| 93 |
|
|---|
| 94 |
|
|---|
| 95 |
def can_refuse? |
|---|
| 96 |
can_apply?(:refuse) |
|---|
| 97 |
end |
|---|
| 98 |
|
|---|
| 99 |
|
|---|
| 100 |
def can_unpublish?(v=version) |
|---|
| 101 |
can_apply?(:unpublish, v) |
|---|
| 102 |
end |
|---|
| 103 |
|
|---|
| 104 |
|
|---|
| 105 |
def can_destroy_version?(v=version) |
|---|
| 106 |
can_apply?(:destroy_version, v) |
|---|
| 107 |
end |
|---|
| 108 |
|
|---|
| 109 |
|
|---|
| 110 |
def empty? |
|---|
| 111 |
return true if new_record? |
|---|
| 112 |
0 == self.class.count_by_sql("SELECT COUNT(*) FROM #{self.class.table_name} WHERE #{ref_field} = #{self[:id]}") |
|---|
| 113 |
end |
|---|
| 114 |
|
|---|
| 115 |
|
|---|
| 116 |
def can_apply?(method, v=version) |
|---|
| 117 |
return false if new_record? |
|---|
| 118 |
return true if visitor.is_su? |
|---|
| 119 |
case method |
|---|
| 120 |
when :drive |
|---|
| 121 |
can_drive? |
|---|
| 122 |
when :propose, :backup |
|---|
| 123 |
v.user_id == visitor[:id] && v.status == Zena::Status[:red] |
|---|
| 124 |
when :refuse |
|---|
| 125 |
v.status > Zena::Status[:red] && can_apply?(:publish) |
|---|
| 126 |
when :publish |
|---|
| 127 |
v.status < Zena::Status[:pub] && |
|---|
| 128 |
( ( can_visible? && (v.status > Zena::Status[:red] || v.status == Zena::Status[:rep] || v.user_id == visitor[:id]) ) || |
|---|
| 129 |
( can_manage? && private? ) |
|---|
| 130 |
) |
|---|
| 131 |
when :unpublish |
|---|
| 132 |
can_drive? && v.status == Zena::Status[:pub] |
|---|
| 133 |
when :remove |
|---|
| 134 |
(can_drive? || v.user_id == visitor[:id] ) && v.status <= Zena::Status[:red] && v.status > Zena::Status[:rem] |
|---|
| 135 |
when :redit |
|---|
| 136 |
can_edit? && v.user_id == visitor[:id] |
|---|
| 137 |
when :edit |
|---|
| 138 |
can_edit? |
|---|
| 139 |
when :destroy_version |
|---|
| 140 |
|
|---|
| 141 |
can_drive? && v.status == Zena::Status[:rem] && !visitor.is_anon? && (self.versions.count > 1 || empty?) |
|---|
| 142 |
when :update_attributes |
|---|
| 143 |
can_write? |
|---|
| 144 |
end |
|---|
| 145 |
end |
|---|
| 146 |
|
|---|
| 147 |
|
|---|
| 148 |
def apply(method, *args) |
|---|
| 149 |
unless can_apply?(method) |
|---|
| 150 |
errors.add('base', 'you do not have the rights to do this') |
|---|
| 151 |
return false |
|---|
| 152 |
end |
|---|
| 153 |
res = case method |
|---|
| 154 |
when :propose |
|---|
| 155 |
version.status = args[0] || Zena::Status[:prop] |
|---|
| 156 |
version.save && after_propose && update_max_status |
|---|
| 157 |
when :backup |
|---|
| 158 |
version.status = Zena::Status[:rep] |
|---|
| 159 |
@redaction = nil |
|---|
| 160 |
redaction.save if version.save |
|---|
| 161 |
when :refuse |
|---|
| 162 |
version.status = Zena::Status[:red] |
|---|
| 163 |
version.save && after_refuse && update_max_status |
|---|
| 164 |
when :publish |
|---|
| 165 |
pub_time = args[0] |
|---|
| 166 |
old_ids = version.class.fetch_ids "node_id = '#{self[:id]}' AND lang = '#{version[:lang]}' AND status = '#{Zena::Status[:pub]}'" |
|---|
| 167 |
case version.status |
|---|
| 168 |
when Zena::Status[:rep] |
|---|
| 169 |
new_status = Zena::Status[:rem] |
|---|
| 170 |
else |
|---|
| 171 |
new_status = Zena::Status[:rep] |
|---|
| 172 |
end |
|---|
| 173 |
pub_time = args[0] |
|---|
| 174 |
version.publish_from = pub_time || version.publish_from || Time.now |
|---|
| 175 |
version.status = Zena::Status[:pub] |
|---|
| 176 |
if version.save |
|---|
| 177 |
|
|---|
| 178 |
self.class.connection.execute "UPDATE #{version.class.table_name} SET status = '#{new_status}' WHERE id IN (#{old_ids.join(', ')})" unless old_ids == [] |
|---|
| 179 |
res = after_publish(pub_time) && update_publish_from && update_max_status |
|---|
| 180 |
if res |
|---|
| 181 |
self.class.connection.execute "UPDATE #{self.class.table_name} SET updated_at = #{self.class.connection.quote(Time.now)} WHERE id=#{self[:id].to_i}" unless new_record? |
|---|
| 182 |
end |
|---|
| 183 |
res |
|---|
| 184 |
else |
|---|
| 185 |
merge_version_errors |
|---|
| 186 |
false |
|---|
| 187 |
end |
|---|
| 188 |
when :unpublish |
|---|
| 189 |
version.status = Zena::Status[:rem] |
|---|
| 190 |
if version.save |
|---|
| 191 |
update_publish_from && update_max_status && after_unpublish |
|---|
| 192 |
else |
|---|
| 193 |
false |
|---|
| 194 |
end |
|---|
| 195 |
when :remove |
|---|
| 196 |
version.status = Zena::Status[:rem] |
|---|
| 197 |
if version.save |
|---|
| 198 |
update_publish_from && update_max_status && after_remove |
|---|
| 199 |
else |
|---|
| 200 |
false |
|---|
| 201 |
end |
|---|
| 202 |
when :redit |
|---|
| 203 |
version.status = Zena::Status[:red] |
|---|
| 204 |
if version.save |
|---|
| 205 |
update_publish_from && update_max_status && after_redit |
|---|
| 206 |
else |
|---|
| 207 |
false |
|---|
| 208 |
end |
|---|
| 209 |
when :destroy_version |
|---|
| 210 |
if versions.count == 1 |
|---|
| 211 |
version.destroy && self.destroy |
|---|
| 212 |
else |
|---|
| 213 |
version.destroy |
|---|
| 214 |
end |
|---|
| 215 |
when :update_attributes |
|---|
| 216 |
attributes = args[0].stringify_keys |
|---|
| 217 |
attributes = remove_attributes_protected_from_mass_assignment(attributes) |
|---|
| 218 |
attributes = remove_attributes_with_same_value(attributes) |
|---|
| 219 |
return true if attributes == {} |
|---|
| 220 |
do_update_attributes(attributes) |
|---|
| 221 |
end |
|---|
| 222 |
end |
|---|
| 223 |
|
|---|
| 224 |
|
|---|
| 225 |
def propose(prop_status=Zena::Status[:prop]) |
|---|
| 226 |
apply(:propose, prop_status) |
|---|
| 227 |
end |
|---|
| 228 |
|
|---|
| 229 |
|
|---|
| 230 |
|
|---|
| 231 |
def backup |
|---|
| 232 |
apply(:backup) |
|---|
| 233 |
end |
|---|
| 234 |
|
|---|
| 235 |
|
|---|
| 236 |
def refuse |
|---|
| 237 |
apply(:refuse) |
|---|
| 238 |
end |
|---|
| 239 |
|
|---|
| 240 |
|
|---|
| 241 |
|
|---|
| 242 |
|
|---|
| 243 |
def publish(pub_time=nil) |
|---|
| 244 |
apply(:publish, pub_time) |
|---|
| 245 |
end |
|---|
| 246 |
|
|---|
| 247 |
def unpublish |
|---|
| 248 |
apply(:unpublish) |
|---|
| 249 |
end |
|---|
| 250 |
|
|---|
| 251 |
|
|---|
| 252 |
|
|---|
| 253 |
def remove |
|---|
| 254 |
apply(:remove) |
|---|
| 255 |
end |
|---|
| 256 |
|
|---|
| 257 |
|
|---|
| 258 |
def redit |
|---|
| 259 |
apply(:redit) |
|---|
| 260 |
end |
|---|
| 261 |
|
|---|
| 262 |
|
|---|
| 263 |
|
|---|
| 264 |
def destroy_version |
|---|
| 265 |
apply(:destroy_version) |
|---|
| 266 |
end |
|---|
| 267 |
|
|---|
| 268 |
|
|---|
| 269 |
def after_propose |
|---|
| 270 |
true |
|---|
| 271 |
end |
|---|
| 272 |
def after_refuse |
|---|
| 273 |
true |
|---|
| 274 |
end |
|---|
| 275 |
def after_publish |
|---|
| 276 |
true |
|---|
| 277 |
end |
|---|
| 278 |
def after_unpublish |
|---|
| 279 |
true |
|---|
| 280 |
end |
|---|
| 281 |
def after_redit |
|---|
| 282 |
true |
|---|
| 283 |
end |
|---|
| 284 |
def after_remove |
|---|
| 285 |
true |
|---|
| 286 |
end |
|---|
| 287 |
def after_all |
|---|
| 288 |
true |
|---|
| 289 |
end |
|---|
| 290 |
|
|---|
| 291 |
|
|---|
| 292 |
|
|---|
| 293 |
def update_publish_from |
|---|
| 294 |
return true if version[:status] == Zena::Status[:pub] && self[:publish_from] == version[:publish_from] |
|---|
| 295 |
pub_string = (self.class.connection.select_one("select publish_from from #{version.class.table_name} WHERE node_id='#{self[:id]}' and status = #{Zena::Status[:pub]} order by publish_from DESC LIMIT 1") || {})['publish_from'] |
|---|
| 296 |
pub_date = ActiveRecord::ConnectionAdapters::Column.string_to_time(pub_string) |
|---|
| 297 |
if self[:publish_from] != pub_date |
|---|
| 298 |
self.class.connection.execute "UPDATE #{self.class.table_name} SET publish_from = #{pub_string ? "'#{pub_string}'" : 'NULL'} WHERE id = #{id}" |
|---|
| 299 |
self[:publish_from] = pub_date |
|---|
| 300 |
end |
|---|
| 301 |
true |
|---|
| 302 |
end |
|---|
| 303 |
|
|---|
| 304 |
|
|---|
| 305 |
def update_max_status(version = self.version) |
|---|
| 306 |
if version[:status] == max_status |
|---|
| 307 |
after_all |
|---|
| 308 |
return true |
|---|
| 309 |
end |
|---|
| 310 |
vers_table = version.class.table_name |
|---|
| 311 |
node_table = self.class.table_name |
|---|
| 312 |
new_max = self.class.connection.select_one("select #{vers_table}.status from #{vers_table} WHERE #{vers_table}.node_id='#{self[:id]}' order by #{vers_table}.status DESC LIMIT 1")['status'] |
|---|
| 313 |
self.class.connection.execute "UPDATE #{node_table} SET max_status = '#{new_max}' WHERE #{node_table}.id = #{id}" if new_max != self[:max_status] |
|---|
| 314 |
self[:max_status] = new_max |
|---|
| 315 |
|
|---|
| 316 |
|
|---|
| 317 |
after_all |
|---|
| 318 |
end |
|---|
| 319 |
|
|---|
| 320 |
|
|---|
| 321 |
|
|---|
| 322 |
|
|---|
| 323 |
def update_attributes(new_attributes) |
|---|
| 324 |
apply(:update_attributes,new_attributes) |
|---|
| 325 |
end |
|---|
| 326 |
|
|---|
| 327 |
|
|---|
| 328 |
|
|---|
| 329 |
|
|---|
| 330 |
def remove_attributes_with_same_value(new_attributes) |
|---|
| 331 |
res = {} |
|---|
| 332 |
new_attributes.each do |k,v| |
|---|
| 333 |
if k == 'v_status' |
|---|
| 334 |
|
|---|
| 335 |
res[k] = v |
|---|
| 336 |
next |
|---|
| 337 |
end |
|---|
| 338 |
if safe_attribute?(k) |
|---|
| 339 |
current_value = self.send(k) rescue nil |
|---|
| 340 |
else |
|---|
| 341 |
|
|---|
| 342 |
next |
|---|
| 343 |
end |
|---|
| 344 |
|
|---|
| 345 |
case current_value.class.to_s |
|---|
| 346 |
when 'NilClass' |
|---|
| 347 |
res[k] = v unless v == nil || v == '' |
|---|
| 348 |
when 'String' |
|---|
| 349 |
res[k] = v unless current_value == v.to_s |
|---|
| 350 |
when 'Float' |
|---|
| 351 |
v = v.blank? ? nil : v.to_f |
|---|
| 352 |
res[k] = v unless current_value == v |
|---|
| 353 |
when 'Fixnum' |
|---|
| 354 |
v = v.blank? ? nil : v.to_i |
|---|
| 355 |
res[k] = v unless current_value == v |
|---|
| 356 |
when 'Date', 'DateTime', 'Time' |
|---|
| 357 |
begin |
|---|
| 358 |
res[k] = v unless current_value.strftime('%Y-%m-%d %H:%M:%S') == (v.kind_of?(String) ? DateTime.parse(v) : v).strftime('%Y-%m-%d %H:%M:%S') |
|---|
| 359 |
rescue |
|---|
| 360 |
res[k] = v |
|---|
| 361 |
end |
|---|
| 362 |
when 'TrueClass', 'FalseClass' |
|---|
| 363 |
res[k] = v unless current_value == v |
|---|
| 364 |
when 'File', 'StringIO' |
|---|
| 365 |
|
|---|
| 366 |
res[k] = v unless Digest::MD5.hexdigest(current_value.read) == Digest::MD5.hexdigest(v.read) |
|---|
| 367 |
v.rewind |
|---|
| 368 |
errors.clear |
|---|
| 369 |
else |
|---|
| 370 |
res[k] = v |
|---|
| 371 |
end |
|---|
| 372 |
end |
|---|
| 373 |
res |
|---|
| 374 |
end |
|---|
| 375 |
|
|---|
| 376 |
|
|---|
| 377 |
|
|---|
| 378 |
|
|---|
| 379 |
|
|---|
| 380 |
|
|---|
| 381 |
|
|---|
| 382 |
|
|---|
| 383 |
|
|---|
| 384 |
|
|---|
| 385 |
def version(key=nil) |
|---|
| 386 |
return @version if @version |
|---|
| 387 |
|
|---|
| 388 |
if key && !key.kind_of?(Symbol) && !new_record? |
|---|
| 389 |
if visitor.is_su? |
|---|
| 390 |
@version = secure!(Version) { Version.find(:first, :conditions => ["node_id = ? AND number = ?", self[:id], key]) } |
|---|
| 391 |
elsif can_drive? |
|---|
| 392 |
@version = secure!(Version) { Version.find(:first, :conditions => ["node_id = ? AND number = ? AND (user_id = ? OR status <> ?)", self[:id], key, visitor[:id], Zena::Status[:red]]) } |
|---|
| 393 |
else |
|---|
| 394 |
@version = secure!(Version) { Version.find(:first, :conditions => ["node_id = ? AND number = ? AND (user_id = ? OR status >= ?)", self[:id], key, visitor[:id], Zena::Status[:pub]]) } |
|---|
| 395 |
end |
|---|
| 396 |
else |
|---|
| 397 |
min_status = (key == :pub) ? Zena::Status[:pub] : Zena::Status[:red] |
|---|
| 398 |
|
|---|
| 399 |
if new_record? |
|---|
| 400 |
@version = version_class.new |
|---|
| 401 |
|
|---|
| 402 |
@version.status = Zena::Status[:red] |
|---|
| 403 |
elsif can_drive? |
|---|
| 404 |
|
|---|
| 405 |
lang = visitor.lang.gsub(/[^\w]/,'') |
|---|
| 406 |
@version = Version.find(:first, |
|---|
| 407 |
:select=>"*, (lang = '#{lang}') as lang_ok, (lang = '#{ref_lang}') as ref_ok", |
|---|
| 408 |
:conditions=>[ "((status >= ? AND user_id = ? AND lang = ?) OR status > ?) AND node_id = ?", |
|---|
| 409 |
min_status, visitor[:id], lang, Zena::Status[:red], self[:id] ], |
|---|
| 410 |
:order=>"lang_ok DESC, ref_ok DESC, status ASC ") |
|---|
| 411 |
if !@version |
|---|
| 412 |
@version = versions.find(:first, :order=>'id DESC') |
|---|
| 413 |
end |
|---|
| 414 |
else |
|---|
| 415 |
|
|---|
| 416 |
lang = visitor.lang.gsub(/[^\w]/,'') |
|---|
| 417 |
@version = Version.find(:first, |
|---|
| 418 |
:select=>"*, (lang = '#{lang}') as lang_ok, (lang = '#{ref_lang}') as ref_ok", |
|---|
| 419 |
:conditions=>[ "((status >= ? AND user_id = ? AND lang = ?) OR status = ?) and node_id = ?", |
|---|
| 420 |
min_status, visitor[:id], lang, Zena::Status[:pub], self[:id] ], |
|---|
| 421 |
:order=>"lang_ok DESC, ref_ok DESC, status ASC, publish_from ASC") |
|---|
| 422 |
|
|---|
| 423 |
end |
|---|
| 424 |
|
|---|
| 425 |
if @version.nil? |
|---|
| 426 |
raise Exception.new("#{self.class} #{self[:id]} does not have any version !!") |
|---|
| 427 |
end |
|---|
| 428 |
end |
|---|
| 429 |
@version.node = self if @version |
|---|
| 430 |
@version |
|---|
| 431 |
end |
|---|
| 432 |
|
|---|
| 433 |
def attributes=(attributes) |
|---|
| 434 |
super @attributes_filtering_done ? attributes : filter_attributes(attributes) |
|---|
| 435 |
end |
|---|
| 436 |
|
|---|
| 437 |
private |
|---|
| 438 |
|
|---|
| 439 |
def do_update_attributes(new_attributes) |
|---|
| 440 |
attributes = filter_attributes(new_attributes) |
|---|
| 441 |
|
|---|
| 442 |
publish_after_save = (attributes.delete('v_status').to_i == Zena::Status[:pub]) || current_site[:auto_publish] |
|---|
| 443 |
redaction_attr = false |
|---|
| 444 |
node_attr = false |
|---|
| 445 |
|
|---|
| 446 |
attributes.each do |k,v| |
|---|
| 447 |
next if k.to_s == 'id' |
|---|
| 448 |
if k.to_s =~ /^(v_|c_|d_)/ |
|---|
| 449 |
redaction_attr = true |
|---|
| 450 |
else |
|---|
| 451 |
node_attr = true |
|---|
| 452 |
end |
|---|
| 453 |
break if node_attr && redaction_attr |
|---|
| 454 |
end |
|---|
| 455 |
|
|---|
| 456 |
if redaction_attr |
|---|
| 457 |
return false unless edit!(nil, publish_after_save) |
|---|
| 458 |
end |
|---|
| 459 |
|
|---|
| 460 |
if node_attr |
|---|
| 461 |
|
|---|
| 462 |
@attributes_filtering_done = true |
|---|
| 463 |
self.attributes = attributes |
|---|
| 464 |
@attributes_filtering_done = false |
|---|
| 465 |
ok = save |
|---|
| 466 |
elsif attributes != {} |
|---|
| 467 |
attributes.each do |k,v| |
|---|
| 468 |
next if k.to_s == 'id' |
|---|
| 469 |
self.send("#{k}=".to_sym, v) |
|---|
| 470 |
end |
|---|
| 471 |
valid_redaction |
|---|
| 472 |
if errors.empty? |
|---|
| 473 |
ok = save_version(false) |
|---|
| 474 |
end |
|---|
| 475 |
|
|---|
| 476 |
if ok |
|---|
| 477 |
|
|---|
| 478 |
update_attribute_without_fuss(:updated_at, Time.now) |
|---|
| 479 |
end |
|---|
| 480 |
else |
|---|
| 481 |
|
|---|
| 482 |
ok = true |
|---|
| 483 |
end |
|---|
| 484 |
|
|---|
| 485 |
if ok && publish_after_save |
|---|
| 486 |
if v_status == Zena::Status[:pub] |
|---|
| 487 |
ok = after_publish && after_all && update_publish_from |
|---|
| 488 |
elsif can_apply?(:publish) |
|---|
| 489 |
ok = apply(:publish) |
|---|
| 490 |
elsif ok |
|---|
| 491 |
ok = update_max_status && update_publish_from |
|---|
| 492 |
end |
|---|
| 493 |
elsif ok |
|---|
| 494 |
ok = update_max_status && update_publish_from |
|---|
| 495 |
end |
|---|
| 496 |
ok |
|---|
| 497 |
end |
|---|
| 498 |
|
|---|
| 499 |
def update_attribute_without_fuss(att, value) |
|---|
| 500 |
self[att] = value |
|---|
| 501 |
if value.kind_of?(Time) |
|---|
| 502 |
value = value.strftime("'%Y-%m-%d %H:%M:%S'") |
|---|
| 503 |
elsif value.nil? |
|---|
| 504 |
value = "NULL" |
|---|
| 505 |
else |
|---|
| 506 |
value = "'#{value}'" |
|---|
| 507 |
end |
|---|
| 508 |
self.class.connection.execute "UPDATE #{self.class.table_name} SET #{att}=#{value} WHERE id=#{self[:id]}" |
|---|
| 509 |
end |
|---|
| 510 |
|
|---|
| 511 |
|
|---|
| 512 |
|
|---|
| 513 |
|
|---|
| 514 |
def redaction(lang = nil, publish_after_save = false) |
|---|
| 515 |
return @redaction if @redaction && (lang.nil? || lang == @redaction.lang) |
|---|
| 516 |
redit = false |
|---|
| 517 |
if new_record? |
|---|
| 518 |
@redaction = version |
|---|
| 519 |
elsif version.lang == lang && version.status == Zena::Status[:red] && version.user_id == visitor[:id] |
|---|
| 520 |
@redaction = version |
|---|
| 521 |
else |
|---|
| 522 |
lang ||= visitor.lang |
|---|
| 523 |
|
|---|
| 524 |
v = versions.find(:first, :conditions=>["status >= #{Zena::Status[:red]} AND status < #{Zena::Status[:prop]} AND lang=?", lang]) |
|---|
| 525 |
if v == nil && can_write? |
|---|
| 526 |
|
|---|
| 527 |
if publish_after_save && version[:status] >= Zena::Status[:prop] && version[:user_id] == visitor[:id] && version[:lang] == lang && (Time.now < version[:updated_at] + current_site[:redit_time].to_i) |
|---|
| 528 |
if can_visible? || (can_manage? && private?) || version[:status] == Zena::Status[:prop] |
|---|
| 529 |
|
|---|
| 530 |
redit = true |
|---|
| 531 |
v = version |
|---|
| 532 |
end |
|---|
| 533 |
end |
|---|
| 534 |
|
|---|
| 535 |
if v == nil |
|---|
| 536 |
|
|---|
| 537 |
v = version.clone |
|---|
| 538 |
v.status = Zena::Status[:red] |
|---|
| 539 |
v.publish_from = v.created_at = nil |
|---|
| 540 |
v.comment = v.number = '' |
|---|
| 541 |
v.user_id = visitor[:id] |
|---|
| 542 |
v.lang = lang |
|---|
| 543 |
v[:content_id] = version[:content_id] || version[:id] |
|---|
| 544 |
end |
|---|
| 545 |
end |
|---|
| 546 |
v.node = self if v |
|---|
| 547 |
|
|---|
| 548 |
if v && (v.user_id == visitor[:id]) && (v.status == Zena::Status[:red] || redit) |
|---|
| 549 |
@old_title = @version.title |
|---|
| 550 |
@redaction = @version = v |
|---|
| 551 |
elsif v |
|---|
| 552 |
errors.add('base', "(#{v.user.login}) is editing this node") |
|---|
| 553 |
nil |
|---|
| 554 |
else |
|---|
| 555 |
errors.add('base', 'you do not have the rights to do this') |
|---|
| 556 |
nil |
|---|
| 557 |
end |
|---|
| 558 |
end |
|---|
| 559 |
end |
|---|
| 560 |
|
|---|
| 561 |
|
|---|
| 562 |
|
|---|
| 563 |
|
|---|
| 564 |
def method_missing(meth, *args) |
|---|
| 565 |
if meth.to_s =~ /^(v_|c_|d_)(([\w_\?]+)(=?))$/ |
|---|
| 566 |
target = $1 |
|---|
| 567 |
method = $2 |
|---|
| 568 |
value = $3 |
|---|
| 569 |
mode = $4 |
|---|
| 570 |
if mode == '=' |
|---|
| 571 |
begin |
|---|
| 572 |
|
|---|
| 573 |
unless recipient = redaction |
|---|
| 574 |
|
|---|
| 575 |
redaction_error(meth.to_s[0..-2], "could not be set (no redaction)") |
|---|
| 576 |
return |
|---|
| 577 |
end |
|---|
| 578 |
|
|---|
| 579 |
case target |
|---|
| 580 |
when 'c_' |
|---|
| 581 |
if recipient.content_class && recipient = recipient.redaction_content |
|---|
| 582 |
recipient.send(method,*args) |
|---|
| 583 |
else |
|---|
| 584 |
redaction_error(meth.to_s[0..-2], "cannot be set") |
|---|
| 585 |
end |
|---|
| 586 |
when 'd_' |
|---|
| 587 |
recipient.dyn[method[0..-2]] = args[0] |
|---|
| 588 |
else |
|---|
| 589 |
recipient.send(method,*args) |
|---|
| 590 |
end |
|---|
| 591 |
rescue NoMethodError |
|---|
| 592 |
|
|---|
| 593 |
end |
|---|
| 594 |
else |
|---|
| 595 |
|
|---|
| 596 |
recipient = version |
|---|
| 597 |
if target == 'd_' |
|---|
| 598 |
version.dyn[method] |
|---|
| 599 |
else |
|---|
| 600 |
recipient = recipient.content if target == 'c_' |
|---|
| 601 |
return nil unless recipient |
|---|
| 602 |
begin |
|---|
| 603 |
recipient.send(method,*args) |
|---|
| 604 |
rescue NoMethodError |
|---|
| 605 |
|
|---|
| 606 |
return nil |
|---|
| 607 |
end |
|---|
| 608 |
end |
|---|
| 609 |
end |
|---|
| 610 |
else |
|---|
| 611 |
super |
|---|
| 612 |
end |
|---|
| 613 |
end |
|---|
| 614 |
|
|---|
| 615 |
|
|---|
| 616 |
def redaction_error(field, message) |
|---|
| 617 |
@redaction_errors ||= [] |
|---|
| 618 |
@redaction_errors << [field, message] |
|---|
| 619 |
end |
|---|
| 620 |
|
|---|
| 621 |
|
|---|
| 622 |
def valid_redaction |
|---|
| 623 |
if @version && !@version.valid? |
|---|
| 624 |
merge_version_errors |
|---|
| 625 |
end |
|---|
| 626 |
if @redaction_errors |
|---|
| 627 |
@redaction_errors.each do |k,v| |
|---|
| 628 |
errors.add(k,v) |
|---|
| 629 |
end |
|---|
| 630 |
end |
|---|
| 631 |
end |
|---|
| 632 |
|
|---|
| 633 |
def merge_version_errors |
|---|
| 634 |
unless @version.errors.empty? |
|---|
| 635 |
@version.errors.each do |k,v| |
|---|
| 636 |
if k.to_s =~ /^c_/ |
|---|
| 637 |
key = k.to_s |
|---|
| 638 |
elsif k.to_s == 'base' |
|---|
| 639 |
key = 'base' |
|---|
| 640 |
else |
|---|
| 641 |
key = "v_#{k}" |
|---|
| 642 |
end |
|---|
| 643 |
errors.add(key, v) |
|---|
| 644 |
end |
|---|
| 645 |
end |
|---|
| 646 |
end |
|---|
| 647 |
|
|---|
| 648 |
def version_class |
|---|
| 649 |
self.class.version_class |
|---|
| 650 |
end |
|---|
| 651 |
|
|---|
| 652 |
def save_version(validations = true) |
|---|
| 653 |
if validations |
|---|
| 654 |
@version.save if (@version && @version.new_record?) || @redaction |
|---|
| 655 |
else |
|---|
| 656 |
@version.save_without_validation if (@version && @version.new_record?) || @redaction |
|---|
| 657 |
end |
|---|
| 658 |
end |
|---|
| 659 |
|
|---|
| 660 |
def set_on_create |
|---|
| 661 |
|
|---|
| 662 |
self[:kpath] = self.class.kpath |
|---|
| 663 |
self[:user_id] = visitor[:id] |
|---|
| 664 |
self[:ref_lang] = visitor.lang |
|---|
| 665 |
version.user_id = visitor[:id] |
|---|
| 666 |
version.lang = visitor.lang if version.lang.blank? |
|---|
| 667 |
version[:status]= Zena::Status[:pub] if current_site[:auto_publish] |
|---|
| 668 |
version[:publish_from] ||= Time.now if version[:status] == Zena::Status[:pub] |
|---|
| 669 |
true |
|---|
| 670 |
end |
|---|
| 671 |
|
|---|
| 672 |
public |
|---|
| 673 |
module ClassMethods |
|---|
| 674 |
|
|---|
| 675 |
|
|---|
| 676 |
|
|---|
| 677 |
def version_class |
|---|
| 678 |
Version |
|---|
| 679 |
end |
|---|
| 680 |
|
|---|
| 681 |
|
|---|
| 682 |
def version(version_id) |
|---|
| 683 |
version = Version.find(version_id.to_i) |
|---|
| 684 |
node = self.find(version.node_id) |
|---|
| 685 |
node.version = version |
|---|
| 686 |
node.eval_with_visitor 'errors.add("base", "you do not have the rights to do this") unless version.status == 50 || can_drive? || version.user_id == visitor[:id]' |
|---|
| 687 |
end |
|---|
| 688 |
end |
|---|
| 689 |
end |
|---|
| 690 |
end |
|---|
| 691 |
end |
|---|
| 692 |
end |
|---|
| 693 |
|
|---|
| 694 |
ActiveRecord::Base.send :include, Zena::Acts::Multiversioned |
|---|