From 06a1bfc17ad3326f3a9f8002688ec0c9a97cbaab Mon Sep 17 00:00:00 2001 From: Justin Coyne Date: Tue, 24 Jan 2017 15:12:59 -0600 Subject: [PATCH] Clear cache when removing permissions Prevents `object.permissions` from returning rows that have been destroyed. Ref https://github.com/projecthydra/sufia/issues/3033 Ref https://github.com/projecthydra/sufia/issues/2820 --- .../concerns/hydra/access_controls/permissions.rb | 4 ++-- .../app/models/hydra/access_control.rb | 14 +++++++++++++- .../spec/unit/permissions_spec.rb | 3 ++- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/hydra-access-controls/app/models/concerns/hydra/access_controls/permissions.rb b/hydra-access-controls/app/models/concerns/hydra/access_controls/permissions.rb index aba23bb67..3c2711ff8 100644 --- a/hydra-access-controls/app/models/concerns/hydra/access_controls/permissions.rb +++ b/hydra-access-controls/app/models/concerns/hydra/access_controls/permissions.rb @@ -415,10 +415,10 @@ def search_by_type_and_mode(type, mode) # @param [RDF::URI] mode One of the permissions modes, e.g. ACL.Write, ACL.Read, etc. # @yieldparam [Array] agent the agent type assertions - # @return [Array] list of permissions where the mode is as selected, the block evaluates to true and the target is not marked for delete + # @return [Array] list of permissions where the mode is as selected, the block evaluates to true def search_by_mode(mode) permissions.to_a.select do |p| - yield(p.agent) && !p.marked_for_destruction? && p.mode.first.rdf_subject == mode + yield(p.agent) && p.mode.first.rdf_subject == mode end end diff --git a/hydra-access-controls/app/models/hydra/access_control.rb b/hydra-access-controls/app/models/hydra/access_control.rb index c5127493a..a384c4233 100644 --- a/hydra-access-controls/app/models/hydra/access_control.rb +++ b/hydra-access-controls/app/models/hydra/access_control.rb @@ -20,11 +20,13 @@ def permissions=(records) def permissions_attributes=(attribute_list) raise ArgumentError unless attribute_list.is_a? Array + any_destroyed = false attribute_list.each do |attributes| if attributes.key?(:id) obj = relationship.find(attributes[:id]) if has_destroy_flag?(attributes) obj.destroy + any_destroyed = true else obj.update(attributes.except(:id, '_destroy')) end @@ -32,18 +34,28 @@ def permissions_attributes=(attribute_list) relationship.create(attributes) end end + # Poison the cache + relationship.reset if any_destroyed end def relationship @relationship ||= CollectionRelationship.new(self, :contains) end + # This is like a has_many :through relationship class CollectionRelationship def initialize(owner, reflection) @owner = owner @relationship = @owner.send(reflection) end + # The graph stored in @owner is now stale, so reload it and clear all caches + def reset + @owner.reload + @relationship.proxy_association.reload + self + end + delegate :to_a, :to_ary, :map, :delete, :first, :last, :size, :count, :[], :==, :detect, :empty?, :each, :any?, :all?, :include?, :destroy_all, to: :@relationship @@ -52,7 +64,7 @@ def initialize(owner, reflection) # delegate find. def find(id) return to_a.find { |record| record.id == id } if @relationship.loaded? - + unless id.start_with?(@owner.id) raise ArgumentError, "requested ACL (#{id}) is not a member of #{@owner.id}" end diff --git a/hydra-access-controls/spec/unit/permissions_spec.rb b/hydra-access-controls/spec/unit/permissions_spec.rb index 61ca9922a..15b1e2c48 100644 --- a/hydra-access-controls/spec/unit/permissions_spec.rb +++ b/hydra-access-controls/spec/unit/permissions_spec.rb @@ -134,6 +134,7 @@ class Foo < ActiveFedora::Base it "removes permissions on existing users" do indexed_result = ActiveFedora::SolrService.query("id:#{subject.id}").first['edit_access_person_ssim'] expect(indexed_result).to eq ['jcoyne'] + expect(subject.permissions.map(&:to_hash)).to eq [{ name: "jcoyne", type: "person", access: "edit" }] expect(reloaded).to eq [{ name: "jcoyne", type: "person", access: "edit" }] end end @@ -188,7 +189,7 @@ class Foo < ActiveFedora::Base subject.update permissions_attributes: [ { id: permissions_id, type: "group", access: "read", name: "group1", _destroy: '1' }, { type: "group", access: "edit", name: "group2" }, - { type: "person", access: "read", name: "joebob" } + { type: "person", access: "read", name: "joebob" } ] end