assembly-objectfile 1.8.3 → 1.8.4
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 +4 -4
- data/.github/ISSUE_TEMPLATE/bug_report.md +30 -0
- data/.github/pull_request_template.md +5 -0
- data/.rubocop.yml +0 -7
- data/.rubocop_todo.yml +35 -47
- data/.travis.yml +3 -4
- data/Gemfile +2 -0
- data/Rakefile +2 -0
- data/assembly-objectfile.gemspec +5 -2
- data/config/boot.rb +2 -0
- data/lib/assembly-objectfile.rb +19 -16
- data/lib/assembly-objectfile/content_metadata.rb +56 -174
- data/lib/assembly-objectfile/content_metadata/config.rb +24 -0
- data/lib/assembly-objectfile/content_metadata/file.rb +43 -0
- data/lib/assembly-objectfile/content_metadata/file_set.rb +71 -0
- data/lib/assembly-objectfile/content_metadata/file_set_builder.rb +61 -0
- data/lib/assembly-objectfile/content_metadata/nokogiri_builder.rb +55 -0
- data/lib/assembly-objectfile/object_file.rb +4 -2
- data/lib/assembly-objectfile/object_fileable.rb +5 -2
- data/lib/assembly-objectfile/version.rb +3 -1
- data/spec/content_metadata_spec.rb +6 -4
- data/spec/object_file_spec.rb +2 -0
- data/spec/spec_helper.rb +5 -3
- metadata +52 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 55d4581c113766a963826ca6e77b15edcab495dfe1a58d029515ac63f71dab61
|
|
4
|
+
data.tar.gz: 6345774179c1af7b1bb179dcb079c79f0c48d15418d15b6c9a8010d2a81d66a8
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 834d7062c0f3ffa547d5c88e051a5148598cbd6ec0debc9b0318da8c97725e9b136ee5cacbd64b49d1cf5e0bd7481ae4eaa5061e9b247772915b821f2af1c0d3
|
|
7
|
+
data.tar.gz: 3c2b9d1496af4400a57b383de90df51b02775e6f15afb6ca869607a4c890dd489cd932f99f473fb346de7fea81121e731ab1e04fb7c58dd4f6ee77bedda37ae3
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Bug report
|
|
3
|
+
about: File a bug report
|
|
4
|
+
title: ''
|
|
5
|
+
labels: bug
|
|
6
|
+
assignees: ''
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
**Describe the bug**
|
|
11
|
+
A clear and concise description of what the bug is.
|
|
12
|
+
|
|
13
|
+
**User Impact**
|
|
14
|
+
A description of the impact of this bug on an end-user (or your own work).
|
|
15
|
+
|
|
16
|
+
**To Reproduce**
|
|
17
|
+
Steps to reproduce the behavior:
|
|
18
|
+
1. Go to '...'
|
|
19
|
+
2. Click on '....'
|
|
20
|
+
3. Scroll down to '....'
|
|
21
|
+
4. See error
|
|
22
|
+
|
|
23
|
+
**Expected behavior**
|
|
24
|
+
A clear and concise description of what you expected to happen.
|
|
25
|
+
|
|
26
|
+
**Screenshots**
|
|
27
|
+
If applicable, add screenshots to help explain your problem.
|
|
28
|
+
|
|
29
|
+
**Additional context**
|
|
30
|
+
Add any other context about the problem here.
|
data/.rubocop.yml
CHANGED
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
inherit_from: .rubocop_todo.yml
|
|
2
2
|
require: rubocop-rspec
|
|
3
3
|
|
|
4
|
-
# Configuration parameters: AllowURI, URISchemes.
|
|
5
|
-
Metrics/LineLength:
|
|
6
|
-
Max: 200
|
|
7
|
-
|
|
8
4
|
RSpec/ContextWording:
|
|
9
5
|
Enabled: false # too dogmatic
|
|
10
6
|
|
|
@@ -15,8 +11,5 @@ RSpec/ExampleLength:
|
|
|
15
11
|
RSpec/MessageSpies:
|
|
16
12
|
Enabled: false
|
|
17
13
|
|
|
18
|
-
RSpec/MultipleExpectations:
|
|
19
|
-
Max: 5
|
|
20
|
-
|
|
21
14
|
RSpec/NestedGroups:
|
|
22
15
|
Max: 4 # default: 3
|
data/.rubocop_todo.yml
CHANGED
|
@@ -1,78 +1,62 @@
|
|
|
1
1
|
# This configuration was generated by
|
|
2
2
|
# `rubocop --auto-gen-config`
|
|
3
|
-
# on
|
|
3
|
+
# on 2019-10-17 23:28:35 -0500 using RuboCop version 0.75.1.
|
|
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
9
|
# Offense count: 1
|
|
10
|
-
|
|
11
|
-
# Configuration parameters: EnforcedStyleAlignWith, AutoCorrect, Severity.
|
|
12
|
-
# SupportedStylesAlignWith: keyword, variable, start_of_line
|
|
13
|
-
Layout/EndAlignment:
|
|
10
|
+
Lint/AmbiguousBlockAssociation:
|
|
14
11
|
Exclude:
|
|
15
|
-
- '
|
|
12
|
+
- 'spec/content_metadata_spec.rb'
|
|
16
13
|
|
|
17
14
|
# Offense count: 1
|
|
18
15
|
Lint/UselessAssignment:
|
|
19
16
|
Exclude:
|
|
20
17
|
- 'config/boot.rb'
|
|
21
18
|
|
|
22
|
-
# Offense count: 5
|
|
23
|
-
# Configuration parameters: CheckForMethodsWithNoSideEffects.
|
|
24
|
-
Lint/Void:
|
|
25
|
-
Exclude:
|
|
26
|
-
- 'spec/content_metadata_spec.rb'
|
|
27
|
-
|
|
28
19
|
# Offense count: 3
|
|
29
20
|
Metrics/AbcSize:
|
|
30
|
-
Max:
|
|
21
|
+
Max: 51
|
|
31
22
|
|
|
32
|
-
# Offense count:
|
|
23
|
+
# Offense count: 11
|
|
33
24
|
# Configuration parameters: CountComments, ExcludedMethods.
|
|
34
25
|
# ExcludedMethods: refine
|
|
35
26
|
Metrics/BlockLength:
|
|
36
|
-
Max:
|
|
27
|
+
Max: 577
|
|
37
28
|
|
|
38
|
-
# Offense count:
|
|
39
|
-
# Configuration parameters: CountComments.
|
|
40
|
-
Metrics/ClassLength:
|
|
41
|
-
Max: 137
|
|
42
|
-
|
|
43
|
-
# Offense count: 1
|
|
29
|
+
# Offense count: 3
|
|
44
30
|
Metrics/CyclomaticComplexity:
|
|
45
|
-
Max:
|
|
46
|
-
|
|
47
|
-
# Offense count: 26
|
|
48
|
-
# Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns.
|
|
49
|
-
# URISchemes: http, https
|
|
50
|
-
Metrics/LineLength:
|
|
51
|
-
Max: 304
|
|
31
|
+
Max: 14
|
|
52
32
|
|
|
53
|
-
# Offense count:
|
|
54
|
-
# Configuration parameters: CountComments.
|
|
33
|
+
# Offense count: 5
|
|
34
|
+
# Configuration parameters: CountComments, ExcludedMethods.
|
|
55
35
|
Metrics/MethodLength:
|
|
56
|
-
Max:
|
|
36
|
+
Max: 30
|
|
57
37
|
|
|
58
38
|
# Offense count: 1
|
|
59
39
|
# Configuration parameters: CountComments.
|
|
60
40
|
Metrics/ModuleLength:
|
|
61
|
-
Max:
|
|
41
|
+
Max: 107
|
|
62
42
|
|
|
63
43
|
# Offense count: 1
|
|
64
|
-
|
|
65
|
-
|
|
44
|
+
# Configuration parameters: CountKeywordArgs.
|
|
45
|
+
Metrics/ParameterLists:
|
|
46
|
+
Max: 11
|
|
66
47
|
|
|
67
48
|
# Offense count: 2
|
|
49
|
+
Metrics/PerceivedComplexity:
|
|
50
|
+
Max: 12
|
|
51
|
+
|
|
52
|
+
# Offense count: 1
|
|
68
53
|
# Configuration parameters: ExpectMatchingDefinition, Regex, IgnoreExecutableScripts, AllowedAcronyms.
|
|
69
54
|
# AllowedAcronyms: CLI, DSL, ACL, API, ASCII, CPU, CSS, DNS, EOF, GUID, HTML, HTTP, HTTPS, ID, IP, JSON, LHS, QPS, RAM, RHS, RPC, SLA, SMTP, SQL, SSH, TCP, TLS, TTL, UDP, UI, UID, UUID, URI, URL, UTF8, VM, XML, XMPP, XSRF, XSS
|
|
70
55
|
Naming/FileName:
|
|
71
56
|
Exclude:
|
|
72
|
-
- 'assembly-objectfile.gemspec'
|
|
73
57
|
- 'lib/assembly-objectfile.rb'
|
|
74
58
|
|
|
75
|
-
# Offense count:
|
|
59
|
+
# Offense count: 1
|
|
76
60
|
# Configuration parameters: NamePrefix, NamePrefixBlacklist, NameWhitelist, MethodDefinitionMacros.
|
|
77
61
|
# NamePrefix: is_, has_, have_
|
|
78
62
|
# NamePrefixBlacklist: is_, has_, have_
|
|
@@ -81,7 +65,6 @@ Naming/FileName:
|
|
|
81
65
|
Naming/PredicateName:
|
|
82
66
|
Exclude:
|
|
83
67
|
- 'spec/**/*'
|
|
84
|
-
- 'lib/assembly-objectfile/content_metadata.rb'
|
|
85
68
|
- 'lib/assembly-objectfile/object_fileable.rb'
|
|
86
69
|
|
|
87
70
|
# Offense count: 8
|
|
@@ -97,13 +80,13 @@ RSpec/FilePath:
|
|
|
97
80
|
- 'spec/content_metadata_spec.rb'
|
|
98
81
|
- 'spec/object_file_spec.rb'
|
|
99
82
|
|
|
100
|
-
# Offense count:
|
|
83
|
+
# Offense count: 67
|
|
101
84
|
# Configuration parameters: AssignmentOnly.
|
|
102
85
|
RSpec/InstanceVariable:
|
|
103
86
|
Exclude:
|
|
104
87
|
- 'spec/object_file_spec.rb'
|
|
105
88
|
|
|
106
|
-
# Offense count:
|
|
89
|
+
# Offense count: 38
|
|
107
90
|
# Configuration parameters: AggregateFailuresByDefault.
|
|
108
91
|
RSpec/MultipleExpectations:
|
|
109
92
|
Max: 29
|
|
@@ -113,20 +96,25 @@ RSpec/RepeatedDescription:
|
|
|
113
96
|
Exclude:
|
|
114
97
|
- 'spec/object_file_spec.rb'
|
|
115
98
|
|
|
116
|
-
# Offense count:
|
|
117
|
-
|
|
99
|
+
# Offense count: 2
|
|
100
|
+
RSpec/RepeatedExample:
|
|
118
101
|
Exclude:
|
|
119
|
-
- '
|
|
102
|
+
- 'spec/object_file_spec.rb'
|
|
120
103
|
|
|
121
|
-
# Offense count:
|
|
122
|
-
Style/
|
|
104
|
+
# Offense count: 2
|
|
105
|
+
Style/CommentedKeyword:
|
|
123
106
|
Exclude:
|
|
124
|
-
- '
|
|
125
|
-
- 'test/**/*'
|
|
126
|
-
- 'lib/assembly-objectfile.rb'
|
|
107
|
+
- 'lib/assembly-objectfile/content_metadata.rb'
|
|
127
108
|
|
|
128
109
|
# Offense count: 1
|
|
129
110
|
# Configuration parameters: MinBodyLength.
|
|
130
111
|
Style/GuardClause:
|
|
131
112
|
Exclude:
|
|
132
113
|
- 'lib/assembly-objectfile/object_file.rb'
|
|
114
|
+
|
|
115
|
+
# Offense count: 346
|
|
116
|
+
# Cop supports --auto-correct.
|
|
117
|
+
# Configuration parameters: AutoCorrect, AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns.
|
|
118
|
+
# URISchemes: http, https
|
|
119
|
+
Metrics/LineLength:
|
|
120
|
+
Max: 304
|
data/.travis.yml
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
|
|
2
1
|
language: ruby
|
|
3
2
|
rvm:
|
|
4
|
-
- 2.
|
|
5
|
-
- 2.
|
|
6
|
-
- 2.5.3
|
|
3
|
+
- 2.5.7
|
|
4
|
+
- 2.6.5
|
|
7
5
|
addons:
|
|
8
6
|
apt:
|
|
9
7
|
packages:
|
|
@@ -13,6 +11,7 @@ before_script:
|
|
|
13
11
|
- chmod +x ./cc-test-reporter
|
|
14
12
|
- ./cc-test-reporter before-build
|
|
15
13
|
script:
|
|
14
|
+
- bundle exec rubocop
|
|
16
15
|
- bundle exec rake
|
|
17
16
|
after_script:
|
|
18
17
|
- ./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT
|
data/Gemfile
CHANGED
data/Rakefile
CHANGED
data/assembly-objectfile.gemspec
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
$LOAD_PATH.push File.expand_path('lib', __dir__)
|
|
2
4
|
require 'assembly-objectfile/version'
|
|
3
5
|
|
|
@@ -12,14 +14,15 @@ Gem::Specification.new do |s|
|
|
|
12
14
|
s.description = 'Get exif data, file sizes and more.'
|
|
13
15
|
s.license = 'ALv2'
|
|
14
16
|
|
|
15
|
-
s.rubyforge_project = 'assembly-objectfile'
|
|
16
|
-
|
|
17
17
|
s.files = `git ls-files`.split("\n")
|
|
18
18
|
s.test_files = `git ls-files -- spec/*`.split("\n")
|
|
19
19
|
s.bindir = 'exe'
|
|
20
20
|
s.executables = s.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
|
21
21
|
s.require_paths = ['lib']
|
|
22
22
|
|
|
23
|
+
s.add_dependency 'activesupport', '>= 5.2.0'
|
|
24
|
+
s.add_dependency 'dry-struct', '~> 1.0'
|
|
25
|
+
s.add_dependency 'dry-types', '~> 1.1'
|
|
23
26
|
s.add_dependency 'mime-types', '> 3'
|
|
24
27
|
s.add_dependency 'mini_exiftool'
|
|
25
28
|
s.add_dependency 'nokogiri'
|
data/config/boot.rb
CHANGED
data/lib/assembly-objectfile.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Assembly
|
|
2
4
|
# the path to the gem, used to access profiles stored with the gem
|
|
3
5
|
PATH_TO_GEM = File.expand_path(File.dirname(__FILE__) + '/..')
|
|
@@ -14,23 +16,24 @@ module Assembly
|
|
|
14
16
|
TRUSTED_MIMETYPES = ['text/plain', 'plain/text', 'application/pdf', 'text/html', 'application/xml'].freeze
|
|
15
17
|
|
|
16
18
|
# default publish/preserve/shelve attributes used in content metadata
|
|
17
|
-
FILE_ATTRIBUTES = {}
|
|
18
19
|
# if no mimetype specific attributes are specified for a given file, define some defaults, and override for specific mimetypes below
|
|
19
|
-
FILE_ATTRIBUTES
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
20
|
+
FILE_ATTRIBUTES = {
|
|
21
|
+
'default' => { preserve: 'yes', shelve: 'no', publish: 'no' },
|
|
22
|
+
'image/tif' => { preserve: 'yes', shelve: 'no', publish: 'no' },
|
|
23
|
+
'image/tiff' => { preserve: 'yes', shelve: 'no', publish: 'no' },
|
|
24
|
+
'image/jp2' => { preserve: 'no', shelve: 'yes', publish: 'yes' },
|
|
25
|
+
'image/jpeg' => { preserve: 'yes', shelve: 'no', publish: 'no' },
|
|
26
|
+
'audio/wav' => { preserve: 'yes', shelve: 'no', publish: 'no' },
|
|
27
|
+
'audio/x-wav' => { preserve: 'yes', shelve: 'no', publish: 'no' },
|
|
28
|
+
'audio/mp3' => { preserve: 'no', shelve: 'yes', publish: 'yes' },
|
|
29
|
+
'audio/mpeg' => { preserve: 'no', shelve: 'yes', publish: 'yes' },
|
|
30
|
+
'application/pdf' => { preserve: 'yes', shelve: 'yes', publish: 'yes' },
|
|
31
|
+
'plain/text' => { preserve: 'yes', shelve: 'yes', publish: 'yes' },
|
|
32
|
+
'text/plain' => { preserve: 'yes', shelve: 'yes', publish: 'yes' },
|
|
33
|
+
'image/png' => { preserve: 'yes', shelve: 'yes', publish: 'no' },
|
|
34
|
+
'application/zip' => { preserve: 'yes', shelve: 'no', publish: 'no' },
|
|
35
|
+
'application/json' => { preserve: 'yes', shelve: 'yes', publish: 'yes' }
|
|
36
|
+
}.freeze
|
|
34
37
|
end
|
|
35
38
|
|
|
36
39
|
require 'assembly-objectfile/content_metadata'
|
|
@@ -1,4 +1,12 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'nokogiri'
|
|
4
|
+
require 'active_support'
|
|
5
|
+
require 'assembly-objectfile/content_metadata/file'
|
|
6
|
+
require 'assembly-objectfile/content_metadata/file_set'
|
|
7
|
+
require 'assembly-objectfile/content_metadata/file_set_builder'
|
|
8
|
+
require 'assembly-objectfile/content_metadata/config'
|
|
9
|
+
require 'assembly-objectfile/content_metadata/nokogiri_builder'
|
|
2
10
|
|
|
3
11
|
module Assembly
|
|
4
12
|
SPECIAL_DPG_FOLDERS = %w[31 44 50].freeze # these special dpg folders will force any files contained in them into their own resources, regardless of filenaming convention
|
|
@@ -43,195 +51,69 @@ module Assembly
|
|
|
43
51
|
# :auto_labels = optional - Will add automated resource labels (e.g. "File 1") when labels are not provided by the user. The default is true.
|
|
44
52
|
# Example:
|
|
45
53
|
# Assembly::ContentMetadata.create_content_metadata(:druid=>'druid:nx288wh8889',:style=>:simple_image,:objects=>object_files,:add_file_attributes=>false)
|
|
46
|
-
def self.create_content_metadata(
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
pid = druid.gsub('druid:', '') # remove druid prefix when creating IDs
|
|
53
|
-
|
|
54
|
-
style = params[:style] || :simple_image
|
|
55
|
-
bundle = params[:bundle] || :default
|
|
56
|
-
add_exif = params[:add_exif] || false
|
|
57
|
-
auto_labels = (params[:auto_labels].nil? ? true : params[:auto_labels])
|
|
58
|
-
add_file_attributes = params[:add_file_attributes] || false
|
|
59
|
-
file_attributes = params[:file_attributes] || {}
|
|
60
|
-
preserve_common_paths = params[:preserve_common_paths] || false
|
|
61
|
-
flatten_folder_structure = params[:flatten_folder_structure] || false
|
|
62
|
-
include_root_xml = params[:include_root_xml]
|
|
63
|
-
|
|
64
|
-
all_paths = []
|
|
65
|
-
objects.flatten.each do |obj|
|
|
66
|
-
raise "File '#{obj.path}' not found" unless obj.file_exists?
|
|
54
|
+
def self.create_content_metadata(druid:, objects:, auto_labels: true,
|
|
55
|
+
add_exif: false, bundle: :default, style: :simple_image,
|
|
56
|
+
add_file_attributes: false, file_attributes: {},
|
|
57
|
+
preserve_common_paths: false, flatten_folder_structure: false,
|
|
58
|
+
include_root_xml: nil)
|
|
67
59
|
|
|
68
|
-
|
|
69
|
-
|
|
60
|
+
common_path = find_common_path(objects) unless preserve_common_paths # find common paths to all files provided if needed
|
|
61
|
+
|
|
62
|
+
filesets = FileSetBuilder.build(bundle: bundle, objects: objects, style: style)
|
|
63
|
+
|
|
64
|
+
config = Config.new(auto_labels: auto_labels,
|
|
65
|
+
flatten_folder_structure: flatten_folder_structure,
|
|
66
|
+
add_file_attributes: add_file_attributes,
|
|
67
|
+
file_attributes: file_attributes,
|
|
68
|
+
add_exif: add_exif,
|
|
69
|
+
type: object_level_type(style))
|
|
70
|
+
|
|
71
|
+
builder = NokogiriBuilder.build(druid: druid,
|
|
72
|
+
filesets: filesets,
|
|
73
|
+
common_path: common_path,
|
|
74
|
+
config: config)
|
|
75
|
+
|
|
76
|
+
result = if include_root_xml == false
|
|
77
|
+
builder.doc.root.to_xml
|
|
78
|
+
else
|
|
79
|
+
builder.to_xml
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
result
|
|
83
|
+
end
|
|
70
84
|
|
|
71
|
-
|
|
85
|
+
def self.special_dpg_folder?(folder)
|
|
86
|
+
SPECIAL_DPG_FOLDERS.include?(folder)
|
|
87
|
+
end
|
|
72
88
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
89
|
+
def self.find_common_path(objects)
|
|
90
|
+
all_paths = objects.flatten.map do |obj|
|
|
91
|
+
raise "File '#{obj.path}' not found" unless obj.file_exists?
|
|
92
|
+
|
|
93
|
+
obj.path # collect all of the filenames into an array
|
|
94
|
+
end
|
|
76
95
|
|
|
77
|
-
#
|
|
78
|
-
|
|
96
|
+
Assembly::ObjectFile.common_path(all_paths) # find common paths to all files provided if needed
|
|
97
|
+
end
|
|
98
|
+
private_class_method :find_common_path
|
|
79
99
|
|
|
80
|
-
|
|
81
|
-
|
|
100
|
+
def self.object_level_type(style)
|
|
101
|
+
puts "WARNING - the style #{style} is now deprecated and should not be used." if DEPRECATED_STYLES.include? style
|
|
82
102
|
|
|
83
|
-
# set the object level content type id
|
|
84
103
|
case style
|
|
85
104
|
when :simple_image
|
|
86
|
-
|
|
105
|
+
'image'
|
|
87
106
|
when :file
|
|
88
|
-
|
|
107
|
+
'file'
|
|
89
108
|
when :simple_book, :book_with_pdf, :book_as_image
|
|
90
|
-
|
|
109
|
+
'book'
|
|
91
110
|
when :map
|
|
92
|
-
|
|
111
|
+
'map'
|
|
93
112
|
when :'3d'
|
|
94
|
-
|
|
113
|
+
'3d'
|
|
95
114
|
else
|
|
96
115
|
raise "Supplied style (#{style}) not valid"
|
|
97
116
|
end
|
|
98
|
-
|
|
99
|
-
puts "WARNING - the style #{style} is now deprecated and should not be used." if DEPRECATED_STYLES.include? style
|
|
100
|
-
|
|
101
|
-
# determine how many resources to create
|
|
102
|
-
# setup an array of arrays, where the first array is the number of resources, and the second array is the object files containined in that resource
|
|
103
|
-
case bundle
|
|
104
|
-
when :default # one resource per object
|
|
105
|
-
resources = objects.collect { |obj| [obj] }
|
|
106
|
-
when :filename # one resource per distinct filename (excluding extension)
|
|
107
|
-
# loop over distinct filenames, this determines how many resources we will have and
|
|
108
|
-
# create one resource node per distinct filename, collecting the relevant objects with the distinct filename into that resource
|
|
109
|
-
resources = []
|
|
110
|
-
distinct_filenames = objects.collect(&:filename_without_ext).uniq # find all the unique filenames in the set of objects, leaving off extensions and base paths
|
|
111
|
-
distinct_filenames.each { |distinct_filename| resources << objects.collect { |obj| obj if obj.filename_without_ext == distinct_filename }.compact }
|
|
112
|
-
when :dpg # group by DPG filename
|
|
113
|
-
# loop over distinct dpg base names, this determines how many resources we will have and
|
|
114
|
-
# create one resource node per distinct dpg base name, collecting the relevant objects with the distinct names into that resource
|
|
115
|
-
resources = []
|
|
116
|
-
distinct_filenames = objects.collect(&:dpg_basename).uniq # find all the unique DPG filenames in the set of objects
|
|
117
|
-
distinct_filenames.each do |distinct_filename|
|
|
118
|
-
resources << objects.collect { |obj| obj if obj.dpg_basename == distinct_filename && !is_special_dpg_folder?(obj.dpg_folder) }.compact
|
|
119
|
-
end
|
|
120
|
-
objects.each { |obj| resources << [obj] if is_special_dpg_folder?(obj.dpg_folder) } # certain subfolders require individual resources for files within them regardless of file-naming convention
|
|
121
|
-
when :prebundled
|
|
122
|
-
# if the user specifies this method, they will pass in an array of arrays, indicating resources, so we don't need to bundle in the gem
|
|
123
|
-
resources = objects
|
|
124
|
-
else
|
|
125
|
-
raise 'Invalid bundle method'
|
|
126
|
-
end
|
|
127
|
-
|
|
128
|
-
resources.delete([]) # delete any empty elements
|
|
129
|
-
|
|
130
|
-
builder = Nokogiri::XML::Builder.new do |xml|
|
|
131
|
-
xml.contentMetadata(objectId: druid.to_s, type: content_type_description) do
|
|
132
|
-
resources.each do |resource_files| # iterate over all the resources
|
|
133
|
-
# start a new resource element
|
|
134
|
-
sequence += 1
|
|
135
|
-
resource_id = "#{pid}_#{sequence}"
|
|
136
|
-
|
|
137
|
-
# grab all of the file types within a resource into an array so we can decide what the resource type should be
|
|
138
|
-
resource_file_types = resource_files.collect(&:object_type)
|
|
139
|
-
resource_has_non_images = !(resource_file_types - [:image]).empty?
|
|
140
|
-
resource_from_special_dpg_folder = resource_files.collect { |obj| is_special_dpg_folder?(obj.dpg_folder) }.uniq
|
|
141
|
-
|
|
142
|
-
if bundle == :dpg && resource_from_special_dpg_folder.include?(true) # objects in the special DPG folders are always type=object when we using :bundle=>:dpg
|
|
143
|
-
resource_type_description = resource_type_descriptions[:object]
|
|
144
|
-
else # otherwise look at the style to determine the resource_type_description
|
|
145
|
-
case style
|
|
146
|
-
when :simple_image
|
|
147
|
-
resource_type_description = resource_type_descriptions[:image]
|
|
148
|
-
when :file
|
|
149
|
-
resource_type_description = resource_type_descriptions[:file]
|
|
150
|
-
when :simple_book # in a simple book project, all resources are pages unless they are *all* non-images -- if so, switch the type to object
|
|
151
|
-
resource_type_description = resource_has_non_images && resource_file_types.include?(:image) == false ? resource_type_descriptions[:object] : resource_type_descriptions[:book]
|
|
152
|
-
when :book_as_image # same as simple book, but all resources are images instead of pages, unless we need to switch them to object type
|
|
153
|
-
resource_type_description = resource_has_non_images && resource_file_types.include?(:image) == false ? resource_type_descriptions[:object] : resource_type_descriptions[:image]
|
|
154
|
-
when :book_with_pdf # in book with PDF type, if we find a resource with *any* non images, switch it's type from book to object
|
|
155
|
-
resource_type_description = resource_has_non_images ? resource_type_descriptions[:object] : resource_type_descriptions[:book]
|
|
156
|
-
when :map
|
|
157
|
-
resource_type_description = resource_type_descriptions[:map]
|
|
158
|
-
when :'3d'
|
|
159
|
-
resource_extensions = resource_files.collect {|obj| obj.ext}
|
|
160
|
-
if (resource_extensions & VALID_THREE_DIMENSION_EXTENTIONS).empty? # if this resource contains no known 3D file extensions, the resource type is file
|
|
161
|
-
resource_type_description = resource_type_descriptions[:file]
|
|
162
|
-
else # otherwise the resource type is 3d
|
|
163
|
-
resource_type_description = resource_type_descriptions[:'3d']
|
|
164
|
-
end
|
|
165
|
-
end
|
|
166
|
-
end
|
|
167
|
-
|
|
168
|
-
resource_type_counters[resource_type_description.to_sym] += 1 # each resource type description gets its own incrementing counter
|
|
169
|
-
|
|
170
|
-
xml.resource(id: resource_id, sequence: sequence, type: resource_type_description) do
|
|
171
|
-
# create a generic resource label if needed
|
|
172
|
-
resource_label = (auto_labels == true ? "#{resource_type_description.capitalize} #{resource_type_counters[resource_type_description.to_sym]}" : '')
|
|
173
|
-
|
|
174
|
-
# but if one of the files has a label, use it instead
|
|
175
|
-
resource_files.each { |obj| resource_label = obj.label unless obj.label.nil? || obj.label.empty? }
|
|
176
|
-
|
|
177
|
-
xml.label(resource_label) unless resource_label.empty?
|
|
178
|
-
|
|
179
|
-
resource_files.each do |obj| # iterate over all the files in a resource
|
|
180
|
-
mimetype = obj.mimetype if add_file_attributes || add_exif # we only need to compute the mimetype if we are adding file attributes or exif info, otherwise skip it for performance reasons
|
|
181
|
-
|
|
182
|
-
# set file id attribute, first check the relative_path parameter on the object, and if it is set, just use that
|
|
183
|
-
if obj.relative_path
|
|
184
|
-
file_id = obj.relative_path
|
|
185
|
-
else
|
|
186
|
-
# if the relative_path attribute is not set, then use the path attribute and check to see if we need to remove the common part of the path
|
|
187
|
-
file_id = preserve_common_paths ? obj.path : obj.path.gsub(common_path, '')
|
|
188
|
-
file_id = File.basename(file_id) if flatten_folder_structure
|
|
189
|
-
end
|
|
190
|
-
|
|
191
|
-
xml_file_params = { id: file_id }
|
|
192
|
-
|
|
193
|
-
if add_file_attributes
|
|
194
|
-
file_attributes_hash = obj.file_attributes || file_attributes[mimetype] || file_attributes['default'] || Assembly::FILE_ATTRIBUTES[mimetype] || Assembly::FILE_ATTRIBUTES['default']
|
|
195
|
-
xml_file_params.merge!(
|
|
196
|
-
preserve: file_attributes_hash[:preserve],
|
|
197
|
-
publish: file_attributes_hash[:publish],
|
|
198
|
-
shelve: file_attributes_hash[:shelve],
|
|
199
|
-
role: file_attributes_hash[:role]
|
|
200
|
-
)
|
|
201
|
-
xml_file_params.reject! { |_k, v| v.nil? || v.empty? }
|
|
202
|
-
end
|
|
203
|
-
|
|
204
|
-
if add_exif
|
|
205
|
-
xml_file_params[:mimetype] = mimetype
|
|
206
|
-
xml_file_params[:size] = obj.filesize
|
|
207
|
-
end
|
|
208
|
-
xml.file(xml_file_params) do
|
|
209
|
-
if add_exif # add exif info if the user requested it
|
|
210
|
-
xml.checksum(obj.sha1, type: 'sha1')
|
|
211
|
-
xml.checksum(obj.md5, type: 'md5')
|
|
212
|
-
xml.imageData(height: obj.exif.imageheight, width: obj.exif.imagewidth) if obj.image? # add image data for an image
|
|
213
|
-
elsif obj.provider_md5 || obj.provider_sha1 # if we did not add exif info, see if there are user supplied checksums to add
|
|
214
|
-
xml.checksum(obj.provider_sha1, type: 'sha1') if obj.provider_sha1
|
|
215
|
-
xml.checksum(obj.provider_md5, type: 'md5') if obj.provider_md5
|
|
216
|
-
end # add_exif
|
|
217
|
-
end
|
|
218
|
-
end # end resource_files.each
|
|
219
|
-
end
|
|
220
|
-
end # resources.each
|
|
221
|
-
end
|
|
222
|
-
end
|
|
223
|
-
|
|
224
|
-
result = if include_root_xml == false
|
|
225
|
-
builder.doc.root.to_xml
|
|
226
|
-
else
|
|
227
|
-
builder.to_xml
|
|
228
|
-
end
|
|
229
|
-
|
|
230
|
-
result
|
|
231
|
-
end # create_content_metadata
|
|
232
|
-
|
|
233
|
-
def self.is_special_dpg_folder?(folder)
|
|
234
|
-
SPECIAL_DPG_FOLDERS.include?(folder)
|
|
235
117
|
end
|
|
236
118
|
end # class
|
|
237
119
|
end # module
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'dry-struct'
|
|
4
|
+
require 'dry-types'
|
|
5
|
+
|
|
6
|
+
module Assembly
|
|
7
|
+
class ContentMetadata
|
|
8
|
+
# Types for the configuration
|
|
9
|
+
module Types
|
|
10
|
+
include Dry.Types()
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# Represents a configuration for generating the content metadata
|
|
14
|
+
class Config < Dry::Struct
|
|
15
|
+
STYLES = %w[image file book map 3d].freeze
|
|
16
|
+
attribute :auto_labels, Types::Strict::Bool.default(true)
|
|
17
|
+
attribute :flatten_folder_structure, Types::Strict::Bool.default(false)
|
|
18
|
+
attribute :add_file_attributes, Types::Strict::Bool.default(false)
|
|
19
|
+
attribute :add_exif, Types::Strict::Bool.default(false)
|
|
20
|
+
attribute :file_attributes, Types::Strict::Hash.default({}.freeze)
|
|
21
|
+
attribute :type, Types::Strict::String.enum(*STYLES)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'active_support/core_ext/module/delegation'
|
|
4
|
+
|
|
5
|
+
module Assembly
|
|
6
|
+
class ContentMetadata
|
|
7
|
+
# Represents a single File
|
|
8
|
+
class File
|
|
9
|
+
# @param [Symbol] bundle
|
|
10
|
+
# @param [Assembly::ObjectFile] file
|
|
11
|
+
# @param style
|
|
12
|
+
def initialize(bundle: nil, file:, style: nil)
|
|
13
|
+
@bundle = bundle
|
|
14
|
+
@file = file
|
|
15
|
+
@style = style
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
delegate :sha1, :md5, :provider_md5, :provider_sha1, :mimetype, :filesize, :image?, to: :file
|
|
19
|
+
|
|
20
|
+
def file_id(common_path:, flatten_folder_structure:)
|
|
21
|
+
# set file id attribute, first check the relative_path parameter on the object, and if it is set, just use that
|
|
22
|
+
return file.relative_path if file.relative_path
|
|
23
|
+
|
|
24
|
+
# if the relative_path attribute is not set, then use the path attribute and check to see if we need to remove the common part of the path
|
|
25
|
+
file_id = common_path ? file.path.gsub(common_path, '') : file.path
|
|
26
|
+
file_id = ::File.basename(file_id) if flatten_folder_structure
|
|
27
|
+
file_id
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def file_attributes(provided_file_attributes)
|
|
31
|
+
file.file_attributes || provided_file_attributes[mimetype] || provided_file_attributes['default'] || Assembly::FILE_ATTRIBUTES[mimetype] || Assembly::FILE_ATTRIBUTES['default']
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def image_data
|
|
35
|
+
{ height: file.exif.imageheight, width: file.exif.imagewidth }
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
private
|
|
39
|
+
|
|
40
|
+
attr_reader :file
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'active_support/core_ext/object/blank'
|
|
4
|
+
|
|
5
|
+
module Assembly
|
|
6
|
+
class ContentMetadata
|
|
7
|
+
# Represents a groups of related Files, such as a single master file and the derivatives
|
|
8
|
+
class FileSet
|
|
9
|
+
# @param [Boolean] dpg (false) is it a dpg bundle?
|
|
10
|
+
# @param [Array] resource_files
|
|
11
|
+
# @param style
|
|
12
|
+
def initialize(dpg: false, resource_files:, style:)
|
|
13
|
+
@dpg = dpg
|
|
14
|
+
@resource_files = resource_files
|
|
15
|
+
@style = style
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# objects in the special DPG folders are always type=object when we using :bundle=>:dpg
|
|
19
|
+
# otherwise look at the style to determine the resource_type_description
|
|
20
|
+
def resource_type_description
|
|
21
|
+
@resource_type_description ||= special_dpg_resource? ? 'object' : resource_type_descriptions
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def label_from_file(default:)
|
|
25
|
+
resource_files.find { |obj| obj.label.present? }&.label || default
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def files
|
|
29
|
+
resource_files.map { |file| File.new(file: file) }
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
private
|
|
33
|
+
|
|
34
|
+
attr_reader :dpg, :resource_files, :style
|
|
35
|
+
|
|
36
|
+
def special_dpg_resource?
|
|
37
|
+
return false unless dpg
|
|
38
|
+
|
|
39
|
+
resource_files.collect { |obj| ContentMetadata.special_dpg_folder?(obj.dpg_folder) }.include?(true)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def resource_type_descriptions
|
|
43
|
+
# grab all of the file types within a resource into an array so we can decide what the resource type should be
|
|
44
|
+
resource_file_types = resource_files.collect(&:object_type)
|
|
45
|
+
resource_has_non_images = !(resource_file_types - [:image]).empty?
|
|
46
|
+
|
|
47
|
+
case style
|
|
48
|
+
when :simple_image
|
|
49
|
+
'image'
|
|
50
|
+
when :file
|
|
51
|
+
'file'
|
|
52
|
+
when :simple_book # in a simple book project, all resources are pages unless they are *all* non-images -- if so, switch the type to object
|
|
53
|
+
resource_has_non_images && resource_file_types.include?(:image) == false ? 'object' : 'page'
|
|
54
|
+
when :book_as_image # same as simple book, but all resources are images instead of pages, unless we need to switch them to object type
|
|
55
|
+
resource_has_non_images && resource_file_types.include?(:image) == false ? 'object' : 'image'
|
|
56
|
+
when :book_with_pdf # in book with PDF type, if we find a resource with *any* non images, switch it's type from book to object
|
|
57
|
+
resource_has_non_images ? 'object' : 'page'
|
|
58
|
+
when :map
|
|
59
|
+
'image'
|
|
60
|
+
when :'3d'
|
|
61
|
+
resource_extensions = resource_files.collect(&:ext)
|
|
62
|
+
if (resource_extensions & VALID_THREE_DIMENSION_EXTENTIONS).empty? # if this resource contains no known 3D file extensions, the resource type is file
|
|
63
|
+
'file'
|
|
64
|
+
else # otherwise the resource type is 3d
|
|
65
|
+
'3d'
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Assembly
|
|
4
|
+
class ContentMetadata
|
|
5
|
+
# Builds a groups of related Files, based on bundle
|
|
6
|
+
class FileSetBuilder
|
|
7
|
+
def self.build(bundle:, objects:, style:)
|
|
8
|
+
new(bundle: bundle, objects: objects, style: style).build
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def initialize(bundle:, objects:, style:)
|
|
12
|
+
@bundle = bundle
|
|
13
|
+
@objects = objects
|
|
14
|
+
@style = style
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# @return [Array<FileSet>] a list of filesets in the object
|
|
18
|
+
def build
|
|
19
|
+
case bundle
|
|
20
|
+
when :default # one resource per object
|
|
21
|
+
objects.collect { |obj| FileSet.new(resource_files: [obj], style: style) }
|
|
22
|
+
when :filename # one resource per distinct filename (excluding extension)
|
|
23
|
+
build_for_filename
|
|
24
|
+
when :dpg # group by DPG filename
|
|
25
|
+
build_for_dpg
|
|
26
|
+
when :prebundled
|
|
27
|
+
# if the user specifies this method, they will pass in an array of arrays, indicating resources, so we don't need to bundle in the gem
|
|
28
|
+
objects.map { |inner| FileSet.new(resource_files: inner, style: style) }
|
|
29
|
+
else
|
|
30
|
+
raise 'Invalid bundle method'
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
private
|
|
35
|
+
|
|
36
|
+
attr_reader :bundle, :objects, :style
|
|
37
|
+
|
|
38
|
+
def build_for_filename
|
|
39
|
+
# loop over distinct filenames, this determines how many resources we will have and
|
|
40
|
+
# create one resource node per distinct filename, collecting the relevant objects with the distinct filename into that resource
|
|
41
|
+
distinct_filenames = objects.collect(&:filename_without_ext).uniq # find all the unique filenames in the set of objects, leaving off extensions and base paths
|
|
42
|
+
distinct_filenames.map do |distinct_filename|
|
|
43
|
+
FileSet.new(resource_files: objects.collect { |obj| obj if obj.filename_without_ext == distinct_filename }.compact,
|
|
44
|
+
style: style)
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def build_for_dpg
|
|
49
|
+
# loop over distinct dpg base names, this determines how many resources we will have and
|
|
50
|
+
# create one resource node per distinct dpg base name, collecting the relevant objects with the distinct names into that resource
|
|
51
|
+
|
|
52
|
+
distinct_filenames = objects.collect(&:dpg_basename).uniq # find all the unique DPG filenames in the set of objects
|
|
53
|
+
resources = distinct_filenames.map do |distinct_filename|
|
|
54
|
+
FileSet.new(dpg: true, resource_files: objects.collect { |obj| obj if obj.dpg_basename == distinct_filename && !ContentMetadata.special_dpg_folder?(obj.dpg_folder) }.compact, style: style)
|
|
55
|
+
end
|
|
56
|
+
objects.each { |obj| resources << FileSet.new(dpg: true, resource_files: [obj], style: style) if ContentMetadata.special_dpg_folder?(obj.dpg_folder) } # certain subfolders require individual resources for files within them regardless of file-naming convention
|
|
57
|
+
resources
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Assembly
|
|
4
|
+
class ContentMetadata
|
|
5
|
+
# Builds a nokogiri representation of the content metadata
|
|
6
|
+
class NokogiriBuilder
|
|
7
|
+
# @param [Array<Fileset>] filesets
|
|
8
|
+
# @param [String] druid
|
|
9
|
+
# @param [String] common_path
|
|
10
|
+
# @param [Config] config
|
|
11
|
+
def self.build(filesets:, druid:, common_path:, config:)
|
|
12
|
+
# a counter to use when creating auto-labels for resources, with incremenets for each type
|
|
13
|
+
resource_type_counters = Hash.new(0)
|
|
14
|
+
pid = druid.gsub('druid:', '') # remove druid prefix when creating IDs
|
|
15
|
+
|
|
16
|
+
Nokogiri::XML::Builder.new do |xml|
|
|
17
|
+
xml.contentMetadata(objectId: druid.to_s, type: config.type) do
|
|
18
|
+
filesets.each_with_index do |fileset, index| # iterate over all the resources
|
|
19
|
+
# start a new resource element
|
|
20
|
+
sequence = index + 1
|
|
21
|
+
|
|
22
|
+
resource_type_counters[fileset.resource_type_description] += 1 # each resource type description gets its own incrementing counter
|
|
23
|
+
|
|
24
|
+
xml.resource(id: "#{pid}_#{sequence}", sequence: sequence, type: fileset.resource_type_description) do
|
|
25
|
+
# create a generic resource label if needed
|
|
26
|
+
default_label = config.auto_labels ? "#{fileset.resource_type_description.capitalize} #{resource_type_counters[fileset.resource_type_description]}" : ''
|
|
27
|
+
|
|
28
|
+
# but if one of the files has a label, use it instead
|
|
29
|
+
resource_label = fileset.label_from_file(default: default_label)
|
|
30
|
+
|
|
31
|
+
xml.label(resource_label) unless resource_label.empty?
|
|
32
|
+
fileset.files.each do |obj| # iterate over all the files in a resource
|
|
33
|
+
xml_file_params = { id: obj.file_id(common_path: common_path, flatten_folder_structure: config.flatten_folder_structure) }
|
|
34
|
+
xml_file_params.merge!(obj.file_attributes(config.file_attributes)) if config.add_file_attributes
|
|
35
|
+
xml_file_params.merge!(mimetype: obj.mimetype, size: obj.filesize) if config.add_exif
|
|
36
|
+
|
|
37
|
+
xml.file(xml_file_params) do
|
|
38
|
+
if config.add_exif # add exif info if the user requested it
|
|
39
|
+
xml.checksum(obj.sha1, type: 'sha1')
|
|
40
|
+
xml.checksum(obj.md5, type: 'md5')
|
|
41
|
+
xml.imageData(obj.image_data) if obj.image? # add image data for an image
|
|
42
|
+
elsif obj.provider_md5 || obj.provider_sha1 # if we did not add exif info, see if there are user supplied checksums to add
|
|
43
|
+
xml.checksum(obj.provider_sha1, type: 'sha1') if obj.provider_sha1
|
|
44
|
+
xml.checksum(obj.provider_md5, type: 'md5') if obj.provider_md5
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Assembly
|
|
2
4
|
# This class contains generic methods to operate on any file.
|
|
3
5
|
class ObjectFile
|
|
@@ -18,9 +20,9 @@ module Assembly
|
|
|
18
20
|
n += 1 while strings.all? { |s| s[n] && (s[n] == x[n]) }
|
|
19
21
|
common_prefix = x[0...n]
|
|
20
22
|
if common_prefix[-1, 1] != '/' # check if last element of the common string is the end of a directory
|
|
21
|
-
|
|
23
|
+
common_prefix.split('/')[0..-2].join('/') + '/' # if not, split string along directories, and reject last one
|
|
22
24
|
else
|
|
23
|
-
|
|
25
|
+
common_prefix # if it was, then return the common prefix directly
|
|
24
26
|
end
|
|
25
27
|
end
|
|
26
28
|
end
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'mini_exiftool'
|
|
2
4
|
require 'mime/types'
|
|
3
5
|
# require 'checksum-tools'
|
|
@@ -120,7 +122,7 @@ module Assembly
|
|
|
120
122
|
exif_mimetype
|
|
121
123
|
elsif file_mimetype # next, try exif/unix file system command
|
|
122
124
|
file_mimetype
|
|
123
|
-
else
|
|
125
|
+
else # finally, get it from the mime-types gem (using the file extension) if both of those failed for some reason
|
|
124
126
|
mtype = MIME::Types.type_for(path).first
|
|
125
127
|
mtype ? mtype.content_type : ''
|
|
126
128
|
end
|
|
@@ -148,7 +150,8 @@ module Assembly
|
|
|
148
150
|
@exif_mimetype ||= begin
|
|
149
151
|
check_for_file
|
|
150
152
|
prefer_exif = !Assembly::TRUSTED_MIMETYPES.include?(file_mimetype) # if it's not a "trusted" mimetype and there is exif data; get the mimetype from the exif
|
|
151
|
-
exif.mimetype if
|
|
153
|
+
exif.mimetype if
|
|
154
|
+
exif&.mimetype && prefer_exif
|
|
152
155
|
end
|
|
153
156
|
end
|
|
154
157
|
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'spec_helper'
|
|
2
4
|
|
|
3
5
|
describe Assembly::ContentMetadata do
|
|
@@ -512,8 +514,8 @@ describe Assembly::ContentMetadata do
|
|
|
512
514
|
end
|
|
513
515
|
|
|
514
516
|
it 'generates valid content metadata for a 3d object with one 3d type files and three other supporting files (where one supporting file is a non-viewable but downloadable 3d file)' do
|
|
515
|
-
objects=[Assembly::ObjectFile.new(TEST_OBJ_FILE),Assembly::ObjectFile.new(TEST_PLY_FILE),Assembly::ObjectFile.new(TEST_TIF_INPUT_FILE),Assembly::ObjectFile.new(TEST_PDF_FILE)]
|
|
516
|
-
result =
|
|
517
|
+
objects = [Assembly::ObjectFile.new(TEST_OBJ_FILE), Assembly::ObjectFile.new(TEST_PLY_FILE), Assembly::ObjectFile.new(TEST_TIF_INPUT_FILE), Assembly::ObjectFile.new(TEST_PDF_FILE)]
|
|
518
|
+
result = described_class.create_content_metadata(druid: TEST_DRUID, style: :'3d', objects: objects)
|
|
517
519
|
expect(result.class).to be String
|
|
518
520
|
xml = Nokogiri::XML(result)
|
|
519
521
|
expect(xml.errors.size).to be 0
|
|
@@ -600,9 +602,9 @@ describe Assembly::ContentMetadata do
|
|
|
600
602
|
|
|
601
603
|
it 'generates an error message when an unknown style is passed in' do
|
|
602
604
|
objects = []
|
|
603
|
-
expect
|
|
605
|
+
expect do
|
|
604
606
|
described_class.create_content_metadata(druid: TEST_DRUID, bundle: :prebundled, style: :borked, objects: objects)
|
|
605
|
-
|
|
607
|
+
end.to raise_error { |error|
|
|
606
608
|
expect(error.message).to eq('Supplied style (borked) not valid')
|
|
607
609
|
}
|
|
608
610
|
end
|
data/spec/object_file_spec.rb
CHANGED
data/spec/spec_helper.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'simplecov'
|
|
2
4
|
SimpleCov.start
|
|
3
5
|
|
|
@@ -52,7 +54,7 @@ TEST_RES3_TEI = File.join(TEST_INPUT_DIR, 'res3_teifile.txt')
|
|
|
52
54
|
|
|
53
55
|
TEST_FILE_NO_EXIF = File.join(TEST_INPUT_DIR, 'file_with_no_exif.xml')
|
|
54
56
|
|
|
55
|
-
TEST_OBJ_FILE=File.join(TEST_INPUT_DIR,'someobject.obj')
|
|
56
|
-
TEST_PLY_FILE=File.join(TEST_INPUT_DIR,'someobject.ply')
|
|
57
|
+
TEST_OBJ_FILE = File.join(TEST_INPUT_DIR, 'someobject.obj')
|
|
58
|
+
TEST_PLY_FILE = File.join(TEST_INPUT_DIR, 'someobject.ply')
|
|
57
59
|
|
|
58
|
-
TEST_DRUID = 'nx288wh8889'
|
|
60
|
+
TEST_DRUID = 'nx288wh8889'
|
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.8.
|
|
4
|
+
version: 1.8.4
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Peter Mangiafico
|
|
@@ -11,8 +11,50 @@ authors:
|
|
|
11
11
|
autorequire:
|
|
12
12
|
bindir: exe
|
|
13
13
|
cert_chain: []
|
|
14
|
-
date:
|
|
14
|
+
date: 2020-01-21 00:00:00.000000000 Z
|
|
15
15
|
dependencies:
|
|
16
|
+
- !ruby/object:Gem::Dependency
|
|
17
|
+
name: activesupport
|
|
18
|
+
requirement: !ruby/object:Gem::Requirement
|
|
19
|
+
requirements:
|
|
20
|
+
- - ">="
|
|
21
|
+
- !ruby/object:Gem::Version
|
|
22
|
+
version: 5.2.0
|
|
23
|
+
type: :runtime
|
|
24
|
+
prerelease: false
|
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
26
|
+
requirements:
|
|
27
|
+
- - ">="
|
|
28
|
+
- !ruby/object:Gem::Version
|
|
29
|
+
version: 5.2.0
|
|
30
|
+
- !ruby/object:Gem::Dependency
|
|
31
|
+
name: dry-struct
|
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
|
33
|
+
requirements:
|
|
34
|
+
- - "~>"
|
|
35
|
+
- !ruby/object:Gem::Version
|
|
36
|
+
version: '1.0'
|
|
37
|
+
type: :runtime
|
|
38
|
+
prerelease: false
|
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
40
|
+
requirements:
|
|
41
|
+
- - "~>"
|
|
42
|
+
- !ruby/object:Gem::Version
|
|
43
|
+
version: '1.0'
|
|
44
|
+
- !ruby/object:Gem::Dependency
|
|
45
|
+
name: dry-types
|
|
46
|
+
requirement: !ruby/object:Gem::Requirement
|
|
47
|
+
requirements:
|
|
48
|
+
- - "~>"
|
|
49
|
+
- !ruby/object:Gem::Version
|
|
50
|
+
version: '1.1'
|
|
51
|
+
type: :runtime
|
|
52
|
+
prerelease: false
|
|
53
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
54
|
+
requirements:
|
|
55
|
+
- - "~>"
|
|
56
|
+
- !ruby/object:Gem::Version
|
|
57
|
+
version: '1.1'
|
|
16
58
|
- !ruby/object:Gem::Dependency
|
|
17
59
|
name: mime-types
|
|
18
60
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -146,6 +188,8 @@ executables: []
|
|
|
146
188
|
extensions: []
|
|
147
189
|
extra_rdoc_files: []
|
|
148
190
|
files:
|
|
191
|
+
- ".github/ISSUE_TEMPLATE/bug_report.md"
|
|
192
|
+
- ".github/pull_request_template.md"
|
|
149
193
|
- ".gitignore"
|
|
150
194
|
- ".rubocop.yml"
|
|
151
195
|
- ".rubocop_todo.yml"
|
|
@@ -161,6 +205,11 @@ files:
|
|
|
161
205
|
- config/boot.rb
|
|
162
206
|
- lib/assembly-objectfile.rb
|
|
163
207
|
- lib/assembly-objectfile/content_metadata.rb
|
|
208
|
+
- lib/assembly-objectfile/content_metadata/config.rb
|
|
209
|
+
- lib/assembly-objectfile/content_metadata/file.rb
|
|
210
|
+
- lib/assembly-objectfile/content_metadata/file_set.rb
|
|
211
|
+
- lib/assembly-objectfile/content_metadata/file_set_builder.rb
|
|
212
|
+
- lib/assembly-objectfile/content_metadata/nokogiri_builder.rb
|
|
164
213
|
- lib/assembly-objectfile/object_file.rb
|
|
165
214
|
- lib/assembly-objectfile/object_fileable.rb
|
|
166
215
|
- lib/assembly-objectfile/version.rb
|
|
@@ -224,7 +273,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
224
273
|
- !ruby/object:Gem::Version
|
|
225
274
|
version: '0'
|
|
226
275
|
requirements: []
|
|
227
|
-
rubygems_version: 3.
|
|
276
|
+
rubygems_version: 3.1.2
|
|
228
277
|
signing_key:
|
|
229
278
|
specification_version: 4
|
|
230
279
|
summary: Ruby immplementation of file services needed to prepare objects to be accessioned
|