dor-services 5.32.1 → 6.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a6a98b91f456de3720fd592ee203e53147e89b316596af0e9f505b624a3fddf9
4
- data.tar.gz: dad70ca22ab235c15281acd92b9a609ddb081b2c1c577e4f94fa51cfe27075d3
3
+ metadata.gz: cddc117f7297f0e5610b46e5ef181dba30fb0fcd57d7a4f21309cd68a5d5eee8
4
+ data.tar.gz: 203483f92135bffbb04b40be6e4673153863eb305518f87922b8a7027797abe8
5
5
  SHA512:
6
- metadata.gz: bffd3df8d64f6206b0e7e2e56ba997b93ff62f0b6cf80b865251505498e8bb340cc820f962875157d3db540593003e1d98f311523acb2f64a1f0db6089043a73
7
- data.tar.gz: f23c44bc73d717373f4acebebaef225d2299ebc2b96db4f10d81d999a2b1546be15bd1ebaf6334f7b7cc43c46628d363938acb991ec694fe6d956cd9c628cf11
6
+ metadata.gz: 14cdd9ea0fa92d23c000de0f992209d9ceff820e143716b0c479ffde26c26c822c73f51f8d799e0ce6820f50beced8e2f0c69f0aca3266227a0341782f1a50ca
7
+ data.tar.gz: 4056a91b565637a56a126c35998ddbf1f1a8653821587d1a4ddba823a33df82b3a626a6747b0bc6bd6b8bd0cd6efb4e42c82178a698fbca300b33e9782198d37
@@ -81,6 +81,16 @@ module Dor
81
81
 
82
82
  require 'druid-tools'
83
83
 
84
+ autoload_under 'indexers' do
85
+ autoload :CompositeIndexer
86
+ autoload :DataIndexer
87
+ autoload :DescribableIndexer
88
+ autoload :EditableIndexer
89
+ autoload :IdentifiableIndexer
90
+ autoload :ProcessableIndexer
91
+ autoload :ReleasableIndexer
92
+ end
93
+
84
94
  # datastreams
85
95
  autoload_under 'datastreams' do
86
96
  autoload :AdministrativeMetadataDS
@@ -154,12 +164,12 @@ module Dor
154
164
  autoload :CleanupResetService
155
165
  autoload :PublicDescMetadataService
156
166
  autoload :PublicXmlService
167
+ autoload :ThumbnailService
157
168
  end
158
169
 
159
170
  # Workflow Classes
160
171
  module Workflow
161
172
  extend ActiveSupport::Autoload
162
- autoload :Graph
163
173
  autoload :Process
164
174
  autoload :Document
165
175
  end
@@ -37,10 +37,6 @@ class WorkflowDefinitionDs < ActiveFedora::OmDatastream
37
37
  add_child_node(ng_xml.at_xpath('/workflow-def'), :process, self, attributes)
38
38
  end
39
39
 
40
- def graph(parent = nil)
41
- Workflow::Graph.from_processes(repo, name, processes, parent)
42
- end
43
-
44
40
  def processes
45
41
  ng_xml.xpath('/workflow-def/process').collect do |node|
46
42
  Workflow::Process.new(repo, name, node)
@@ -49,17 +49,6 @@ module Dor
49
49
  @workflows ||= workflow.nodeset.collect { |wf_node| Workflow::Document.new wf_node.to_xml }
50
50
  end
51
51
 
52
- def graph(dir = nil)
53
- result = GraphViz.digraph(pid)
54
- sg = result.add_graph('rank') { |g| g[:rank => 'same'] }
55
- workflows.reject(&:nil?).each do |wf|
56
- g = wf.graph(result)
57
- sg.add_node(g.root.id) unless g.nil?
58
- end
59
- result['rankdir'] = dir || 'TB'
60
- result
61
- end
62
-
63
52
  # Finds the first workflow that is expedited, then returns the value of its priority
64
53
  #
