diff --git a/app/services/versioned_files_service/versions_manifest.rb b/app/services/versioned_files_service/versions_manifest.rb index a9425827..8834e40a 100644 --- a/app/services/versioned_files_service/versions_manifest.rb +++ b/app/services/versioned_files_service/versions_manifest.rb @@ -30,6 +30,7 @@ def update_version(version:, version_metadata:) manifest[:versions][version] = version_metadata.as_json update_head_version if !version_metadata.withdrawn? && (head_version.nil? || version >= head_version) + backfill_withdrawn_versions write! end @@ -81,7 +82,8 @@ def version_metadata_for(version:) check_version(version:) version_data = manifest[:versions][version] - VersionMetadata.new(version: version.to_i, withdrawn: version_data[:withdrawn], date: DateTime.iso8601(version_data[:date])) + date = version_data[:date].present? ? DateTime.iso8601(version_data[:date]) : nil + VersionMetadata.new(version: version.to_i, withdrawn: version_data[:withdrawn], date:) end def version_metadata @@ -110,6 +112,7 @@ def manifest attr_reader :path def write! + manifest[:versions] = manifest[:versions].sort.to_h if manifest.key?(:versions) FileUtils.mkdir_p(path.dirname) path.write(manifest.to_json) end @@ -117,5 +120,15 @@ def write! def check_version(version:) raise UnknownVersionError, "Version #{version} not found" unless version?(version:) end + + def backfill_withdrawn_versions + return unless head_version + + (1..head_version).each do |version| + next if version?(version:) + + manifest[:versions][version] = { withdrawn: true, date: nil } + end + end end end diff --git a/spec/services/versioned_files_service/versions_manifest_spec.rb b/spec/services/versioned_files_service/versions_manifest_spec.rb new file mode 100644 index 00000000..636d7c30 --- /dev/null +++ b/spec/services/versioned_files_service/versions_manifest_spec.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe VersionedFilesService::VersionsManifest do + subject(:manifest) { described_class.new(path: pathname) } + + let(:pathname) { Pathname.new('tmp/versions_manifest.json') } + + after do + pathname.delete if pathname.exist? + end + + describe '.update_version' do + context 'when backfilling withdrawn versions' do + let(:now) { DateTime.now } + + let(:expected_manifest) do + { + "$schemaVersion" => 1, + 'head' => 3, + 'versions' => { + '1' => { 'withdrawn' => true, 'date' => nil }, + '2' => { 'withdrawn' => true, 'date' => nil }, + '3' => { 'withdrawn' => false, 'date' => now.iso8601 } + } + } + end + + it 'backfills withdrawn versions' do + manifest.update_version(version: 3, version_metadata: described_class::VersionMetadata.new(3, false, now)) + + expect(JSON.parse(pathname.read)).to eq expected_manifest + end + end + end +end