ddr-models 2.8.0 → 2.9.0.rc1
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/app/models/collection.rb +55 -0
- data/app/models/component.rb +23 -13
- data/app/models/item.rb +28 -0
- data/config/initializers/active_fedora_base.rb +8 -0
- data/lib/ddr/datastreams.rb +2 -0
- data/lib/ddr/datastreams/administrative_metadata_datastream.rb +3 -0
- data/lib/ddr/datastreams/caption_datastream.rb +5 -0
- data/lib/ddr/index/fields.rb +2 -0
- data/lib/ddr/models.rb +27 -5
- data/lib/ddr/models/base.rb +15 -2
- data/lib/ddr/models/captionable.rb +37 -0
- data/lib/ddr/models/has_children.rb +0 -28
- data/lib/ddr/models/has_intermediate_file.rb +23 -0
- data/lib/ddr/models/indexing.rb +2 -0
- data/lib/ddr/models/solr_document.rb +99 -0
- data/lib/ddr/models/streamable.rb +15 -0
- data/lib/ddr/models/version.rb +1 -1
- data/lib/ddr/vocab/asset.rb +4 -0
- data/spec/fixtures/abcd1234.vtt +38 -0
- data/spec/models/active_fedora_base_spec.rb +3 -0
- data/spec/models/collection_spec.rb +152 -0
- data/spec/models/component_spec.rb +32 -2
- data/spec/models/has_children_spec.rb +0 -51
- data/spec/models/indexing_spec.rb +8 -0
- data/spec/models/item_spec.rb +64 -0
- data/spec/models/solr_document_spec.rb +131 -0
- data/spec/support/shared_examples_for_captionable.rb +23 -0
- data/spec/support/shared_examples_for_streamable_media.rb +1 -0
- metadata +10 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0cc0364fbbf04479e361ddf450e21d70aa9d9f21
|
4
|
+
data.tar.gz: a18facc359b48603080daf6cbf8f82b22e41a15e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 08988037c01145241f52c2914b5f0330d93b79865e1effbdcea509f79b42b2a926956ec8aa049b406a788385d534f252f180aad054899618175598eefd1fcc87
|
7
|
+
data.tar.gz: 4bdc44aaf67465193eac2c5302a5f30abcefe6b60df8bb44653083f8f3f0441346a907df6a7b74fa53c880dd8cf9820537ca1365a0ca8d9802c7d5f7233c6864
|
data/app/models/collection.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'htmlentities'
|
1
2
|
#
|
2
3
|
# A Collection is a conceptual and administrative entity containing a set of items.
|
3
4
|
#
|
@@ -51,6 +52,10 @@ class Collection < Ddr::Models::Base
|
|
51
52
|
true
|
52
53
|
end
|
53
54
|
|
55
|
+
def default_structure
|
56
|
+
build_default_structure
|
57
|
+
end
|
58
|
+
|
54
59
|
private
|
55
60
|
|
56
61
|
def default_roles
|
@@ -69,4 +74,54 @@ class Collection < Ddr::Models::Base
|
|
69
74
|
save!
|
70
75
|
end
|
71
76
|
|
77
|
+
def build_default_structure
|
78
|
+
document = Ddr::Models::Structure.xml_template
|
79
|
+
structure = Ddr::Models::Structure.new(document)
|
80
|
+
metshdr = structure.add_metshdr
|
81
|
+
structure.add_agent(parent: metshdr, role: Ddr::Models::Structures::Agent::ROLE_CREATOR,
|
82
|
+
name: Ddr::Models::Structures::Agent::NAME_REPOSITORY_DEFAULT)
|
83
|
+
structmap = structure.add_structmap(type: Ddr::Models::Structure::TYPE_DEFAULT)
|
84
|
+
add_items_to_structure(structure, structmap)
|
85
|
+
structure
|
86
|
+
end
|
87
|
+
|
88
|
+
def add_items_to_structure(structure, structmap)
|
89
|
+
sorted_items_for_structure.each do |item|
|
90
|
+
if path = item[Ddr::Index::Fields::NESTED_PATH]
|
91
|
+
nest = path.split(File::SEPARATOR)
|
92
|
+
else
|
93
|
+
nest = []
|
94
|
+
end
|
95
|
+
find_or_create_div(structure, structmap, nest, item[Ddr::Index::Fields::PERMANENT_ID])
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def find_or_create_div(structure, parent, nest, permanent_id)
|
100
|
+
label = nest.shift
|
101
|
+
order = parent.elements.count + 1
|
102
|
+
if nest.empty?
|
103
|
+
div = structure.add_div(parent: parent, order: order)
|
104
|
+
add_mptr(structure, div, permanent_id)
|
105
|
+
else
|
106
|
+
label = HTMLEntities.new.encode(label)
|
107
|
+
div = parent.xpath(%Q[xmlns:div[@LABEL="#{label}"]]).first ||
|
108
|
+
structure.add_div(parent: parent, type: 'Directory', label: label, order: order)
|
109
|
+
find_or_create_div(structure, div, nest, permanent_id)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def add_mptr(structure, div, permanent_id)
|
114
|
+
structure.add_mptr(parent: div, href: permanent_id)
|
115
|
+
end
|
116
|
+
|
117
|
+
def sorted_items_for_structure
|
118
|
+
ActiveFedora::SolrService.query(association_query(:children), sort: item_sort_for_structure, rows: 999999)
|
119
|
+
end
|
120
|
+
|
121
|
+
def item_sort_for_structure
|
122
|
+
"#{Ddr::Index::Fields::NESTED_PATH} ASC,
|
123
|
+
#{Ddr::Index::Fields::LOCAL_ID} ASC,
|
124
|
+
#{Ddr::Index::Fields::OBJECT_CREATE_DATE} ASC"
|
125
|
+
end
|
126
|
+
|
72
127
|
end
|
data/app/models/component.rb
CHANGED
@@ -5,6 +5,7 @@
|
|
5
5
|
#
|
6
6
|
class Component < Ddr::Models::Base
|
7
7
|
|
8
|
+
include Ddr::Models::Captionable
|
8
9
|
include Ddr::Models::HasContent
|
9
10
|
include Ddr::Models::HasIntermediateFile
|
10
11
|
include Ddr::Models::HasMultiresImage
|
@@ -17,6 +18,10 @@ class Component < Ddr::Models::Base
|
|
17
18
|
alias_method :item, :parent
|
18
19
|
alias_method :item=, :parent=
|
19
20
|
|
21
|
+
STRUCTURALLY_RELEVANT_DATASTREAMS = [ Ddr::Datastreams::CAPTION, Ddr::Datastreams::CONTENT,
|
22
|
+
Ddr::Datastreams::INTERMEDIATE_FILE, Ddr::Datastreams::MULTIRES_IMAGE,
|
23
|
+
Ddr::Datastreams::STREAMABLE_MEDIA, Ddr::Datastreams::THUMBNAIL ]
|
24
|
+
|
20
25
|
def collection
|
21
26
|
self.parent.parent rescue nil
|
22
27
|
end
|
@@ -30,7 +35,7 @@ class Component < Ddr::Models::Base
|
|
30
35
|
end
|
31
36
|
|
32
37
|
def default_structure
|
33
|
-
build_default_structure
|
38
|
+
build_default_structure
|
34
39
|
end
|
35
40
|
|
36
41
|
private
|
@@ -41,19 +46,24 @@ class Component < Ddr::Models::Base
|
|
41
46
|
metshdr = structure.add_metshdr
|
42
47
|
structure.add_agent(parent: metshdr, role: Ddr::Models::Structures::Agent::ROLE_CREATOR,
|
43
48
|
name: Ddr::Models::Structures::Agent::NAME_REPOSITORY_DEFAULT)
|
44
|
-
filesec = structure.add_filesec
|
45
49
|
structmap = structure.add_structmap(type: Ddr::Models::Structure::TYPE_DEFAULT)
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
50
|
+
if has_content?
|
51
|
+
filesec = structure.add_filesec
|
52
|
+
div = structure.add_div(parent: structmap)
|
53
|
+
filegrp = structure.add_filegrp(parent: filesec)
|
54
|
+
add_use_to_structure(structure, filegrp, div, Ddr::Models::Structure::USE_ORIGINAL_FILE,
|
55
|
+
Ddr::Datastreams::CONTENT)
|
56
|
+
add_use_to_structure(structure, filegrp, div, Ddr::Models::Structure::USE_PRESERVATION_MASTER_FILE,
|
57
|
+
Ddr::Datastreams::CONTENT)
|
58
|
+
add_use_to_structure(structure, filegrp, div, Ddr::Models::Structure::USE_INTERMEDIATE_FILE,
|
59
|
+
Ddr::Datastreams::INTERMEDIATE_FILE) if has_intermediate_file?
|
60
|
+
add_service_file_uses_to_default_structure(structure, filegrp, div)
|
61
|
+
add_use_to_structure(structure, filegrp, div, Ddr::Models::Structure::USE_THUMBNAIL_IMAGE,
|
62
|
+
Ddr::Datastreams::THUMBNAIL) if has_thumbnail?
|
63
|
+
add_use_to_structure(structure, filegrp, div, Ddr::Models::Structure::USE_TRANSCRIPT,
|
64
|
+
Ddr::Datastreams::CAPTION) if captioned?
|
65
|
+
|
66
|
+
end
|
57
67
|
structure
|
58
68
|
end
|
59
69
|
|
data/app/models/item.rb
CHANGED
@@ -11,6 +11,8 @@ class Item < Ddr::Models::Base
|
|
11
11
|
has_many :children, property: :is_part_of, class_name: 'Component'
|
12
12
|
belongs_to :parent, property: :is_member_of_collection, class_name: 'Collection'
|
13
13
|
|
14
|
+
has_attributes :nested_path, datastream: Ddr::Datastreams::ADMIN_METADATA, multiple: false
|
15
|
+
|
14
16
|
alias_method :components, :children
|
15
17
|
alias_method :component_ids, :child_ids
|
16
18
|
|
@@ -37,4 +39,30 @@ class Item < Ddr::Models::Base
|
|
37
39
|
children_having_extracted_text.docs.map(&:extracted_text).flatten
|
38
40
|
end
|
39
41
|
|
42
|
+
def default_structure
|
43
|
+
build_default_structure
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def build_default_structure
|
49
|
+
document = Ddr::Models::Structure.xml_template
|
50
|
+
structure = Ddr::Models::Structure.new(document)
|
51
|
+
metshdr = structure.add_metshdr
|
52
|
+
structure.add_agent(parent: metshdr, role: Ddr::Models::Structures::Agent::ROLE_CREATOR,
|
53
|
+
name: Ddr::Models::Structures::Agent::NAME_REPOSITORY_DEFAULT)
|
54
|
+
structmap = structure.add_structmap(type: Ddr::Models::Structure::TYPE_DEFAULT)
|
55
|
+
add_components_to_structure(structure, structmap)
|
56
|
+
structure
|
57
|
+
end
|
58
|
+
|
59
|
+
def add_components_to_structure(structure, structmap)
|
60
|
+
count = 0
|
61
|
+
sorted_children.each do |child|
|
62
|
+
count += 1
|
63
|
+
div = structure.add_div(parent: structmap, order: count)
|
64
|
+
structure.add_mptr(parent: div, href: child[Ddr::Index::Fields::PERMANENT_ID])
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
40
68
|
end
|
@@ -69,6 +69,14 @@ module ActiveFedora
|
|
69
69
|
can_have_thumbnail? && thumbnail.has_content?
|
70
70
|
end
|
71
71
|
|
72
|
+
def captionable?
|
73
|
+
datastreams.include? Ddr::Datastreams::CAPTION
|
74
|
+
end
|
75
|
+
|
76
|
+
def captioned?
|
77
|
+
captionable? && datastreams[Ddr::Datastreams::CAPTION].has_content?
|
78
|
+
end
|
79
|
+
|
72
80
|
def can_be_streamable?
|
73
81
|
datastreams.include? Ddr::Datastreams::STREAMABLE_MEDIA
|
74
82
|
end
|
data/lib/ddr/datastreams.rb
CHANGED
@@ -5,6 +5,7 @@ module Ddr
|
|
5
5
|
extend ActiveSupport::Autoload
|
6
6
|
|
7
7
|
ADMIN_METADATA = "adminMetadata"
|
8
|
+
CAPTION = "caption"
|
8
9
|
CONTENT = "content"
|
9
10
|
DC = "DC"
|
10
11
|
DESC_METADATA = "descMetadata"
|
@@ -29,6 +30,7 @@ module Ddr
|
|
29
30
|
CHECKSUM_TYPES = [ CHECKSUM_TYPE_MD5, CHECKSUM_TYPE_SHA1, CHECKSUM_TYPE_SHA256, CHECKSUM_TYPE_SHA384, CHECKSUM_TYPE_SHA512 ]
|
30
31
|
|
31
32
|
autoload :AdministrativeMetadataDatastream
|
33
|
+
autoload :CaptionDatastream
|
32
34
|
autoload :ContentDatastream
|
33
35
|
autoload :DatastreamBehavior
|
34
36
|
autoload :DeleteExternalFiles
|
data/lib/ddr/index/fields.rb
CHANGED
@@ -74,6 +74,8 @@ module Ddr::Index
|
|
74
74
|
MEDIA_TYPE = Field.new :content_media_type, :symbol
|
75
75
|
MEDIUM_FACET = Field.new :medium_facet, :facetable
|
76
76
|
MULTIRES_IMAGE_FILE_PATH = Field.new :multires_image_file_path, :stored_sortable
|
77
|
+
NESTED_PATH = Field.new :nested_path, :stored_sortable
|
78
|
+
NESTED_PATH_TEXT = Field.new :nested_path_text, :searchable
|
77
79
|
OBJECT_PROFILE = Field.new :object_profile, :displayable
|
78
80
|
OBJECT_STATE = Field.new :object_state, :stored_sortable
|
79
81
|
OBJECT_CREATE_DATE = Field.new :system_create, :stored_sortable, type: :date
|
data/lib/ddr/models.rb
CHANGED
@@ -37,6 +37,7 @@ module Ddr
|
|
37
37
|
autoload :AdminSet
|
38
38
|
autoload :Base
|
39
39
|
autoload :Cache
|
40
|
+
autoload :Captionable
|
40
41
|
autoload :ChecksumInvalid, 'ddr/models/error'
|
41
42
|
autoload :Contact
|
42
43
|
autoload :ContentModelError, 'ddr/models/error'
|
@@ -134,15 +135,36 @@ module Ddr
|
|
134
135
|
# Maps file extensions to preferred media types
|
135
136
|
mattr_accessor :preferred_media_types do
|
136
137
|
{
|
137
|
-
'.mp4' => 'video/mp4',
|
138
|
-
'.flv' => 'video/flv',
|
139
|
-
'.webm' => 'video/webm',
|
140
138
|
'.aac' => 'audio/mp4',
|
141
|
-
'.m4a' => 'audio/mp4',
|
142
139
|
'.f4a' => 'audio/mp4',
|
140
|
+
'.flv' => 'video/flv',
|
141
|
+
'.m4a' => 'audio/mp4',
|
142
|
+
'.mov' => 'video/quicktime',
|
143
143
|
'.mp3' => 'audio/mpeg',
|
144
|
-
'.
|
144
|
+
'.mp4' => 'video/mp4',
|
145
145
|
'.oga' => 'audio/ogg',
|
146
|
+
'.ogg' => 'audio/ogg',
|
147
|
+
'.srt' => 'text/plain',
|
148
|
+
'.vtt' => 'text/vtt',
|
149
|
+
'.wav' => 'audio/wav',
|
150
|
+
'.webm' => 'video/webm',
|
151
|
+
'.zip' => 'application/zip'
|
152
|
+
}
|
153
|
+
end
|
154
|
+
|
155
|
+
# Maps media types to preferred file extensions
|
156
|
+
mattr_accessor :preferred_file_extensions do
|
157
|
+
{
|
158
|
+
'application/zip' => 'zip',
|
159
|
+
'audio/mp4' => 'm4a',
|
160
|
+
'audio/mpeg' => 'mp3',
|
161
|
+
'audio/ogg' => 'ogg',
|
162
|
+
'audio/wav' => 'wav',
|
163
|
+
'text/vtt' => 'vtt',
|
164
|
+
'video/flv' => 'flv',
|
165
|
+
'video/mp4' => 'mp4',
|
166
|
+
'video/quicktime' => 'mov',
|
167
|
+
'video/webm' => 'webm'
|
146
168
|
}
|
147
169
|
end
|
148
170
|
|
data/lib/ddr/models/base.rb
CHANGED
@@ -31,8 +31,8 @@ module Ddr
|
|
31
31
|
before_create :set_ingested_by, if: :performed_by, unless: :ingested_by
|
32
32
|
before_create :grant_default_roles
|
33
33
|
|
34
|
-
after_create :notify_ingest
|
35
34
|
after_create :assign_permanent_id!, if: :assign_permanent_id?
|
35
|
+
after_create :notify_ingest
|
36
36
|
|
37
37
|
around_save :notify_update, unless: :new_record?
|
38
38
|
|
@@ -95,6 +95,10 @@ module Ddr
|
|
95
95
|
datastreams.select { |dsid, ds| ds.changed? }
|
96
96
|
end
|
97
97
|
|
98
|
+
def new_datastreams_having_content
|
99
|
+
datastreams.select { |dsid, ds| ds.new? && ds.has_content? }
|
100
|
+
end
|
101
|
+
|
98
102
|
def datastreams_having_content
|
99
103
|
datastreams.select { |dsid, ds| ds.has_content? }
|
100
104
|
end
|
@@ -108,6 +112,12 @@ module Ddr
|
|
108
112
|
end
|
109
113
|
end
|
110
114
|
|
115
|
+
def parent_id
|
116
|
+
parent.id
|
117
|
+
rescue NoMethodError
|
118
|
+
nil
|
119
|
+
end
|
120
|
+
|
111
121
|
private
|
112
122
|
|
113
123
|
def grant_default_roles
|
@@ -141,7 +151,9 @@ module Ddr
|
|
141
151
|
.merge(pid: pid,
|
142
152
|
user_key: performed_by,
|
143
153
|
permanent_id: permanent_id,
|
144
|
-
model: self.class.to_s
|
154
|
+
model: self.class.to_s,
|
155
|
+
parent: parent_id,
|
156
|
+
skip_structure_updates: cache.fetch(:skip_structure_updates, false))
|
145
157
|
end
|
146
158
|
|
147
159
|
def notify_ingest
|
@@ -156,6 +168,7 @@ module Ddr
|
|
156
168
|
event_params = default_notification_payload.merge(
|
157
169
|
attributes_changed: changes,
|
158
170
|
datastreams_changed: datastreams_changed.keys,
|
171
|
+
new_datastreams: new_datastreams_having_content.keys,
|
159
172
|
skip_update_derivatives: cache.fetch(:skip_update_derivatives, false)
|
160
173
|
)
|
161
174
|
ActiveSupport::Notifications.instrument(UPDATE, event_params) do |payload|
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Ddr::Models
|
2
|
+
module Captionable
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
has_file_datastream name: Ddr::Datastreams::CAPTION,
|
7
|
+
type: Ddr::Datastreams::CaptionDatastream,
|
8
|
+
versionable: true,
|
9
|
+
label: "Caption file for this object",
|
10
|
+
control_group: "E"
|
11
|
+
end
|
12
|
+
|
13
|
+
def caption_type
|
14
|
+
datastreams[Ddr::Datastreams::CAPTION].mimeType
|
15
|
+
end
|
16
|
+
|
17
|
+
def caption_extension
|
18
|
+
extensions = Ddr::Models.preferred_file_extensions
|
19
|
+
if extensions.include? caption_type
|
20
|
+
extensions[caption_type]
|
21
|
+
else
|
22
|
+
caption_extension_default
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def caption_path
|
27
|
+
datastreams[Ddr::Datastreams::CAPTION].file_path
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def caption_extension_default
|
33
|
+
datastreams[Ddr::Datastreams::CAPTION].default_file_extension
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
@@ -8,38 +8,10 @@ module Ddr
|
|
8
8
|
ActiveFedora::SolrService.lazy_reify_solr_results(sorted_children).first
|
9
9
|
end
|
10
10
|
|
11
|
-
def default_structure
|
12
|
-
if children.present?
|
13
|
-
build_default_structure
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
11
|
def sorted_children
|
18
12
|
ActiveFedora::SolrService.query(association_query(:children), sort: DEFAULT_SORT, rows: 999999)
|
19
13
|
end
|
20
14
|
|
21
|
-
private
|
22
|
-
|
23
|
-
def build_default_structure
|
24
|
-
document = Ddr::Models::Structure.xml_template
|
25
|
-
structure = Ddr::Models::Structure.new(document)
|
26
|
-
metshdr = structure.add_metshdr
|
27
|
-
structure.add_agent(parent: metshdr, role: Ddr::Models::Structures::Agent::ROLE_CREATOR,
|
28
|
-
name: Ddr::Models::Structures::Agent::NAME_REPOSITORY_DEFAULT)
|
29
|
-
structmap = structure.add_structmap(type: Ddr::Models::Structure::TYPE_DEFAULT)
|
30
|
-
add_children(structure, structmap, sorted_children)
|
31
|
-
structure
|
32
|
-
end
|
33
|
-
|
34
|
-
def add_children(structure, structmap, children)
|
35
|
-
count = 0
|
36
|
-
children.each do |child|
|
37
|
-
count += 1
|
38
|
-
div = structure.add_div(parent: structmap, order: count)
|
39
|
-
structure.add_mptr(parent: div, href: child[Ddr::Index::Fields::PERMANENT_ID])
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
15
|
end
|
44
16
|
end
|
45
17
|
end
|
@@ -13,6 +13,29 @@ module Ddr
|
|
13
13
|
include FileManagement
|
14
14
|
end
|
15
15
|
|
16
|
+
def intermediate_type
|
17
|
+
datastreams[Ddr::Datastreams::INTERMEDIATE_FILE].mimeType
|
18
|
+
end
|
19
|
+
|
20
|
+
def intermediate_extension
|
21
|
+
extensions = Ddr::Models.preferred_file_extensions
|
22
|
+
if extensions.include? intermediate_type
|
23
|
+
extensions[intermediate_type]
|
24
|
+
else
|
25
|
+
intermediate_extension_default
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def intermediate_path
|
30
|
+
datastreams[Ddr::Datastreams::INTERMEDIATE_FILE].file_path
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def intermediate_extension_default
|
36
|
+
datastreams[Ddr::Datastreams::INTERMEDIATE_FILE].default_file_extension
|
37
|
+
end
|
38
|
+
|
16
39
|
end
|
17
40
|
end
|
18
41
|
end
|