65
54
  # @return [Integer] value of the priority. Defaults to 0 if none of the workflows are expedited
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dor
4
+ class CompositeIndexer
5
+ attr_reader :indexers
6
+ def initialize(*indexers)
7
+ @indexers = indexers
8
+ end
9
+
10
+ def new(resource:)
11
+ Instance.new(indexers, resource: resource)
12
+ end
13
+
14
+ class Instance
15
+ attr_reader :indexers, :resource
16
+ def initialize(indexers, resource:)
17
+ @resource = resource
18
+ @indexers = indexers.map { |i| i.new(resource: resource) }
19
+ end
20
+
21
+ # @return [Hash] the merged solr document for all the sub-indexers
22
+ def to_solr
23
+ indexers.map(&:to_solr).inject({}, &:merge)
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,14 @@
1
+ module Dor
2
+ # Indexing provided by ActiveFedora
3
+ class DataIndexer
4
+ include ActiveFedora::Indexing
5
+
6
+ attr_reader :resource
7
+ def initialize(resource:)
8
+ @resource = resource
9
+ end
10
+
11
+ delegate :create_date, :modified_date, :state, :pid, :inner_object,
12
+ :datastreams, :relationships, to: :resource
13
+ end
14
+ end
@@ -0,0 +1,58 @@
1
+ module Dor
2
+ class DescribableIndexer
3
+ attr_reader :resource
4
+ def initialize(resource:)
5
+ @resource = resource
6
+ end
7
+
8
+ # @return [Hash] the partial solr document for describable concerns
9
+ def to_solr
10
+ add_metadata_format_to_solr_doc.merge(add_mods_to_solr_doc)
11
+ end
12
+
13
+ def add_metadata_format_to_solr_doc
14
+ { 'metadata_format_ssim' => 'mods' }
15
+ end
16
+
17
+ def add_mods_to_solr_doc
18
+ solr_doc = {}
19
+ mods_sources = {
20
+ sw_title_display: %w(sw_display_title_tesim),
21
+ main_author_w_date: %w(sw_author_ssim sw_author_tesim),
22
+ sw_sort_author: %w(sw_author_sort_ssi),
23
+ sw_language_facet: %w(sw_language_ssim sw_language_tesim),
24
+ sw_genre: %w(sw_genre_ssim sw_genre_tesim),
25
+ format_main: %w(sw_format_ssim sw_format_tesim),
26
+ topic_facet: %w(sw_topic_ssim sw_topic_tesim),
27
+ era_facet: %w(sw_subject_temporal_ssim sw_subject_temporal_tesim),
28
+ geographic_facet: %w(sw_subject_geographic_ssim sw_subject_geographic_tesim),
29
+ [:term_values, :typeOfResource] => %w(mods_typeOfResource_ssim mods_typeOfResource_tesim),
30
+ pub_year_sort_str: %w(sw_pub_date_sort_ssi),
31
+ pub_year_int: %w(sw_pub_date_sort_isi),
32
+ pub_year_display_str: %w(sw_pub_date_facet_ssi)
33
+ }
34
+
35
+ mods_sources.each_pair do |meth, solr_keys|
36
+ vals = meth.is_a?(Array) ? resource.stanford_mods.send(meth.shift, *meth) : resource.stanford_mods.send(meth)
37
+
38
+ next if vals.nil? || (vals.respond_to?(:empty?) && vals.empty?)
39
+
40
+ solr_keys.each do |key|
41
+ solr_doc[key] ||= []
42
+ solr_doc[key].push(*vals)
43
+ end
44
+ # asterisk to avoid multi-dimensional array: push values, not the array
45
+ end
46
+
47
+ # convert multivalued fields to single value
48
+ %w(sw_pub_date_sort_ssi sw_pub_date_sort_isi sw_pub_date_facet_ssi).each do |key|
49
+ solr_doc[key] = solr_doc[key].first unless solr_doc[key].nil?
50
+ end
51
+ # some fields get explicit "(none)" placeholder values, mostly for faceting
52
+ %w(sw_language_tesim sw_genre_tesim sw_format_tesim).each do |key|
53
+ solr_doc[key] = ['(none)'] if solr_doc[key].nil? || solr_doc[key].empty?
54
+ end
55
+ solr_doc
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,23 @@
1
+ module Dor
2
+ class EditableIndexer
3
+ include SolrDocHelper
4
+
5
+ attr_reader :resource
6
+ def initialize(resource:)
7
+ @resource = resource
8
+ end
9
+
10
+ def to_solr
11
+ {}.tap do |solr_doc|
12
+ add_solr_value(solr_doc, 'default_rights', default_rights_for_indexing, :string, [:symbol])
13
+ add_solr_value(solr_doc, 'agreement', resource.agreement, :string, [:symbol]) if resource.agreement_object
14
+ add_solr_value(solr_doc, 'default_use_license_machine', resource.use_license, :string, [:stored_sortable])
15
+ end
16
+ end
17
+
18
+ # @return [String] A description of the rights defined in the default object rights datastream. Can be 'Stanford', 'World', 'Dark' or 'None'
19
+ def default_rights_for_indexing
20
+ RightsMetadataDS::RIGHTS_TYPE_CODES.fetch(resource.default_rights, 'Unrecognized default rights value')
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,84 @@
1
+ module Dor
2
+ class IdentifiableIndexer
3
+ include SolrDocHelper
4
+
5
+ attr_reader :resource
6
+ def initialize(resource:)
7
+ @resource = resource
8
+ end
9
+
10
+ ## Module-level variables, shared between ALL mixin includers (and ALL *their* includers/extenders)!
11
+ ## used for caching found values
12
+ @@collection_hash = {}
13
+ @@apo_hash = {}
14
+
15
+ # @return [Hash] the partial solr document for identifiable concerns
16
+ def to_solr
17
+ solr_doc = {}
18
+ resource.assert_content_model
19
+
20
+ solr_doc[Dor::INDEX_VERSION_FIELD] = Dor::VERSION
21
+ solr_doc['indexed_at_dtsi'] = Time.now.utc.xmlschema
22
+ resource.datastreams.values.each do |ds|
23
+ add_solr_value(solr_doc, 'ds_specs', ds.datastream_spec_string, :string, [:symbol]) unless ds.new?
24
+ end
25
+
26
+ add_solr_value(solr_doc, 'title_sort', resource.label, :string, [:stored_sortable])
27
+
28
+ rels_doc = Nokogiri::XML(resource.datastreams['RELS-EXT'].content)
29
+ ns_hash = {'hydra' => 'http://projecthydra.org/ns/relations#', 'fedora' => 'info:fedora/fedora-system:def/relations-external#', 'rdf' => 'http://www.w3.org/1999/02/22-rdf-syntax-ns#'}
30
+ apos = rels_doc.search('//rdf:RDF/rdf:Description/hydra:isGovernedBy', ns_hash)
31
+ collections = rels_doc.search('//rdf:RDF/rdf:Description/fedora:isMemberOfCollection', ns_hash)
32
+ solrize_related_obj_titles(solr_doc, apos, @@apo_hash, 'apo_title', 'nonhydrus_apo_title', 'hydrus_apo_title')
33
+ solrize_related_obj_titles(solr_doc, collections, @@collection_hash, 'collection_title', 'nonhydrus_collection_title', 'hydrus_collection_title')
34
+ solr_doc['public_dc_relation_tesim'] ||= solr_doc['collection_title_tesim'] if solr_doc['collection_title_tesim']
35
+ solr_doc['metadata_source_ssi'] = identity_metadata_source
36
+ solr_doc
37
+ end
38
+
39
+ # @return [String] calculated value for Solr index
40
+ def identity_metadata_source
41
+ if resource.identityMetadata.otherId('catkey').first ||
42
+ resource.identityMetadata.otherId('barcode').first
43
+ 'Symphony'
44
+ else
45
+ 'DOR'
46
+ end
47
+ end
48
+
49
+ private
50
+
51
+ def solrize_related_obj_titles(solr_doc, relationships, title_hash, union_field_name, nonhydrus_field_name, hydrus_field_name)
52
+ # TODO: if you wanted to get a little fancier, you could also solrize a 2 level hierarchy and display using hierarchial facets, like
53
+ # ["SOURCE", "SOURCE : TITLE"] (e.g. ["Hydrus", "Hydrus : Special Collections"], see (exploded) tags in IdentityMetadataDS#to_solr).
54
+ title_type = :symbol # we'll get an _ssim because of the type
55
+ title_attrs = [:stored_searchable] # we'll also get a _tesim from this attr
56
+ relationships.each do |rel_node|
57
+ rel_druid = rel_node['rdf:resource']
58
+ next unless rel_druid # TODO: warning here would also be useful
59
+ rel_druid = rel_druid.gsub('info:fedora/', '')
60
+
61
+ # populate cache if necessary
62
+ unless title_hash.key?(rel_druid)
63
+ begin
64
+ related_obj = Dor.find(rel_druid)
65
+ related_obj_title = get_related_obj_display_title(related_obj, rel_druid)
66
+ is_from_hydrus = (related_obj && related_obj.tags.include?('Project : Hydrus'))
67
+ title_hash[rel_druid] = {'related_obj_title' => related_obj_title, 'is_from_hydrus' => is_from_hydrus}
68
+ rescue ActiveFedora::ObjectNotFoundError
69
+ # This may happen if the given APO or Collection does not exist (bad data)
70
+ title_hash[rel_druid] = {'related_obj_title' => rel_druid, 'is_from_hydrus' => false}
71
+ end
72
+ end
73
+
74
+ # cache should definitely be populated, so just use that to write solr field
75
+ if title_hash[rel_druid]['is_from_hydrus']
76
+ add_solr_value(solr_doc, hydrus_field_name, title_hash[rel_druid]['related_obj_title'], title_type, title_attrs)
77
+ else
78
+ add_solr_value(solr_doc, nonhydrus_field_name, title_hash[rel_druid]['related_obj_title'], title_type, title_attrs)
79
+ end
80
+ add_solr_value(solr_doc, union_field_name, title_hash[rel_druid]['related_obj_title'], title_type, title_attrs)
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,70 @@
1
+ module Dor
2
+ class ProcessableIndexer
3
+ include SolrDocHelper
4
+
5
+ attr_reader :resource
6
+ def initialize(resource:)
7
+ @resource = resource
8
+ end
9
+
10
+ # @return [Hash] the partial solr document for processable concerns
11
+ def to_solr
12
+ solr_doc = {}
13
+ sortable_milestones = {}
14
+ current_version = '1'
15
+ begin
16
+ current_version = resource.versionMetadata.current_version_id
17
+ rescue StandardError
18
+ end
19
+ current_version_num = current_version.to_i
20
+
21
+ if resource.respond_to?('versionMetadata')
22
+ # add an entry with version id, tag and description for each version
23
+ while current_version_num > 0
24
+ new_val = "#{current_version_num};#{resource.versionMetadata.tag_for_version(current_version_num.to_s)};#{resource.versionMetadata.description_for_version(current_version_num.to_s)}"
25
+ add_solr_value(solr_doc, 'versions', new_val, :string, [:displayable])
26
+ current_version_num -= 1
27
+ end
28
+ end
29
+
30
+ resource.milestones.each do |milestone|
31
+ timestamp = milestone[:at].utc.xmlschema
32
+ sortable_milestones[milestone[:milestone]] ||= []
33
+ sortable_milestones[milestone[:milestone]] << timestamp
34
+ milestone[:version] ||= current_version
35
+ solr_doc['lifecycle_ssim'] ||= []
36
+ solr_doc['lifecycle_ssim'] << milestone[:milestone]
37
+ add_solr_value(solr_doc, 'lifecycle', "#{milestone[:milestone]}:#{timestamp};#{milestone[:version]}", :symbol)
38
+ end
39
+
40
+ sortable_milestones.each do |milestone, unordered_dates|
41
+ dates = unordered_dates.sort
42
+ # create the published_dttsi and published_day fields and the like
43
+ dates.each do |date|
44
+ solr_doc["#{milestone}_dttsim"] ||= []
45
+ solr_doc["#{milestone}_dttsim"] << date unless solr_doc["#{milestone}_dttsim"].include?(date)
46
+ end
47
+ # fields for OAI havester to sort on: _dttsi is trie date +stored +indexed (single valued, i.e. sortable)
48
+ solr_doc["#{milestone}_earliest_dttsi"] = dates.first
49
+ solr_doc["#{milestone}_latest_dttsi"] = dates.last
50
+ end
51
+ solr_doc['status_ssi'] = resource.status # status is singular (i.e. the current one)
52
+ solr_doc['current_version_isi'] = current_version.to_i
53
+ solr_doc['modified_latest_dttsi'] = resource.modified_date.to_datetime.utc.strftime('%FT%TZ')
54
+ add_solr_value(solr_doc, 'rights', resource.rights, :string, [:symbol]) if resource.respond_to? :rights
55
+
56
+ status_info_hash = resource.status_info
57
+ status_code = status_info_hash[:status_code]
58
+ add_solr_value(solr_doc, 'processing_status_text', simplified_status_code_disp_txt(status_code), :string, [:stored_sortable])
59
+ solr_doc['processing_status_code_isi'] = status_code # no _isi in Solrizer's default descriptors
60
+
61
+ solr_doc
62
+ end
63
+
64
+ # @return [String] text translation of the status code, minus any trailing parenthetical explanation
65
+ # e.g. 'In accessioning (described)' and 'In accessioning (described, published)' both return 'In accessioning'
66
+ def simplified_status_code_disp_txt(status_code)
67
+ Processable::STATUS_CODE_DISP_TXT[status_code].gsub(/\(.*\)$/, '').strip
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,26 @@
1
+ module Dor
2
+ class ReleasableIndexer
3
+ include SolrDocHelper
4
+
5
+ attr_reader :resource
6
+ def initialize(resource:)
7
+ @resource = resource
8
+ end
9
+
10
+ # @return [Hash] the partial solr document for releasable concerns
11
+ def to_solr
12
+ solr_doc = {}
13
+
14
+ # TODO: sort of worried about the performance impact in bulk reindex
15
+ # situations, since released_for recurses all parent collections. jmartin 2015-07-14
16
+ resource.released_for(true).each { |release_target, release_info|
17
+ add_solr_value(solr_doc, 'released_to', release_target, :symbol, []) if release_info['release']
18
+ }
19
+
20
+ # TODO: need to solrize whether item is released to purl? does released_for return that?
21
+ # logic is: "True when there is a published lifecycle and Access Rights is anything but Dark"
22
+
23
+ solr_doc
24
+ end
25
+ end
26
+ end
@@ -7,6 +7,10 @@ module Dor
7
7
  include Describable
