Skip to content

Commit

Permalink
Merge pull request #6183 from avalonmediasystem/read_only
Browse files Browse the repository at this point in the history
Repository read only mode
  • Loading branch information
cjcolvar authored Feb 5, 2025
2 parents 898e85d + 59dc021 commit d182acb
Show file tree
Hide file tree
Showing 5 changed files with 230 additions and 3 deletions.
14 changes: 12 additions & 2 deletions app/models/ability.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ class Ability
:marker_permissions,
:encode_dashboard_permissions,
:timeline_permissions,
:checkout_permissions]
:checkout_permissions,
:repository_read_only_permissions]

# Override to add handling of SpeedyAF proxy objects
def edit_permissions
Expand Down Expand Up @@ -260,6 +261,16 @@ def checkout_permissions
end
end

def repository_read_only_permissions
if Settings.repository_read_only_mode
cannot [:create, :edit, :update, :destroy, :update_access_control, :unpublish], [MediaObject, SpeedyAF::Proxy::MediaObject]
cannot [:create, :edit, :update, :destroy], [MasterFile, SpeedyAF::Proxy::MasterFile]
cannot [:create, :edit, :update, :destroy], [Derivative, SpeedyAF::Proxy::Derivative]
cannot [:create, :edit, :update, :destroy, :update_unit, :update_access_control, :update_managers, :update_editors, :update_depositors], [Admin::Collection, SpeedyAF::Proxy::Admin::Collection]
cannot [:create, :edit, :update, :destroy], SpeedyAF::Base
end
end

def is_administrator?
@user_groups.include?("administrator")
end
Expand Down Expand Up @@ -289,5 +300,4 @@ def is_api_request?
@json_api_login ||= false
@json_api_login
end

end
6 changes: 6 additions & 0 deletions config/initializers/active_fedora_general.rb
Original file line number Diff line number Diff line change
Expand Up @@ -209,3 +209,9 @@ def initialize(file)
get_values(:type) << self.class.type
end
end

ActiveFedora::Common.module_eval do
def readonly?
@readonly || Settings.repository_read_only_mode
end
end
7 changes: 6 additions & 1 deletion config/settings.yml
Original file line number Diff line number Diff line change
Expand Up @@ -129,4 +129,9 @@ derivative:
# If the default system /tmp directory is storage constrained, you can define an alternative here.
# Leave commented out to use the system default.
# tempfile:
# location: '/tmp'
# location: '/tmp'

# Enable read-only mode for disabling all save interactions with fedora and solr
# Does not affect actions that only affect the database
# This is useful when running long migrations
repository_read_only_mode: false
41 changes: 41 additions & 0 deletions spec/lib/active_fedora_base.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Copyright 2011-2024, The Trustees of Indiana University and Northwestern
# University. Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
#
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software distributed
# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
# CONDITIONS OF ANY KIND, either express or implied. See the License for the
# specific language governing permissions and limitations under the License.
# --- END LICENSE_HEADER BLOCK ---

require 'rails_helper'

describe 'ActiveFedora::Base' do
let(:new_obj) { ActiveFedora::Base.new }
let(:obj) { ActiveFedora::Base.create }

# This tests changes overrides that are in config/initializers/active_fedora_general.rb
context 'when read-only mode' do
before { allow(Settings).to receive(:repository_read_only_mode).and_return(true) }

it 'raises ReadOnlyRecord for any write operation' do
expect { ActiveFedora::Base.create }.to raise_error ActiveFedora::ReadOnlyRecord
expect { new_obj.save }.to raise_error ActiveFedora::ReadOnlyRecord
expect { new_obj.save! }.to raise_error ActiveFedora::ReadOnlyRecord
expect { obj.save }.to raise_error ActiveFedora::ReadOnlyRecord
expect { obj.save! }.to raise_error ActiveFedora::ReadOnlyRecord
expect { obj.update }.to raise_error ActiveFedora::ReadOnlyRecord
expect { obj.update! }.to raise_error ActiveFedora::ReadOnlyRecord
expect { obj.delete }.to raise_error ActiveFedora::ReadOnlyRecord
expect { obj.destroy }.to raise_error ActiveFedora::ReadOnlyRecord
expect { obj.destroy! }.to raise_error ActiveFedora::ReadOnlyRecord
expect { obj.eradicate }.to raise_error ActiveFedora::ReadOnlyRecord
expect { ActiveFedora::Base.eradicate(obj.to_uri) }.to raise_error ActiveFedora::ReadOnlyRecord
expect { ActiveFedora::Base.delete_tombstone(obj.to_uri) }.to raise_error ActiveFedora::ReadOnlyRecord
end
end
end
165 changes: 165 additions & 0 deletions spec/models/ability_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,169 @@
expect(Ability.new(nil).user_groups).to eq ["public"]
end
end

describe 'repository read-only mode' do
# Next line is let! to ensure that it runs before the before block which would stop the object from being created
let!(:media_object) { FactoryBot.create(:media_object) }
let(:media_object_proxy) { SpeedyAF::Base.find(media_object.id) }
let(:collection) { media_object.collection }
let(:collection_proxy) { SpeedyAF::Base.find(collection.id) }
let(:admin) { FactoryBot.create(:administrator) }
let(:session) { {} }
subject(:admin_ability) { Ability.new(admin, session) }

