Skip to content

Commit

Permalink
Override ActiveFedora and HydraAccessControls to ensure AccessControl…
Browse files Browse the repository at this point in the history
… objects are marked dirty and autosave so they get indexed properly
  • Loading branch information
cjcolvar committed Mar 31, 2023
1 parent 1367acb commit 406a0f6
Show file tree
Hide file tree
Showing 2 changed files with 98 additions and 0 deletions.
68 changes: 68 additions & 0 deletions config/initializers/active_fedora_general.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,71 @@ def content_disposition_filename
::RDF::URI.decode(filename) if filename
end
end

# Overrides that ensure AccessControl objects are marked dirty when read/edit/discover groups/users are changed and autosave if dirty
# This fixes a timing bug where AccessControl objects are saved in an after_save callback which runs after normal indexing occurs
# See https://github.com/avalonmediasystem/avalon/issues/5140

# Override contained_rdf_sources to ensure AccessControl objects get autosaved when dirty
ActiveFedora::Base.class_eval do
private
def _create_record(_options = {})
assign_rdf_subject
serialize_attached_files
@ldp_source = @ldp_source.create
assign_uri_to_contained_resources
save_contained_resources
save_access_control_resources
refresh
end

def _update_record(_options = {})
serialize_attached_files
execute_sparql_update
save_contained_resources
save_access_control_resources
refresh
end

def save_access_control_resources
access_control_sources.changed.each do |_, resource|
resource.save
end
end

def access_control_sources
@access_control_sources ||= ActiveFedora::AssociationHash.new(self, access_control_reflections)
end

def access_control_reflections
self.class.reflect_on_all_associations(:belongs_to).select { |_, reflection| reflection.klass <= Hydra::AccessControl }
end
end

# Enable dirty tracking for the permissions attribute
Rails.application.config.to_prepare do
Hydra::AccessControl.define_attribute_methods :permissions
end

# Override set_entities to notify ActiveModel::Dirty dirty tracking that the permissions attribute is changing
Hydra::AccessControls::Permissions.module_eval do
private
# @param [Symbol] permission either :discover, :read or :edit
# @param [Symbol] type either :person or :group
# @param [Array<String>] values Values to set
# @param [Array<String>] changeable Values we are allowed to change
def set_entities(permission, type, values, changeable)
(changeable - values).each do |entity|
for_destroy = search_by_type_and_mode(type, permission_to_uri(permission)).select { |p| p.agent_name == entity }
access_control.permissions_will_change!
permissions.delete(for_destroy)
end

values.each do |agent_name|
exists = search_by_type_and_mode(type, permission_to_uri(permission)).select { |p| p.agent_name == agent_name }
access_control.permissions_will_change!
permissions.build(name: agent_name, access: permission.to_s, type: type) unless exists.present?
end
end
end
# End of overrides for AccessControl dirty tracking and autosaving
30 changes: 30 additions & 0 deletions spec/models/media_object_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1062,4 +1062,34 @@
end
end
end

describe 'read_groups=' do
let(:solr_doc) { ActiveFedora::SolrService.query("id:#{media_object.id}").first }

context 'when creating a MediaObject' do
let(:media_object) { FactoryBot.build(:media_object) }

it 'saves and indexes' do
expect(media_object.read_groups).to be_empty
media_object.read_groups = ["ExternalGroup"]
expect(media_object.access_control).to be_changed
media_object.save
expect(media_object.reload.read_groups).to eq ["ExternalGroup"]
expect(solr_doc["read_access_group_ssim"]).to eq ["ExternalGroup"]
end
end

context 'when updating a MediaObject' do
let(:media_object) { FactoryBot.create(:media_object) }

it 'saves and indexes' do
expect(media_object.read_groups).to be_empty
media_object.read_groups = ["ExternalGroup"]
expect(media_object.access_control).to be_changed
media_object.save
expect(media_object.reload.read_groups).to eq ["ExternalGroup"]
expect(solr_doc["read_access_group_ssim"]).to eq ["ExternalGroup"]
end
end
end
end

0 comments on commit 406a0f6

Please sign in to comment.