ddr-models 2.8.0 → 2.9.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|