From: Tom Clegg Date: Mon, 18 Mar 2013 19:50:22 +0000 (-0700) Subject: add helpers: current_group_permissions, groups_i_can(:read). refs #1415 X-Git-Tag: 1.1.0~3413 X-Git-Url: https://git.arvados.org/arvados.git/commitdiff_plain/cf70bb6f00f0ded0624bac59a909a1cf8602dbff?ds=inline add helpers: current_group_permissions, groups_i_can(:read). refs #1415 --- diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index df9ae84817..ba0c253ec6 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -1,7 +1,69 @@ module ApplicationHelper + ALL_PERMISSIONS = {read: true, write: true, manage: true} + def current_user controller.current_user end + def invalidate_permissions_cache + Rails.cache.delete_matched(/^groups_for_user_/) + end + + def current_groups + return {} unless current_user + Rails.cache.fetch "groups_for_user_#{current_user.uuid}" do + permissions_from = {} + todo = {current_user.uuid => true} + done = {} + while !todo.empty? + lookup_uuids = todo.keys + lookup_uuids.each do |uuid| done[uuid] = true end + todo = {} + Link.where('tail_uuid in (?) and link_class = ? and head_kind = ?', + lookup_uuids, + 'permission', + 'orvos#group').each do |link| + unless done.has_key? link.head_uuid + todo[link.head_uuid] = true + end + link_permissions = {} + case link.name + when 'can_read' + link_permissions = {read:true} + when 'can_write' + link_permissions = {read:true,write:true} + when 'can_manage' + link_permissions = ALL_PERMISSIONS + end + permissions_from[link.tail_uuid] ||= {} + permissions_from[link.tail_uuid][link.head_uuid] ||= {} + link_permissions.each do |k,v| + permissions_from[link.tail_uuid][link.head_uuid][k] ||= v + end + end + end + search_permissions(current_user.uuid, permissions_from) + end + end + + protected + + def search_permissions(start, graph, merged={}, upstream_mask=nil, upstream_path={}) + nextpaths = graph[start] + return merged if !nextpaths + return merged if upstream_path.has_key? start + upstream_path[start] = true + upstream_mask ||= ALL_PERMISSIONS + nextpaths.each do |head, mask| + merged[head] ||= {} + mask.each do |k,v| + merged[head][k] ||= v if upstream_mask[k] + end + search_permissions(head, graph, merged, upstream_mask.select { |k,v| v && merged[head][k] }, upstream_path) + end + upstream_path.delete start + merged + end + end diff --git a/app/models/link.rb b/app/models/link.rb index 153f6c223b..55aecdc7cc 100644 --- a/app/models/link.rb +++ b/app/models/link.rb @@ -5,6 +5,9 @@ class Link < OrvosModel serialize :properties, Hash before_create :permission_to_attach_to_objects before_update :permission_to_attach_to_objects + after_update :maybe_invalidate_permissions_cache + after_create :maybe_invalidate_permissions_cache + after_destroy :maybe_invalidate_permissions_cache attr_accessor :head attr_accessor :tail @@ -58,4 +61,16 @@ class Link < OrvosModel # Default = deny. false end + + def maybe_invalidate_permissions_cache + if self.link_class == 'permission' + # Clearing the entire permissions cache can generate many + # unnecessary queries if many active users are not affected by + # this change. In such cases it would be better to search cached + # permissions for head_uuid and tail_uuid, and invalidate the + # cache for only those users. (This would require a browseable + # cache.) + invalidate_permissions_cache + end + end end