Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Always use a versioned layout if the feature flag is set. #870

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 1 addition & 8 deletions app/controllers/v1/resources_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class ResourcesController < ApplicationController
def create
PurlCocinaUpdater.new(@purl, @cocina_object).update

PurlAndStacksService.update(purl: @purl, cocina_object: @cocina_object, file_uploads:, version:, version_date:, must_version:)
PurlAndStacksService.update(purl: @purl, cocina_object: @cocina_object, file_uploads:, version:, version_date:)

render json: true, location: @purl, status: :created
end
Expand Down Expand Up @@ -68,12 +68,5 @@ def version
# TODO: Once DSA is providing the version, || '1' can be removed.
version || '1'
end

def must_version
# This allows DSA to indicate that the object must be in the versioned layout.
# TODO: This is a temporary parameter until migration is complete.
# It is necessary so that DSA that a previously unversioned object now has versions.
params.require(:resource)[:must_version] || false
end
end
end
42 changes: 9 additions & 33 deletions app/services/purl_and_stacks_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ def self.delete(purl:, version:)
new(purl:).delete(version:)
end

def self.update(purl:, cocina_object:, file_uploads:, version:, version_date:, must_version:) # rubocop:disable Metrics/ParameterLists
new(purl:).update(cocina_object:, file_uploads:, version:, version_date:, must_version:)
def self.update(purl:, cocina_object:, file_uploads:, version:, version_date:)
new(purl:).update(cocina_object:, file_uploads:, version:, version_date:)
end

# @param purl [Purl] the PURL model object.
Expand All @@ -18,20 +18,18 @@ def initialize(purl:)
# @param file_uploads [Hash<String,String>] map of cocina filenames to staging filenames (UUIDs)
# @param version [String] the version number
# @param version_date [DateTime] the version date
# @param must_version [Boolean] true if the versioned layout is required
def update(cocina_object:, file_uploads:, version:, version_date:, must_version:)
def update(cocina_object:, file_uploads:, version:, version_date:)
version_metadata = VersionedFilesService::VersionMetadata.new(withdrawn: false, date: version_date)
VersionedFilesService.new(druid:).migrate(version_metadata:) if migrate_to_versioned_layout?(must_version)
VersionedFilesService.new(druid:).migrate(version_metadata:) if versioned_files_enabled? && !(new_object? || already_versioned_layout?)

if use_versioned_layout?
if versioned_files_enabled?
VersionedFilesService.new(druid:).update(version:,
version_metadata:,
cocina: cocina_object,
public_xml: PublicXmlWriter.generate(cocina_object),
file_transfers: file_uploads)
# Writes to purl. In the future when PURL Application can handle versioned layout, this will be removed.
UpdatePurlMetadataService.new(purl).write! if legacy_purl_enabled?

else
# Writes to stacks with unversioned layout.
UpdateStacksFilesService.write!(cocina_object, file_uploads) unless cocina_object.collection?
Expand Down Expand Up @@ -71,33 +69,11 @@ def legacy_purl_enabled?
Settings.features.legacy_purl
end

def use_versioned_layout?
return false unless versioned_files_enabled?

# Use versioned layout (1) if the object is already using the versioned layout; (2) if the object is new; or
# (3) if the object is using the unversioned layout, but DSA indicates that the object is versioned.
# 3 may be the case for existing H2 objects, as they were previously unversioned but versions are being added.

# TODO: Support DSA indicating if an object is versioned.

# Is it already in versioned layout?
return true if already_versioned_layout?
# Does the object already exist and is versioned?
# The presence of the Stacks object directory indicates that it is versioned.
# For example, /stacks/bc/123/df/4567/bc123df4567 indicates that versioned layout is being used.
# /stacks/bc/123/df/4567 but NOT bc123df4567 indicates that unversioned layout is being used.
return true unless DruidTools::PurlDruid.new(druid, Settings.filesystems.stacks_root).pathname.exist?

false
end

def migrate_to_versioned_layout?(must_version)
return false unless versioned_files_enabled?

!already_versioned_layout? && must_version
end

def already_versioned_layout?
VersionedFilesService.versioned_files?(druid:)
end

def new_object?
!DruidTools::PurlDruid.new(druid, Settings.filesystems.stacks_root).pathname.exist?
end
end
28 changes: 3 additions & 25 deletions spec/requests/v1/publish_dro_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,11 @@
{
object: dro.to_h,
file_uploads:,
must_version:,
version:,
version_date: version_date.iso8601
}.to_json
end
let(:file_uploads) { { 'file2.txt' => 'd7e54aed-c0c4-48af-af93-bc673f079f9a', 'files/file2.txt' => '7f807e3c-4cde-4b6d-8e76-f24455316a01' } }
let(:must_version) { false }
let(:version) { '1' }
let(:version_date) { DateTime.now }

Expand Down Expand Up @@ -108,29 +106,7 @@
# rubocop:enable RSpec/ExpectActual
end

context 'when versioned files is enabled and object already exists' do
before do
allow(Settings.features).to receive(:versioned_files).and_return(true)
FileUtils.mkdir_p('tmp/stacks/bc/123/df/4567')
end

it 'creates the resource in unversioned layout' do
post '/v1/resources',
params: request,
headers: { 'Content-Type' => 'application/json', 'Authorization' => "Bearer #{jwt}" }
expect(response).to be_created
expect(File).to exist('tmp/purl_doc_cache/bc/123/df/4567/cocina.json')
expect(File).to exist('tmp/purl_doc_cache/bc/123/df/4567/public')
expect(File).to exist('tmp/stacks/bc/123/df/4567/file2.txt')
expect(File).to exist('tmp/stacks/bc/123/df/4567/files/file2.txt')
expect(File).not_to be_symlink('tmp/stacks/bc/123/df/4567/file2.txt')
expect(File).not_to be_symlink('tmp/stacks/bc/123/df/4567/files/file2.txt')
end
end

context 'when version files is enabled and must_version is true' do
let(:must_version) { true }

context 'when version files is enabled' do
let(:versioned_files_service) { instance_double(VersionedFilesService, migrate: true, update: true) }

let(:version_metadata) { VersionedFilesService::VersionMetadata.new(withdrawn: false, date: version_date) }
Expand All @@ -142,6 +118,8 @@
end

it 'performs a migration before updating the resource' do
FileUtils.mkdir_p('tmp/stacks/bc/123/df/4567')

post '/v1/resources',
params: request,
headers: { 'Content-Type' => 'application/json', 'Authorization' => "Bearer #{jwt}" }
Expand Down