dor-services 5.32.1 → 6.0.0

Sign up to get free protection for your applications and to get access to all the features.
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