8
8
  include Versionable
9
9
  include Processable
10
- include Preservable
10
+ class_attribute :resource_indexer
11
+
12
+ def to_solr
13
+ resource_indexer.new(resource: self).to_solr
14
+ end
11
15
  end
12
16
  end
@@ -7,5 +7,13 @@ module Dor
7
7
  has_metadata :name => 'administrativeMetadata', :type => Dor::AdministrativeMetadataDS, :label => 'Administrative Metadata'
8
8
  has_metadata :name => 'roleMetadata', :type => Dor::RoleMetadataDS, :label => 'Role Metadata'
9
9
  has_metadata :name => 'defaultObjectRights', :type => Dor::DefaultObjectRightsDS, :label => 'Default Object Rights'
10
+
11
+ self.resource_indexer = CompositeIndexer.new(
12
+ DataIndexer,
13
+ DescribableIndexer,
14
+ EditableIndexer,
15
+ IdentifiableIndexer,
16
+ ProcessableIndexer
17
+ )
10
18
  end
11
19
  end
@@ -1,3 +1,5 @@
1
- class Dor::Agreement < ::Dor::Item
2
- has_object_type 'agreement'
1
+ module Dor
2
+ class Agreement < Item
3
+ has_object_type 'agreement'
4
+ end
3
5
  end
@@ -3,5 +3,12 @@ module Dor
3
3
  include Releaseable
4
4
 
5
5
  has_object_type 'collection'
6
+
7
+ self.resource_indexer = CompositeIndexer.new(
8
+ DescribableIndexer,
9
+ IdentifiableIndexer,
10
+ ProcessableIndexer,
11
+ ReleasableIndexer
12
+ )
6
13
  end
7
14
  end
@@ -64,57 +64,6 @@ module Dor
64
64
  PublicDescMetadataService.new(self).to_xml(**options)
65
65
  end
66
66
 
