assembly-objectfile 1.10.1 → 1.12.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/pull_request_template.md +3 -5
- data/.rubocop_todo.yml +12 -56
- data/Gemfile +2 -0
- data/assembly-objectfile.gemspec +1 -1
- data/lib/assembly-objectfile/content_metadata/config.rb +2 -0
- data/lib/assembly-objectfile/content_metadata/file.rb +1 -1
- data/lib/assembly-objectfile/content_metadata/nokogiri_builder.rb +12 -10
- data/lib/assembly-objectfile/content_metadata.rb +4 -1
- data/lib/assembly-objectfile/object_fileable.rb +14 -4
- data/lib/assembly-objectfile/version.rb +1 -1
- data/lib/assembly-objectfile.rb +8 -0
- data/spec/content_metadata_spec.rb +79 -45
- data/spec/object_file_spec.rb +7 -0
- data/spec/spec_helper.rb +5 -2
- data/spec/test_data/input/test.json +1 -0
- data/spec/test_data/input/test.svg +2 -0
- metadata +11 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e964d66148904c190829abd7d9c65d09459405f184a48a2350602d1f4c6b6a5f
|
4
|
+
data.tar.gz: 85fca1341b29f0c3f5b3858b419e0273754de1a47140b5ae36d2cbf2a77feea4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f2cf693279f7c43392f92b3dd8bf28df4baca673276c3c96208b420c6ec26415b37b9498149a0ee6fe8ff4606046768582107f1e71b66199f04463b8f5dec918
|
7
|
+
data.tar.gz: fcdc3f9041410416893e8ba1258c677a9eb0f6ede6eb833deb74f9dcb30e005d226d4486419a6fc2a1ae24b9e0ceda579e1acb7f189cf022af822fc32e275fa6
|
@@ -1,12 +1,10 @@
|
|
1
|
-
## Why was this change made?
|
1
|
+
## Why was this change made? 🤔
|
2
2
|
|
3
3
|
|
4
4
|
|
5
|
-
## How was this change tested?
|
5
|
+
## How was this change tested? 🤨
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
## Which documentation and/or configurations were updated?
|
7
|
+
⚡ ⚠ If this change has cross service impact, ***run [integration tests](https://github.com/sul-dlss/infrastructure-integration-test) that do accessioning*** and/or test in [stage|qa] environment, in addition to specs. ⚡
|
10
8
|
|
11
9
|
|
12
10
|
|
data/.rubocop_todo.yml
CHANGED
@@ -1,33 +1,11 @@
|
|
1
1
|
# This configuration was generated by
|
2
2
|
# `rubocop --auto-gen-config`
|
3
|
-
# on 2021-
|
3
|
+
# on 2021-04-26 18:43:37 UTC using RuboCop version 1.11.0.
|
4
4
|
# The point is for the user to remove these configuration records
|
5
5
|
# one by one as the offenses are removed from the code base.
|
6
6
|
# Note that changes in the inspected code, or installation of new
|
7
7
|
# versions of RuboCop, may require this file to be generated again.
|
8
8
|
|
9
|
-
# Offense count: 1
|
10
|
-
# Cop supports --auto-correct.
|
11
|
-
# Configuration parameters: EnforcedStyleAlignWith, Severity.
|
12
|
-
# SupportedStylesAlignWith: start_of_line, begin
|
13
|
-
Layout/BeginEndAlignment:
|
14
|
-
Exclude:
|
15
|
-
- 'lib/assembly-objectfile/object_fileable.rb'
|
16
|
-
|
17
|
-
# Offense count: 1
|
18
|
-
# Cop supports --auto-correct.
|
19
|
-
# Configuration parameters: AllowAliasSyntax, AllowedMethods.
|
20
|
-
# AllowedMethods: alias_method, public, protected, private
|
21
|
-
Layout/EmptyLinesAroundAttributeAccessor:
|
22
|
-
Exclude:
|
23
|
-
- 'lib/assembly-objectfile/object_fileable.rb'
|
24
|
-
|
25
|
-
# Offense count: 1
|
26
|
-
# Cop supports --auto-correct.
|
27
|
-
Layout/RescueEnsureAlignment:
|
28
|
-
Exclude:
|
29
|
-
- 'lib/assembly-objectfile/object_fileable.rb'
|
30
|
-
|
31
9
|
# Offense count: 1
|
32
10
|
Lint/UselessAssignment:
|
33
11
|
Exclude:
|
@@ -36,38 +14,38 @@ Lint/UselessAssignment:
|
|
36
14
|
# Offense count: 3
|
37
15
|
# Configuration parameters: IgnoredMethods, CountRepeatedAttributes.
|
38
16
|
Metrics/AbcSize:
|
39
|
-
Max:
|
17
|
+
Max: 55
|
40
18
|
|
41
19
|
# Offense count: 1
|
42
20
|
# Configuration parameters: CountComments, CountAsOne, ExcludedMethods, IgnoredMethods.
|
43
21
|
# IgnoredMethods: refine
|
44
22
|
Metrics/BlockLength:
|
45
|
-
Max:
|
23
|
+
Max: 27
|
46
24
|
|
47
25
|
# Offense count: 2
|
48
26
|
# Configuration parameters: IgnoredMethods.
|
49
27
|
Metrics/CyclomaticComplexity:
|
50
|
-
Max:
|
28
|
+
Max: 14
|
51
29
|
|
52
30
|
# Offense count: 4
|
53
31
|
# Configuration parameters: CountComments, CountAsOne, ExcludedMethods, IgnoredMethods.
|
54
32
|
Metrics/MethodLength:
|
55
|
-
Max:
|
33
|
+
Max: 31
|
56
34
|
|
57
35
|
# Offense count: 1
|
58
36
|
# Configuration parameters: CountComments, CountAsOne.
|
59
37
|
Metrics/ModuleLength:
|
60
|
-
Max:
|
38
|
+
Max: 120
|
61
39
|
|
62
40
|
# Offense count: 1
|
63
41
|
# Configuration parameters: CountKeywordArgs, MaxOptionalParameters.
|
64
42
|
Metrics/ParameterLists:
|
65
|
-
Max:
|
43
|
+
Max: 12
|
66
44
|
|
67
45
|
# Offense count: 2
|
68
46
|
# Configuration parameters: IgnoredMethods.
|
69
47
|
Metrics/PerceivedComplexity:
|
70
|
-
Max:
|
48
|
+
Max: 15
|
71
49
|
|
72
50
|
# Offense count: 1
|
73
51
|
# Configuration parameters: ExpectMatchingDefinition, CheckDefinitionPathHierarchy, Regex, IgnoreExecutableScripts, AllowedAcronyms.
|
@@ -87,7 +65,7 @@ Naming/PredicateName:
|
|
87
65
|
- 'spec/**/*'
|
88
66
|
- 'lib/assembly-objectfile/object_fileable.rb'
|
89
67
|
|
90
|
-
# Offense count:
|
68
|
+
# Offense count: 9
|
91
69
|
# Configuration parameters: Max.
|
92
70
|
RSpec/ExampleLength:
|
93
71
|
Exclude:
|
@@ -101,13 +79,13 @@ RSpec/FilePath:
|
|
101
79
|
- 'spec/content_metadata_spec.rb'
|
102
80
|
- 'spec/object_file_spec.rb'
|
103
81
|
|
104
|
-
# Offense count:
|
82
|
+
# Offense count: 74
|
105
83
|
# Configuration parameters: AssignmentOnly.
|
106
84
|
RSpec/InstanceVariable:
|
107
85
|
Exclude:
|
108
86
|
- 'spec/object_file_spec.rb'
|
109
87
|
|
110
|
-
# Offense count:
|
88
|
+
# Offense count: 40
|
111
89
|
RSpec/MultipleExpectations:
|
112
90
|
Max: 29
|
113
91
|
|
@@ -132,29 +110,7 @@ Style/CommentedKeyword:
|
|
132
110
|
Exclude:
|
133
111
|
- 'lib/assembly-objectfile/content_metadata.rb'
|
134
112
|
|
135
|
-
# Offense count:
|
136
|
-
# Cop supports --auto-correct.
|
137
|
-
Style/KeywordParametersOrder:
|
138
|
-
Exclude:
|
139
|
-
- 'lib/assembly-objectfile/content_metadata/file.rb'
|
140
|
-
- 'lib/assembly-objectfile/content_metadata/file_set.rb'
|
141
|
-
|
142
|
-
# Offense count: 1
|
143
|
-
# Cop supports --auto-correct.
|
144
|
-
Style/RedundantAssignment:
|
145
|
-
Exclude:
|
146
|
-
- 'lib/assembly-objectfile/content_metadata.rb'
|
147
|
-
|
148
|
-
# Offense count: 5
|
149
|
-
# Cop supports --auto-correct.
|
150
|
-
Style/StringConcatenation:
|
151
|
-
Exclude:
|
152
|
-
- 'config/boot.rb'
|
153
|
-
- 'lib/assembly-objectfile.rb'
|
154
|
-
- 'lib/assembly-objectfile/object_file.rb'
|
155
|
-
- 'spec/spec_helper.rb'
|
156
|
-
|
157
|
-
# Offense count: 113
|
113
|
+
# Offense count: 122
|
158
114
|
# Cop supports --auto-correct.
|
159
115
|
# Configuration parameters: AutoCorrect, AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns.
|
160
116
|
# URISchemes: http, https
|
data/Gemfile
CHANGED
data/assembly-objectfile.gemspec
CHANGED
@@ -20,7 +20,7 @@ Gem::Specification.new do |s|
|
|
20
20
|
s.executables = s.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
21
21
|
s.require_paths = ['lib']
|
22
22
|
|
23
|
-
s.required_ruby_version = '
|
23
|
+
s.required_ruby_version = '>= 2.5', '< 4'
|
24
24
|
|
25
25
|
s.add_dependency 'activesupport', '>= 5.2.0'
|
26
26
|
s.add_dependency 'deprecation'
|
@@ -13,12 +13,14 @@ module Assembly
|
|
13
13
|
# Represents a configuration for generating the content metadata
|
14
14
|
class Config < Dry::Struct
|
15
15
|
STYLES = %w[image file book map 3d document webarchive-seed].freeze
|
16
|
+
READING_ORDERS = %w[ltr rtl].freeze
|
16
17
|
attribute :auto_labels, Types::Strict::Bool.default(true)
|
17
18
|
attribute :flatten_folder_structure, Types::Strict::Bool.default(false)
|
18
19
|
attribute :add_file_attributes, Types::Strict::Bool.default(false)
|
19
20
|
attribute :add_exif, Types::Strict::Bool.default(false)
|
20
21
|
attribute :file_attributes, Types::Strict::Hash.default({}.freeze)
|
21
22
|
attribute :type, Types::Strict::String.enum(*STYLES)
|
23
|
+
attribute :reading_order, Types::Strict::String.default('ltr').enum(*READING_ORDERS)
|
22
24
|
end
|
23
25
|
end
|
24
26
|
end
|
@@ -35,7 +35,7 @@ module Assembly
|
|
35
35
|
@style = style
|
36
36
|
end
|
37
37
|
|
38
|
-
delegate :sha1, :md5, :provider_md5, :provider_sha1, :mimetype, :filesize, :image?, to: :file
|
38
|
+
delegate :sha1, :md5, :provider_md5, :provider_sha1, :mimetype, :filesize, :image?, :valid_image?, to: :file
|
39
39
|
|
40
40
|
def file_id(common_path:, flatten_folder_structure:)
|
41
41
|
# set file id attribute, first check the relative_path parameter on the object, and if it is set, just use that
|
@@ -15,6 +15,8 @@ module Assembly
|
|
15
15
|
|
16
16
|
Nokogiri::XML::Builder.new do |xml|
|
17
17
|
xml.contentMetadata(objectId: druid.to_s, type: config.type) do
|
18
|
+
xml.bookData(readingOrder: config.reading_order) if config.type == 'book'
|
19
|
+
|
18
20
|
filesets.each_with_index do |fileset, index| # iterate over all the resources
|
19
21
|
# start a new resource element
|
20
22
|
sequence = index + 1
|
@@ -29,19 +31,19 @@ module Assembly
|
|
29
31
|
resource_label = fileset.label_from_file(default: default_label)
|
30
32
|
|
31
33
|
xml.label(resource_label) unless resource_label.empty?
|
32
|
-
fileset.files.each do |
|
33
|
-
xml_file_params = { id:
|
34
|
-
xml_file_params.merge!(
|
35
|
-
xml_file_params.merge!(mimetype:
|
34
|
+
fileset.files.each do |cm_file| # iterate over all the files in a resource
|
35
|
+
xml_file_params = { id: cm_file.file_id(common_path: common_path, flatten_folder_structure: config.flatten_folder_structure) }
|
36
|
+
xml_file_params.merge!(cm_file.file_attributes(config.file_attributes)) if config.add_file_attributes
|
37
|
+
xml_file_params.merge!(mimetype: cm_file.mimetype, size: cm_file.filesize) if config.add_exif
|
36
38
|
|
37
39
|
xml.file(xml_file_params) do
|
38
40
|
if config.add_exif # add exif info if the user requested it
|
39
|
-
xml.checksum(
|
40
|
-
xml.checksum(
|
41
|
-
xml.imageData(
|
42
|
-
elsif
|
43
|
-
xml.checksum(
|
44
|
-
xml.checksum(
|
41
|
+
xml.checksum(cm_file.sha1, type: 'sha1')
|
42
|
+
xml.checksum(cm_file.md5, type: 'md5')
|
43
|
+
xml.imageData(cm_file.image_data) if cm_file.valid_image? # add image data for an image
|
44
|
+
elsif cm_file.provider_md5 || cm_file.provider_sha1 # if we did not add exif info, see if there are user supplied checksums to add
|
45
|
+
xml.checksum(cm_file.provider_sha1, type: 'sha1') if cm_file.provider_sha1
|
46
|
+
xml.checksum(cm_file.provider_md5, type: 'md5') if cm_file.provider_md5
|
45
47
|
end
|
46
48
|
end
|
47
49
|
end
|
@@ -52,13 +52,15 @@ module Assembly
|
|
52
52
|
# :flatten_folder_structure = optional - Will remove *all* folder structure when genearting file IDs (e.g. DPG subfolders like '00','05' will be removed) when generating file IDs. This is useful if the folder structure is flattened when staging files (like for DPG).
|
53
53
|
# The default is false. If set to true, will override the "preserve_common_paths" parameter.
|
54
54
|
# :auto_labels = optional - Will add automated resource labels (e.g. "File 1") when labels are not provided by the user. The default is true.
|
55
|
+
# See https://consul.stanford.edu/pages/viewpage.action?spaceKey=chimera&title=DOR+content+types%2C+resource+types+and+interpretive+metadata for next two settings
|
56
|
+
# :reading_order = optional - only valid for simple_book, can be 'rtl' or 'ltr'. The default is 'ltr'.
|
55
57
|
# Example:
|
56
58
|
# Assembly::ContentMetadata.create_content_metadata(:druid=>'druid:nx288wh8889',:style=>:simple_image,:objects=>object_files,:add_file_attributes=>false)
|
57
59
|
def self.create_content_metadata(druid:, objects:, auto_labels: true,
|
58
60
|
add_exif: false, bundle: :default, style: :simple_image,
|
59
61
|
add_file_attributes: false, file_attributes: {},
|
60
62
|
preserve_common_paths: false, flatten_folder_structure: false,
|
61
|
-
include_root_xml: nil)
|
63
|
+
include_root_xml: nil, reading_order: 'ltr')
|
62
64
|
|
63
65
|
common_path = find_common_path(objects) unless preserve_common_paths # find common paths to all files provided if needed
|
64
66
|
|
@@ -68,6 +70,7 @@ module Assembly
|
|
68
70
|
add_file_attributes: add_file_attributes,
|
69
71
|
file_attributes: file_attributes,
|
70
72
|
add_exif: add_exif,
|
73
|
+
reading_order: reading_order,
|
71
74
|
type: object_level_type(style))
|
72
75
|
|
73
76
|
builder = NokogiriBuilder.build(druid: druid,
|
@@ -8,7 +8,7 @@ module Assembly
|
|
8
8
|
module ObjectFileable
|
9
9
|
attr_accessor :file_attributes, :label, :path, :provider_md5, :provider_sha1, :relative_path, :mime_type_order
|
10
10
|
|
11
|
-
VALID_MIMETYPE_METHODS = %i[exif file extension].freeze
|
11
|
+
VALID_MIMETYPE_METHODS = %i[override exif file extension].freeze
|
12
12
|
|
13
13
|
# @param [String] path full path to the file to be worked with
|
14
14
|
# @param [Hash<Symbol => Object>] params options used during content metadata generation
|
@@ -18,7 +18,8 @@ module Assembly
|
|
18
18
|
# @option params [String] :provider_sha1 pre-computed SHA1 checksum
|
19
19
|
# @option params [String] :relative_path if you want the file ids in the content metadata it can be set, otherwise content metadata will get the full path
|
20
20
|
# @option params [Array] :mime_type_order can be set to the order in which you want mimetypes to be determined
|
21
|
-
# options are :
|
21
|
+
# options are :override (from manual overide mapping if exists), :exif (from exif if exists),
|
22
|
+
# :extension (from file extension), and :file (from unix file system command)
|
22
23
|
# the default is defined in the private `default_mime_type_order` method but you can override to set your own order
|
23
24
|
# @example
|
24
25
|
# Assembly::ObjectFile.new('/input/path_to_file.tif')
|
@@ -127,12 +128,21 @@ module Assembly
|
|
127
128
|
mimetype = ''
|
128
129
|
mime_type_order.each do |mime_type_method|
|
129
130
|
mimetype = public_send("#{mime_type_method}_mimetype") if VALID_MIMETYPE_METHODS.include?(mime_type_method)
|
130
|
-
break if
|
131
|
+
break if mimetype.present?
|
131
132
|
end
|
132
133
|
mimetype
|
133
134
|
end
|
134
135
|
end
|
135
136
|
|
137
|
+
# Returns mimetype information using the manual override mapping (based on a file extension lookup)
|
138
|
+
# @return [String] mime type for supplied file if a mapping exists for the file's extension
|
139
|
+
# @example
|
140
|
+
# source_file = Assembly::ObjectFile.new('/input/path_to_file.json')
|
141
|
+
# puts source_file.override_mimetype # 'application/json'
|
142
|
+
def override_mimetype
|
143
|
+
@override_mimetype ||= Assembly::OVERRIDE_MIMETYPES.fetch(ext.to_sym, '')
|
144
|
+
end
|
145
|
+
|
136
146
|
# Returns mimetype information using the mime-types gem (based on a file extension lookup)
|
137
147
|
# @return [String] mime type for supplied file
|
138
148
|
# @example
|
@@ -257,7 +267,7 @@ exif&.mimetype && prefer_exif
|
|
257
267
|
|
258
268
|
# prive method defining default preferred ordering of how mimetypes are determined
|
259
269
|
def default_mime_type_order
|
260
|
-
%i[exif file extension]
|
270
|
+
%i[override exif file extension]
|
261
271
|
end
|
262
272
|
|
263
273
|
# private method to check for file existence before operating on it
|
data/lib/assembly-objectfile.rb
CHANGED
@@ -14,6 +14,14 @@ module Assembly
|
|
14
14
|
# by the file command, then a check will be made to see if exif data exists...if so, the mimetype returned by the exif data will be used
|
15
15
|
# if no exif data exists, then the mimetype returned by the unix file command will be used
|
16
16
|
TRUSTED_MIMETYPES = ['text/plain', 'plain/text', 'application/pdf', 'text/html', 'application/xml'].freeze
|
17
|
+
|
18
|
+
# this is a manual override mapping of file extension to mimetype; if a file with the given extension is found, the mapped
|
19
|
+
# mimetype will be returned and no further methods will be used - this is used to force a specific mimetype to be returned for
|
20
|
+
# for a given file extension regardless of what exif or the unix file system command returns
|
21
|
+
# the mapping format is "extension with period: returned mimetype", e.g. for any .json file, you will always get `application/json`
|
22
|
+
OVERRIDE_MIMETYPES = {
|
23
|
+
'.json': 'application/json'
|
24
|
+
}.freeze
|
17
25
|
end
|
18
26
|
|
19
27
|
require 'assembly-objectfile/content_metadata'
|
@@ -8,8 +8,8 @@ RSpec.describe Assembly::ContentMetadata do
|
|
8
8
|
|
9
9
|
let(:xml) { Nokogiri::XML(result) }
|
10
10
|
|
11
|
-
context 'when style
|
12
|
-
context 'when using a single tif and jp2' do
|
11
|
+
context 'when style=simple_image' do
|
12
|
+
context 'when using a single tif and jp2 with add_exif: true' do
|
13
13
|
it 'generates valid content metadata with exif, adding file attributes' do
|
14
14
|
objects = [Assembly::ObjectFile.new(TEST_TIF_INPUT_FILE), Assembly::ObjectFile.new(TEST_JP2_INPUT_FILE)]
|
15
15
|
result = described_class.create_content_metadata(druid: TEST_DRUID, add_exif: true, add_file_attributes: true, objects: objects)
|
@@ -44,46 +44,8 @@ RSpec.describe Assembly::ContentMetadata do
|
|
44
44
|
expect(xml.xpath('//resource/file/imageData')[1].attributes['width'].value).to eq('100')
|
45
45
|
expect(xml.xpath('//resource/file/imageData')[1].attributes['height'].value).to eq('100')
|
46
46
|
end
|
47
|
-
end
|
48
|
-
|
49
|
-
context 'when using a single tif and jp2' do
|
50
|
-
it 'generates valid content metadata with no exif adding specific file attributes for 2 objects, and defaults for 1 object' do
|
51
|
-
obj1 = Assembly::ObjectFile.new(TEST_TIF_INPUT_FILE)
|
52
|
-
obj2 = Assembly::ObjectFile.new(TEST_JP2_INPUT_FILE)
|
53
|
-
obj3 = Assembly::ObjectFile.new(TEST_JP2_INPUT_FILE2)
|
54
|
-
obj1.file_attributes = { publish: 'no', preserve: 'no', shelve: 'no' }
|
55
|
-
obj2.file_attributes = { publish: 'yes', preserve: 'yes', shelve: 'yes' }
|
56
|
-
objects = [obj1, obj2, obj3]
|
57
|
-
result = described_class.create_content_metadata(druid: TEST_DRUID, add_exif: false, add_file_attributes: true, objects: objects)
|
58
|
-
expect(result.class).to be String
|
59
|
-
xml = Nokogiri::XML(result)
|
60
|
-
expect(xml.errors.size).to eq 0
|
61
|
-
expect(xml.xpath('//contentMetadata')[0].attributes['type'].value).to eq('image')
|
62
|
-
expect(xml.xpath('//resource').length).to eq 3
|
63
|
-
expect(xml.xpath('//resource/file').length).to eq 3
|
64
|
-
expect(xml.xpath('//resource/file/checksum').length).to eq 0
|
65
|
-
expect(xml.xpath('//resource/file/imageData').length).to eq 0
|
66
|
-
expect(xml.xpath('//label').length).to eq 3
|
67
|
-
expect(xml.xpath('//label')[0].text).to match(/Image 1/)
|
68
|
-
expect(xml.xpath('//label')[1].text).to match(/Image 2/)
|
69
|
-
expect(xml.xpath('//label')[2].text).to match(/Image 3/)
|
70
|
-
expect(xml.xpath('//resource')[0].attributes['type'].value).to eq('image')
|
71
|
-
expect(xml.xpath('//resource')[1].attributes['type'].value).to eq('image')
|
72
|
-
expect(xml.xpath('//resource')[2].attributes['type'].value).to eq('image')
|
73
|
-
expect(xml.xpath('//resource/file')[0].attributes['publish'].value).to eq('no') # specificially set in object
|
74
|
-
expect(xml.xpath('//resource/file')[0].attributes['preserve'].value).to eq('no') # specificially set in object
|
75
|
-
expect(xml.xpath('//resource/file')[0].attributes['shelve'].value).to eq('no') # specificially set in object
|
76
|
-
expect(xml.xpath('//resource/file')[1].attributes['publish'].value).to eq('yes') # specificially set in object
|
77
|
-
expect(xml.xpath('//resource/file')[1].attributes['preserve'].value).to eq('yes') # specificially set in object
|
78
|
-
expect(xml.xpath('//resource/file')[1].attributes['shelve'].value).to eq('yes') # specificially set in object
|
79
|
-
expect(xml.xpath('//resource/file')[2].attributes['publish'].value).to eq('yes') # defaults by mimetype
|
80
|
-
expect(xml.xpath('//resource/file')[2].attributes['preserve'].value).to eq('no') # defaults by mimetype
|
81
|
-
expect(xml.xpath('//resource/file')[2].attributes['shelve'].value).to eq('yes') # defaults by mimetype
|
82
|
-
end
|
83
|
-
end
|
84
47
|
|
85
|
-
|
86
|
-
it 'generates valid content metadata with exif, overriding file labels' do
|
48
|
+
it 'generates valid content metadata, overriding file labels' do
|
87
49
|
objects = [Assembly::ObjectFile.new(TEST_TIF_INPUT_FILE, label: 'Sample tif label!'), Assembly::ObjectFile.new(TEST_JP2_INPUT_FILE, label: 'Sample jp2 label!')]
|
88
50
|
result = described_class.create_content_metadata(druid: TEST_DRUID, add_exif: true, add_file_attributes: true, objects: objects)
|
89
51
|
expect(result.class).to be String
|
@@ -119,6 +81,42 @@ RSpec.describe Assembly::ContentMetadata do
|
|
119
81
|
end
|
120
82
|
end
|
121
83
|
|
84
|
+
context 'when using a single tif and jp2 with add_exif: false' do
|
85
|
+
it 'generates valid content metadata adding specific file attributes for 2 objects, and defaults for 1 object' do
|
86
|
+
obj1 = Assembly::ObjectFile.new(TEST_TIF_INPUT_FILE)
|
87
|
+
obj2 = Assembly::ObjectFile.new(TEST_JP2_INPUT_FILE)
|
88
|
+
obj3 = Assembly::ObjectFile.new(TEST_JP2_INPUT_FILE2)
|
89
|
+
obj1.file_attributes = { publish: 'no', preserve: 'no', shelve: 'no' }
|
90
|
+
obj2.file_attributes = { publish: 'yes', preserve: 'yes', shelve: 'yes' }
|
91
|
+
objects = [obj1, obj2, obj3]
|
92
|
+
result = described_class.create_content_metadata(druid: TEST_DRUID, add_exif: false, add_file_attributes: true, objects: objects)
|
93
|
+
expect(result.class).to be String
|
94
|
+
xml = Nokogiri::XML(result)
|
95
|
+
expect(xml.errors.size).to eq 0
|
96
|
+
expect(xml.xpath('//contentMetadata')[0].attributes['type'].value).to eq('image')
|
97
|
+
expect(xml.xpath('//resource').length).to eq 3
|
98
|
+
expect(xml.xpath('//resource/file').length).to eq 3
|
99
|
+
expect(xml.xpath('//resource/file/checksum').length).to eq 0
|
100
|
+
expect(xml.xpath('//resource/file/imageData').length).to eq 0
|
101
|
+
expect(xml.xpath('//label').length).to eq 3
|
102
|
+
expect(xml.xpath('//label')[0].text).to match(/Image 1/)
|
103
|
+
expect(xml.xpath('//label')[1].text).to match(/Image 2/)
|
104
|
+
expect(xml.xpath('//label')[2].text).to match(/Image 3/)
|
105
|
+
expect(xml.xpath('//resource')[0].attributes['type'].value).to eq('image')
|
106
|
+
expect(xml.xpath('//resource')[1].attributes['type'].value).to eq('image')
|
107
|
+
expect(xml.xpath('//resource')[2].attributes['type'].value).to eq('image')
|
108
|
+
expect(xml.xpath('//resource/file')[0].attributes['publish'].value).to eq('no') # specificially set in object
|
109
|
+
expect(xml.xpath('//resource/file')[0].attributes['preserve'].value).to eq('no') # specificially set in object
|
110
|
+
expect(xml.xpath('//resource/file')[0].attributes['shelve'].value).to eq('no') # specificially set in object
|
111
|
+
expect(xml.xpath('//resource/file')[1].attributes['publish'].value).to eq('yes') # specificially set in object
|
112
|
+
expect(xml.xpath('//resource/file')[1].attributes['preserve'].value).to eq('yes') # specificially set in object
|
113
|
+
expect(xml.xpath('//resource/file')[1].attributes['shelve'].value).to eq('yes') # specificially set in object
|
114
|
+
expect(xml.xpath('//resource/file')[2].attributes['publish'].value).to eq('yes') # defaults by mimetype
|
115
|
+
expect(xml.xpath('//resource/file')[2].attributes['preserve'].value).to eq('no') # defaults by mimetype
|
116
|
+
expect(xml.xpath('//resource/file')[2].attributes['shelve'].value).to eq('yes') # defaults by mimetype
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
122
120
|
context 'when using a single tif and jp2' do
|
123
121
|
it 'generates valid content metadata with exif, overriding file labels for one, and skipping auto labels for the others or for where the label is set but is blank' do
|
124
122
|
objects = [Assembly::ObjectFile.new(TEST_TIF_INPUT_FILE, label: 'Sample tif label!'), Assembly::ObjectFile.new(TEST_JP2_INPUT_FILE), Assembly::ObjectFile.new(TEST_JP2_INPUT_FILE, label: '')]
|
@@ -331,9 +329,29 @@ RSpec.describe Assembly::ContentMetadata do
|
|
331
329
|
end
|
332
330
|
end
|
333
331
|
end
|
332
|
+
|
333
|
+
context 'when using a single svg with add_exif: true' do
|
334
|
+
subject(:result) { described_class.create_content_metadata(druid: TEST_DRUID, add_exif: true, auto_labels: false, add_file_attributes: true, objects: objects) }
|
335
|
+
|
336
|
+
let(:objects) { [Assembly::ObjectFile.new(TEST_SVG_INPUT_FILE)] }
|
337
|
+
|
338
|
+
it 'generates no imageData node' do
|
339
|
+
xml = Nokogiri::XML(result)
|
340
|
+
expect(xml.errors.size).to eq 0
|
341
|
+
expect(xml.xpath('//contentMetadata')[0].attributes['type'].value).to eq('image')
|
342
|
+
expect(xml.xpath('//resource/file').length).to eq 1
|
343
|
+
expect(xml.xpath('//resource/file')[0]['mimetype']).to eq 'image/svg+xml'
|
344
|
+
expect(xml.xpath('//resource/file')[0]['publish']).to eq('no')
|
345
|
+
expect(xml.xpath('//resource/file')[0]['preserve']).to eq('yes')
|
346
|
+
expect(xml.xpath('//resource/file')[0]['shelve']).to eq('no')
|
347
|
+
expect(xml.xpath("//resource[@sequence='1']/file").length).to eq 1
|
348
|
+
expect(xml.xpath('//imageData')).not_to be_present
|
349
|
+
expect(xml.xpath('//resource')[0].attributes['type'].value).to eq('image')
|
350
|
+
end
|
351
|
+
end
|
334
352
|
end
|
335
353
|
|
336
|
-
context 'when style
|
354
|
+
context 'when style=webarchive-seed' do
|
337
355
|
context 'when using a jp2' do
|
338
356
|
it 'generates valid content metadata with exif, adding file attributes' do
|
339
357
|
objects = [Assembly::ObjectFile.new(TEST_JP2_INPUT_FILE)]
|
@@ -342,6 +360,7 @@ RSpec.describe Assembly::ContentMetadata do
|
|
342
360
|
xml = Nokogiri::XML(result)
|
343
361
|
expect(xml.errors.size).to eq 0
|
344
362
|
expect(xml.xpath('//contentMetadata')[0].attributes['type'].value).to eq('webarchive-seed')
|
363
|
+
expect(xml.xpath('//bookData').length).to eq 0
|
345
364
|
expect(xml.xpath('//resource').length).to eq 1
|
346
365
|
expect(xml.xpath('//resource/file').length).to eq 1
|
347
366
|
expect(xml.xpath('//resource/file/checksum').length).to eq 2
|
@@ -375,6 +394,7 @@ RSpec.describe Assembly::ContentMetadata do
|
|
375
394
|
xml = Nokogiri::XML(result)
|
376
395
|
expect(xml.errors.size).to eq 0
|
377
396
|
expect(xml.xpath('//contentMetadata')[0].attributes['type'].value).to eq('map')
|
397
|
+
expect(xml.xpath('//bookData').length).to eq 0
|
378
398
|
expect(xml.xpath('//resource/file').length).to eq 2
|
379
399
|
expect(xml.xpath('//resource/file')[0].attributes['mimetype']).to be_nil
|
380
400
|
expect(xml.xpath('//resource/file')[0].attributes['publish'].value).to eq('yes')
|
@@ -404,6 +424,7 @@ RSpec.describe Assembly::ContentMetadata do
|
|
404
424
|
expect(xml.errors.size).to eq 0
|
405
425
|
expect(xml.xpath('//contentMetadata')[0].attributes['type'].value).to eq('book')
|
406
426
|
expect(xml.xpath('//contentMetadata')[0].attributes['objectId'].value).to eq(TEST_DRUID.to_s)
|
427
|
+
expect(xml.xpath('//bookData')[0].attributes['readingOrder'].value).to eq('ltr')
|
407
428
|
expect(xml.xpath('//resource').length).to eq 4
|
408
429
|
expect(xml.xpath('//resource/file').length).to eq 6
|
409
430
|
expect(xml.xpath("//resource[@sequence='1']/file")[0].attributes['id'].value).to eq('oo000oo0001_00_001.tif')
|
@@ -428,20 +449,21 @@ RSpec.describe Assembly::ContentMetadata do
|
|
428
449
|
end
|
429
450
|
end
|
430
451
|
|
431
|
-
context "when item has a 'druid:' prefix. Using two tifs, two associated jp2s, two associated pdfs and one lingering PDF using bundle=dpg" do
|
452
|
+
context "when item has a 'druid:' prefix and specified book order. Using two tifs, two associated jp2s, two associated pdfs and one lingering PDF using bundle=dpg" do
|
432
453
|
it 'generates valid content metadata with flattening folder structure' do
|
433
454
|
objects = [Assembly::ObjectFile.new(TEST_DPG_TIF), Assembly::ObjectFile.new(TEST_DPG_JP),
|
434
455
|
Assembly::ObjectFile.new(TEST_DPG_PDF), Assembly::ObjectFile.new(TEST_DPG_TIF2),
|
435
456
|
Assembly::ObjectFile.new(TEST_DPG_JP2), Assembly::ObjectFile.new(TEST_DPG_PDF2),
|
436
457
|
Assembly::ObjectFile.new(TEST_DPG_SPECIAL_PDF1)]
|
437
458
|
test_druid = "druid:#{TEST_DRUID}"
|
438
|
-
result = described_class.create_content_metadata(druid: test_druid, bundle: :dpg, objects: objects, style: :simple_book, flatten_folder_structure: true)
|
459
|
+
result = described_class.create_content_metadata(druid: test_druid, bundle: :dpg, objects: objects, style: :simple_book, flatten_folder_structure: true, reading_order: 'rtl')
|
439
460
|
expect(result.class).to be String
|
440
461
|
expect(result.include?('<?xml')).to be true
|
441
462
|
xml = Nokogiri::XML(result)
|
442
463
|
expect(xml.errors.size).to eq 0
|
443
464
|
expect(xml.xpath('//contentMetadata')[0].attributes['type'].value).to eq('book')
|
444
465
|
expect(xml.xpath('//contentMetadata')[0].attributes['objectId'].value).to eq(test_druid)
|
466
|
+
expect(xml.xpath('//bookData')[0].attributes['readingOrder'].value).to eq('rtl')
|
445
467
|
expect(test_druid).to eq("druid:#{TEST_DRUID}")
|
446
468
|
expect(xml.xpath('//resource').length).to eq 3
|
447
469
|
expect(xml.xpath('//resource/file').length).to be 7
|
@@ -466,6 +488,14 @@ RSpec.describe Assembly::ContentMetadata do
|
|
466
488
|
end
|
467
489
|
end
|
468
490
|
|
491
|
+
context 'throws an error with invalid reading order' do
|
492
|
+
subject(:result) { described_class.create_content_metadata(druid: "druid:#{TEST_DRUID}", bundle: :dpg, objects: [], style: :simple_book, flatten_folder_structure: true, reading_order: 'bogus') }
|
493
|
+
|
494
|
+
it 'generates valid content metadata with flattening folder structure' do
|
495
|
+
expect { result }.to raise_error(Dry::Struct::Error)
|
496
|
+
end
|
497
|
+
end
|
498
|
+
|
469
499
|
context 'when using two tifs' do
|
470
500
|
it 'generates valid content metadata for two tifs of style=simple_book' do
|
471
501
|
objects = [Assembly::ObjectFile.new(TEST_TIF_INPUT_FILE), Assembly::ObjectFile.new(TEST_TIF_INPUT_FILE2)]
|
@@ -493,7 +523,7 @@ RSpec.describe Assembly::ContentMetadata do
|
|
493
523
|
end
|
494
524
|
end
|
495
525
|
|
496
|
-
context 'when
|
526
|
+
context 'when style=book_with_pdf' do
|
497
527
|
context 'when using two tiffs and a pdf' do
|
498
528
|
let(:objects) do
|
499
529
|
[Assembly::ObjectFile.new(TEST_TIF_INPUT_FILE),
|
@@ -580,6 +610,7 @@ RSpec.describe Assembly::ContentMetadata do
|
|
580
610
|
xml = Nokogiri::XML(result)
|
581
611
|
expect(xml.errors.size).to eq 0
|
582
612
|
expect(xml.xpath('//contentMetadata')[0].attributes['type'].value).to eq('file')
|
613
|
+
expect(xml.xpath('//bookData').length).to eq 0
|
583
614
|
expect(xml.xpath('//resource').length).to eq 4
|
584
615
|
expect(xml.xpath('//resource/file').length).to eq 4
|
585
616
|
expect(xml.xpath('//label').length).to eq 4
|
@@ -611,6 +642,7 @@ RSpec.describe Assembly::ContentMetadata do
|
|
611
642
|
it 'generates valid content metadata for two tifs' do
|
612
643
|
expect(xml.errors.size).to eq 0
|
613
644
|
expect(xml.xpath('//contentMetadata')[0].attributes['type'].value).to eq('book')
|
645
|
+
expect(xml.xpath('//bookData').length).to eq 1
|
614
646
|
expect(xml.xpath('//resource').length).to eq 2
|
615
647
|
expect(xml.xpath('//resource/file').length).to eq 2
|
616
648
|
expect(xml.xpath('//label').length).to eq 2
|
@@ -641,6 +673,7 @@ RSpec.describe Assembly::ContentMetadata do
|
|
641
673
|
it 'generates valid content metadata' do
|
642
674
|
expect(xml.errors.size).to eq 0
|
643
675
|
expect(xml.xpath('//contentMetadata')[0].attributes['type'].value).to eq('document')
|
676
|
+
expect(xml.xpath('//bookData').length).to eq 0
|
644
677
|
expect(xml.xpath('//resource').length).to eq 1
|
645
678
|
expect(xml.xpath('//resource/file').length).to eq 1
|
646
679
|
expect(xml.xpath('//label').length).to eq 1
|
@@ -713,6 +746,7 @@ RSpec.describe Assembly::ContentMetadata do
|
|
713
746
|
it 'generates valid content metadata' do
|
714
747
|
expect(xml.errors.size).to eq 0
|
715
748
|
expect(xml.xpath('//contentMetadata')[0].attributes['type'].value).to eq('3d')
|
749
|
+
expect(xml.xpath('//bookData').length).to eq 0
|
716
750
|
expect(xml.xpath('//resource').length).to eq 4
|
717
751
|
expect(xml.xpath('//resource/file').length).to eq 4
|
718
752
|
expect(xml.xpath('//label').length).to eq 4
|
data/spec/object_file_spec.rb
CHANGED
@@ -70,6 +70,13 @@ describe Assembly::ObjectFile do
|
|
70
70
|
expect(@ai.mimetype).to eq('text/plain')
|
71
71
|
end
|
72
72
|
|
73
|
+
it 'overrides the mimetype generators and uses the manual mapping to set the correct mimetype of application/json for a .json file' do
|
74
|
+
@ai = described_class.new(TEST_JSON_FILE)
|
75
|
+
expect(@ai.exif_mimetype).to be_nil # exif returns nil
|
76
|
+
expect(@ai.file_mimetype).to eq('text/plain') # unix file system command returns plain text
|
77
|
+
expect(@ai.mimetype).to eq('application/json') # but our configured mapping overrides both and returns application/json
|
78
|
+
end
|
79
|
+
|
73
80
|
it 'sets the correct mimetype of image/tiff for .tif files' do
|
74
81
|
@ai = described_class.new(TEST_TIF_INPUT_FILE)
|
75
82
|
expect(@ai.mimetype).to eq('image/tiff')
|
data/spec/spec_helper.rb
CHANGED
@@ -3,8 +3,8 @@
|
|
3
3
|
require 'simplecov'
|
4
4
|
SimpleCov.start
|
5
5
|
|
6
|
-
|
7
|
-
require
|
6
|
+
require File.expand_path("#{File.dirname(__FILE__)}/../config/boot")
|
7
|
+
require 'byebug'
|
8
8
|
|
9
9
|
RSpec.configure do |config|
|
10
10
|
config.order = 'random'
|
@@ -18,6 +18,7 @@ TEST_TIF_INPUT_FILE2 = File.join(TEST_INPUT_DIR, 'test2.tif')
|
|
18
18
|
TEST_JPEG_INPUT_FILE = File.join(TEST_INPUT_DIR, 'test.jpg')
|
19
19
|
TEST_JP2_INPUT_FILE = File.join(TEST_INPUT_DIR, 'test.jp2')
|
20
20
|
TEST_JP2_INPUT_FILE2 = File.join(TEST_INPUT_DIR, 'test2.jp2')
|
21
|
+
TEST_SVG_INPUT_FILE = File.join(TEST_INPUT_DIR, 'test.svg')
|
21
22
|
TEST_JP2_OUTPUT_FILE = File.join(TEST_OUTPUT_DIR, 'test.jp2')
|
22
23
|
TEST_PDF_FILE = File.join(TEST_INPUT_DIR, 'test.pdf')
|
23
24
|
|
@@ -54,6 +55,8 @@ TEST_RES3_TEI = File.join(TEST_INPUT_DIR, 'res3_teifile.txt')
|
|
54
55
|
|
55
56
|
TEST_FILE_NO_EXIF = File.join(TEST_INPUT_DIR, 'file_with_no_exif.xml')
|
56
57
|
|
58
|
+
TEST_JSON_FILE = File.join(TEST_INPUT_DIR, 'test.json')
|
59
|
+
|
57
60
|
TEST_OBJ_FILE = File.join(TEST_INPUT_DIR, 'someobject.obj')
|
58
61
|
TEST_PLY_FILE = File.join(TEST_INPUT_DIR, 'someobject.ply')
|
59
62
|
|
@@ -0,0 +1 @@
|
|
1
|
+
{some: 'thing'}
|
@@ -0,0 +1,2 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<svg width="507.3" height="508.2" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" overflow="hidden"><defs><clipPath id="clip0"><rect x="2361" y="213" width="507" height="508"/></clipPath></defs><g clip-path="url(#clip0)" transform="translate(-2361 -213)"><path d="M2361 467C2361 326.72 2474.5 213 2614.5 213 2754.5 213 2868 326.72 2868 467 2868 607.28 2754.5 721 2614.5 721 2474.5 721 2361 607.28 2361 467Z" fill="#BF9000" fill-rule="evenodd"/></g></svg>
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: assembly-objectfile
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.12.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Peter Mangiafico
|
@@ -11,7 +11,7 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: exe
|
13
13
|
cert_chain: []
|
14
|
-
date:
|
14
|
+
date: 2022-02-18 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: activesupport
|
@@ -263,7 +263,9 @@ files:
|
|
263
263
|
- spec/test_data/input/someobject.obj
|
264
264
|
- spec/test_data/input/someobject.ply
|
265
265
|
- spec/test_data/input/test.jp2
|
266
|
+
- spec/test_data/input/test.json
|
266
267
|
- spec/test_data/input/test.pdf
|
268
|
+
- spec/test_data/input/test.svg
|
267
269
|
- spec/test_data/input/test.tif
|
268
270
|
- spec/test_data/input/test2.jp2
|
269
271
|
- spec/test_data/input/test2.tif
|
@@ -278,16 +280,19 @@ require_paths:
|
|
278
280
|
- lib
|
279
281
|
required_ruby_version: !ruby/object:Gem::Requirement
|
280
282
|
requirements:
|
281
|
-
- - "
|
283
|
+
- - ">="
|
282
284
|
- !ruby/object:Gem::Version
|
283
285
|
version: '2.5'
|
286
|
+
- - "<"
|
287
|
+
- !ruby/object:Gem::Version
|
288
|
+
version: '4'
|
284
289
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
285
290
|
requirements:
|
286
291
|
- - ">="
|
287
292
|
- !ruby/object:Gem::Version
|
288
293
|
version: '0'
|
289
294
|
requirements: []
|
290
|
-
rubygems_version: 3.2.
|
295
|
+
rubygems_version: 3.2.32
|
291
296
|
signing_key:
|
292
297
|
specification_version: 4
|
293
298
|
summary: Ruby immplementation of file services needed to prepare objects to be accessioned
|
@@ -326,7 +331,9 @@ test_files:
|
|
326
331
|
- spec/test_data/input/someobject.obj
|
327
332
|
- spec/test_data/input/someobject.ply
|
328
333
|
- spec/test_data/input/test.jp2
|
334
|
+
- spec/test_data/input/test.json
|
329
335
|
- spec/test_data/input/test.pdf
|
336
|
+
- spec/test_data/input/test.svg
|
330
337
|
- spec/test_data/input/test.tif
|
331
338
|
- spec/test_data/input/test2.jp2
|
332
339
|
- spec/test_data/input/test2.tif
|