validate :permission_to_attach_to_objects
before_update :restrict_alter_permissions
before_update :apply_max_overlapping_permissions
+ before_create :apply_max_overlapping_permissions
after_update :delete_overlapping_permissions
- after_update :call_update_permissions
- after_create :call_update_permissions
+ after_update :call_update_permissions, :if => Proc.new { @need_update_permissions }
+ after_create :call_update_permissions, :if => Proc.new { @need_update_permissions }
before_destroy :clear_permissions
after_destroy :delete_overlapping_permissions
after_destroy :check_permissions
+ before_save :check_need_update_permissions
api_accessible :user, extend: :common do |t|
t.add :tail_uuid
def apply_max_overlapping_permissions
return if self.link_class != 'permission' || !PermLevel[self.name]
- Link.where(link_class: 'permission',
- tail_uuid: self.tail_uuid,
- head_uuid: self.head_uuid,
- name: PermLevel.keys).
+ Link.
+ lock. # select ... for update
+ where(link_class: 'permission',
+ tail_uuid: self.tail_uuid,
+ head_uuid: self.head_uuid,
+ name: PermLevel.keys).
where('uuid <> ?', self.uuid).each do |other|
if PermLevel[other.name] > PermLevel[self.name]
self.name = other.name
def delete_overlapping_permissions
return if self.link_class != 'permission'
+ redundant = nil
if PermLevel[self.name]
- Link.where(link_class: 'permission',
- tail_uuid: self.tail_uuid,
- head_uuid: self.head_uuid,
- name: PermLevel.keys).
- where('uuid <> ?', self.uuid).
- delete_all
+ redundant = Link.
+ lock. # select ... for update
+ where(link_class: 'permission',
+ tail_uuid: self.tail_uuid,
+ head_uuid: self.head_uuid,
+ name: PermLevel.keys).
+ where('uuid <> ?', self.uuid)
elsif self.name == 'can_login' &&
self.properties.respond_to?(:has_key?) &&
self.properties.has_key?('username')
- Link.where(link_class: 'permission',
- tail_uuid: self.tail_uuid,
- head_uuid: self.head_uuid,
- name: 'can_login').
- where('properties @> ?', SafeJSON.dump({'username' => self.properties['username']})).
- where('uuid <> ?', self.uuid).
- delete_all
+ redundant = Link.
+ lock. # select ... for update
+ where(link_class: 'permission',
+ tail_uuid: self.tail_uuid,
+ head_uuid: self.head_uuid,
+ name: 'can_login').
+ where('properties @> ?', SafeJSON.dump({'username' => self.properties['username']})).
+ where('uuid <> ?', self.uuid)
+ end
+ if redundant
+ redundant.each do |link|
+ link.clear_permissions
+ end
+ redundant.delete_all
end
end
'can_manage' => 3,
}
+ def check_need_update_permissions
+ @need_update_permissions = self.link_class == 'permission' && (name != name_was || new_record?)
+ end
+
def call_update_permissions
- if self.link_class == 'permission'
update_permissions tail_uuid, head_uuid, PERM_LEVEL[name], self.uuid
current_user.forget_cached_group_perms
- end
end
def clear_permissions