67
- def to_solr(solr_doc = {}, *args)
68
- solr_doc = super solr_doc, *args
69
- add_metadata_format_to_solr_doc(solr_doc)
70
- add_mods_to_solr_doc(solr_doc)
71
- end
72
-
73
- def add_metadata_format_to_solr_doc(solr_doc)
74
- solr_doc['metadata_format_ssim'] ||= []
75
- solr_doc['metadata_format_ssim'] += ['mods']
76
- end
77
-
78
- def add_mods_to_solr_doc(solr_doc)
79
- mods_sources = {
80
- sw_title_display: %w(sw_display_title_tesim),
81
- main_author_w_date: %w(sw_author_ssim sw_author_tesim),
82
- sw_sort_author: %w(sw_author_sort_ssi),
83
- sw_language_facet: %w(sw_language_ssim sw_language_tesim),
84
- sw_genre: %w(sw_genre_ssim sw_genre_tesim),
85
- format_main: %w(sw_format_ssim sw_format_tesim),
86
- topic_facet: %w(sw_topic_ssim sw_topic_tesim),
87
- era_facet: %w(sw_subject_temporal_ssim sw_subject_temporal_tesim),
88
- geographic_facet: %w(sw_subject_geographic_ssim sw_subject_geographic_tesim),
89
- [:term_values, :typeOfResource] => %w(mods_typeOfResource_ssim mods_typeOfResource_tesim),
90
- pub_year_sort_str: %w(sw_pub_date_sort_ssi),
91
- pub_year_int: %w(sw_pub_date_sort_isi),
92
- pub_year_display_str: %w(sw_pub_date_facet_ssi)
93
- }
94
-
95
- mods_sources.each_pair do |meth, solr_keys|
96
- vals = meth.is_a?(Array) ? stanford_mods.send(meth.shift, *meth) : stanford_mods.send(meth)
97
-
98
- next if vals.nil? || (vals.respond_to?(:empty?) && vals.empty?)
99
-
100
- solr_keys.each do |key|
101
- solr_doc[key] ||= []
102
- solr_doc[key].push *vals
103
- end
104
- # asterisk to avoid multi-dimensional array: push values, not the array
105
- end
106
-
107
- # convert multivalued fields to single value
108
- %w(sw_pub_date_sort_ssi sw_pub_date_sort_isi sw_pub_date_facet_ssi).each do |key|
109
- solr_doc[key] = solr_doc[key].first unless solr_doc[key].nil?
110
- end
111
- # some fields get explicit "(none)" placeholder values, mostly for faceting
112
- %w(sw_language_tesim sw_genre_tesim sw_format_tesim).each do |key|
113
- solr_doc[key] = ['(none)'] if solr_doc[key].nil? || solr_doc[key].empty?
114
- end
115
- solr_doc
116
- end
117
-
118
67
  # @param [Boolean] force Overwrite existing XML
119
68
  # @return [String] descMetadata.content XML
120
69
  def set_desc_metadata_using_label(force = false)
@@ -45,14 +45,6 @@ module Dor
45
45
  :uri => 'http://opendatacommons.org/licenses/odbl/1.0/' }
46
46
  }.freeze
47
47
 
48
- def to_solr(solr_doc = {}, *args)
49
- solr_doc = super(solr_doc, *args)
50
- add_solr_value(solr_doc, 'default_rights', default_rights_for_indexing, :string, [:symbol])
51
- add_solr_value(solr_doc, 'agreement', agreement, :string, [:symbol]) if agreement_object
52
- add_solr_value(solr_doc, 'default_use_license_machine', use_license, :string, [:stored_sortable])
53
- solr_doc
54
- end
55
-
56
48
  # Adds a person or group to a role in the APO role metadata datastream
57
49
  #
58
50
  # @param role [String] the role the group or person will be filed under, ex. dor-apo-manager
@@ -280,11 +272,6 @@ module Dor
280
272
  end
281
273
  end
282
274
 
283
- # @return [String] A description of the rights defined in the default object rights datastream. Can be 'Stanford', 'World', 'Dark' or 'None'
284
- def default_rights_for_indexing
285
- RightsMetadataDS::RIGHTS_TYPE_CODES.fetch(default_rights, 'Unrecognized default rights value')
286
- end
287
-
288
275
  # Set the rights in default object rights
289
276
  # @param rights [String] Stanford, World, Dark, or None
290
277
  def default_rights=(rights)
@@ -1,7 +1,6 @@
1
1
  module Dor
2
2
  module Identifiable
3
3
  extend ActiveSupport::Concern
4
- include SolrDocHelper
5
4
 
6
5
  # ids for previous and current catkeys
7
6
  CATKEY_TYPE_ID = 'catkey'.freeze
@@ -18,13 +17,13 @@ module Dor
18
17
  @object_type = str
19
18
  Dor.registered_classes[str] = self
20
19
  end
21
- end
22
20
 
23
- def initialize(attrs = {})
24
- if Dor::Config.suri.mint_ids && !attrs[:pid]
25
- attrs = attrs.merge!({:pid => Dor::SuriService.mint_id, :new_object => true})
21
+ # Overrides the method in ActiveFedora to mint a pid using SURI rather
22
+ # than the default Fedora sequence
23
+ def assign_pid(_obj)
24
+ return Dor::SuriService.mint_id if Dor::Config.suri.mint_ids
25
+ super
26
26
  end
27
- super
28
27
  end
29
28
 
30
29
  # helper method to get the tags as an array
@@ -38,44 +37,6 @@ module Dor
38
37
  content_tag.size == 1 ? content_tag[0].split(':').last.strip : ''
39
38
  end
40
39
 
41
- ## Module-level variables, shared between ALL mixin includers (and ALL *their* includers/extenders)!
42
- ## used for caching found values
43
- @@collection_hash = {}
44
- @@apo_hash = {}
45
-
46
- def to_solr(solr_doc = {}, *args)
47
- assert_content_model
48
- solr_doc = super(solr_doc, *args)
49
-
50
- solr_doc[Dor::INDEX_VERSION_FIELD] = Dor::VERSION
51
- solr_doc['indexed_at_dtsi'] = Time.now.utc.xmlschema
52
- datastreams.values.each do |ds|
53
- add_solr_value(solr_doc, 'ds_specs', ds.datastream_spec_string, :string, [:symbol]) unless ds.new?
54
- end
55
-
56
- add_solr_value(solr_doc, 'title_sort', label, :string, [:stored_sortable])
57
-
58
- rels_doc = Nokogiri::XML(datastreams['RELS-EXT'].content)
59
- ns_hash = {'hydra' => 'http://projecthydra.org/ns/relations#', 'fedora' => 'info:fedora/fedora-system:def/relations-external#', 'rdf' => 'http://www.w3.org/1999/02/22-rdf-syntax-ns#'}
60
- apos = rels_doc.search('//rdf:RDF/rdf:Description/hydra:isGovernedBy', ns_hash)
61
- collections = rels_doc.search('//rdf:RDF/rdf:Description/fedora:isMemberOfCollection', ns_hash)
62
- solrize_related_obj_titles(solr_doc, apos, @@apo_hash, 'apo_title', 'nonhydrus_apo_title', 'hydrus_apo_title')
63
- solrize_related_obj_titles(solr_doc, collections, @@collection_hash, 'collection_title', 'nonhydrus_collection_title', 'hydrus_collection_title')
64
- solr_doc['public_dc_relation_tesim'] ||= solr_doc['collection_title_tesim'] if solr_doc['collection_title_tesim']
65
- solr_doc['metadata_source_ssi'] = identity_metadata_source
66
- solr_doc
67
- end
68
-
69
- # @return [String] calculated value for Solr index
70
- def identity_metadata_source
71
- if identityMetadata.otherId('catkey').first ||
72
- identityMetadata.otherId('barcode').first
73
- 'Symphony'
74
- else
75
- 'DOR'
76
- end
77
- end
78
-
79
40
  # Convenience method
