dor-services 6.0.0 → 6.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/dor-services.rb +7 -6
- data/lib/dor/certificate_authenticated_rest_resource_factory.rb +2 -1
- data/lib/dor/config.rb +38 -37
- data/lib/dor/datastreams/administrative_metadata_ds.rb +98 -98
- data/lib/dor/datastreams/content_metadata_ds.rb +26 -17
- data/lib/dor/datastreams/datastream_spec_solrizer.rb +4 -2
- data/lib/dor/datastreams/default_object_rights_ds.rb +10 -7
- data/lib/dor/datastreams/desc_metadata_ds.rb +6 -6
- data/lib/dor/datastreams/embargo_metadata_ds.rb +94 -94
- data/lib/dor/datastreams/events_ds.rb +55 -54
- data/lib/dor/datastreams/geo_metadata_ds.rb +7 -6
- data/lib/dor/datastreams/identity_metadata_ds.rb +128 -125
- data/lib/dor/datastreams/provenance_metadata_ds.rb +3 -1
- data/lib/dor/datastreams/rights_metadata_ds.rb +4 -4
- data/lib/dor/datastreams/role_metadata_ds.rb +42 -42
- data/lib/dor/datastreams/simple_dublin_core_ds.rb +45 -43
- data/lib/dor/datastreams/technical_metadata_ds.rb +3 -1
- data/lib/dor/datastreams/version_metadata_ds.rb +12 -5
- data/lib/dor/datastreams/workflow_definition_ds.rb +74 -73
- data/lib/dor/datastreams/workflow_ds.rb +12 -7
- data/lib/dor/exceptions.rb +2 -0
- data/lib/dor/indexers/data_indexer.rb +16 -0
- data/lib/dor/indexers/describable_indexer.rb +2 -0
- data/lib/dor/indexers/editable_indexer.rb +2 -0
- data/lib/dor/indexers/identifiable_indexer.rb +23 -8
- data/lib/dor/indexers/processable_indexer.rb +2 -0
- data/lib/dor/indexers/releasable_indexer.rb +2 -0
- data/lib/dor/models/abstract.rb +2 -0
- data/lib/dor/models/admin_policy_object.rb +2 -0
- data/lib/dor/models/agreement.rb +2 -0
- data/lib/dor/models/collection.rb +3 -0
- data/lib/dor/models/concerns/assembleable.rb +2 -0
- data/lib/dor/models/concerns/contentable.rb +5 -2
- data/lib/dor/models/concerns/describable.rb +7 -2
- data/lib/dor/models/concerns/editable.rb +28 -21
- data/lib/dor/models/concerns/embargoable.rb +4 -0
- data/lib/dor/models/concerns/eventable.rb +2 -0
- data/lib/dor/models/concerns/geoable.rb +2 -0
- data/lib/dor/models/concerns/governable.rb +7 -2
- data/lib/dor/models/concerns/identifiable.rb +33 -34
- data/lib/dor/models/concerns/itemizable.rb +4 -1
- data/lib/dor/models/concerns/preservable.rb +2 -0
- data/lib/dor/models/concerns/processable.rb +15 -9
- data/lib/dor/models/concerns/publishable.rb +9 -4
- data/lib/dor/models/concerns/releaseable.rb +21 -11
- data/lib/dor/models/concerns/rightsable.rb +2 -0
- data/lib/dor/models/concerns/shelvable.rb +6 -2
- data/lib/dor/models/concerns/versionable.rb +8 -4
- data/lib/dor/models/item.rb +2 -0
- data/lib/dor/models/set.rb +2 -0
- data/lib/dor/models/workflow_object.rb +5 -1
- data/lib/dor/rest_resource_factory.rb +2 -0
- data/lib/dor/services/cleanup_reset_service.rb +2 -1
- data/lib/dor/services/cleanup_service.rb +2 -1
- data/lib/dor/services/digital_stacks_service.rb +3 -1
- data/lib/dor/services/indexing_service.rb +3 -1
- data/lib/dor/services/merge_service.rb +6 -4
- data/lib/dor/services/metadata_handlers/catalog_handler.rb +2 -0
- data/lib/dor/services/metadata_service.rb +4 -4
- data/lib/dor/services/public_desc_metadata_service.rb +16 -8
- data/lib/dor/services/public_xml_service.rb +7 -4
- data/lib/dor/services/registration_service.rb +25 -20
- data/lib/dor/services/reset_workspace_service.rb +4 -4
- data/lib/dor/services/sdr_ingest_service.rb +4 -2
- data/lib/dor/services/search_service.rb +8 -9
- data/lib/dor/services/suri_service.rb +3 -2
- data/lib/dor/services/technical_metadata_service.rb +15 -9
- data/lib/dor/services/thumbnail_service.rb +14 -10
- data/lib/dor/utils/hydrus_shims.rb +2 -0
- data/lib/dor/utils/ng_tidy.rb +3 -7
- data/lib/dor/utils/predicate_patch.rb +2 -0
- data/lib/dor/utils/sdr_client.rb +3 -0
- data/lib/dor/utils/solr_doc_helper.rb +4 -2
- data/lib/dor/version.rb +3 -1
- data/lib/dor/workflow/document.rb +113 -108
- data/lib/dor/workflow/process.rb +90 -87
- data/lib/tasks/rdoc.rake +4 -3
- metadata +4 -4
@@ -1,27 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Dor
|
2
4
|
# Responsible for finding a path to a thumbnail based on the contentMetadata of an object
|
3
5
|
class ThumbnailService
|
4
6
|
# allow the mimetype attribute to be lower or camelcase when searching to make it more robust
|
5
|
-
MIME_TYPE_FINDER = "@mimetype='image/jp2' or @mimeType='image/jp2'"
|
7
|
+
MIME_TYPE_FINDER = "@mimetype='image/jp2' or @mimeType='image/jp2'"
|
6
8
|
|
7
9
|
# these are the finders we will use to search for a thumb resource in contentMetadata, they will be searched in the order provided, stopping when one is reached
|
8
10
|
THUMB_XPATH_FINDERS = [
|
9
11
|
# first find a file of mimetype jp2 explicitly marked as a thumb in the resource type and with a thumb=yes attribute
|
10
|
-
{ image_type: 'local', finder: "/contentMetadata/resource[@type='thumb' and @thumb='yes']/file[#{MIME_TYPE_FINDER}]"},
|
12
|
+
{ image_type: 'local', finder: "/contentMetadata/resource[@type='thumb' and @thumb='yes']/file[#{MIME_TYPE_FINDER}]" },
|
11
13
|
# same thing for external files
|
12
|
-
{ image_type: 'external', finder: "/contentMetadata/resource[@type='thumb' and @thumb='yes']/externalFile[#{MIME_TYPE_FINDER}]"},
|
14
|
+
{ image_type: 'external', finder: "/contentMetadata/resource[@type='thumb' and @thumb='yes']/externalFile[#{MIME_TYPE_FINDER}]" },
|
13
15
|
# next find any image or page resource types with the thumb=yes attribute of mimetype jp2
|
14
|
-
{ image_type: 'local', finder: "/contentMetadata/resource[(@type='page' or @type='image') and @thumb='yes']/file[#{MIME_TYPE_FINDER}]"},
|
16
|
+
{ image_type: 'local', finder: "/contentMetadata/resource[(@type='page' or @type='image') and @thumb='yes']/file[#{MIME_TYPE_FINDER}]" },
|
15
17
|
# same thing for external file
|
16
|
-
{ image_type: 'external', finder: "/contentMetadata/resource[(@type='page' or @type='image') and @thumb='yes']/externalFile[#{MIME_TYPE_FINDER}]"},
|
18
|
+
{ image_type: 'external', finder: "/contentMetadata/resource[(@type='page' or @type='image') and @thumb='yes']/externalFile[#{MIME_TYPE_FINDER}]" },
|
17
19
|
# next find a file of mimetype jp2 and resource type=thumb but not marked with the thumb directive
|
18
|
-
{ image_type: 'local', finder: "/contentMetadata/resource[@type='thumb']/file[#{MIME_TYPE_FINDER}]"},
|
20
|
+
{ image_type: 'local', finder: "/contentMetadata/resource[@type='thumb']/file[#{MIME_TYPE_FINDER}]" },
|
19
21
|
# same thing for external file
|
20
|
-
{ image_type: 'external', finder: "/contentMetadata/resource[@type='thumb']/externalFile[#{MIME_TYPE_FINDER}]"},
|
22
|
+
{ image_type: 'external', finder: "/contentMetadata/resource[@type='thumb']/externalFile[#{MIME_TYPE_FINDER}]" },
|
21
23
|
# finally find the first page or image resource of mimetype jp2
|
22
|
-
{ image_type: 'local', finder: "/contentMetadata/resource[@type='page' or @type='image']/file[#{MIME_TYPE_FINDER}]"},
|
24
|
+
{ image_type: 'local', finder: "/contentMetadata/resource[@type='page' or @type='image']/file[#{MIME_TYPE_FINDER}]" },
|
23
25
|
# same thing for external file
|
24
|
-
{ image_type: 'external', finder: "/contentMetadata/resource[@type='page' or @type='image']/externalFile[#{MIME_TYPE_FINDER}]"}
|
26
|
+
{ image_type: 'external', finder: "/contentMetadata/resource[@type='page' or @type='image']/externalFile[#{MIME_TYPE_FINDER}]" }
|
25
27
|
].freeze
|
26
28
|
|
27
29
|
# @params [Dor::Item] object
|
@@ -34,19 +36,21 @@ module Dor
|
|
34
36
|
# @return [String] the computed thumb filename, with the druid prefix and a slash in front of it, e.g. oo000oo0001/filenamewith space.jp2
|
35
37
|
def thumb
|
36
38
|
return unless object.respond_to?(:contentMetadata) && object.contentMetadata.present?
|
39
|
+
|
37
40
|
cm = object.contentMetadata.ng_xml
|
38
41
|
thumb_image = nil
|
39
42
|
|
40
43
|
THUMB_XPATH_FINDERS.each do |search_path|
|
41
44
|
thumb_files = cm.xpath(search_path[:finder]) # look for a thumb
|
42
45
|
next if thumb_files.empty?
|
46
|
+
|
43
47
|
# if we find one, return the filename based on whether it is a local file or external file
|
44
48
|
thumb_image = if search_path[:image_type] == 'local'
|
45
49
|
"#{object.remove_druid_prefix}/#{thumb_files[0]['id']}"
|
46
50
|
else
|
47
51
|
"#{object.remove_druid_prefix(thumb_files[0]['objectId'])}/#{thumb_files[0]['fileId']}"
|
48
52
|
end
|
49
|
-
break
|
53
|
+
break # break out of the loop so we stop searching
|
50
54
|
end
|
51
55
|
|
52
56
|
thumb_image
|
data/lib/dor/utils/ng_tidy.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
+
class Nokogiri::XML::Text
|
3
4
|
def normalize
|
4
5
|
content =~ /\S/ ? content.gsub(/\s+/, ' ').strip : content
|
5
6
|
end
|
@@ -7,19 +8,15 @@ class Nokogiri::XML::Text
|
|
7
8
|
def normalize!
|
8
9
|
self.content = normalize
|
9
10
|
end
|
10
|
-
|
11
11
|
end
|
12
12
|
|
13
13
|
class Nokogiri::XML::Node
|
14
|
-
|
15
14
|
def normalize_text!
|
16
15
|
xpath('//text()').each { |t| t.normalize! }
|
17
16
|
end
|
18
|
-
|
19
17
|
end
|
20
18
|
|
21
19
|
class Nokogiri::XML::Document
|
22
|
-
|
23
20
|
PRETTIFY_XSLT = Nokogiri::XSLT <<-EOC
|
24
21
|
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
|
25
22
|
<xsl:output omit-xml-declaration="yes" indent="yes"/>
|
@@ -29,10 +26,9 @@ class Nokogiri::XML::Document
|
|
29
26
|
</xsl:copy>
|
30
27
|
</xsl:template>
|
31
28
|
</xsl:stylesheet>
|
32
|
-
|
29
|
+
EOC
|
33
30
|
|
34
31
|
def prettify
|
35
32
|
PRETTIFY_XSLT.transform(self).to_xml
|
36
33
|
end
|
37
|
-
|
38
34
|
end
|
data/lib/dor/utils/sdr_client.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'moab'
|
2
4
|
module Sdr
|
3
5
|
class Client
|
@@ -10,6 +12,7 @@ module Sdr
|
|
10
12
|
begin
|
11
13
|
doc = Nokogiri::XML xml
|
12
14
|
raise if doc.root.name != 'currentVersion'
|
15
|
+
|
13
16
|
return Integer(doc.text)
|
14
17
|
rescue
|
15
18
|
raise "Unable to parse XML from SDR current_version API call: #{xml}"
|
@@ -1,8 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module SolrDocHelper
|
2
4
|
def add_solr_value(solr_doc, field_name, value, field_type = :default, index_types = [:searchable])
|
3
5
|
case field_type
|
4
|
-
|
5
|
-
|
6
|
+
when :symbol
|
7
|
+
index_types << field_type
|
6
8
|
end
|
7
9
|
::Solrizer.insert_field(solr_doc, field_name, value, *index_types)
|
8
10
|
end
|
data/lib/dor/version.rb
CHANGED
@@ -1,130 +1,135 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Dor
|
2
|
-
module Workflow
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
4
|
+
module Workflow
|
5
|
+
class Document
|
6
|
+
include SolrDocHelper
|
7
|
+
include ::OM::XML::Document
|
8
|
+
|
9
|
+
set_terminology do |t|
|
10
|
+
t.root(:path => 'workflow')
|
11
|
+
t.repository(:path => { :attribute => 'repository' })
|
12
|
+
t.workflowId(:path => { :attribute => 'id' })
|
13
|
+
t.process do
|
14
|
+
t.name_(:path => { :attribute => 'name' })
|
15
|
+
t.status(:path => { :attribute => 'status' })
|
16
|
+
t.timestamp(:path => { :attribute => 'datetime' }) # , :data_type => :date)
|
17
|
+
t.elapsed(:path => { :attribute => 'elapsed' })
|
18
|
+
t.lifecycle(:path => { :attribute => 'lifecycle' })
|
19
|
+
t.attempts(:path => { :attribute => 'attempts' }, :index_as => [:not_searchable])
|
20
|
+
t.version(:path => { :attribute => 'version' })
|
21
|
+
end
|
19
22
|
end
|
20
|
-
end
|
21
23
|
|
22
|
-
|
24
|
+
@@definitions = {}
|
23
25
|
|
24
|
-
|
25
|
-
|
26
|
-
|
26
|
+
def initialize(node)
|
27
|
+
self.ng_xml = Nokogiri::XML(node)
|
28
|
+
end
|
27
29
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
30
|
+
# is this an incomplete workflow with steps that have a priority > 0
|
31
|
+
def expedited?
|
32
|
+
processes.any? { |proc| !proc.completed? && proc.priority.to_i > 0 }
|
33
|
+
end
|
32
34
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
35
|
+
# @return [Integer] value of the first > 0 priority. Defaults to 0
|
36
|
+
def priority
|
37
|
+
processes.map { |proc| proc.priority.to_i }.detect(0) { |p| p > 0 }
|
38
|
+
end
|
37
39
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
40
|
+
# @return [Boolean] if any process node does not have version, returns true, false otherwise (all processes have version)
|
41
|
+
def active?
|
42
|
+
ng_xml.at_xpath('/workflow/process[not(@version)]') ? true : false
|
43
|
+
end
|
42
44
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
45
|
+
# @return [Dor::WorkflowDefinitionDs]
|
46
|
+
def definition
|
47
|
+
@definition ||= begin
|
48
|
+
if @@definitions.key? workflowId.first
|
49
|
+
@@definitions[workflowId.first]
|
50
|
+
else
|
51
|
+
wfo = Dor::WorkflowObject.find_by_name(workflowId.first)
|
52
|
+
wf_def = wfo ? wfo.definition : nil
|
53
|
+
@@definitions[workflowId.first] = wf_def
|
54
|
+
wf_def
|
55
|
+
end
|
53
56
|
end
|
54
57
|
end
|
55
|
-
end
|
56
58
|
|
57
|
-
|
58
|
-
|
59
|
-
|
59
|
+
def [](value)
|
60
|
+
processes.find { |p| p.name == value }
|
61
|
+
end
|
60
62
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
63
|
+
def processes
|
64
|
+
# if the workflow service didnt return any processes, dont return any processes from the reified wf
|
65
|
+
return [] if ng_xml.search('/workflow/process').length == 0
|
66
|
+
|
67
|
+
@processes ||=
|
68
|
+
if definition
|
69
|
+
definition.processes.collect do |process|
|
70
|
+
node = ng_xml.at("/workflow/process[@name = '#{process.name}']")
|
71
|
+
process.update!(node, self)
|
72
|
+
end
|
73
|
+
else
|
74
|
+
find_by_terms(:workflow, :process).collect do |x|
|
75
|
+
pnode = Dor::Workflow::Process.new(repository, workflowId, {})
|
76
|
+
pnode.update!(x, self)
|
77
|
+
end.sort_by(&:datetime)
|
78
|
+
end
|
75
79
|
end
|
76
|
-
end
|
77
80
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
+
def workflow_should_show_completed?(processes)
|
82
|
+
processes.all? { |p| ['skipped', 'completed', '', nil].include?(p.status) }
|
83
|
+
end
|
84
|
+
|
85
|
+
def to_solr(solr_doc = {}, *args)
|
86
|
+
wf_name = workflowId.first
|
87
|
+
repo = repository.first
|
88
|
+
wf_solr_type = :string
|
89
|
+
wf_solr_attrs = [:symbol]
|
90
|
+
add_solr_value(solr_doc, 'wf', wf_name, wf_solr_type, wf_solr_attrs)
|
91
|
+
add_solr_value(solr_doc, 'wf_wps', wf_name, wf_solr_type, wf_solr_attrs)
|
92
|
+
add_solr_value(solr_doc, 'wf_wsp', wf_name, wf_solr_type, wf_solr_attrs)
|
93
|
+
status = processes.empty? ? 'empty' : (workflow_should_show_completed?(processes) ? 'completed' : 'active')
|
94
|
+
errors = processes.count(&:error?)
|
95
|
+
add_solr_value(solr_doc, 'workflow_status', [wf_name, status, errors, repo].join('|'), wf_solr_type, wf_solr_attrs)
|
81
96
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
97
|
+
processes.each do |process|
|
98
|
+
next unless process.status.present?
|
99
|
+
|
100
|
+
# add a record of the robot having operated on this item, so we can track robot activity
|
101
|
+
if !process.date_time.blank? && process.status && (process.status == 'completed' || process.status == 'error')
|
102
|
+
solr_doc["wf_#{wf_name}_#{process.name}_dttsi"] = Time.parse(process.date_time).utc.iso8601
|
103
|
+
end
|
104
|
+
# index the error message without the druid so we hopefully get some overlap
|
105
|
+
add_solr_value(solr_doc, 'wf_error', "#{wf_name}:#{process.name}:#{process.error_message}", wf_solr_type, wf_solr_attrs) if process.error_message
|
106
|
+
add_solr_value(solr_doc, 'wf_wsp', "#{wf_name}:#{process.status}", wf_solr_type, wf_solr_attrs)
|
107
|
+
add_solr_value(solr_doc, 'wf_wsp', "#{wf_name}:#{process.status}:#{process.name}", wf_solr_type, wf_solr_attrs)
|
108
|
+
add_solr_value(solr_doc, 'wf_wps', "#{wf_name}:#{process.name}", wf_solr_type, wf_solr_attrs)
|
109
|
+
add_solr_value(solr_doc, 'wf_wps', "#{wf_name}:#{process.name}:#{process.status}", wf_solr_type, wf_solr_attrs)
|
110
|
+
add_solr_value(solr_doc, 'wf_swp', "#{process.status}", wf_solr_type, wf_solr_attrs)
|
111
|
+
add_solr_value(solr_doc, 'wf_swp', "#{process.status}:#{wf_name}", wf_solr_type, wf_solr_attrs)
|
112
|
+
add_solr_value(solr_doc, 'wf_swp', "#{process.status}:#{wf_name}:#{process.name}", wf_solr_type, wf_solr_attrs)
|
113
|
+
next unless process.state != process.status
|
114
|
+
|
115
|
+
add_solr_value(solr_doc, 'wf_wsp', "#{wf_name}:#{process.state}:#{process.name}", wf_solr_type, wf_solr_attrs)
|
116
|
+
add_solr_value(solr_doc, 'wf_wps', "#{wf_name}:#{process.name}:#{process.state}", wf_solr_type, wf_solr_attrs)
|
117
|
+
add_solr_value(solr_doc, 'wf_swp', "#{process.state}", wf_solr_type, wf_solr_attrs)
|
118
|
+
add_solr_value(solr_doc, 'wf_swp', "#{process.state}:#{wf_name}", wf_solr_type, wf_solr_attrs)
|
119
|
+
add_solr_value(solr_doc, 'wf_swp', "#{process.state}:#{wf_name}:#{process.name}", wf_solr_type, wf_solr_attrs)
|
99
120
|
end
|
100
|
-
# index the error message without the druid so we hopefully get some overlap
|
101
|
-
add_solr_value(solr_doc, 'wf_error', "#{wf_name}:#{process.name}:#{process.error_message}", wf_solr_type, wf_solr_attrs) if process.error_message
|
102
|
-
add_solr_value(solr_doc, 'wf_wsp', "#{wf_name}:#{process.status}", wf_solr_type, wf_solr_attrs)
|
103
|
-
add_solr_value(solr_doc, 'wf_wsp', "#{wf_name}:#{process.status}:#{process.name}", wf_solr_type, wf_solr_attrs)
|
104
|
-
add_solr_value(solr_doc, 'wf_wps', "#{wf_name}:#{process.name}", wf_solr_type, wf_solr_attrs)
|
105
|
-
add_solr_value(solr_doc, 'wf_wps', "#{wf_name}:#{process.name}:#{process.status}", wf_solr_type, wf_solr_attrs)
|
106
|
-
add_solr_value(solr_doc, 'wf_swp', "#{process.status}", wf_solr_type, wf_solr_attrs)
|
107
|
-
add_solr_value(solr_doc, 'wf_swp', "#{process.status}:#{wf_name}", wf_solr_type, wf_solr_attrs)
|
108
|
-
add_solr_value(solr_doc, 'wf_swp', "#{process.status}:#{wf_name}:#{process.name}", wf_solr_type, wf_solr_attrs)
|
109
|
-
next unless process.state != process.status
|
110
|
-
add_solr_value(solr_doc, 'wf_wsp', "#{wf_name}:#{process.state}:#{process.name}", wf_solr_type, wf_solr_attrs)
|
111
|
-
add_solr_value(solr_doc, 'wf_wps', "#{wf_name}:#{process.name}:#{process.state}", wf_solr_type, wf_solr_attrs)
|
112
|
-
add_solr_value(solr_doc, 'wf_swp', "#{process.state}", wf_solr_type, wf_solr_attrs)
|
113
|
-
add_solr_value(solr_doc, 'wf_swp', "#{process.state}:#{wf_name}", wf_solr_type, wf_solr_attrs)
|
114
|
-
add_solr_value(solr_doc, 'wf_swp', "#{process.state}:#{wf_name}:#{process.name}", wf_solr_type, wf_solr_attrs)
|
115
|
-
end
|
116
121
|
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
122
|
+
solr_doc[Solrizer.solr_name('wf_wps', :symbol)]&.uniq!
|
123
|
+
solr_doc[Solrizer.solr_name('wf_wsp', :symbol)]&.uniq!
|
124
|
+
solr_doc[Solrizer.solr_name('wf_swp', :symbol)]&.uniq!
|
125
|
+
solr_doc['workflow_status']&.uniq!
|
121
126
|
|
122
|
-
|
123
|
-
|
127
|
+
solr_doc
|
128
|
+
end
|
124
129
|
|
125
|
-
|
126
|
-
|
130
|
+
def inspect
|
131
|
+
"#<#{self.class.name}:#{object_id}>"
|
132
|
+
end
|
127
133
|
end
|
128
134
|
end
|
129
135
|
end
|
130
|
-
end
|
data/lib/dor/workflow/process.rb
CHANGED
@@ -1,108 +1,111 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Dor
|
2
|
-
module Workflow
|
3
|
-
|
4
|
-
|
4
|
+
module Workflow
|
5
|
+
class Process
|
6
|
+
attr_reader :owner, :repo, :workflow
|
5
7
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
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
|
+
@workflow = workflow
|
13
|
+
@repo = repo
|
14
|
+
if attrs.is_a? Nokogiri::XML::Node
|
15
|
+
init_from_node(attrs)
|
16
|
+
else
|
17
|
+
@attrs = attrs
|
18
|
+
end
|
16
19
|
end
|
17
|
-
end
|
18
20
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
21
|
+
def init_from_node(node)
|
22
|
+
@attrs = {
|
23
|
+
'name' => node['name'],
|
24
|
+
'sequence' => node['sequence'] ? node['sequence'].to_i : nil,
|
25
|
+
'status' => node['status'], # TODO: see how this affects argo
|
26
|
+
'lifecycle' => node['lifecycle'],
|
27
|
+
'label' => node.at_xpath('label/text()').to_s,
|
28
|
+
'batch_limit' => node['batch-limit'] ? node['batch-limit'].to_i : nil,
|
29
|
+
'error_limit' => node['error-limit'] ? node['error-limit'].to_i : nil,
|
30
|
+
'priority' => node['priority'] ? node['priority'].to_i : 0,
|
31
|
+
'prerequisite' => node.xpath('prereq').collect { |p|
|
32
|
+
repo = (p['repository'].nil? || p['repository'] == @repo) ? nil : p['repository']
|
33
|
+
wf = (p['workflow'].nil? || p['workflow'] == @workflow) ? nil : p['workflow']
|
34
|
+
[repo, wf, p.text.to_s].compact.join(':')
|
35
|
+
}
|
33
36
|
}
|
34
|
-
|
35
|
-
end
|
37
|
+
end
|
36
38
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
39
|
+
def name; @attrs['name']; end
|
40
|
+
def sequence; @attrs['sequence']; end
|
41
|
+
def lifecycle; @attrs['lifecycle']; end
|
42
|
+
def label; @attrs['label']; end
|
43
|
+
def batch_limit; @attrs['batch_limit']; end
|
44
|
+
def error_limit; @attrs['error_limit']; end
|
45
|
+
def error_message; @attrs['errorMessage']; end
|
46
|
+
def prerequisite; @attrs['prerequisite']; end
|
47
|
+
def status; @attrs['status']; end
|
48
|
+
def note; @attrs['note']; end
|
49
|
+
def version; @attrs['version']; end
|
50
|
+
def priority; @attrs['priority']; end
|
51
|
+
def completed?; status == 'completed'; end
|
52
|
+
def error?; status == 'error'; end
|
53
|
+
def waiting?; status == 'waiting'; end
|
54
|
+
def date_time; @attrs['datetime']; end
|
53
55
|
|
54
|
-
|
55
|
-
|
56
|
-
|
56
|
+
def archived?
|
57
|
+
@attrs['archived'] =~ /true$/i
|
58
|
+
end
|
57
59
|
|
58
|
-
|
59
|
-
|
60
|
-
|
60
|
+
def ready?
|
61
|
+
self.waiting? && !prerequisite.nil? && prerequisite.all? { |pr| (prq = owner[pr]) && prq.completed? }
|
62
|
+
end
|
61
63
|
|
62
|
-
|
63
|
-
|
64
|
-
|
64
|
+
def blocked?
|
65
|
+
self.waiting? && !prerequisite.nil? && prerequisite.any? { |pr| (prq = owner[pr]) && (prq.error? || prq.blocked?) }
|
66
|
+
end
|
65
67
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
68
|
+
def state
|
69
|
+
if blocked?
|
70
|
+
'blocked'
|
71
|
+
elsif ready?
|
72
|
+
'ready'
|
73
|
+
else
|
74
|
+
status
|
75
|
+
end
|
73
76
|
end
|
74
|
-
end
|
75
77
|
|
76
|
-
|
77
|
-
|
78
|
-
|
78
|
+
def attempts
|
79
|
+
@attrs['attempts'].to_i
|
80
|
+
end
|
79
81
|
|
80
|
-
|
81
|
-
|
82
|
-
|
82
|
+
def datetime
|
83
|
+
@attrs['datetime'] ? Time.parse(@attrs['datetime']) : nil
|
84
|
+
end
|
83
85
|
|
84
|
-
|
85
|
-
|
86
|
-
|
86
|
+
def elapsed
|
87
|
+
@attrs['elapsed'].nil? ? nil : @attrs['elapsed'].to_f
|
88
|
+
end
|
89
|
+
|
90
|
+
# Updates this object with the attributes passed in.
|
91
|
+
# @param info [Hash,Nokogiri::XML::Element,NilClass]
|
92
|
+
# @param new_owner [Dor::Workflow::Document]
|
93
|
+
def update!(info, new_owner)
|
94
|
+
raise ArgumentError, 'Owner can not be nil. It must be an instance of Dor::Workflow::Document' unless new_owner
|
87
95
|
|
88
|
-
|
89
|
-
|
90
|
-
# @param new_owner [Dor::Workflow::Document]
|
91
|
-
def update!(info, new_owner)
|
92
|
-
raise ArgumentError, 'Owner can not be nil. It must be an instance of Dor::Workflow::Document' unless new_owner
|
93
|
-
@owner = new_owner
|
94
|
-
return self if info.nil?
|
96
|
+
@owner = new_owner
|
97
|
+
return self if info.nil?
|
95
98
|
|
96
|
-
|
97
|
-
|
99
|
+
if info.is_a? Nokogiri::XML::Node
|
100
|
+
info = Hash[info.attributes.collect { |k, v| [k, v.value] }]
|
101
|
+
end
|
102
|
+
@attrs.merge! info
|
103
|
+
self
|
98
104
|
end
|
99
|
-
@attrs.merge! info
|
100
|
-
self
|
101
|
-
end
|
102
105
|
|
103
|
-
|
104
|
-
|
106
|
+
def to_hash
|
107
|
+
@attrs.reject { |k, v| v.nil? || v == 0 || (v.respond_to?(:empty?) && v.empty?) }
|
108
|
+
end
|
105
109
|
end
|
106
110
|
end
|
107
111
|
end
|
108
|
-
end
|