before { allow(Settings).to receive(:repository_read_only_mode).and_return(read_only) }

context 'with read-only enabled' do
let(:read_only) { true }

it 'has read-only abilities' do
expect(subject.can?(:manage, :all)).to eq true
expect(subject.can?(:manage, MediaObject)).to eq true
expect(subject.can?(:discover_everything, MediaObject)).to eq true

expect(subject.can?(:read, media_object)).to eq true
expect(subject.can?(:read, media_object_proxy)).to eq true
expect(subject.can?(:read, collection)).to eq true
expect(subject.can?(:read, collection_proxy)).to eq true

expect(subject.can?(:create, MediaObject)).to eq false
expect(subject.can?(:read, MediaObject)).to eq true
expect(subject.can?(:edit, MediaObject)).to eq false
expect(subject.can?(:update, MediaObject)).to eq false
expect(subject.can?(:destroy, MediaObject)).to eq false
expect(subject.can?(:update_access_control, MediaObject)).to eq false
expect(subject.can?(:unpublish, MediaObject)).to eq false

expect(subject.can?(:create, SpeedyAF::Proxy::MediaObject)).to eq false
expect(subject.can?(:read, SpeedyAF::Proxy::MediaObject)).to eq true
expect(subject.can?(:edit, SpeedyAF::Proxy::MediaObject)).to eq false
expect(subject.can?(:update, SpeedyAF::Proxy::MediaObject)).to eq false
expect(subject.can?(:destroy, SpeedyAF::Proxy::MediaObject)).to eq false
expect(subject.can?(:update_access_control, SpeedyAF::Proxy::MediaObject)).to eq false
expect(subject.can?(:unpublish, SpeedyAF::Proxy::MediaObject)).to eq false

expect(subject.can?(:create, MasterFile)).to eq false
expect(subject.can?(:read, MasterFile)).to eq true
expect(subject.can?(:edit, MasterFile)).to eq false
expect(subject.can?(:update, MasterFile)).to eq false
expect(subject.can?(:destroy, MasterFile)).to eq false

expect(subject.can?(:create, SpeedyAF::Proxy::MasterFile)).to eq false
expect(subject.can?(:read, SpeedyAF::Proxy::MasterFile)).to eq true
expect(subject.can?(:edit, SpeedyAF::Proxy::MasterFile)).to eq false
expect(subject.can?(:update, SpeedyAF::Proxy::MasterFile)).to eq false
expect(subject.can?(:destroy, SpeedyAF::Proxy::MasterFile)).to eq false

expect(subject.can?(:create, Derivative)).to eq false
expect(subject.can?(:read, Derivative)).to eq true
expect(subject.can?(:edit, Derivative)).to eq false
expect(subject.can?(:update, Derivative)).to eq false
expect(subject.can?(:destroy, Derivative)).to eq false

expect(subject.can?(:create, SpeedyAF::Proxy::Derivative)).to eq false
expect(subject.can?(:read, SpeedyAF::Proxy::Derivative)).to eq true
expect(subject.can?(:edit, SpeedyAF::Proxy::Derivative)).to eq false
expect(subject.can?(:update, SpeedyAF::Proxy::Derivative)).to eq false
expect(subject.can?(:destroy, SpeedyAF::Proxy::Derivative)).to eq false

expect(subject.can?(:create, Admin::Collection)).to eq false
expect(subject.can?(:read, Admin::Collection)).to eq true
expect(subject.can?(:edit, Admin::Collection)).to eq false
expect(subject.can?(:update, Admin::Collection)).to eq false
expect(subject.can?(:destroy, Admin::Collection)).to eq false
expect(subject.can?(:update_unit, Admin::Collection)).to eq false
expect(subject.can?(:update_access_control, Admin::Collection)).to eq false
expect(subject.can?(:update_managers, Admin::Collection)).to eq false
expect(subject.can?(:update_editors, Admin::Collection)).to eq false
expect(subject.can?(:update_depositors, Admin::Collection)).to eq false

expect(subject.can?(:create, SpeedyAF::Proxy::Admin::Collection)).to eq false
expect(subject.can?(:read, SpeedyAF::Proxy::Admin::Collection)).to eq true
expect(subject.can?(:edit, SpeedyAF::Proxy::Admin::Collection)).to eq false
expect(subject.can?(:update, SpeedyAF::Proxy::Admin::Collection)).to eq false
expect(subject.can?(:destroy, SpeedyAF::Proxy::Admin::Collection)).to eq false
expect(subject.can?(:update_unit, SpeedyAF::Proxy::Admin::Collection)).to eq false
expect(subject.can?(:update_access_control, SpeedyAF::Proxy::Admin::Collection)).to eq false
expect(subject.can?(:update_managers, SpeedyAF::Proxy::Admin::Collection)).to eq false
expect(subject.can?(:update_editors, SpeedyAF::Proxy::Admin::Collection)).to eq false
expect(subject.can?(:update_depositors, SpeedyAF::Proxy::Admin::Collection)).to eq false
end
end