80
41
  def source_id
81
42
  identityMetadata.sourceId
@@ -268,40 +229,5 @@ module Dor
268
229
  end
269
230
  end
270
231
  end
271
-
272
- private
273
-
274
- def solrize_related_obj_titles(solr_doc, relationships, title_hash, union_field_name, nonhydrus_field_name, hydrus_field_name)
275
- # TODO: if you wanted to get a little fancier, you could also solrize a 2 level hierarchy and display using hierarchial facets, like
276
- # ["SOURCE", "SOURCE : TITLE"] (e.g. ["Hydrus", "Hydrus : Special Collections"], see (exploded) tags in IdentityMetadataDS#to_solr).
277
- title_type = :symbol # we'll get an _ssim because of the type
278
- title_attrs = [:stored_searchable] # we'll also get a _tesim from this attr
279
- relationships.each do |rel_node|
280
- rel_druid = rel_node['rdf:resource']
281
- next unless rel_druid # TODO: warning here would also be useful
282
- rel_druid = rel_druid.gsub('info:fedora/', '')
283
-
284
- # populate cache if necessary
285
- unless title_hash.key?(rel_druid)
286
- begin
287
- related_obj = Dor.find(rel_druid)
288
- related_obj_title = get_related_obj_display_title(related_obj, rel_druid)
289
- is_from_hydrus = (related_obj && related_obj.tags.include?('Project : Hydrus'))
290
- title_hash[rel_druid] = {'related_obj_title' => related_obj_title, 'is_from_hydrus' => is_from_hydrus}
291
- rescue ActiveFedora::ObjectNotFoundError
292
- # This may happen if the given APO or Collection does not exist (bad data)
293
- title_hash[rel_druid] = {'related_obj_title' => rel_druid, 'is_from_hydrus' => false}
294
- end
295
- end
296
-
297
- # cache should definitely be populated, so just use that to write solr field
298
- if title_hash[rel_druid]['is_from_hydrus']
299
- add_solr_value(solr_doc, hydrus_field_name, title_hash[rel_druid]['related_obj_title'], title_type, title_attrs)
300
- else
301
- add_solr_value(solr_doc, nonhydrus_field_name, title_hash[rel_druid]['related_obj_title'], title_type, title_attrs)
302
- end
303
- add_solr_value(solr_doc, union_field_name, title_hash[rel_druid]['related_obj_title'], title_type, title_attrs)
304
- end
305
- end
306
232
  end
307
233
  end
@@ -3,7 +3,6 @@ require 'equivalent-xml'
3
3
  module Dor
4
4
  module Processable
5
5
  extend ActiveSupport::Concern
6
- include SolrDocHelper
7
6
 
8
7
  included do
9
8
  has_metadata :name => 'workflows', :type => Dor::WorkflowDs, :label => 'Workflows', :control_group => 'E'
@@ -147,65 +146,6 @@ module Dor
147
146
  result
148
147
  end
149
148
 
150
- # @return [String] text translation of the status code, minus any trailing parenthetical explanation
151
- # e.g. 'In accessioning (described)' and 'In accessioning (described, published)' both return 'In accessioning'
152
- def simplified_status_code_disp_txt(status_code)
153
- STATUS_CODE_DISP_TXT[status_code].gsub(/\(.*\)$/, '').strip
154
- end
155
-
156
- def to_solr(solr_doc = {}, *args)
157
- solr_doc = super(solr_doc, *args)
158
- sortable_milestones = {}
159
- current_version = '1'
160
- begin
161
- current_version = versionMetadata.current_version_id
162
- rescue
163
- end
164
- current_version_num = current_version.to_i
165
-
166
- if self.respond_to?('versionMetadata')
167
- # add an entry with version id, tag and description for each version
168
- while current_version_num > 0
169
- new_val = "#{current_version_num};#{versionMetadata.tag_for_version(current_version_num.to_s)};#{versionMetadata.description_for_version(current_version_num.to_s)}"
170
- add_solr_value(solr_doc, 'versions', new_val, :string, [:displayable])
171
- current_version_num -= 1
172
- end
173
- end
174
-
175
- milestones.each do |milestone|
176
- timestamp = milestone[:at].utc.xmlschema
177
- sortable_milestones[milestone[:milestone]] ||= []
178
- sortable_milestones[milestone[:milestone]] << timestamp
179
- milestone[:version] ||= current_version
180
- solr_doc['lifecycle_ssim'] ||= []
181
- solr_doc['lifecycle_ssim'] << milestone[:milestone]
182
- add_solr_value(solr_doc, 'lifecycle', "#{milestone[:milestone]}:#{timestamp};#{milestone[:version]}", :symbol)
183
- end
184
-
185
- sortable_milestones.each do |milestone, unordered_dates|
186
- dates = unordered_dates.sort
187
- # create the published_dttsi and published_day fields and the like
188
- dates.each do |date|
189
- solr_doc["#{milestone}_dttsim"] ||= []
190
- solr_doc["#{milestone}_dttsim"] << date unless solr_doc["#{milestone}_dttsim"].include?(date)
191
- end
192
- # fields for OAI havester to sort on: _dttsi is trie date +stored +indexed (single valued, i.e. sortable)
193
- solr_doc["#{milestone}_earliest_dttsi"] = dates.first
194
- solr_doc["#{milestone}_latest_dttsi" ] = dates.last
195
- end
196
- solr_doc['status_ssi'] = status # status is singular (i.e. the current one)
197
- solr_doc['current_version_isi'] = current_version.to_i
198
- solr_doc['modified_latest_dttsi'] = modified_date.to_datetime.utc.strftime('%FT%TZ')
199
- add_solr_value(solr_doc, 'rights', rights, :string, [:symbol]) if self.respond_to? :rights
200
-
201
- status_info_hash = status_info
202
- status_code = status_info_hash[:status_code]
203
- add_solr_value(solr_doc, 'processing_status_text', simplified_status_code_disp_txt(status_code), :string, [:stored_sortable])
204
- solr_doc['processing_status_code_isi'] = status_code # no _isi in Solrizer's default descriptors
205
-
206
- solr_doc
207
- end
208
-
209
149
  # Initilizes workflow for the object in the workflow service
210
150
  # It will set the priorty of the new workflow to the current_priority if it is > 0
211
151
  # It will set lane_id from the item's APO default workflow lane
@@ -3,50 +3,17 @@ require 'fileutils'
3
3
 
4
4
  module Dor
5
5
  module Publishable
6
+ extend Deprecation
6
7
  extend ActiveSupport::Concern
8
+ self.deprecation_horizon = 'dor-services version 7.0.0'
7
9
 
8
10
  # Compute the thumbnail for this object following the rules at https://consul.stanford.edu/display/chimera/The+Rules+of+Thumb
11
+ # Used by PublicXmlService
9
12
  # @return [String] the computed thumb filename, with the druid prefix and a slash in front of it, e.g. oo000oo0001/filenamewith space.jp2
