diff --git a/.rubocop.yml b/.rubocop.yml index 6adcedabc5..3ccb3f3142 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,3 +1,4 @@ + inherit_from: .rubocop_todo.yml require: @@ -14,6 +15,9 @@ AllCops: Rails: Enabled: true +Lint/AssignmentInCondition: + Enabled: false + Lint/UnusedMethodArgument: AllowUnusedKeywordArguments: true diff --git a/app/controllers/metadata_controller.rb b/app/controllers/metadata_controller.rb index 3ebb80e3b3..e3f9ea0f2a 100644 --- a/app/controllers/metadata_controller.rb +++ b/app/controllers/metadata_controller.rb @@ -13,4 +13,24 @@ def descriptive service = PublicDescMetadataService.new(@item) render xml: service end + + # This supports the Legacy Fedora 3 data model. This is used by the accessionWF. + def update_legacy_metadata + datastream_names = { descriptive: 'descMetadata', + technical: 'technicalMetadata', + content: 'contentMetadata', + rights: 'rightsMetadata' } + + datastream_names.each do |section, datastream_name| + next unless values = params[section] + + update_datastream_if_newer(datastream: @item.datastreams[datastream_name], + updated: Time.zone.parse(values[:updated]), + content: values[:content]) + end + + @item.save! + end + + delegate :update_datastream_if_newer, to: LegacyMetadataService end diff --git a/app/services/legacy_metadata_service.rb b/app/services/legacy_metadata_service.rb new file mode 100644 index 0000000000..20e8aebbd2 --- /dev/null +++ b/app/services/legacy_metadata_service.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +# Operations on the legacy Fedora 3 metadata. +# This is used by the accessionWF +class LegacyMetadataService + # If the updated value is newer than then createDate of the datastream, then update it. + def self.update_datastream_if_newer(datastream:, updated:, content:) + datastream.content = content if !datastream.createDate || updated > datastream.createDate + return if !datastream.createDate || updated > datastream.createDate + + Honeybadger.notify("Found #{datasteam.pid}/#{datastream.dsid} that had a create " \ + "date (#{datastream.createDate}) after the file was modified (#{updated}). " \ + 'Doing an experiment to see if this ever happens.') + end +end diff --git a/config/routes.rb b/config/routes.rb index 415e989a7d..2c077f6e6e 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -56,6 +56,7 @@ resources :metadata, only: [] do collection do + patch 'legacy', action: :update_legacy_metadata get 'dublin_core' get 'descriptive' end diff --git a/openapi.json b/openapi.json index f4ac42bebc..286d1cb24d 100644 --- a/openapi.json +++ b/openapi.json @@ -787,6 +787,41 @@ ] } }, + "/objects/{object_id}/metadata/legacy": { + "post": { + "tags": [ + "objects" + ], + "summary": "Update the legacy (datastream) metadata for the object", + "description": "", + "operationId": "metadata#update_legacy_metadata", + "responses": { + "200": { + "description": "OK" + } + }, + "parameters": [ + { + "name": "object_id", + "in": "path", + "description": "ID of object", + "required": true, + "schema": { + "$ref": "#/components/schemas/Druid" + } + }, + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateLegacyMetadata" + } + } + } + } + } + }, "/objects/{object_id}/metadata/dublin_core": { "get": { "tags": [ @@ -1244,6 +1279,37 @@ } } } + }, + "UpdateLegacyMetadata": { + "properties": { + "descriptive": { + "$ref": "#/components/schemas/LegacyDatastream" + }, + "rights": { + "$ref": "#/components/schemas/LegacyDatastream" + }, + "content": { + "$ref": "#/components/schemas/LegacyDatastream" + }, + "technical": { + "$ref": "#/components/schemas/LegacyDatastream" + }, + } + }, + "LegacyDatastream": { + "properties": { + "updated": { + "type": "string", + "format": "date-time", + "description": "The date the xml was produced. This may be used to see if the server wants to accept this or if it already has a more recent version." + + }, + "content": { + "type": "string", + "description": "The XML datastream content", + "example": "..." + } + } } }, "securitySchemes": { diff --git a/spec/requests/legacy_metadata_update_spec.rb b/spec/requests/legacy_metadata_update_spec.rb new file mode 100644 index 0000000000..eef4ae4bfc --- /dev/null +++ b/spec/requests/legacy_metadata_update_spec.rb @@ -0,0 +1,62 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe 'Update the legacy (datastream) metadata' do + let(:work) { instance_double(Dor::Item, pid: 'druid:bc123df4567', datastreams: datastreams, save!: nil) } + let(:create_date) { Time.zone.parse('2019-08-09T19:18:15Z') } + let(:descMetadata) { instance_double(Dor::DescMetadataDS, createDate: create_date) } + let(:rightsMetadata) { instance_double(Dor::RightsMetadataDS, createDate: create_date) } + let(:technicalMetadata) { instance_double(Dor::TechnicalMetadataDS, createDate: create_date) } + let(:contentMetadata) { instance_double(Dor::ContentMetadataDS, createDate: create_date) } + + let(:datastreams) do + { + 'descMetadata' => descMetadata, + 'rightsMetadata' => rightsMetadata, + 'technicalMetadata' => technicalMetadata, + 'contentMetadata' => contentMetadata + } + end + + context 'when update is successful' do + before do + allow(Dor).to receive(:find).and_return(work) + allow(LegacyMetadataService).to receive(:update_datastream_if_newer) + end + + let(:data) do + <<~JSON + { + "descriptive": { + "updated": "2019-11-08T15:15:43Z", + "content": "" + }, + "rights": { + "updated": "2019-11-08T15:15:43Z", + "content": "" + } + } + JSON + end + + it 'updates the object datastreams' do + patch "/v1/objects/#{work.pid}/metadata/legacy", + params: data, + headers: { 'Authorization' => "Bearer #{jwt}", 'CONTENT_TYPE' => 'application/json' } + expect(response).to have_http_status(:no_content) + + expect(LegacyMetadataService).to have_received(:update_datastream_if_newer) + .with(datastream: descMetadata, + updated: Time.zone.parse('2019-11-08T15:15:43Z'), + content: '') + + expect(LegacyMetadataService).to have_received(:update_datastream_if_newer) + .with(datastream: rightsMetadata, + updated: Time.zone.parse('2019-11-08T15:15:43Z'), + content: '') + + expect(work).to have_received(:save!) + end + end +end diff --git a/spec/services/legacy_metadata_service_spec.rb b/spec/services/legacy_metadata_service_spec.rb new file mode 100644 index 0000000000..10dee27a64 --- /dev/null +++ b/spec/services/legacy_metadata_service_spec.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe LegacyMetadataService do + describe '.update_datastream_if_newer' do + subject(:update) { described_class.update_datastream_if_newer(datastream: datastream, updated: updated, content: content) } + + let(:updated) { Time.zone.parse('2019-08-09T19:18:15Z') } + let(:content) { '' } + let(:datastream) { instance_double(Dor::DescMetadataDS, createDate: create_date, :content= => nil) } + + context 'with a new datastream' do + let(:create_date) { nil } + + it 'updates the content' do + update + expect(datastream).to have_received(:content=).with(content) + end + end + + context 'with a datastream that is older than the content' do + let(:create_date) { Time.zone.parse('2019-07-09T19:18:15Z') } + + it 'updates the content' do + update + expect(datastream).to have_received(:content=).with(content) + end + end + end +end