Skip to content

Commit

Permalink
Adds rake tasks for creating new object versions and moving user vers…
Browse files Browse the repository at this point in the history
…ions.
  • Loading branch information
justinlittman committed Aug 20, 2024
1 parent 82604ad commit 57eea30
Show file tree
Hide file tree
Showing 5 changed files with 80 additions and 12 deletions.
8 changes: 5 additions & 3 deletions app/models/repository_object.rb
Original file line number Diff line number Diff line change
Expand Up @@ -90,12 +90,14 @@ def update_opened_version_from(cocina_object:)
reload # Syncs up head_version and opened_version
end

def open_version!(description:)
# @param [String] description for the version
# @param [RepositoryObjectVersion,nil] from_version existing version to base the new version on. If nil, then uses last_closed_version.
def open_version!(description:, from_version: nil)
raise VersionAlreadyOpened, "Cannot open new version because one is already open: #{head_version.version}" if open?

RepositoryObject.transaction do
new_version = last_closed_version.dup
new_version.update!(version: new_version.version + 1, version_description: description, closed_at: nil)
new_version = (from_version || last_closed_version).dup
new_version.update!(version: last_closed_version.version + 1, version_description: description, closed_at: nil)
update!(opened_version: new_version, head_version: new_version)
end
end
Expand Down
16 changes: 8 additions & 8 deletions app/services/version_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,9 @@ def self.open?(...)
new(...).open?
end

def self.open(cocina_object:, description:, opening_user_name: nil, assume_accessioned: false)
def self.open(cocina_object:, description:, opening_user_name: nil, assume_accessioned: false, from_version: nil)
new(druid: cocina_object.externalIdentifier, version: cocina_object.version)
.open(description:,
opening_user_name:,
assume_accessioned:,
cocina_object:)
.open(description:, opening_user_name:, assume_accessioned:, cocina_object:, from_version:)
end

def self.can_open?(druid:, version:, assume_accessioned: false)
Expand Down Expand Up @@ -48,17 +45,20 @@ def initialize(druid:, version:)
# @param [String] description set description of version change (required)
# @param [String] opening_user_name add opening username to the events datastream (optional)
# @param [Boolean] assume_accessioned If true, does not check whether object has been accessioned.
# @param [Integer,nil] from_version existing version to base the new version on, otherwise uses last_closed_version
# @return [Cocina::Models::DROWithMetadata, Cocina::Models::AdminPolicyWithMetadata, Cocina::Models::CollectionWithMetadata] updated cocina object
# @raise [VersionService::VersioningError] if the object hasn't been accessioned, or if a version is already opened
# @raise [Preservation::Client::Error] if bad response from preservation catalog.
def open(cocina_object:, description:, assume_accessioned:, opening_user_name: nil)
def open(cocina_object:, description:, assume_accessioned:, opening_user_name: nil, from_version: nil)
raise ArgumentError, 'description is required to open a new version' if description.blank?

ensure_openable!(assume_accessioned:)
repository_object = RepositoryObject.find_by!(external_identifier: cocina_object.externalIdentifier)
check_version!(current_version: repository_object.head_version.version)
check_version!(current_version: repository_object.head_version.version) unless from_version

repository_object.open_version!(description:)
from_repository_object_version = from_version ? repository_object.versions.find_by!(version: from_version) : nil

repository_object.open_version!(description:, from_version: from_repository_object_version)

# Reloading to get correct lock value.
Indexer.reindex_later(cocina_object: repository_object.reload.to_cocina_with_metadata)
Expand Down
18 changes: 18 additions & 0 deletions lib/tasks/dor_services_app.rake
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,22 @@ namespace :dsa do
task embargo_release: :environment do
EmbargoReleaseService.release_all
end

desc 'Open a new version from an existing version'
task :open_version, %i[druid description from_version] => :environment do |_task, args|
repository_object = RepositoryObject.find_by!(external_identifier: args[:druid])
VersionService.open(cocina_object: repository_object.to_cocina, description: args[:description],
assume_accessioned: false, from_version: args[:from_version].to_i)
end

desc 'Move a user version'
task :move_user_version, %i[druid user_version to_version] => :environment do |_task, args|
UserVersionService.move(druid: args[:druid], version: args[:to_version].to_i, user_version: args[:user_version].to_i)
end

desc 'Closes a repository object without changing a user version'
task :close_version, %i[druid] => :environment do |_task, args|
repository_object = RepositoryObject.find_by!(external_identifier: args[:druid])
VersionService.close(druid: args[:druid], version: repository_object.head_version.version, user_version_mode: :none)
end
end
20 changes: 20 additions & 0 deletions spec/models/repository_object_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,26 @@
expect(newly_created_version.closed_at).to be_nil
end
end

context 'when based on an earlier version' do
before do
repository_object.head_version.label = 'Version 1'
repository_object.close_version!
repository_object.open_version!(description: 'Another version')
repository_object.head_version.label = 'Version 2'
repository_object.close_version!
end

it 'creates a new version and updates the head and opened version pointers' do
expect { repository_object.open_version!(description:, from_version: repository_object.versions.first) }.to change(RepositoryObjectVersion, :count).by(1)
newly_created_version = repository_object.versions.last
expect(newly_created_version.version).to eq(3)
expect(repository_object.head_version).to eq(newly_created_version)
expect(repository_object.opened_version).to eq(newly_created_version)
expect(newly_created_version.label).to eq 'Version 1'
expect(newly_created_version.closed_at).to be_nil
end
end
end

describe '#close_version!' do
Expand Down
30 changes: 29 additions & 1 deletion spec/services/version_service_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@
end

describe '.open' do
subject(:open) { described_class.open(cocina_object:, description: 'same as it ever was', opening_user_name: 'sunetid') }
subject(:open) { described_class.open(cocina_object:, description: 'same as it ever was', opening_user_name: 'sunetid', from_version:) }

let(:from_version) { nil }

let(:workflow_client) do
instance_double(Dor::Workflow::Client, create_workflow_by_name: true)
Expand Down Expand Up @@ -90,6 +92,32 @@
expect { open }.to raise_error(VersionService::VersioningError, errmsg)
end
end

context 'when a from version is provided' do
let(:from_version) { 1 }

before do
repository_object.open_version!(description: 'A new version')
repository_object.head_version.update!(label: 'New version label')
repository_object.close_version!
end

it 'creates an object version and starts a workflow' do
expect(open).to be_a(Cocina::Models::DROWithMetadata)
expect(open.label).not_to eq 'New version label'
expect(workflow_state_service).to have_received(:accessioned?)
expect(workflow_state_service).to have_received(:accessioning?)
expect(workflow_client).to have_received(:create_workflow_by_name).with(druid, 'versioningWF', version: '3')

expect(EventFactory).to have_received(:create).with(data: { version: '3', who: 'sunetid' },
druid:,
event_type: 'version_open')

expect(Indexer).to have_received(:reindex_later).with(cocina_object: repository_object.reload.to_cocina_with_metadata)
expect(repository_object.opened_version.version).to eq 3
expect(repository_object.opened_version.version_description).to eq 'same as it ever was'
end
end
end

describe '.open?' do
Expand Down

0 comments on commit 57eea30

Please sign in to comment.