10
13
  def thumb
11
- return unless respond_to?(:contentMetadata) && !contentMetadata.nil?
12
- cm = contentMetadata.ng_xml
13
- mime_type_finder = "@mimetype='image/jp2' or @mimeType='image/jp2'" # allow the mimetype attribute to be lower or camelcase when searching to make it more robust
14
- thumb_image=nil
15
-
16
- # 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
17
- thumb_xpath_finders = [
18
- # first find a file of mimetype jp2 explicitly marked as a thumb in the resource type and with a thumb=yes attribute
19
- {image_type: 'local', finder: "/contentMetadata/resource[@type='thumb' and @thumb='yes']/file[#{mime_type_finder}]"},
20
- # same thing for external files
21
- {image_type: 'external', finder: "/contentMetadata/resource[@type='thumb' and @thumb='yes']/externalFile[#{mime_type_finder}]"},
22
- # next find any image or page resource types with the thumb=yes attribute of mimetype jp2
23
- {image_type: 'local', finder: "/contentMetadata/resource[(@type='page' or @type='image') and @thumb='yes']/file[#{mime_type_finder}]"},
24
- # same thing for external file
25
- {image_type: 'external', finder: "/contentMetadata/resource[(@type='page' or @type='image') and @thumb='yes']/externalFile[#{mime_type_finder}]"},
26
- # next find a file of mimetype jp2 and resource type=thumb but not marked with the thumb directive
27
- {image_type: 'local', finder: "/contentMetadata/resource[@type='thumb']/file[#{mime_type_finder}]"},
28
- # same thing for external file
29
- {image_type: 'external', finder: "/contentMetadata/resource[@type='thumb']/externalFile[#{mime_type_finder}]"},
30
- # finally find the first page or image resource of mimetype jp2
31
- {image_type: 'local', finder: "/contentMetadata/resource[@type='page' or @type='image']/file[#{mime_type_finder}]"},
32
- # same thing for external file
33
- {image_type: 'external', finder: "/contentMetadata/resource[@type='page' or @type='image']/externalFile[#{mime_type_finder}]"}
34
- ]
35
-
36
- thumb_xpath_finders.each do |search_path|
37
- thumb_files = cm.xpath(search_path[:finder]) # look for a thumb
38
- if thumb_files.size > 0 # if we find one, return the filename based on whether it is a local file or external file
39
- if search_path[:image_type] == 'local'
40
- thumb_image="#{remove_druid_prefix}/#{thumb_files[0]['id']}"
41
- else
42
- thumb_image="#{remove_druid_prefix(thumb_files[0]['objectId'])}/#{thumb_files[0]['fileId']}"
43
- end
44
- break # break out of the loop so we stop searching
45
- end
46
- end
47
-
48
- thumb_image
14
+ ThumbnailService.new(self).thumb
49
15
  end
16
+ deprecation_deprecate :thumb
50
17
 
51
18
  # Return a URI encoded version of the thumb image for use by indexers (leaving the extension of the filename)
52
19
  # @return [String] URI encoded version of the thumb with the druid prefix, e.g. oo000oo0001%2Ffilenamewith%20space.jp2
