dor-services 8.6.0 → 9.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/config/config_defaults.yml +0 -1
  3. data/config/dev_console_env.rb.example +0 -1
  4. data/lib/dor-services.rb +0 -34
  5. data/lib/dor/models/abstract.rb +1 -47
  6. data/lib/dor/models/admin_policy_object.rb +0 -9
  7. data/lib/dor/models/collection.rb +0 -9
  8. data/lib/dor/models/etd.rb +0 -6
  9. data/lib/dor/models/item.rb +0 -9
  10. data/lib/dor/models/part.rb +0 -2
  11. data/lib/dor/models/set.rb +0 -8
  12. data/lib/dor/services/search_service.rb +1 -0
  13. data/lib/dor/static_config.rb +0 -8
  14. data/lib/dor/static_config/stacks_config.rb +0 -15
  15. data/lib/dor/version.rb +1 -1
  16. metadata +2 -55
  17. data/lib/dor/datastreams/simple_dublin_core_ds.rb +0 -59
  18. data/lib/dor/datastreams/workflow_definition_ds.rb +0 -71
  19. data/lib/dor/datastreams/workflow_ds.rb +0 -20
  20. data/lib/dor/indexers/composite_indexer.rb +0 -27
  21. data/lib/dor/indexers/data_indexer.rb +0 -24
  22. data/lib/dor/indexers/describable_indexer.rb +0 -60
  23. data/lib/dor/indexers/editable_indexer.rb +0 -25
  24. data/lib/dor/indexers/identifiable_indexer.rb +0 -102
  25. data/lib/dor/indexers/process_indexer.rb +0 -58
  26. data/lib/dor/indexers/processable_indexer.rb +0 -99
  27. data/lib/dor/indexers/releasable_indexer.rb +0 -33
  28. data/lib/dor/indexers/workflow_indexer.rb +0 -47
  29. data/lib/dor/indexers/workflows_indexer.rb +0 -34
  30. data/lib/dor/models/workflow_object.rb +0 -28
  31. data/lib/dor/models/workflow_solr_document.rb +0 -93
  32. data/lib/dor/release_tags.rb +0 -13
  33. data/lib/dor/release_tags/identity_metadata.rb +0 -145
  34. data/lib/dor/release_tags/purl.rb +0 -51
  35. data/lib/dor/release_tags/purl_client.rb +0 -44
  36. data/lib/dor/services/release_tag_service.rb +0 -40
  37. data/lib/dor/services/state_service.rb +0 -34
  38. data/lib/dor/services/status_service.rb +0 -125
  39. data/lib/dor/static_config/workflow_config.rb +0 -51
  40. data/lib/dor/workflow/document.rb +0 -72
  41. data/lib/dor/workflow/process.rb +0 -157
