| 1 |
module Zena |
|---|
| 2 |
|
|---|
| 3 |
Status = { |
|---|
| 4 |
:pub => 50, |
|---|
| 5 |
:prop => 40, |
|---|
| 6 |
:prop_with => 35, |
|---|
| 7 |
:red_visible => 33, |
|---|
| 8 |
:red => 30, |
|---|
| 9 |
:rep => 20, |
|---|
| 10 |
:rem => 10, |
|---|
| 11 |
:del => 0, |
|---|
| 12 |
}.freeze |
|---|
| 13 |
|
|---|
| 14 |
module Acts |
|---|
| 15 |
=begin rdoc |
|---|
| 16 |
== Secure model |
|---|
| 17 |
Read, write and publication access to an node is defined with four elements: one user and three groups. |
|---|
| 18 |
link://rwp_groups.png |
|---|
| 19 |
|
|---|
| 20 |
=== Definitions : |
|---|
| 21 |
[inherit] Defines how the groups propagate. If +inherit+ is set to '1', the node inherits rwp groups from it's reference. If |
|---|
| 22 |
+inherit+ is set to '0', the node has custom rwp groups. When set to '-1', the node is becomes private and all |
|---|
| 23 |
rwp groups are set to '0'. |
|---|
| 24 |
[read] |
|---|
| 25 |
This means that the node can be seen. |
|---|
| 26 |
[write] |
|---|
| 27 |
This means that new versions can be proposed for the node as well as new |
|---|
| 28 |
sub-pages, documents, events, etc. Basically can write = can add content. If a user has write access to |
|---|
| 29 |
a #Tag, this means he can add nodes to this #Tag (#Tag available as a category for other nodes). |
|---|
| 30 |
[publish] |
|---|
| 31 |
This means that the content viewed by all can be altered by |
|---|
| 32 |
1. publishing new versions |
|---|
| 33 |
2. changing the node itself (name, groups, location, categories, etc) |
|---|
| 34 |
3. removing the node and/or sub-nodes |
|---|
| 35 |
4. people with this access can see nodes that are not published yet |
|---|
| 36 |
[manage] |
|---|
| 37 |
This is for nodes that <em>have not yet been published</em> or for <em>private nodes</em> |
|---|
| 38 |
A. <em>private node</em> |
|---|
| 39 |
1. can 'publish' node (it is not really published as the node is private...) |
|---|
| 40 |
2. can 'unpublish' (make this node a 'not published yet') |
|---|
| 41 |
3. can change node itself (cannot change groups) |
|---|
| 42 |
4. can destroy |
|---|
| 43 |
B. <em>node not published yet</em> only : |
|---|
| 44 |
5. make an node private (sets all groups to 0) or revert node to default groups (same as parent or project) if node not published yet |
|---|
| 45 |
5. can see node (edition = personal redaction or latest version) |
|---|
| 46 |
[max_status] |
|---|
| 47 |
This is set to the highest status of all versions. Order from highest to lowest are : 'pub', 'prop', 'red', 'rep', 'rem', 'del' |
|---|
| 48 |
|
|---|
| 49 |
=== Who can do what |
|---|
| 50 |
[read] |
|---|
| 51 |
* super user |
|---|
| 52 |
* owner |
|---|
| 53 |
* members of +read_group+ if the node is published and the current date is greater or equal to the publication date |
|---|
| 54 |
* members of +publish_group+ if +max_status+ >= prop |
|---|
| 55 |
|
|---|
| 56 |
[write] |
|---|
| 57 |
* super user |
|---|
| 58 |
* owner |
|---|
| 59 |
* members of +write_group+ if node is published and the current date is greater or equal to the publication date |
|---|
| 60 |
|
|---|
| 61 |
[publish] |
|---|
| 62 |
* super user |
|---|
| 63 |
* members of +publish_group+ if +max_status+ >= prop |
|---|
| 64 |
* owner if member of +publish_group+ |
|---|
| 65 |
|
|---|
| 66 |
[manage] |
|---|
| 67 |
* owner if +max_status+ <= red |
|---|
| 68 |
* owner if private |
|---|
| 69 |
|
|---|
| 70 |
=== Misc |
|---|
| 71 |
|
|---|
| 72 |
* A user can only set a group in which he/she belongs. |
|---|
| 73 |
* Only people from the 'admin' group can change an node's owner. |
|---|
| 74 |
* Setting all groups to _public_ transforms the node into a wiki. |
|---|
| 75 |
* A user who belongs to the 'admin' group (id=2), automatically belongs to all other groups. |
|---|
| 76 |
|
|---|
| 77 |
=== Usage |
|---|
| 78 |
|
|---|
| 79 |
In the controller : |
|---|
| 80 |
require 'lib/acts_as_secure' |
|---|
| 81 |
class PagesController < ApplicationController |
|---|
| 82 |
before_filter :set_logged_in_user |
|---|
| 83 |
acts_as_secure |
|---|
| 84 |
|
|---|
| 85 |
def show |
|---|
| 86 |
@page = secure { Page.find(params[:id]) } |
|---|
| 87 |
end |
|---|
| 88 |
private |
|---|
| 89 |
def set_logged_in_user |
|---|
| 90 |
|
|---|
| 91 |
session[:user] = @user[:id] |
|---|
| 92 |
end |
|---|
| 93 |
|
|---|
| 94 |
|
|---|
| 95 |
In the model : |
|---|
| 96 |
require 'lib/acts_as_secure' |
|---|
| 97 |
class Page < ActiveRecord::Base |
|---|
| 98 |
acts_as_secure_node |
|---|
| 99 |
end |
|---|
| 100 |
|
|---|
| 101 |
In the helpers (if you intend to use secure find there...) |
|---|
| 102 |
require 'lib/acts_as_secure' |
|---|
| 103 |
module ApplicationHelper |
|---|
| 104 |
include Zena::Acts::Secure |
|---|
| 105 |
|
|---|
| 106 |
end |
|---|
| 107 |
Just doing the above will filter all result according to the logged in user. |
|---|
| 108 |
=end |
|---|
| 109 |
module SecureNode |
|---|
| 110 |
|
|---|
| 111 |
def self.included(base) |
|---|
| 112 |
|
|---|
| 113 |
base.extend AddActsAsMethod |
|---|
| 114 |
end |
|---|
| 115 |
module AddActsAsMethod |
|---|
| 116 |
def acts_as_secure_node |
|---|
| 117 |
belongs_to :rgroup, :class_name=>'Group', :foreign_key=>'rgroup_id' |
|---|
| 118 |
belongs_to :wgroup, :class_name=>'Group', :foreign_key=>'wgroup_id' |
|---|
| 119 |
belongs_to :pgroup, :class_name=>'Group', :foreign_key=>'pgroup_id' |
|---|
| 120 |
belongs_to :user |
|---|
| 121 |
before_validation :secure_before_validation |
|---|
| 122 |
after_save :check_inheritance |
|---|
| 123 |
before_destroy :secure_on_destroy |
|---|
| 124 |
class_eval <<-END |
|---|
| 125 |
include Zena::Acts::SecureNode::InstanceMethods |
|---|
| 126 |
END |
|---|
| 127 |
end |
|---|
| 128 |
end |
|---|
| 129 |
|
|---|
| 130 |
|
|---|
| 131 |
module InstanceMethods |
|---|
| 132 |
|
|---|
| 133 |
def self.included(base) |
|---|
| 134 |
base.extend ClassMethods |
|---|
| 135 |
end |
|---|
| 136 |
|
|---|
| 137 |
|
|---|
| 138 |
def visitor=(visitor) |
|---|
| 139 |
@visitor = visitor |
|---|
| 140 |
if new_record? |
|---|
| 141 |
set_on_create |
|---|
| 142 |
end |
|---|
| 143 |
|
|---|
| 144 |
if @eval_on_visitor |
|---|
| 145 |
@eval_on_visitor.each do |str| |
|---|
| 146 |
eval(str) |
|---|
| 147 |
end |
|---|
| 148 |
unless errors.empty? |
|---|
| 149 |
raise ActiveRecord::RecordNotFound |
|---|
| 150 |
end |
|---|
| 151 |
end |
|---|
| 152 |
self |
|---|
| 153 |
end |
|---|
| 154 |
|
|---|
| 155 |
|
|---|
| 156 |
def eval_with_visitor(str) |
|---|
| 157 |
@eval_on_visitor ||= [] |
|---|
| 158 |
@eval_on_visitor << str |
|---|
| 159 |
self |
|---|
| 160 |
end |
|---|
| 161 |
|
|---|
| 162 |
|
|---|
| 163 |
def private? |
|---|
| 164 |
(rgroup_id==0 && wgroup_id==0 && pgroup_id==0) |
|---|
| 165 |
end |
|---|
| 166 |
|
|---|
| 167 |
|
|---|
| 168 |
def public? |
|---|
| 169 |
can_read?(visitor.site.anon,visitor.site.anon.group_ids) |
|---|
| 170 |
end |
|---|
| 171 |
|
|---|
| 172 |
|
|---|
| 173 |
|
|---|
| 174 |
|
|---|
| 175 |
|
|---|
| 176 |
|
|---|
| 177 |
def can_read?(vis = visitor, ugps=visitor.group_ids) |
|---|
| 178 |
( vis.is_su? ) || |
|---|
| 179 |
( vis[:id] == user_id ) || |
|---|
| 180 |
( ugps.include?(rgroup_id) && publish_from && Time.now >= publish_from ) || |
|---|
| 181 |
( ugps.include?(pgroup_id) && max_status != Zena::Status[:red] ) |
|---|
| 182 |
end |
|---|
| 183 |
|
|---|
| 184 |
|
|---|
| 185 |
|
|---|
| 186 |
|
|---|
| 187 |
|
|---|
| 188 |
def can_write?(vis=visitor, ugps=visitor.group_ids) |
|---|
| 189 |
( vis.is_su? ) || |
|---|
| 190 |
( vis.user? && (( vis[:id] == user_id ) || |
|---|
| 191 |
( ugps.include?(wgroup_id) && max_status != Zena::Status[:red] ))) |
|---|
| 192 |
end |
|---|
| 193 |
|
|---|
| 194 |
|
|---|
| 195 |
|
|---|
| 196 |
|
|---|
| 197 |
|
|---|
| 198 |
def can_visible?(vis=visitor, ugps=visitor.group_ids) |
|---|
| 199 |
( vis.is_su? ) || |
|---|
| 200 |
( vis.user? && (( ugps.include?(pgroup_id) ) || |
|---|
| 201 |
( private? && ugps.include?(ref.pgroup_id)))) |
|---|
| 202 |
end |
|---|
| 203 |
|
|---|
| 204 |
|
|---|
| 205 |
|
|---|
| 206 |
|
|---|
| 207 |
def can_manage?(vis=visitor) |
|---|
| 208 |
( vis.is_su? ) || |
|---|
| 209 |
( vis.user? && (( publish_from == nil && vis[:id] == user_id && max_status <= Zena::Status[:red] ) || |
|---|
| 210 |
( private? && vis[:id] == user_id ))) |
|---|
| 211 |
end |
|---|
| 212 |
|
|---|
| 213 |
|
|---|
| 214 |
def can_drive? |
|---|
| 215 |
can_manage? || can_visible? |
|---|
| 216 |
end |
|---|
| 217 |
|
|---|
| 218 |
def secure_before_validation |
|---|
| 219 |
unless @visitor |
|---|
| 220 |
errors.add('base', "record not secured") |
|---|
| 221 |
return false |
|---|
| 222 |
end |
|---|
| 223 |
self[:site_id] = @visitor.site[:id] |
|---|
| 224 |
if new_record? |
|---|
| 225 |
set_on_create |
|---|
| 226 |
secure_on_create |
|---|
| 227 |
else |
|---|
| 228 |
secure_on_update |
|---|
| 229 |
end |
|---|
| 230 |
end |
|---|
| 231 |
|
|---|
| 232 |
|
|---|
| 233 |
def set_on_create |
|---|
| 234 |
|
|---|
| 235 |
self[:kpath] = self.class.kpath |
|---|
| 236 |
self[:user_id] = visitor[:id] |
|---|
| 237 |
self[:ref_lang] = visitor.lang |
|---|
| 238 |
end |
|---|
| 239 |
|
|---|
| 240 |
|
|---|
| 241 |
|
|---|
| 242 |
|
|---|
| 243 |
|
|---|
| 244 |
|
|---|
| 245 |
|
|---|
| 246 |
|
|---|
| 247 |
def secure_on_create |
|---|
| 248 |
|
|---|
| 249 |
if ref == nil |
|---|
| 250 |
errors.add(ref_field, "invalid reference") |
|---|
| 251 |
return false |
|---|
| 252 |
end |
|---|
| 253 |
[:rgroup_id, :wgroup_id, :pgroup_id, :skin].each do |sym| |
|---|
| 254 |
|
|---|
| 255 |
self[sym] ||= ref[sym] |
|---|
| 256 |
self[sym] = 0 if self[sym] == '' |
|---|
| 257 |
end |
|---|
| 258 |
if inherit.nil? |
|---|
| 259 |
if rgroup_id == ref.rgroup_id && wgroup_id == ref.wgroup_id && pgroup_id == ref.pgroup_id |
|---|
| 260 |
self[:inherit ] = 1 |
|---|
| 261 |
else |
|---|
| 262 |
self[:inherit ] = 0 |
|---|
| 263 |
end |
|---|
| 264 |
end |
|---|
| 265 |
case inherit |
|---|
| 266 |
when 1 |
|---|
| 267 |
|
|---|
| 268 |
self[:rgroup_id] = ref.rgroup_id |
|---|
| 269 |
self[:wgroup_id] = ref.wgroup_id |
|---|
| 270 |
self[:pgroup_id] = ref.pgroup_id |
|---|
| 271 |
self[:skin ] = ref.skin |
|---|
| 272 |
when -1 |
|---|
| 273 |
|
|---|
| 274 |
if visitor.site[:allow_private] |
|---|
| 275 |
self[:rgroup_id] = 0 |
|---|
| 276 |
self[:wgroup_id] = 0 |
|---|
| 277 |
self[:pgroup_id] = 0 |
|---|
| 278 |
else |
|---|
| 279 |
errors.add('inherit', "you cannot change this") |
|---|
| 280 |
end |
|---|
| 281 |
when 0 |
|---|
| 282 |
if ref.can_visible? |
|---|
| 283 |
errors.add('rgroup_id', "unknown group") unless visitor.group_ids.include?(rgroup_id) |
|---|
| 284 |
errors.add('wgroup_id', "unknown group") unless visitor.group_ids.include?(wgroup_id) |
|---|
| 285 |
errors.add('pgroup_id', "unknown group") unless visitor.group_ids.include?(pgroup_id) |
|---|
| 286 |
elsif private? |
|---|
| 287 |
|
|---|
| 288 |
else |
|---|
| 289 |
errors.add('inherit', "invalid value") |
|---|
| 290 |
errors.add('rgroup_id', "you cannot change this") unless rgroup_id == ref.rgroup_id |
|---|
| 291 |
errors.add('wgroup_id', "you cannot change this") unless wgroup_id == ref.wgroup_id |
|---|
| 292 |
errors.add('pgroup_id', "you cannot change this") unless pgroup_id == ref.pgroup_id |
|---|
| 293 |
errors.add('skin' , "you cannot change this") unless skin == ref.skin |
|---|
| 294 |
end |
|---|
| 295 |
else |
|---|
| 296 |
errors.add('inherit', "bad inheritance mode") |
|---|
| 297 |
end |
|---|
| 298 |
|
|---|
| 299 |
|
|---|
| 300 |
self[:publish_from] = version.publish_from |
|---|
| 301 |
|
|---|
| 302 |
self[:max_status] = version.status |
|---|
| 303 |
return errors.empty? |
|---|
| 304 |
end |
|---|
| 305 |
|
|---|
| 306 |
|
|---|
| 307 |
|
|---|
| 308 |
|
|---|
| 309 |
|
|---|
| 310 |
|
|---|
| 311 |
|
|---|
| 312 |
|
|---|
| 313 |
|
|---|
| 314 |
|
|---|
| 315 |
def secure_on_update |
|---|
| 316 |
@old = nil |
|---|
| 317 |
unless old |
|---|
| 318 |
|
|---|
| 319 |
errors.add('base', "you do not have the rights to do this") |
|---|
| 320 |
return false |
|---|
| 321 |
end |
|---|
| 322 |
if !( old.can_drive? ) |
|---|
| 323 |
errors.add('base', "you do not have the rights to do this") |
|---|
| 324 |
return false |
|---|
| 325 |
end |
|---|
| 326 |
if user_id != old.user_id |
|---|
| 327 |
if visitor.is_admin? |
|---|
| 328 |
|
|---|
| 329 |
unless User.find(:first, :conditions => ["id = ?",user_id]) |
|---|
| 330 |
errors.add('user_id', "unknown user") |
|---|
| 331 |
end |
|---|
| 332 |
else |
|---|
| 333 |
errors.add('user_id', "you cannot change this") |
|---|
| 334 |
end |
|---|
| 335 |
end |
|---|
| 336 |
return false unless errors.empty? |
|---|
| 337 |
|
|---|
| 338 |
if ref == nil |
|---|
| 339 |
errors.add(ref_field, "invalid reference") |
|---|
| 340 |
return false |
|---|
| 341 |
end |
|---|
| 342 |
if self[ref_field] != old[ref_field] |
|---|
| 343 |
|
|---|
| 344 |
if old.private? || old.publish_from == nil |
|---|
| 345 |
|
|---|
| 346 |
if self[ref_field] == self[:id] || |
|---|
| 347 |
! secure_write(ref_class) { ref_class.find(self[ref_field])} || |
|---|
| 348 |
! secure_write(ref_class) { ref_class.find(old[ref_field])} |
|---|
| 349 |
errors.add(ref_field, "invalid reference") |
|---|
| 350 |
return false |
|---|
| 351 |
end |
|---|
| 352 |
else |
|---|
| 353 |
|
|---|
| 354 |
|
|---|
| 355 |
if self[ref_field] == self[:id] || |
|---|
| 356 |
! secure_drive(ref_class) { ref_class.find(self[ref_field]) } || |
|---|
| 357 |
! secure_drive(ref_class) { ref_class.find(old[ref_field]) } |
|---|
| 358 |
errors.add(ref_field, "invalid reference") |
|---|
| 359 |
return false |
|---|
| 360 |
end |
|---|
| 361 |
end |
|---|
| 362 |
|
|---|
| 363 |
ref_ids = [self[:id]] |
|---|
| 364 |
curr_ref = self[:parent_id] |
|---|
| 365 |
ok = true |
|---|
| 366 |
while curr_ref != 0 |
|---|
| 367 |
if ref_ids.include?(curr_ref) |
|---|
| 368 |
ok = false |
|---|
| 369 |
break |
|---|
| 370 |
end |
|---|
| 371 |
ref_ids << curr_ref |
|---|
| 372 |
rows = self.class.connection.execute("SELECT #{ref_field} FROM #{self.class.table_name} WHERE id=#{curr_ref}") |
|---|
| 373 |
if rows.num_rows == 0 |
|---|
| 374 |
errors.add(ref_field, "reference missing in reference hierarchy") |
|---|
| 375 |
raise ActiveRecord::RecordNotFound |
|---|
| 376 |
end |
|---|
| 377 |
curr_ref = rows.fetch_row[0].to_i |
|---|
| 378 |
end |
|---|
| 379 |
unless ok |
|---|
| 380 |
errors.add(ref_field, 'circular reference') |
|---|
| 381 |
return false |
|---|
| 382 |
end |
|---|
| 383 |
end |
|---|
| 384 |
|
|---|
| 385 |
self[:publish_from] = @publish_from || old.publish_from |
|---|
| 386 |
|
|---|
| 387 |
self[:max_status] = @max_status || old.max_status |
|---|
| 388 |
|
|---|
| 389 |
[:rgroup_id, :wgroup_id, :pgroup_id].each do |sym| |
|---|
| 390 |
|
|---|
| 391 |
self[sym] = 0 if !self[sym] || self[sym] == '' |
|---|
| 392 |
end |
|---|
| 393 |
if self[:inherit] == 0 && pgroup_id == 0 |
|---|
| 394 |
|
|---|
| 395 |
self[:inherit] = -1 |
|---|
| 396 |
end |
|---|
| 397 |
case inherit |
|---|
| 398 |
when 1 |
|---|
| 399 |
|
|---|
| 400 |
if inherit != old.inherit && !(old.can_visible? || ( old.can_manage? && (old.max_status_with_heirs < Zena::Status[:pub]) )) |
|---|
| 401 |
errors.add('inherit', 'you cannot change this') |
|---|
| 402 |
return false |
|---|
| 403 |
end |
|---|
| 404 |
|
|---|
| 405 |
|
|---|
| 406 |
[:rgroup_id, :wgroup_id, :pgroup_id, :skin].each do |sym| |
|---|
| 407 |
self[sym] = ref[sym] |
|---|
| 408 |
end |
|---|
| 409 |
when -1 |
|---|
| 410 |
|
|---|
| 411 |
unless (inherit == old.inherit) |
|---|
| 412 |
if old.can_drive? && (user_id == visitor[:id]) && visitor.site[:allow_private] |
|---|
| 413 |
[:rgroup_id, :wgroup_id, :pgroup_id].each do |sym| |
|---|
| 414 |
self[sym] = 0 |
|---|
| 415 |
end |
|---|
| 416 |
else |
|---|
| 417 |
errors.add('inherit', "you cannot change this") |
|---|
| 418 |
end |
|---|
| 419 |
end |
|---|
| 420 |
when 0 |
|---|
| 421 |
if old.can_visible? |
|---|
| 422 |
if ref.can_visible? |
|---|
| 423 |
|
|---|
| 424 |
if private? |
|---|
| 425 |
|
|---|
| 426 |
else |
|---|
| 427 |
[:rgroup_id, :wgroup_id, :pgroup_id].each do |sym| |
|---|
| 428 |
if self[sym] != 0 && self[sym] != old[:rgroup_id] && !visitor.group_ids.include?(self[sym]) |
|---|
| 429 |
errors.add(sym.to_s, "unknown group") |
|---|
| 430 |
end |
|---|
| 431 |
end |
|---|
| 432 |
end |
|---|
| 433 |
else |
|---|
| 434 |
|
|---|
| 435 |
errors.add('inherit', "you cannot change this") unless inherit == old.inherit |
|---|
| 436 |
errors.add('rgroup_id', "you cannot change this") unless rgroup_id == old.rgroup_id |
|---|
| 437 |
errors.add('wgroup_id', "you cannot change this") unless wgroup_id == old.wgroup_id |
|---|
| 438 |
errors.add('pgroup_id', "you cannot change this") unless pgroup_id == old.pgroup_id |
|---|
| 439 |
|
|---|
| 440 |
end |
|---|
| 441 |
else |
|---|
| 442 |
|
|---|
| 443 |
errors.add('inherit', "you cannot change this") unless inherit == old.inherit |
|---|
| 444 |
errors.add('rgroup_id', "you cannot change this") unless rgroup_id == old.rgroup_id |
|---|
| 445 |
errors.add('wgroup_id', "you cannot change this") unless wgroup_id == old.wgroup_id |
|---|
| 446 |
errors.add('pgroup_id', "you cannot change this") unless pgroup_id == old.pgroup_id |
|---|
| 447 |
errors.add('skin', "you cannot change this") unless skin == old.skin |
|---|
| 448 |
end |
|---|
| 449 |
else |
|---|
| 450 |
errors.add('inherit', "bad inheritance mode") |
|---|
| 451 |
end |
|---|
| 452 |
@needs_inheritance_spread = (rgroup_id != old.rgroup_id || wgroup_id != old.wgroup_id || pgroup_id != old.pgroup_id || skin != old.skin) |
|---|
| 453 |
return errors.empty? |
|---|
| 454 |
end |
|---|
| 455 |
|
|---|
| 456 |
def secure_on_destroy |
|---|
| 457 |
if old && old.can_drive? |
|---|
| 458 |
return true |
|---|
| 459 |
else |
|---|
| 460 |
errors.add('base', "you do not have the rights to do this") |
|---|
| 461 |
return false |
|---|
| 462 |
end |
|---|
| 463 |
end |
|---|
| 464 |
|
|---|
| 465 |
|
|---|
| 466 |
def ref |
|---|
| 467 |
return self if ref_field == :id && new_record? |
|---|
| 468 |
if !@ref || (@ref.id != self[ref_field]) |
|---|
| 469 |
|
|---|
| 470 |
@ref = secure(ref_class) { ref_class.find(:first, :conditions => ["id = ?", self[ref_field]]) } |
|---|
| 471 |
end |
|---|
| 472 |
if @ref && (self.new_record? || (:id == ref_field) || (self[:id] != @ref[:id] )) |
|---|
| 473 |
|
|---|
| 474 |
@ref.freeze |
|---|
| 475 |
else |
|---|
| 476 |
nil |
|---|
| 477 |
end |
|---|
| 478 |
end |
|---|
| 479 |
|
|---|
| 480 |
protected |
|---|
| 481 |
|
|---|
| 482 |
def check_inheritance |
|---|
| 483 |
if @needs_inheritance_spread |
|---|
| 484 |
spread_inheritance |
|---|
| 485 |
end |
|---|
| 486 |
true |
|---|
| 487 |
end |
|---|
| 488 |
|
|---|
| 489 |
|
|---|
| 490 |
|
|---|
| 491 |
|
|---|
| 492 |
|
|---|
| 493 |
def spread_inheritance(i = self[:id]) |
|---|
| 494 |
base_class.connection.execute "UPDATE nodes SET rgroup_id='#{rgroup_id}', wgroup_id='#{wgroup_id}', pgroup_id='#{pgroup_id}', skin='#{skin}' WHERE #{ref_field(false)}='#{i}' AND inherit='1'" |
|---|
| 495 |
ids = nil |
|---|
| 496 |
base_class.with_exclusive_scope do |
|---|
| 497 |
ids = base_class.fetch_ids("SELECT id FROM #{base_class.table_name} WHERE #{ref_field(true)} = '#{i.to_i}' AND inherit='1'") |
|---|
| 498 |
end |
|---|
| 499 |
|
|---|
| 500 |
ids.each { |i| spread_inheritance(i) } |
|---|
| 501 |
end |
|---|
| 502 |
|
|---|
| 503 |
|
|---|
| 504 |
|
|---|
| 505 |
def max_status_with_heirs(max=0) |
|---|
| 506 |
max = [max, max_status].max |
|---|
| 507 |
return max if max == Zena::Status[:pub] |
|---|
| 508 |
heirs.each do |h| |
|---|
| 509 |
max = [max, h.max_status_with_heirs(max)].max |
|---|
| 510 |
break if max == Zena::Status[:pub] |
|---|
| 511 |
end |
|---|
| 512 |
return max |
|---|
| 513 |
end |
|---|
| 514 |
|
|---|
| 515 |
private |
|---|
| 516 |
|
|---|
| 517 |
|
|---|
| 518 |
def old |
|---|
| 519 |
if new_record? |
|---|
| 520 |
nil |
|---|
| 521 |
else |
|---|
| 522 |
@old ||= secure_drive(self.class) { self.class.find(self[:id]) } |
|---|
| 523 |
end |
|---|
| 524 |
end |
|---|
| 525 |
|
|---|
| 526 |
|
|---|
| 527 |
|
|---|
| 528 |
def heirs |
|---|
| 529 |
base_class.with_exclusive_scope do |
|---|
| 530 |
base_class.find(:all, :conditions=>["#{ref_field(true)} = ? AND inherit='1'" , self[:id] ] ) || [] |
|---|
| 531 |
end |
|---|
| 532 |
end |
|---|
| 533 |
|
|---|
| 534 |
|
|---|
| 535 |
def ref_class |
|---|
| 536 |
self.class |
|---|
| 537 |
end |
|---|
| 538 |
|
|---|
| 539 |
|
|---|
| 540 |
def base_class |
|---|
| 541 |
self.class |
|---|
| 542 |
end |
|---|
| 543 |
|
|---|
| 544 |
|
|---|
| 545 |
def ref_field(for_heirs=false) |
|---|
| 546 |
:reference_id |
|---|
| 547 |
end |
|---|
| 548 |
|
|---|
| 549 |
public |
|---|
| 550 |
|
|---|
| 551 |
|
|---|
| 552 |
def show_errors |
|---|
| 553 |
errors.each {|k,m| puts "[#{k}] #{m}"} |
|---|
| 554 |
end |
|---|
| 555 |
|
|---|
| 556 |
module ClassMethods |
|---|
| 557 |
|
|---|
| 558 |
|
|---|
| 559 |
|
|---|
| 560 |
|
|---|
| 561 |
|
|---|
| 562 |
|
|---|
| 563 |
|
|---|
| 564 |
|
|---|
| 565 |
|
|---|
| 566 |
|
|---|
| 567 |
|
|---|
| 568 |
def kpath |
|---|
| 569 |
@@kpath[self] ||= superclass == ActiveRecord::Base ? ksel : (superclass.kpath + ksel) |
|---|
| 570 |
end |
|---|
| 571 |
|
|---|
| 572 |
|
|---|
| 573 |
|
|---|
| 574 |
def clean_options(options) |
|---|
| 575 |
options.reject do |k,v| |
|---|
| 576 |
! [ :conditions, :select, :include, :offset, :limit, :order, :lock ].include?(k) |
|---|
| 577 |
end |
|---|
| 578 |
end |
|---|
| 579 |
|
|---|
| 580 |
|
|---|
| 581 |
def ksel |
|---|
| 582 |
self.to_s[0..0] |
|---|
| 583 |
end |
|---|
| 584 |
|
|---|
| 585 |
@@kpath = {} |
|---|
| 586 |
|
|---|
| 587 |
|
|---|
| 588 |
def type_condition |
|---|
| 589 |
" #{table_name}.kpath LIKE '#{kpath}%' " |
|---|
| 590 |
end |
|---|
| 591 |
end |
|---|
| 592 |
end |
|---|
| 593 |
end |
|---|
| 594 |
|
|---|
| 595 |
|
|---|
| 596 |
module Secure |
|---|
| 597 |
|
|---|
| 598 |
def site_id=(i) |
|---|
| 599 |
raise Zena::AccessViolation, "#{self.class.to_s} '#{self.id}': tried to change 'site_id' to '#{i}'." |
|---|
| 600 |
end |
|---|
| 601 |
|
|---|
| 602 |
|
|---|
| 603 |
def visitor=(visitor) |
|---|
| 604 |
@visitor = visitor |
|---|
| 605 |
end |
|---|
| 606 |
|
|---|
| 607 |
|
|---|
| 608 |
protected |
|---|
| 609 |
|
|---|
| 610 |
def secure_with_scope(klass, find_scope, opts={}) |
|---|
| 611 |
if ((klass.send(:scoped_methods)[0] || {})[:create] || {})[:visitor] |
|---|
| 612 |
|
|---|
| 613 |
last_scope = klass.send(:scoped_methods).shift |
|---|
| 614 |
end |
|---|
| 615 |
|
|---|
| 616 |
scope = {:create => { :visitor => visitor }} |
|---|
| 617 |
if klass.ancestors.include?(User) |
|---|
| 618 |
scope[:find] ||= {} |
|---|
| 619 |
ptbl = Participation.table_name |
|---|
| 620 |
scope[:find][:joins] = "INNER JOIN #{ptbl} ON #{klass.table_name}.id = #{ptbl}.user_id AND #{ptbl}.site_id = #{visitor.site[:id]}" |
|---|
| 621 |
scope[:find][:readonly] = false |
|---|
| 622 |
scope[:find][:select] = "#{User.table_name}.*" |
|---|
| 623 |
scope[:find][:conditions] = find_scope |
|---|
| 624 |
elsif klass.column_names.include?('site_id') |
|---|
| 625 |
if find_scope && !opts[:site_id_clause_set] |
|---|
| 626 |
find_scope = "(#{find_scope}) AND (#{klass.table_name}.site_id = #{visitor.site[:id]})" |
|---|
| 627 |
elsif !opts[:site_id_clause_set] |
|---|
| 628 |
find_scope = "#{klass.table_name}.site_id = #{visitor.site[:id]}" |
|---|
| 629 |
end |
|---|
| 630 |
scope[:find] = { :conditions => find_scope } |
|---|
| 631 |
elsif klass.ancestors.include?(Site) |
|---|
| 632 |
|
|---|
| 633 |
scope[:find] ||= {} |
|---|
| 634 |
ptbl = Participation.table_name |
|---|
| 635 |
scope[:find][:joins] = "INNER JOIN #{ptbl} ON #{klass.table_name}.id = #{ptbl}.site_id AND #{ptbl}.user_id = #{visitor[:id]} AND #{ptbl}.status = #{User::Status[:admin]}" |
|---|
| 636 |
scope[:find][:readonly] = false |
|---|
| 637 |
scope[:find][:select] = "#{Site.table_name}.*" |
|---|
| 638 |
scope[:find][:conditions] = find_scope |
|---|
| 639 |
end |
|---|
| 640 |
|
|---|
| 641 |
result = klass.with_scope( scope ) { yield } |
|---|
| 642 |
|
|---|
| 643 |
klass.send(:scoped_methods).unshift last_scope if last_scope |
|---|
| 644 |
|
|---|
| 645 |
secure_result(klass,result) |
|---|
| 646 |
end |
|---|
| 647 |
|
|---|
| 648 |
def secure_result(klass,result) |
|---|
| 649 |
if result && result != [] |
|---|
| 650 |
if klass.ancestors.include?(Node) |
|---|
| 651 |
if result.kind_of? Array |
|---|
| 652 |
result.each {|r| visitor.visit(r) } |
|---|
| 653 |
else |
|---|
| 654 |
visitor.visit(result) |
|---|
| 655 |
end |
|---|
| 656 |
end |
|---|
| 657 |
result |
|---|
| 658 |
else |
|---|
| 659 |
nil |
|---|
| 660 |
end |
|---|
| 661 |
end |
|---|
| 662 |
|
|---|
| 663 |
|
|---|
| 664 |
|
|---|
| 665 |
|
|---|
| 666 |
|
|---|
| 667 |
|
|---|
| 668 |
|
|---|
| 669 |
|
|---|
| 670 |
def secure(klass, opts={}, &block) |
|---|
| 671 |
if opts[:secure] == false |
|---|
| 672 |
yield |
|---|
| 673 |
elsif klass.ancestors.include?(Zena::Acts::SecureNode::InstanceMethods) && !visitor.is_su? |
|---|
| 674 |
secure_with_scope(klass, secure_scope(klass.table_name), :site_id_clause_set => true, &block) |
|---|
| 675 |
else |
|---|
| 676 |
secure_with_scope(klass, nil, &block) |
|---|
| 677 |
end |
|---|
| 678 |
rescue ActiveRecord::RecordNotFound |
|---|
| 679 |
|
|---|
| 680 |
|
|---|
| 681 |
nil |
|---|
| 682 |
end |
|---|
| 683 |
|
|---|
| 684 |
def secure!(klass, opts={}, &block) |
|---|
| 685 |
unless res = secure(klass, opts={}, &block) |
|---|
| 686 |
raise ActiveRecord::RecordNotFound |
|---|
| 687 |
end |
|---|
| 688 |
res |
|---|
| 689 |
end |
|---|
| 690 |
|
|---|
| 691 |
|
|---|
| 692 |
def secure_scope(table_name) |
|---|
| 693 |
if visitor.is_su? |
|---|
| 694 |
"#{table_name}.site_id = #{visitor.site.id}" |
|---|
| 695 |
else |
|---|
| 696 |
|
|---|
| 697 |
"#{table_name}.site_id = #{visitor.site.id} AND (#{table_name}.user_id = '#{visitor[:id]}' OR "+ |
|---|
| 698 |
|
|---|
| 699 |
"(#{table_name}.rgroup_id IN (#{visitor.group_ids.join(',')}) AND #{table_name}.publish_from <= now() ) OR " + |
|---|
| 700 |
|
|---|
| 701 |
"(#{table_name}.pgroup_id IN (#{visitor.group_ids.join(',')}) AND #{table_name}.max_status <> #{Zena::Status[:red]}))" |
|---|
| 702 |
end |
|---|
| 703 |
end |
|---|
| 704 |
|
|---|
| 705 |
|
|---|
| 706 |
|
|---|
| 707 |
|
|---|
|
|---|