@@ -57,6 +24,7 @@ module Dor
57
24
  thumb_filename=thumb_image.split(/#{pid_regex}[\/]/).last # everything after the druid
58
25
  "#{thumb_druid}%2F#{ERB::Util.url_encode(thumb_filename)}"
59
26
  end
27
+ deprecation_deprecate :encoded_thumb
60
28
 
61
29
  # Return a full qualified thumbnail image URL if the thumb is computable
62
30
  # @return [String] fully qualified image URL for the computed thumbnail, e.g. https://stacks.stanford.edu/image/iiif/oo000oo0001%2Ffilenamewith%20space/full
@@ -65,6 +33,7 @@ module Dor
65
33
  thumb_basename=File.basename(encoded_thumb, File.extname(encoded_thumb)) # strip the extension for URL generation
66
34
  "https://#{Dor::Config.stacks.host}/image/iiif/#{thumb_basename}/full/!400,400/0/default.jpg"
67
35
  end
36
+ deprecation_deprecate :thumb_url
68
37
 
69
38
  # strips away the relationships that should not be shown in public desc metadata
70
39
  # @return [Nokogiri::XML]
@@ -304,20 +304,5 @@ module Dor
304
304
  end
305
305
  new_tags
306
306
  end
307
-
308
- def to_solr(solr_doc = {}, *args)
309
- solr_doc = super(solr_doc, *args)
310
-
311
- # TODO: sort of worried about the performance impact in bulk reindex
312
- # situations, since released_for recurses all parent collections. jmartin 2015-07-14
313
- released_for(true).each { |release_target, release_info|
314
- add_solr_value(solr_doc, 'released_to', release_target, :symbol, []) if release_info['release']
315
- }
316
-
317
- # TODO: need to solrize whether item is released to purl? does released_for return that?
318
- # logic is: "True when there is a published lifecycle and Access Rights is anything but Dark"
319
-
320
- solr_doc
321
- end
322
307
  end
323
308
  end
@@ -4,12 +4,21 @@ module Dor
4
4
  include Embargoable
5
5
  include Publishable
6
6
  include Itemizable
7
+ include Preservable
7
8
  include Assembleable
8
9
  include Contentable
9
10
  include Geoable
10
11
  include Releaseable
11
12
 
12
13
  has_object_type 'item'
14
+
15
+ self.resource_indexer = CompositeIndexer.new(
16
+ DataIndexer,
17
+ DescribableIndexer,
18
+ IdentifiableIndexer,
19
+ ProcessableIndexer,
20
+ ReleasableIndexer
21
+ )
13
22
  end
14
23
  end
15
24
 
@@ -4,5 +4,12 @@ module Dor
4
4
 
5
5
  has_many :members, :property => :is_member_of_collection, :class_name => 'ActiveFedora::Base'
6
6
  has_object_type 'set'
7
+
8
+ self.resource_indexer = CompositeIndexer.new(
9
+ DataIndexer,
10
+ DescribableIndexer,
11
+ IdentifiableIndexer,
12
+ ProcessableIndexer
13
+ )
7
14
  end
8
15
  end
@@ -8,6 +8,13 @@ module Dor
8
8
  has_object_type 'workflow'
9
9
  has_metadata :name => 'workflowDefinition', :type => Dor::WorkflowDefinitionDs, :label => 'Workflow Definition'
10
10
 
11
+ self.resource_indexer = CompositeIndexer.new(
12
+ DataIndexer,
13
+ DescribableIndexer,
14
+ IdentifiableIndexer,
15
+ ProcessableIndexer
16
+ )
17
+
11
18
  def self.find_by_name(name)
12
19
  Dor::WorkflowObject.where(Solrizer.solr_name('workflow_name', :symbol) => name).first
13
20
  end
@@ -38,10 +45,6 @@ module Dor
38
45
  datastreams['workflowDefinition']
39
46
  end
40
47
 
41
- def graph(*args)
42
- definition.graph *args
43
- end
44
-
45
48
  def generate_initial_workflow
46
49
  datastreams['workflowDefinition'].initial_workflow
47
50
  end
@@ -5,7 +5,7 @@ module Dor
5
5
  def initialize(object)
6
6
  @object = object
7
7
  end
8
-
8
+
9
9
  def to_xml
10
10
  pub = Nokogiri::XML('<publicObject/>').root
11
11
  pub['id'] = object.pid
@@ -21,8 +21,10 @@ module Dor
21
21
  pub.add_child(Nokogiri::XML(object.generate_public_desc_md).root)
22
22
  pub.add_child(release_xml.root) unless release_xml.xpath('//release').children.size == 0 # If there are no release_tags, this prevents an empty <releaseData/> from being added
23
23
  # Note we cannot base this on if an individual object has release tags or not, because the collection may cause one to be generated for an item,
24
- # so we need to calculate it and then look at the final result.s
25
- pub.add_child(Nokogiri("<thumb>#{object.thumb}</thumb>").root) unless object.thumb.nil?
24
+ # so we need to calculate it and then look at the final result.
25
+
26
+ thumb = ThumbnailService.new(object).thumb
27
+ pub.add_child(Nokogiri("<thumb>#{thumb}</thumb>").root) unless thumb.nil?
26
28
 
27
29
  new_pub = Nokogiri::XML(pub.to_xml) { |x| x.noblanks }
28
30
  new_pub.encoding = 'UTF-8'
@@ -0,0 +1,55 @@
1
+ module Dor
2
+ # Responsible for finding a path to a thumbnail based on the contentMetadata of an object
3
+ class ThumbnailService
4
+ # 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'".freeze
6
+
7
+ # 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
+ THUMB_XPATH_FINDERS = [
9
+ # 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}]"},
11
+ # same thing for external files
12
+ { image_type: 'external', finder: "/contentMetadata/resource[@type='thumb' and @thumb='yes']/externalFile[#{MIME_TYPE_FINDER}]"},
13
+ # 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}]"},
15
+ # same thing for external file
16
+ { image_type: 'external', finder: "/contentMetadata/resource[(@type='page' or @type='image') and @thumb='yes']/externalFile[#{MIME_TYPE_FINDER}]"},
17
+ # 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}]"},
19
+ # same thing for external file
20
+ { image_type: 'external', finder: "/contentMetadata/resource[@type='thumb']/externalFile[#{MIME_TYPE_FINDER}]"},
21
+ # 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}]"},
23
+ # same thing for external file
24
+ { image_type: 'external', finder: "/contentMetadata/resource[@type='page' or @type='image']/externalFile[#{MIME_TYPE_FINDER}]"}
25
+ ].freeze
26
+
27
+ # @params [Dor::Item] object
28
+ def initialize(object)
29
+ @object = object
30
+ end
31
+
32
+ attr_reader :object
33
+
34
+ # @return [String] the computed thumb filename, with the druid prefix and a slash in front of it, e.g. oo000oo0001/filenamewith space.jp2
35
+ def thumb
36
+ return unless object.respond_to?(:contentMetadata) && object.contentMetadata.present?
37
+ cm = object.contentMetadata.ng_xml
38
+ thumb_image = nil
39
+
40
+ THUMB_XPATH_FINDERS.each do |search_path|
41
+ thumb_files = cm.xpath(search_path[:finder]) # look for a thumb
42
+ next if thumb_files.empty?
43
+ # if we find one, return the filename based on whether it is a local file or external file
44
+ thumb_image = if search_path[:image_type] == 'local'
45
+ "#{object.remove_druid_prefix}/#{thumb_files[0]['id']}"
46
+ else
47
+ "#{object.remove_druid_prefix(thumb_files[0]['objectId'])}/#{thumb_files[0]['fileId']}"
48
+ end
49
+ break # break out of the loop so we stop searching
50
+ end
51
+
52
+ thumb_image
53
+ end
54
+ end
55
+ end
@@ -1,3 +1,3 @@
1
1
  module Dor
2
- VERSION = '5.32.1'.freeze
2
+ VERSION = '6.0.0'.freeze
3
3
  end
@@ -54,13 +54,6 @@ module Workflow
54
54
  end
55
55
  end
56
56
 
57
- def graph(parent = nil, dir = nil)
58
- wf_definition = definition
59
- result = wf_definition ? Workflow::Graph.from_processes(wf_definition.repo, wf_definition.name, processes, parent) : nil
60
- result['rankdir'] = dir || 'TB' unless result.nil?
61
- result
62
- end
63
-
64
57
  def [](value)
65
58
  processes.find { |p| p.name == value }
66
59
  end
@@ -89,6 +89,7 @@ module Workflow
89
89
  # @param info [Hash,Nokogiri::XML::Element,NilClass]
90
90
  # @param new_owner [Dor::Workflow::Document]
91
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
92
93
  @owner = new_owner
93
94
  return self if info.nil?
94
95
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dor-services
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.32.1
4
+ version: 6.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Klein
@@ -14,7 +14,7 @@ authors:
14
14
  autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
- date: 2018-11-16 00:00:00.000000000 Z
17
+ date: 2018-11-28 00:00:00.000000000 Z
18
18
  dependencies:
19
19
  - !ruby/object:Gem::Dependency
20
20
  name: active-fedora
@@ -70,6 +70,20 @@ dependencies:
70
70
  - - "~>"
71
71
  - !ruby/object:Gem::Version
72
72
  version: 0.2.7
73
+ - !ruby/object:Gem::Dependency
74
+ name: deprecation
75
+ requirement: !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - "~>"
78
+ - !ruby/object:Gem::Version
79
+ version: '0'
80
+ type: :runtime
81
+ prerelease: false
82
+ version_requirements: !ruby/object:Gem::Requirement
83
+ requirements:
84
+ - - "~>"
85
+ - !ruby/object:Gem::Version
86
+ version: '0'
73
87
  - !ruby/object:Gem::Dependency
74
88
  name: equivalent-xml
75
89
  requirement: !ruby/object:Gem::Requirement
@@ -220,20 +234,6 @@ dependencies:
220
234
  - - "~>"
221
235
  - !ruby/object:Gem::Version
222
236
  version: 0.3.0
223
- - !ruby/object:Gem::Dependency
224
- name: ruby-graphviz
225
- requirement: !ruby/object:Gem::Requirement
226
- requirements:
227
- - - ">="
228
- - !ruby/object:Gem::Version
229
- version: '0'
230
- type: :runtime
231
- prerelease: false
232
- version_requirements: !ruby/object:Gem::Requirement
233
- requirements:
234
- - - ">="
235
- - !ruby/object:Gem::Version
236
- version: '0'
237
237
  - !ruby/object:Gem::Dependency
238
238
  name: rubydora
239
239
  requirement: !ruby/object:Gem::Requirement
@@ -588,6 +588,13 @@ files:
588
588
  - lib/dor/datastreams/workflow_definition_ds.rb
589
589
  - lib/dor/datastreams/workflow_ds.rb
590
590
  - lib/dor/exceptions.rb
591
+ - lib/dor/indexers/composite_indexer.rb
592
+ - lib/dor/indexers/data_indexer.rb
593
+ - lib/dor/indexers/describable_indexer.rb
594
+ - lib/dor/indexers/editable_indexer.rb
595
+ - lib/dor/indexers/identifiable_indexer.rb
596
+ - lib/dor/indexers/processable_indexer.rb
597
+ - lib/dor/indexers/releasable_indexer.rb
591
598
  - lib/dor/models/abstract.rb
592
599
  - lib/dor/models/admin_policy_object.rb
593
600
  - lib/dor/models/agreement.rb
@@ -629,6 +636,7 @@ files:
629
636
  - lib/dor/services/search_service.rb
630
637
  - lib/dor/services/suri_service.rb
631
638
  - lib/dor/services/technical_metadata_service.rb
639
+ - lib/dor/services/thumbnail_service.rb
632
640
  - lib/dor/utils/hydrus_shims.rb
633
641
  - lib/dor/utils/ng_tidy.rb
634
642
  - lib/dor/utils/predicate_patch.rb
@@ -636,7 +644,6 @@ files:
636
644
  - lib/dor/utils/solr_doc_helper.rb
637
645
  - lib/dor/version.rb
638
646
  - lib/dor/workflow/document.rb
639
- - lib/dor/workflow/graph.rb
640
647
  - lib/dor/workflow/process.rb
641
648
  - lib/tasks/rdoc.rake
642
649
  homepage:
@@ -1,163 +0,0 @@
1
- require 'graphviz'
2
-
3
- module Dor
4
- module Workflow
5
- class Graph
6
-
7
- FILL_COLORS = { 'waiting' => 'white', 'ready' => 'white', 'error' => '#8B0000', 'blocked' => 'white', 'completed' => 'darkgreen', 'unknown' => '#CFCFCF' }.freeze
8
- TEXT_COLORS = { 'waiting' => 'black', 'ready' => 'black', 'error' => 'white', 'blocked' => '#8B0000', 'completed' => 'white', 'unknown' => 'black' }.freeze
9
- PATTERNS = { 'waiting' => 'diagonals', 'ready' => 'filled', 'error' => 'filled', 'blocked' => 'diagonals', 'completed' => 'filled', 'unknown' => 'filled' }.freeze
10
- RESERVED_KEYS = %w(repository name).freeze
11
-
12
- attr_reader :repo, :name, :processes, :graph, :root
13
-
14
- def self.from_config(name, config, parent = nil)
15
- wf = new(config['repository'], name, parent)
16
- config.keys.each { |p| wf.add_process(p.to_s) unless RESERVED_KEYS.include?(p) }
17
- config.keys.each { |p|
18
- next unless wf.processes[p]
19
- Array(config[p]['prerequisite']).each { |prereq|
20
- prereq.sub!(/^#{config['repository']}:#{name}:/e, '')
21
- if wf.processes[prereq]
22
- wf.processes[p].depends_on(wf.processes[prereq])
23
- else
24
- wf.processes[p].depends_on(wf.add_process(prereq).set_status('external'))
25
- end
26
- }
27
- }
28
- wf.finish
29
- wf
30
- end
31
-
32
- def self.from_processes(repo, name, processes, parent = nil)
33
- wf = new(repo, name, parent)
34
- processes.each { |p|
35
- wf.add_process(p.name).status = p.state || 'unknown'
36
- }
37
- processes.each { |p|
38
- p.prerequisite.each { |prereq|
39
- prereq.sub!(/^#{repo}:#{name}:/e, '')
40
- if wf.processes[prereq]
41
- wf.processes[p.name].depends_on(wf.processes[prereq])
42
- else
43
- wf.processes[p.name].depends_on(wf.add_process(prereq).set_status('external'))
44
- end
45
- }
46
- }
47
- wf.finish
48
- wf
49
- end
50
-
51
- def initialize(repo, name, parent = nil)
52
- @repo = repo
53
- @name = name
54
- if parent.nil?
55
- @graph = GraphViz.new(qname)
56
- @root = add_nodes(name)
57
- else
58
- @graph = parent.subgraph(qname)
59
- @root = parent.add_nodes(name)
60
- end
61
- @graph[:truecolor => true]
62
- @root.shape = 'plaintext'
63
- @processes = {}
64
- end
65
-
66
- def qname
67
- [@repo, @name].join(':')
68
- end
69
-
70
- def add_process(name, external = false)
71
- pqname = name.split(/:/).length == 3 ? name : [qname, name].join(':')
72
- p = Process.new(self, pqname, name)
73
- @processes[name] = p
74
- p
75
- end
76
-
77
- def finish
78
- @processes.values.each do |process|
79
- process.node.fontname = 'Helvetica'
80
- if process.id =~ %r{^#{qname}} && process.prerequisites.length == 0
81
- (@root << process.node)[:arrowhead => 'none', :arrowtail => 'none', :dir => 'both', :style => 'invisible']
82
- end
83
- end
84
-
85
- @root.fontname = 'Helvetica'
86
- self
87
- end
88
-
89
- def inspect
90
- "#{to_s[0..-2]} #{repo}:#{name} (#{processes.keys.join(', ')})>"
91
- end
92
-
93
- def method_missing(sym, *args)
94
- if @graph.respond_to?(sym)
95
- @graph.send(sym, *args)
96
- else
97
- super
98
- end
99
- end
100
-
101
- class Process
102
-
103
- attr_reader :name, :status, :node, :prerequisites
104
-
105
- def initialize(graph, id, name)
106
- @name = name
107
- @graph = graph
108
- @node = @graph.add_nodes(id)
109
- @node.shape = 'box'
110
- @node.label = name
111
- @prerequisites = []
112
- set_status('unknown')
113
- end
114
-
115
- def id
116
- @node.id
117
- end
118
-
119
- def status=(s)
120
- @status = s
121
- if s == 'external'
122
- @node.fillcolor = 'gray'
123
- @node.fontcolor = 'black'
124
- @node.style = 'dashed'
125
- else
126
- @node.fillcolor = FILL_COLORS[s] || 'yellow'
127
- @node.fontcolor = TEXT_COLORS[s]
128
- @node.style = PATTERNS[s]
129
- end
130
- end
131
-
132
- def set_status(s)
133
- self.status = s
134
- self
135
- end
136
-
137
- def depends_on(*processes)
138
- wf1 = id.split(/:/)[0..1].join(':')
139
- processes.each { |process|
140
- wf2 = process.id.split(/:/)[0..1].join(':')
141
- edge = (process.node << @node)
142
- edge.dir = 'both'
143
- edge.arrowhead = 'none'
144
- edge.arrowtail = 'none'
145
- edge.style = 'dashed' if wf1 != wf2
146
- prerequisites << process
147
- }
148
- self
149
- end
150
-
151
- def same_as(process)
152
- @node = process.node
153
- end
154
-
155
- def all_prerequisites
156
- prerequisites.collect { |p| p.all_prerequisites + [p.name] }.flatten.uniq
157
- end
158
-
159
- end
160
-
161
- end
162
- end
163
- end