context 'with read-only disabled' do
let(:read_only) { false }

it 'has all abilities' do
expect(subject.can?(:manage, :all)).to eq true
expect(subject.can?(:manage, MediaObject)).to eq true
expect(subject.can?(:discover_everything, MediaObject)).to eq true

expect(subject.can?(:read, media_object)).to eq true
expect(subject.can?(:read, collection)).to eq true

expect(subject.can?(:create, MediaObject)).to eq true
expect(subject.can?(:read, MediaObject)).to eq true
expect(subject.can?(:edit, MediaObject)).to eq true
expect(subject.can?(:update, MediaObject)).to eq true
expect(subject.can?(:destroy, MediaObject)).to eq true
expect(subject.can?(:update_access_control, MediaObject)).to eq true
expect(subject.can?(:unpublish, MediaObject)).to eq true

expect(subject.can?(:create, SpeedyAF::Proxy::MediaObject)).to eq true
expect(subject.can?(:read, SpeedyAF::Proxy::MediaObject)).to eq true
expect(subject.can?(:edit, SpeedyAF::Proxy::MediaObject)).to eq true
expect(subject.can?(:update, SpeedyAF::Proxy::MediaObject)).to eq true
expect(subject.can?(:destroy, SpeedyAF::Proxy::MediaObject)).to eq true
expect(subject.can?(:update_access_control, SpeedyAF::Proxy::MediaObject)).to eq true
expect(subject.can?(:unpublish, SpeedyAF::Proxy::MediaObject)).to eq true

expect(subject.can?(:create, MasterFile)).to eq true
expect(subject.can?(:read, MasterFile)).to eq true
expect(subject.can?(:edit, MasterFile)).to eq true
expect(subject.can?(:update, MasterFile)).to eq true
expect(subject.can?(:destroy, MasterFile)).to eq true

expect(subject.can?(:create, SpeedyAF::Proxy::MasterFile)).to eq true
expect(subject.can?(:read, SpeedyAF::Proxy::MasterFile)).to eq true
expect(subject.can?(:edit, SpeedyAF::Proxy::MasterFile)).to eq true
expect(subject.can?(:update, SpeedyAF::Proxy::MasterFile)).to eq true
expect(subject.can?(:destroy, SpeedyAF::Proxy::MasterFile)).to eq true

expect(subject.can?(:create, Derivative)).to eq true
expect(subject.can?(:read, Derivative)).to eq true
expect(subject.can?(:edit, Derivative)).to eq true
expect(subject.can?(:update, Derivative)).to eq true
expect(subject.can?(:destroy, Derivative)).to eq true

expect(subject.can?(:create, SpeedyAF::Proxy::Derivative)).to eq true
expect(subject.can?(:read, SpeedyAF::Proxy::Derivative)).to eq true
expect(subject.can?(:edit, SpeedyAF::Proxy::Derivative)).to eq true
expect(subject.can?(:update, SpeedyAF::Proxy::Derivative)).to eq true
expect(subject.can?(:destroy, SpeedyAF::Proxy::Derivative)).to eq true

expect(subject.can?(:create, Admin::Collection)).to eq true
expect(subject.can?(:read, Admin::Collection)).to eq true
expect(subject.can?(:edit, Admin::Collection)).to eq true
expect(subject.can?(:update, Admin::Collection)).to eq true
expect(subject.can?(:destroy, Admin::Collection)).to eq true
expect(subject.can?(:update_unit, Admin::Collection)).to eq true
expect(subject.can?(:update_access_control, Admin::Collection)).to eq true
expect(subject.can?(:update_managers, Admin::Collection)).to eq true
expect(subject.can?(:update_editors, Admin::Collection)).to eq true
expect(subject.can?(:update_depositors, Admin::Collection)).to eq true

expect(subject.can?(:create, SpeedyAF::Proxy::Admin::Collection)).to eq true
expect(subject.can?(:read, SpeedyAF::Proxy::Admin::Collection)).to eq true
expect(subject.can?(:edit, SpeedyAF::Proxy::Admin::Collection)).to eq true
expect(subject.can?(:update, SpeedyAF::Proxy::Admin::Collection)).to eq true
expect(subject.can?(:destroy, SpeedyAF::Proxy::Admin::Collection)).to eq true
expect(subject.can?(:update_unit, SpeedyAF::Proxy::Admin::Collection)).to eq true
expect(subject.can?(:update_access_control, SpeedyAF::Proxy::Admin::Collection)).to eq true
expect(subject.can?(:update_managers, SpeedyAF::Proxy::Admin::Collection)).to eq true
expect(subject.can?(:update_editors, SpeedyAF::Proxy::Admin::Collection)).to eq true
expect(subject.can?(:update_depositors, SpeedyAF::Proxy::Admin::Collection)).to eq true
end
end
end
end

0 comments on commit d182acb

Please sign in to comment.