@@ -1,51 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Dor
4
- module ReleaseTags
5
- class Purl
6
- # Determine projects in which an item is released
7
- # @param [String] pid identifier of the item to get the release tags for
8
- def initialize(pid:, purl_host:)
9
- Deprecation.warn(self, "Dor::ReleaseTags::Purl is deprecated and will be removed in dor-services 9.0. (it's moving to dor-services-app)")
10
- @pid = pid
11
- @purl_host = purl_host
12
- end
13
-
14
- # This function calls purl and gets a list of all release tags currently in purl. It then compares to the list you have generated.
15
- # Any tag that is on purl, but not in the newly generated list is added to the new list with a value of false.
16
- # @param new_tags [Hash{String => Boolean}] all new tags in the form of !{"Project" => Boolean}
17
- # @return [Hash{String => Boolean}] all namespaces, keys are Project name Strings, values are Boolean
18
- def released_for(new_tags)
19
- missing_tags = release_tags_from_purl.map(&:downcase) - new_tags.keys.map(&:downcase)
20
- missing_tags.each do |missing_tag|
21
- new_tags[missing_tag.capitalize] = { 'release' => false }
22
- end
23
- new_tags
24
- end
25
-
26
- private
27
-
28
- # Pull all release nodes from the public xml obtained via the purl query
29
- # @param doc [Nokogiri::HTML::Document] The druid of the object you want
30
- # @return [Array] An array containing all the release tags
31
- def release_tags_from_purl_xml(doc)
32
- nodes = doc.xpath('//publicObject/releaseData').children
33
- # We only want the nodes with a name that isn't text
34
- nodes.reject { |n| n.name.nil? || n.name.casecmp('text') == 0 }.map { |n| n.attr('to') }.uniq
35
- end
36
-
37
- # Pull all release nodes from the public xml obtained via the purl query
38
- # @return [Array] An array containing all the release tags
39
- def release_tags_from_purl
40
- release_tags_from_purl_xml(purl_client.fetch)
41
- end
42
-
43
- def purl_client
44
- PurlClient.new(host: @purl_host,
45
- pid: pid)
46
- end
47
-
48
- attr_reader :pid
49
- end
50
- end
51
- end
@@ -1,44 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Dor
4
- module ReleaseTags
5
- # Calls the purl service and returns the XML document
6
- class PurlClient
7
- def initialize(host:, pid:)
8
- @host = host
9
- @pid = pid
10
- end
11
-
12
- # Get XML from the purl service
13
- # Fetches purl xml for a druid
14
- # @raise [OpenURI::HTTPError]
15
- # @return [Nokogiri::HTML::Document] parsed XML for the druid or an empty document if no purl is found
16
- def fetch
17
- handler = proc do |exception, attempt_number, total_delay|
18
- # We assume a 404 means the document has never been published before and thus has no purl
19
- Dor.logger.warn "[Attempt #{attempt_number}] GET #{url} -- #{exception.class}: #{exception.message}; #{total_delay} seconds elapsed."
20
- raise exception unless exception.is_a? OpenURI::HTTPError
21
- return Nokogiri::HTML::Document.new if exception.io.status.first == '404' # ["404", "Not Found"] from OpenURI::Meta.status
22
- end
23
-
24
- with_retries(max_retries: 3, base_sleep_seconds: 3, max_sleep_seconds: 5, handler: handler) do |attempt|
25
- # If you change the method used for opening the webpage, you can change the :rescue param to handle the new method's errors
26
- Dor.logger.debug "[Attempt #{attempt}] GET #{url}"
27
- return Nokogiri::XML(OpenURI.open_uri(url))
28
- end
29
- end
30
-
31
- private
32
-
33
- # Take the and create the entire purl url that will usable for the open method in open-uri, returns http
34
- # @return [String] the full url
35
- def url
36
- @url ||= "https://#{@host}/#{druid_without_prefix}.xml"
37
- end
38
-
39
- def druid_without_prefix
40
- PidUtils.remove_druid_prefix(@pid)
41
- end
42
- end
43
- end
44
- end
@@ -1,40 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Dor
4
- class ReleaseTagService
5
- # Determine projects in which an item is released
6
- # @param [Dor::Item] item to get the release tags for
7
- # @return [Hash{String => Boolean}] all namespaces, keys are Project name Strings, values are Boolean
8
- def self.for(item)
9
- new(item)
10
- end
11
-
12
- def initialize(item)
13
- Deprecation.warn(self, "Dor::ReleaseTagService is deprecated and will be removed in dor-services 9.0. (it's moving to dor-services-app)")
14
- @identity_metadata_service = ReleaseTags::IdentityMetadata.new(item)
15
- @purl_service = ReleaseTags::Purl.new(pid: item.pid, purl_host: Dor::Config.stacks.document_cache_host)
16
- end
17
-
18
- # Called in Dor::UpdateMarcRecordService (in dor-services-app too)
19
- # Determine projects in which an item is released
20
- # @return [Hash{String => Boolean}] all namespaces, keys are Project name Strings, values are Boolean
21
- def released_for(skip_live_purl:)
22
- released_hash = identity_metadata_service.released_for({})
23
- released_hash = purl_service.released_for(released_hash) unless skip_live_purl
24
- released_hash
25
- end
26
-
27
- # Helper method to get the release tags as a nodeset
28
- # @return [Hash] all release tags and their attributes
29
- delegate :release_tags, to: :identity_metadata_service
30
-
31
- # Take a hash of tags as obtained via Dor::Item.release_tags and returns the newest tag for each namespace
32
- # @param tags [Hash] a hash of tags obtained via Dor::Item.release_tags or matching format
33
- # @return [Hash] a hash of latest tags for each to value
34
- delegate :newest_release_tag, to: :identity_metadata_service
35
-
36
- private
37
-
38
- attr_reader :identity_metadata_service, :purl_service
39
- end
40
- end
@@ -1,34 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Dor
4
- class StateService
5
- extend Deprecation
6
-
7
- # having version is preferred as without it, a call to
8
- # fedora will be made to retrieve it.
9
- def initialize(pid, version: nil)
10
- Deprecation.warn(self, 'Dor::StateService is deprecated and will be removed in dor-services 9')
11
- @pid = pid
12
- @version = version || fetch_version
13
- end
14
-
15
- def allows_modification?
16
- !client.lifecycle('dor', pid, 'submitted') ||
17
- client.active_lifecycle('dor', pid, 'opened', version: version) ||
18
- client.workflow_status('dor', pid, 'accessionWF', 'sdr-ingest-transfer') == 'hold'
19
- end
20
-
21
- private
22
-
23
- attr_reader :pid, :version
24
-
25
- def fetch_version
26
- Deprecation.warn(self, 'Calling the state service without passing in a version is deprecated and will be removed in dor-services 9')
27
- Dor.find(pid).current_version
28
- end
29
-
30
- def client
31
- Dor::Config.workflow.client
32
- end
33
- end
34
- end
@@ -1,125 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Dor
4
- # Query the processing status of an item.
5
- # This has a dependency on the workflow service (app) to get milestones.
6
- class StatusService
7
- # verbiage we want to use to describe an item when it has completed a particular step
8
- STATUS_CODE_DISP_TXT = {
9
- 0 => 'Unknown Status', # if there are no milestones for the current version, someone likely messed up the versioning process.
10
- 1 => 'Registered',
11
- 2 => 'In accessioning',
12
- 3 => 'In accessioning (described)',
13
- 4 => 'In accessioning (described, published)',
14
- 5 => 'In accessioning (described, published, deposited)',
15
- 6 => 'Accessioned',
16
- 7 => 'Accessioned (indexed)',
17
- 8 => 'Accessioned (indexed, ingested)',
18
- 9 => 'Opened'
19
- }.freeze
20
-
21
- # milestones from accessioning and the order they happen in
22
- STEPS = {
23
- 'registered' => 1,
24
- 'submitted' => 2,
25
- 'described' => 3,
26
- 'published' => 4,
27
- 'deposited' => 5,
28
- 'accessioned' => 6,
29
- 'indexed' => 7,
30
- 'shelved' => 8,
31
- 'opened' => 9
32
- }.freeze
33
-
34
- # @return [Hash{Symbol => Object}] including :current_version, :status_code and :status_time
35
- def self.status_info(work)
36
- new(work).status_info
37
- end
38
-
39
- def self.status(work, include_time = false)
40
- new(work).status(include_time)
41
- end
42
-
43
- def initialize(work)
44
- @work = work
45
- end
46
-
47
- # @return [Hash{Symbol => Object}] including :current_version, :status_code and :status_time
48
- def status_info
49
- # if we have an accessioned milestone, this is the last possible step and should be the status regardless of time stamp
50
- accessioned_milestones = current_milestones.select { |m| m[:milestone] == 'accessioned' }
51
- return { current_version: current_version, status_code: STEPS['accessioned'], status_time: accessioned_milestones.last[:at].utc.xmlschema } unless accessioned_milestones.empty?
52
-
53
- status_code = 0
54
- status_time = nil
55
- # for each milestone in the current version, see if it comes at the same time or after the current 'last' step, if so, make it the last and record the date/time
56
- current_milestones.each do |m|
57
- m_name = m[:milestone]
58
- m_time = m[:at].utc.xmlschema
59
- next unless STEPS.key?(m_name) && (!status_time || m_time >= status_time)
60
-
61
- status_code = STEPS[m_name]
62
- status_time = m_time
63
- end
64
-
65
- { current_version: current_version, status_code: status_code, status_time: status_time }
66
- end
67
-
68
- # @param [Boolean] include_time
69
- # @return [String] single composed status from status_info
70
- def status(include_time = false)
71
- status_info_hash = status_info
72
- current_version = status_info_hash[:current_version]
73
- status_code = status_info_hash[:status_code]
74
- status_time = status_info_hash[:status_time]
75
-
76
- # use the translation table to get the appropriate verbage for the latest step
77
- result = "v#{current_version} #{STATUS_CODE_DISP_TXT[status_code]}"
78
- result += " #{format_date(status_time)}" if include_time
79
- result
80
- end
81
-
82
- def milestones
83
- @milestones ||= Dor::Config.workflow.client.milestones('dor', work.pid)
84
- end
85
-
86
- private
87
-
88
- attr_reader :work
89
-
90
- def current_version
91
- @current_version ||= begin
92
- work.versionMetadata.current_version_id
93
- rescue StandardError
94
- '1'
95
- end
96
- end
97
-
98
- def current_milestones
99
- current = []
100
- # only get steps that are part of accessioning and part of the current version. That can mean they were archived with the current version
101
- # number, or they might be active (no version number).
102
- milestones.each do |m|
103
- if STEPS.key?(m[:milestone]) && (m[:version].nil? || m[:version] == current_version)
104
- current << m unless m[:milestone] == 'registered' && current_version.to_i > 1
105
- end
106
- end
107
- current
108
- end
109
-
110
- # handles formating utc date/time to human readable
111
- # XXX: bad form to hardcode TZ here.
112
- def format_date(datetime)
113
- d =
114
- if datetime.is_a?(Time)
115
- datetime
116
- else
117
- DateTime.parse(datetime).in_time_zone(ActiveSupport::TimeZone.new('Pacific Time (US & Canada)'))
118
- end
119
- I18n.l(d).strftime('%Y-%m-%d %I:%M%p')
120
- rescue StandardError
121
- d = datetime.is_a?(Time) ? datetime : Time.parse(datetime.to_s)
122
- d.strftime('%Y-%m-%d %I:%M%p')
123
- end
124
- end
125
- end
@@ -1,51 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Dor
4
- class StaticConfig
5
- # Represents the configuration for the workflow service
6
- class WorkflowConfig
7
- def initialize(hash)
8
- @url = hash.fetch(:url)
9
- @timeout = hash.fetch(:timeout)
10
- @logfile = hash.fetch(:logfile)
11
- @shift_age = hash.fetch(:shift_age)
12
- end
13
-
14
- def configure(&block)
15
- instance_eval(&block)
16
- end
17
-
18
- def client
19
- @client ||= Dor::Workflow::Client.new(url: url, logger: client_logger, timeout: timeout)
20
- end
21
-
22
- def url(new_value = nil)
23
- @url = new_value if new_value
24
- @url
25
- end
26
-
27
- def timeout(new_value = nil)
28
- @timeout = new_value if new_value
29
- @timeout
30
- end
31
-
32
- def logfile(new_value = nil)
33
- @logfile = new_value if new_value
34
- @logfile
35
- end
36
-
37
- def shift_age(new_value = nil)
38
- @shift_age = new_value if new_value
39
- @shift_age
40
- end
41
-
42
- def client_logger
43
- if logfile && shift_age
44
- Logger.new(logfile, shift_age)
45
- elsif logfile
46
- Logger.new(logfile)
47
- end
48
- end
49
- end
50
- end
51
- end
@@ -1,72 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Dor
4
- module Workflow
5
- class Document
6
- include ::OM::XML::Document
7
-
8
- set_terminology do |t|
9
- t.root(path: 'workflow')
10
- t.repository(path: { attribute: 'repository' })
11
- t.workflowId(path: { attribute: 'id' })
12
- t.process do
13
- t.name_(path: { attribute: 'name' })
14
- t.status(path: { attribute: 'status' })
15
- t.timestamp(path: { attribute: 'datetime' }) # , :data_type => :date)
16
- t.elapsed(path: { attribute: 'elapsed' })
17
- t.lifecycle(path: { attribute: 'lifecycle' })
18
- t.attempts(path: { attribute: 'attempts' }, index_as: [:not_searchable])
19
- t.version(path: { attribute: 'version' })
20
- end
21
- end
22
-
23
- @@definitions = {}
24
-
25
- def initialize(node)
26
- Deprecation.warn(self, 'Dor::Workflow::Document is deprecated and will be removed from dor-services version 9')
27
- self.ng_xml = Nokogiri::XML(node)
28
- end
29
-
30
- # @return [Dor::WorkflowDefinitionDs]
31
- def definition
32
- @definition ||= begin
33
- if @@definitions.key? workflowId.first
34
- @@definitions[workflowId.first]
35
- else
36
- wfo = Dor::WorkflowObject.find_by_name(workflowId.first)
37
- wf_def = wfo ? wfo.definition : nil
38
- @@definitions[workflowId.first] = wf_def
39
- wf_def
40
- end
41
- end
42
- end
43
-
44
- def [](value)
45
- processes.find { |p| p.name == value }
46
- end
47
-
48
- def processes
49
- # if the workflow service didnt return any processes, dont return any processes from the reified wf
50
- return [] if ng_xml.search('/workflow/process').length == 0
51
-
52
- @processes ||=
53
- if definition
54
- definition.processes.collect do |process|
55
- nodes = ng_xml.xpath("/workflow/process[@name = '#{process.name}']")
56
- node = nodes.max { |a, b| a.attr('version').to_i <=> b.attr('version').to_i }
57
- process.update!(node, self)
58
- end
59
- else
60
- find_by_terms(:workflow, :process).collect do |x|
61
- pnode = Dor::Workflow::Process.new(repository, workflowId, {})
62
- pnode.update!(x, self)
63
- end.sort_by(&:datetime)
64
- end
65
- end
66
-
67
- def inspect
68
- "#<#{self.class.name}:#{object_id}>"
69
- end
70
- end
71
- end
72
- end
@@ -1,157 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Dor
4
- module Workflow
5
- class Process
6
- attr_reader :owner, :repo, :workflow
7
-
8
- # @param repo [String] the name of the repository, typically 'dor'
9
- # @param workflow [String] the name of the workflow, e.g. 'assemblyWF'
10
- # @param attrs [Nokogiri::XML::Node, Hash]
11
- def initialize(repo, workflow, attrs)
12
- Deprecation.warn(self, 'Dor::Workflow::Process is deprecated and will be removed from dor-services version 9')
13
- @workflow = workflow
14
- @repo = repo
15
- if attrs.is_a? Nokogiri::XML::Node
16
- init_from_node(attrs)
17
- else
18
- @attrs = attrs
19
- end
20
- end
21
-
22
- def init_from_node(node)
23
- @attrs = {
24
- 'name' => node['name'],
25
- 'sequence' => node['sequence'] ? node['sequence'].to_i : nil,
26
- 'status' => node['status'], # TODO: see how this affects argo
27
- 'lifecycle' => node['lifecycle'],
28
- 'label' => node.at_xpath('label/text()').to_s,
29
- 'batch_limit' => node['batch-limit'] ? node['batch-limit'].to_i : nil,
30
- 'error_limit' => node['error-limit'] ? node['error-limit'].to_i : nil,
31
- 'priority' => node['priority'] ? node['priority'].to_i : 0,
32
- 'prerequisite' => node.xpath('prereq').collect do |p|
33
- repo = p['repository'].nil? || p['repository'] == @repo ? nil : p['repository']
34
- wf = p['workflow'].nil? || p['workflow'] == @workflow ? nil : p['workflow']
35
- [repo, wf, p.text.to_s].compact.join(':')
36
- end
37
- }
38
- end
39
-
40
- def name
41
- @attrs['name']
42
- end
43
-
44
- def sequence
45
- @attrs['sequence']
46
- end
47
-
48
- def lifecycle
49
- @attrs['lifecycle']
50
- end
51
-
52
- def label
53
- @attrs['label']
54
- end
55
-
56
- def batch_limit
57
- @attrs['batch_limit']
58
- end
59
-
60
- def error_limit
61
- @attrs['error_limit']
62
- end
63
-
64
- def error_message
65
- @attrs['errorMessage']
66
- end
67
-
68
- def prerequisite
69
- @attrs['prerequisite']
70
- end
71
-
72
- def status
73
- @attrs['status']
74
- end
75
-
76
- def note
77
- @attrs['note']
78
- end
79
-
80
- def version
81
- @attrs['version']
82
- end
83
-
84
- def priority
85
- @attrs['priority']
86
- end
87
-
88
- def completed?
89
- status == 'completed'
90
- end
91
-
92
- def error?
93
- status == 'error'
94
- end
95
-
96
- def waiting?
97
- status == 'waiting'
98
- end
99
-
100
- def date_time
101
- @attrs['datetime']
102
- end
103
-
104
- def archived?
105
- @attrs['archived'] =~ /true$/i
106
- end
107
-
108
- def ready?
109
- waiting? && !prerequisite.nil? && prerequisite.all? { |pr| (prq = owner[pr]) && prq.completed? }
110
- end
111
-
112
- def blocked?
113
- waiting? && !prerequisite.nil? && prerequisite.any? { |pr| (prq = owner[pr]) && (prq.error? || prq.blocked?) }
114
- end
115
-
116
- def state
117
- if blocked?
118
- 'blocked'
119
- elsif ready?
120
- 'ready'
121
- else
122
- status
123
- end
124
- end
125
-
126
- def attempts
127
- @attrs['attempts'].to_i
128
- end
129
-
130
- def datetime
131
- @attrs['datetime'] ? Time.parse(@attrs['datetime']) : nil
132
- end
133
-
134
- def elapsed
135
- @attrs['elapsed'].nil? ? nil : @attrs['elapsed'].to_f
136
- end
137
-
138
- # Updates this object with the attributes passed in.
139
- # @param info [Hash,Nokogiri::XML::Element,NilClass]
140
- # @param new_owner [Dor::Workflow::Document]
141
- def update!(info, new_owner)
142
- raise ArgumentError, 'Owner can not be nil. It must be an instance of Dor::Workflow::Document' unless new_owner
143
-
144
- @owner = new_owner
145
- return self if info.nil?
146
-
147
- info = Hash[info.attributes.collect { |k, v| [k, v.value] }] if info.is_a? Nokogiri::XML::Node
148
- @attrs.merge! info
149
- self
150
- end
151
-
152
- def to_hash
153
- @attrs.reject { |_k, v| v.nil? || v == 0 || (v.respond_to?(:empty?) && v.empty?) }
154
- end
155
- end
156
- end
157
- end