ddr-core 1.1.2 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/Rakefile +5 -0
- data/app/models/concerns/ddr/describable.rb +8 -12
- data/app/models/concerns/ddr/embargoable.rb +28 -0
- data/app/models/concerns/ddr/has_admin_metadata.rb +6 -0
- data/app/models/concerns/ddr/has_parent.rb +14 -2
- data/app/models/concerns/ddr/solr_document_behavior.rb +11 -0
- data/app/models/ddr/collection.rb +5 -4
- data/app/models/ddr/component.rb +9 -0
- data/app/models/ddr/finding_aid.rb +13 -21
- data/app/models/ddr/item.rb +1 -0
- data/app/models/ddr/resource.rb +13 -0
- data/config/locales/ddr-core.en.yml +2 -0
- data/lib/ddr/auth.rb +1 -0
- data/lib/ddr/auth/ability.rb +1 -0
- data/lib/ddr/auth/ability_definitions/embargo_ability_definitions.rb +18 -0
- data/lib/ddr/auth/ability_definitions/publication_ability_definitions.rb +8 -1
- data/lib/ddr/auth/ability_definitions/superuser_ability_definitions.rb +3 -0
- data/lib/ddr/auth/effective_roles.rb +1 -1
- data/lib/ddr/auth/permissions.rb +14 -11
- data/lib/ddr/auth/role_based_access_controls_enforcement.rb +1 -1
- data/lib/ddr/auth/roles.rb +15 -3
- data/lib/ddr/auth/roles/role.rb +27 -24
- data/lib/ddr/auth/roles/role_types.rb +14 -6
- data/lib/ddr/auth/web_auth_context.rb +6 -2
- data/lib/ddr/core.rb +8 -0
- data/lib/ddr/core/version.rb +1 -1
- data/lib/ddr/index/csv_query_result.rb +27 -20
- data/lib/ddr/index/fields.rb +2 -0
- data/lib/ddr/index/query_clause.rb +4 -4
- data/lib/ddr/vocab/asset.rb +4 -0
- data/lib/ddr/workflow.rb +1 -0
- metadata +9 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 61fa03b921f6c0f3b15a68938f568c4547f324facd5f57bf753ca5b28ae756e2
|
4
|
+
data.tar.gz: e74b196e266a1d4a21c24c90490374d2f7054fb52921623adba198bbc9948eca
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 95ab554ea0873c8b6f8db7ae981f0d6336d180731f91bfd57d19f8806682142fdc47bce3fb09a8aae485bd41e7e9389e0c4cf16fdfa992406032335350085041
|
7
|
+
data.tar.gz: 5239037ba065ed2034951311c260d988b19cbd45f3d2c2f6f10e78e9cd311e866e9fc7ca49619fca3de2ec791dea19942b41b4b22863383b9442456ade3ff0ac
|
data/README.md
CHANGED
data/Rakefile
CHANGED
@@ -15,6 +15,8 @@ module Ddr
|
|
15
15
|
term_names
|
16
16
|
end
|
17
17
|
|
18
|
+
# Dublin Core vocabulary comes from the rdf-vocab gem (https://github.com/ruby-rdf/rdf-vocab)
|
19
|
+
# DDR vocabulary is defined locally
|
18
20
|
def self.vocabularies
|
19
21
|
[RDF::Vocab::DC, Ddr::Vocab::DukeTerms].freeze
|
20
22
|
end
|
@@ -34,7 +36,11 @@ module Ddr
|
|
34
36
|
|
35
37
|
included do
|
36
38
|
Ddr::Describable.term_names.each do |term_name|
|
37
|
-
|
39
|
+
if term_name == :available # Intercept dcterms:available and set it to a single date so it can be used for embargoes
|
40
|
+
attribute term_name, Valkyrie::Types::DateTime.optional
|
41
|
+
else
|
42
|
+
attribute term_name, Valkyrie::Types::Set
|
43
|
+
end
|
38
44
|
end
|
39
45
|
end
|
40
46
|
|
@@ -53,7 +59,7 @@ module Ddr
|
|
53
59
|
arg = args.pop
|
54
60
|
terms = case arg.to_sym
|
55
61
|
when :empty
|
56
|
-
desc_metadata_terms.select { |t| values(t).empty? }
|
62
|
+
desc_metadata_terms.select { |t| values(t).nil? || values(t).empty? }
|
57
63
|
when :present
|
58
64
|
desc_metadata_terms.select { |t| values(t).present? }
|
59
65
|
when :defined_attributes
|
@@ -94,15 +100,5 @@ module Ddr
|
|
94
100
|
desc_metadata_terms.each { |t| set_desc_metadata_values(t, term_values_hash[t]) }
|
95
101
|
end
|
96
102
|
|
97
|
-
################
|
98
|
-
# I do not believe this method is needed any longer since I can't find any usage of it in ddr-models, ddr-batch,
|
99
|
-
# dul-hydra, ddr-public, or ddr-portals
|
100
|
-
################
|
101
|
-
# module ClassMethods
|
102
|
-
# def find_by_identifier(identifier)
|
103
|
-
# find(Ddr::Index::Fields::IDENTIFIER_ALL => identifier)
|
104
|
-
# end
|
105
|
-
# end
|
106
|
-
|
107
103
|
end
|
108
104
|
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Ddr
|
2
|
+
module Embargoable
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
def embargo
|
6
|
+
result = available.present? ? available : parent&.available
|
7
|
+
normalize(result)
|
8
|
+
end
|
9
|
+
|
10
|
+
def embargoed?
|
11
|
+
!embargo.nil? && embargo > DateTime.now
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def normalize(value)
|
17
|
+
case value
|
18
|
+
when ::Time
|
19
|
+
value.to_datetime
|
20
|
+
when ::Array
|
21
|
+
value.first
|
22
|
+
else
|
23
|
+
value
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
@@ -7,6 +7,7 @@ module Ddr
|
|
7
7
|
affiliation: Valkyrie::Types::Set,
|
8
8
|
aleph_id: Valkyrie::Types::Strict::String.optional,
|
9
9
|
aspace_id: Valkyrie::Types::Strict::String.optional,
|
10
|
+
contentdm_id: Valkyrie::Types::Strict::String.optional,
|
10
11
|
depositor: Valkyrie::Types::Strict::String.optional,
|
11
12
|
display_format: Valkyrie::Types::Strict::String.optional,
|
12
13
|
doi: Valkyrie::Types::Strict::String.optional,
|
@@ -54,6 +55,11 @@ module Ddr
|
|
54
55
|
workflow_state == Ddr::Workflow::UNPUBLISHED
|
55
56
|
end
|
56
57
|
|
58
|
+
# Usually won't be called directly. See `publishable?` on Resource and its derivatives
|
59
|
+
def nonpublishable?
|
60
|
+
workflow_state == Ddr::Workflow::NONPUBLISHABLE
|
61
|
+
end
|
62
|
+
|
57
63
|
def resource_roles
|
58
64
|
roles.select(&:in_resource_scope?)
|
59
65
|
end
|
@@ -7,12 +7,24 @@ module Ddr
|
|
7
7
|
attribute :parent_id, Valkyrie::Types::ID.optional
|
8
8
|
end
|
9
9
|
|
10
|
+
def has_parent?
|
11
|
+
parent_id.present?
|
12
|
+
end
|
13
|
+
|
10
14
|
def parent
|
11
|
-
Ddr.query_service.find_by(id: parent_id) if
|
15
|
+
Ddr.query_service.find_by(id: parent_id) if has_parent?
|
12
16
|
end
|
13
17
|
|
18
|
+
# Resources with parents (currently, Items and Components) are publishable only if they have not been marked
|
19
|
+
# nonpublishable and their parent is published
|
14
20
|
def publishable?
|
15
|
-
|
21
|
+
!nonpublishable? && parental_publication_guard
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def parental_publication_guard
|
27
|
+
parent.present? && parent.published?
|
16
28
|
end
|
17
29
|
|
18
30
|
end
|
@@ -21,6 +21,9 @@ module Ddr
|
|
21
21
|
end
|
22
22
|
|
23
23
|
def find_by_permanent_id(ark)
|
24
|
+
if ark.blank?
|
25
|
+
raise ArgumentError, "ARK argument must be present."
|
26
|
+
end
|
24
27
|
query = Ddr::Index::Query.new do
|
25
28
|
q *:*
|
26
29
|
where permanent_id: ark
|
@@ -294,6 +297,14 @@ module Ddr
|
|
294
297
|
resource.children
|
295
298
|
end
|
296
299
|
|
300
|
+
def embargo
|
301
|
+
resource.embargo
|
302
|
+
end
|
303
|
+
|
304
|
+
def embargoed?
|
305
|
+
resource.embargoed?
|
306
|
+
end
|
307
|
+
|
297
308
|
private
|
298
309
|
|
299
310
|
def query_service
|
@@ -16,12 +16,13 @@ module Ddr
|
|
16
16
|
query.docs
|
17
17
|
end
|
18
18
|
|
19
|
-
|
20
|
-
|
19
|
+
# Collection resources are publishable unless they have been marked nonpublishable
|
20
|
+
def publishable?
|
21
|
+
!nonpublishable?
|
21
22
|
end
|
22
23
|
|
23
|
-
def
|
24
|
-
|
24
|
+
def targets
|
25
|
+
Ddr.query_service.find_inverse_references_by(resource: self, property: 'for_collection_id')
|
25
26
|
end
|
26
27
|
|
27
28
|
end
|
data/app/models/ddr/component.rb
CHANGED
@@ -2,6 +2,7 @@ module Ddr
|
|
2
2
|
class Component < Resource
|
3
3
|
|
4
4
|
include Captionable
|
5
|
+
include Embargoable
|
5
6
|
include HasContent
|
6
7
|
include HasExtractedText
|
7
8
|
include HasIntermediateFile
|
@@ -29,5 +30,13 @@ module Ddr
|
|
29
30
|
Ddr.query_service.find_by(id: target_id) if target_id
|
30
31
|
end
|
31
32
|
|
33
|
+
def inherited_roles
|
34
|
+
if has_parent?
|
35
|
+
super | parent.policy_roles
|
36
|
+
else
|
37
|
+
super
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
32
41
|
end
|
33
42
|
end
|
@@ -1,61 +1,53 @@
|
|
1
|
-
# TODO: 'https://duldev.atlassian.net/browse/DDR-1755'
|
2
|
-
|
3
1
|
module Ddr
|
4
2
|
class FindingAid
|
5
3
|
attr_reader :ead_id
|
6
4
|
|
7
|
-
EAD_XMLNS = "urn:isbn:1-931666-22-9"
|
8
|
-
|
9
5
|
def initialize(ead_id)
|
10
6
|
@ead_id = ead_id
|
11
7
|
end
|
12
8
|
|
9
|
+
# TODO: use permalinks in the future when all finding aids have ARKs
|
13
10
|
def url
|
14
|
-
|
11
|
+
[Ddr.finding_aid_base_url, '/catalog/', ead_id].join
|
15
12
|
end
|
16
13
|
|
17
|
-
# The finding aid title
|
18
14
|
def title
|
19
|
-
doc.
|
15
|
+
doc.fetch('normalized_title_ssm',[])&.first
|
20
16
|
end
|
21
17
|
|
22
18
|
def repository
|
23
|
-
|
19
|
+
doc.fetch('repository_ssm',[])&.first
|
24
20
|
end
|
25
21
|
|
26
22
|
def collection_date_span
|
27
|
-
|
23
|
+
doc.fetch('normalized_date_ssm',[])&.first
|
28
24
|
end
|
29
25
|
|
30
26
|
def collection_number
|
31
|
-
|
27
|
+
doc.fetch('unitid_ssm',[])&.first
|
32
28
|
end
|
33
29
|
|
34
30
|
def collection_title
|
35
|
-
|
31
|
+
doc.fetch('title_ssm',[])&.first
|
36
32
|
end
|
37
33
|
|
38
34
|
def extent
|
39
|
-
|
35
|
+
doc.fetch('extent_ssm',[]).join("; ")
|
40
36
|
end
|
41
37
|
|
42
38
|
def abstract
|
43
|
-
|
39
|
+
first_abstract = doc.fetch('abstract_tesim',[])&.first
|
40
|
+
ActionController::Base.helpers.strip_tags(first_abstract)
|
44
41
|
end
|
45
42
|
|
46
43
|
private
|
47
44
|
|
48
|
-
def collection
|
49
|
-
doc.xpath('//ead:archdesc[@level="collection"]', ead: EAD_XMLNS)
|
50
|
-
end
|
51
|
-
|
52
|
-
# @raise [OpenURI::HTTPError] if 404, etc.
|
53
45
|
def doc
|
54
|
-
@doc ||=
|
46
|
+
@doc ||= JSON.parse(open(arclight_collection_data_url).read)
|
55
47
|
end
|
56
48
|
|
57
|
-
def
|
58
|
-
Ddr.
|
49
|
+
def arclight_collection_data_url
|
50
|
+
[Ddr.finding_aid_base_url, '/catalog/', ead_id, '/raw.json'].join
|
59
51
|
end
|
60
52
|
end
|
61
53
|
end
|
data/app/models/ddr/item.rb
CHANGED
data/app/models/ddr/resource.rb
CHANGED
@@ -90,10 +90,23 @@ module Ddr
|
|
90
90
|
send(f)&.file_identifier.present?
|
91
91
|
end
|
92
92
|
|
93
|
+
# By default, no resources are publishable. To enable publication of a particular class of resource, (1) include
|
94
|
+
# the `HasAdminMetadata` concern in the model class, which defines a `nonpublishable?` method which returns true
|
95
|
+
# if the workflow_state is "nonpublishable" and (2) override the `publishable?` method to provide the logic
|
96
|
+
# for determining if a particular resource is publishable.
|
93
97
|
def publishable?
|
94
98
|
false
|
95
99
|
end
|
96
100
|
|
101
|
+
# Embargoes are enforced by the `Embargoable` concern, which overrides the `embargo` and `embargoed?` methods
|
102
|
+
def embargo
|
103
|
+
nil
|
104
|
+
end
|
105
|
+
|
106
|
+
def embargoed?
|
107
|
+
false
|
108
|
+
end
|
109
|
+
|
97
110
|
def has_admin_policy?
|
98
111
|
governable? && admin_policy_id.present?
|
99
112
|
end
|
data/lib/ddr/auth.rb
CHANGED
@@ -35,6 +35,7 @@ module Ddr
|
|
35
35
|
autoload :CollectionAbilityDefinitions
|
36
36
|
autoload :ComponentAbilityDefinitions
|
37
37
|
autoload :ItemAbilityDefinitions
|
38
|
+
autoload :EmbargoAbilityDefinitions
|
38
39
|
autoload :PublicationAbilityDefinitions
|
39
40
|
autoload :LockAbilityDefinitions
|
40
41
|
autoload :RoleBasedAbilityDefinitions
|
data/lib/ddr/auth/ability.rb
CHANGED
@@ -0,0 +1,18 @@
|
|
1
|
+
module Ddr
|
2
|
+
module Auth
|
3
|
+
class EmbargoAbilityDefinitions < AbilityDefinitions
|
4
|
+
|
5
|
+
def call
|
6
|
+
cannot :read, [::SolrDocument, Ddr::Resource] do |obj|
|
7
|
+
obj.embargoed? && cannot?(:update, obj)
|
8
|
+
end
|
9
|
+
|
10
|
+
cannot :download, [::SolrDocument, Ddr::Resource] do |obj|
|
11
|
+
obj.embargoed? && cannot?(:update, obj)
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -2,12 +2,19 @@ module Ddr
|
|
2
2
|
module Auth
|
3
3
|
class PublicationAbilityDefinitions < AbilityDefinitions
|
4
4
|
|
5
|
+
# An object can't be published if it's already published or not publishable
|
6
|
+
# It can't be unpublished if it's already unpublished
|
7
|
+
# It can't be made nonpublishable if it's already published (must be unpublished
|
8
|
+
# first) or already nonpublishable
|
5
9
|
def call
|
6
10
|
cannot :publish, Ddr::Resource do |obj|
|
7
11
|
obj.published? || !obj.publishable?
|
8
12
|
end
|
9
13
|
cannot :unpublish, Ddr::Resource do |obj|
|
10
|
-
!obj.published?
|
14
|
+
!obj.published? && !obj.nonpublishable?
|
15
|
+
end
|
16
|
+
cannot :make_nonpublishable, Ddr::Resource do |obj|
|
17
|
+
obj.published? || !obj.publishable?
|
11
18
|
end
|
12
19
|
end
|
13
20
|
|
@@ -1,6 +1,9 @@
|
|
1
1
|
module Ddr::Auth
|
2
2
|
class SuperuserAbilityDefinitions < AbilityDefinitions
|
3
3
|
|
4
|
+
# This bypasses all checks, including ones that look at whether an
|
5
|
+
# action is possible, not just allowed. So superusers may initiate
|
6
|
+
# actions which will fail.
|
4
7
|
def call
|
5
8
|
can :manage, :all
|
6
9
|
end
|
data/lib/ddr/auth/permissions.rb
CHANGED
@@ -1,18 +1,21 @@
|
|
1
1
|
module Ddr::Auth
|
2
2
|
class Permissions
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
4
|
+
DISCOVER = :discover
|
5
|
+
READ = :read
|
6
|
+
DOWNLOAD = :download
|
7
|
+
ADD_CHILDREN = :add_children
|
8
|
+
UPDATE = :update
|
9
|
+
REPLACE = :replace
|
10
|
+
ARRANGE = :arrange
|
11
|
+
PUBLISH = :publish
|
12
|
+
UNPUBLISH = :unpublish
|
13
|
+
MAKE_NONPUBLISHABLE = :make_nonpublishable
|
14
|
+
AUDIT = :audit
|
15
|
+
GRANT = :grant
|
14
16
|
|
15
|
-
ALL = [ READ, DOWNLOAD, ADD_CHILDREN, UPDATE,
|
17
|
+
ALL = [ DISCOVER, READ, DOWNLOAD, ADD_CHILDREN, UPDATE,
|
18
|
+
REPLACE, ARRANGE, PUBLISH, UNPUBLISH, MAKE_NONPUBLISHABLE, AUDIT, GRANT ]
|
16
19
|
|
17
20
|
end
|
18
21
|
end
|
data/lib/ddr/auth/roles.rb
CHANGED
@@ -10,18 +10,30 @@ module Ddr::Auth
|
|
10
10
|
|
11
11
|
RESOURCE_SCOPE = "resource".freeze
|
12
12
|
POLICY_SCOPE = "policy".freeze
|
13
|
-
SCOPES = [RESOURCE_SCOPE, POLICY_SCOPE].freeze
|
13
|
+
SCOPES = [ RESOURCE_SCOPE, POLICY_SCOPE ].freeze
|
14
|
+
|
15
|
+
ORDERED_ROLE_TYPES = [
|
16
|
+
CURATOR,
|
17
|
+
EDITOR,
|
18
|
+
METADATA_EDITOR,
|
19
|
+
CONTRIBUTOR,
|
20
|
+
DOWNLOADER,
|
21
|
+
VIEWER,
|
22
|
+
METADATA_VIEWER
|
23
|
+
]
|
14
24
|
|
15
25
|
class << self
|
16
|
-
|
17
26
|
def type_map
|
18
27
|
@type_map ||= role_types.map { |role_type| [role_type.to_s, role_type] }.to_h
|
19
28
|
end
|
20
29
|
|
21
30
|
def role_types
|
22
|
-
|
31
|
+
ORDERED_ROLE_TYPES
|
23
32
|
end
|
24
33
|
|
34
|
+
def titles
|
35
|
+
@titles ||= role_types.map(&:title)
|
36
|
+
end
|
25
37
|
end
|
26
38
|
|
27
39
|
end
|
data/lib/ddr/auth/roles/role.rb
CHANGED
@@ -8,35 +8,38 @@ module Ddr
|
|
8
8
|
|
9
9
|
DEFAULT_SCOPE = Roles::RESOURCE_SCOPE
|
10
10
|
|
11
|
-
ValidScope = Valkyrie::Types::
|
12
|
-
ValidRoleType = Valkyrie::Types::Strict::String.enum(*(Roles
|
11
|
+
ValidScope = Valkyrie::Types::Coercible::String.default(DEFAULT_SCOPE).enum(*(Roles::SCOPES))
|
12
|
+
ValidRoleType = Valkyrie::Types::Strict::String.enum(*(Roles.titles))
|
13
|
+
ValidAgent = Valkyrie::Types::Coercible::String.constrained(min_size: 1)
|
13
14
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
# @param args [Hash] the attributes
|
22
|
-
# @return [Role] the role
|
23
|
-
# @example
|
24
|
-
# Role.build type: "Curator", agent: "bob", scope: "resource"
|
25
|
-
def build(args={})
|
26
|
-
new.tap do |role|
|
27
|
-
args[:role_type] ||= args.delete(:type)
|
28
|
-
args[:agent] ||= nil # Triggers a constraint error
|
29
|
-
args[:agent] = args[:agent].to_s # Coerce Ddr::Auth:Group to string
|
30
|
-
|
31
|
-
args.each do |attr, val|
|
32
|
-
role.set_value(attr, val)
|
33
|
-
end
|
15
|
+
# Symbolize input keys
|
16
|
+
# https://dry-rb.org/gems/dry-struct/1.0/recipes/#symbolize-input-keys
|
17
|
+
transform_keys do |key|
|
18
|
+
_k = key.to_sym
|
19
|
+
# For backwards compat allow :type as an alias for :role_type
|
20
|
+
_k == :type ? :role_type : _k
|
21
|
+
end
|
34
22
|
|
35
|
-
|
23
|
+
# Make nils use default values
|
24
|
+
# https://dry-rb.org/gems/dry-struct/1.0/recipes/#resolving-default-values-on-code-nil-code
|
25
|
+
transform_types do |type|
|
26
|
+
if type.default?
|
27
|
+
type.constructor do |value|
|
28
|
+
value.nil? ? Dry::Types::Undefined : value
|
36
29
|
end
|
30
|
+
else
|
31
|
+
type
|
37
32
|
end
|
33
|
+
end
|
38
34
|
|
39
|
-
|
35
|
+
attribute :agent, ValidAgent
|
36
|
+
attribute :role_type, ValidRoleType
|
37
|
+
attribute :scope, ValidScope
|
38
|
+
|
39
|
+
# DEPRECATED: Use constructor
|
40
|
+
def self.build(args={})
|
41
|
+
new(args)
|
42
|
+
end
|
40
43
|
|
41
44
|
# Roles are considered equal (==) if they
|
42
45
|
# are of the same type and have the same agent and scope.
|
@@ -14,36 +14,44 @@ module Ddr
|
|
14
14
|
"Editor",
|
15
15
|
"The Editor role conveys reponsibility for managing the content, " \
|
16
16
|
"description and structural arrangement of a resource.",
|
17
|
-
[ Permissions::
|
18
|
-
Permissions::
|
17
|
+
[ Permissions::DISCOVER, Permissions::READ, Permissions::DOWNLOAD,
|
18
|
+
Permissions::ADD_CHILDREN, Permissions::UPDATE,
|
19
|
+
Permissions::REPLACE, Permissions::ARRANGE ]
|
19
20
|
)
|
20
21
|
|
21
22
|
METADATA_EDITOR = RoleType.new(
|
22
23
|
"MetadataEditor",
|
23
24
|
"The Metadata Editor role conveys responsibility for " \
|
24
25
|
"managing the description of a resource.",
|
25
|
-
[ Permissions::
|
26
|
+
[ Permissions::DISCOVER, Permissions::READ, Permissions::DOWNLOAD,
|
27
|
+
Permissions::UPDATE ]
|
26
28
|
)
|
27
29
|
|
28
30
|
CONTRIBUTOR = RoleType.new(
|
29
31
|
"Contributor",
|
30
32
|
"The Contributor role conveys responsibility for adding related " \
|
31
33
|
"resources to a resource, such as works to a collection.",
|
32
|
-
[ Permissions::READ, Permissions::ADD_CHILDREN ]
|
34
|
+
[ Permissions::DISCOVER, Permissions::READ, Permissions::ADD_CHILDREN ]
|
33
35
|
)
|
34
36
|
|
35
37
|
DOWNLOADER = RoleType.new(
|
36
38
|
"Downloader",
|
37
39
|
"The Downloader role conveys access to the \"master\" file " \
|
38
40
|
"(original content bitstream) of a resource.",
|
39
|
-
[ Permissions::READ, Permissions::DOWNLOAD ]
|
41
|
+
[ Permissions::DISCOVER, Permissions::READ, Permissions::DOWNLOAD ]
|
40
42
|
)
|
41
43
|
|
42
44
|
VIEWER = RoleType.new(
|
43
45
|
"Viewer",
|
44
46
|
"The Viewer role conveys access to the description and \"access\" " \
|
45
47
|
"files (e.g., derivative bitstreams) of a resource.",
|
46
|
-
[ Permissions::READ ]
|
48
|
+
[ Permissions::DISCOVER, Permissions::READ ]
|
49
|
+
)
|
50
|
+
|
51
|
+
METADATA_VIEWER = RoleType.new(
|
52
|
+
"MetadataViewer",
|
53
|
+
"The MetadataViewer role conveys access to the description of a resource.",
|
54
|
+
[ Permissions::DISCOVER ]
|
47
55
|
)
|
48
56
|
|
49
57
|
end
|
@@ -11,12 +11,16 @@ module Ddr::Auth
|
|
11
11
|
|
12
12
|
# @return [Array<String>]
|
13
13
|
def affiliation
|
14
|
-
|
14
|
+
if anonymous?
|
15
|
+
super
|
16
|
+
else
|
17
|
+
split_env("affiliation").map { |a| a.sub(/@duke\.edu\z/, "") }
|
18
|
+
end
|
15
19
|
end
|
16
20
|
|
17
21
|
# @return [Array<String>]
|
18
22
|
def ismemberof
|
19
|
-
split_env("isMemberOf")
|
23
|
+
anonymous? ? super : split_env("isMemberOf")
|
20
24
|
end
|
21
25
|
|
22
26
|
private
|
data/lib/ddr/core.rb
CHANGED
@@ -84,10 +84,13 @@ module Ddr
|
|
84
84
|
'.aac' => 'audio/mp4',
|
85
85
|
'.f4a' => 'audio/mp4',
|
86
86
|
'.flv' => 'video/flv',
|
87
|
+
'.m2t' => 'video/vnd.dlna.mpeg-tts',
|
88
|
+
'.m2ts' => 'video/m2ts',
|
87
89
|
'.m4a' => 'audio/mp4',
|
88
90
|
'.mov' => 'video/quicktime',
|
89
91
|
'.mp3' => 'audio/mpeg',
|
90
92
|
'.mp4' => 'video/mp4',
|
93
|
+
'.mts' => 'video/vnd.dlna.mpeg-tts',
|
91
94
|
'.oga' => 'audio/ogg',
|
92
95
|
'.ogg' => 'audio/ogg',
|
93
96
|
'.srt' => 'text/plain',
|
@@ -108,10 +111,15 @@ module Ddr
|
|
108
111
|
ENV["DDR_AUX_API_URL"]
|
109
112
|
end
|
110
113
|
|
114
|
+
# Deprecated in ddr-core 1.2.0. Remove in future.
|
111
115
|
mattr_accessor :ead_xml_base_url do
|
112
116
|
ENV["EAD_XML_BASE_URL"]
|
113
117
|
end
|
114
118
|
|
119
|
+
mattr_accessor :finding_aid_base_url do
|
120
|
+
ENV["FINDING_AID_BASE_URL"] || 'https://archives.lib.duke.edu'
|
121
|
+
end
|
122
|
+
|
115
123
|
module Core
|
116
124
|
|
117
125
|
end
|
data/lib/ddr/core/version.rb
CHANGED
@@ -6,8 +6,35 @@ module Ddr::Index
|
|
6
6
|
MAX_ROWS = 10**8 # Just set to a really high number :)
|
7
7
|
CSV_MV_SEPARATOR = ";"
|
8
8
|
|
9
|
+
DEFAULT_CSV_OPTIONS = {
|
10
|
+
headers: :first_row,
|
11
|
+
return_headers: false,
|
12
|
+
write_headers: true,
|
13
|
+
converters: [
|
14
|
+
# convert semicolons
|
15
|
+
lambda { |f| f.gsub(/\\#{CSV_MV_SEPARATOR}/, CSV_MV_SEPARATOR) rescue f },
|
16
|
+
# convert escaped newlines
|
17
|
+
lambda { |f| f.gsub(/\\r/, "\r").gsub(/\\n/, "\n") rescue f }
|
18
|
+
],
|
19
|
+
}.freeze
|
20
|
+
|
9
21
|
delegate :headers, :to_s, :to_csv, to: :table
|
10
22
|
|
23
|
+
attr_reader :csv_opts
|
24
|
+
|
25
|
+
#
|
26
|
+
# See Ruby docs on CSV::new for details on available keys
|
27
|
+
# and values for the optional `csv_options' Hash parameter.
|
28
|
+
#
|
29
|
+
# N.B. If you want to *add* a converter and retain the
|
30
|
+
# default converters, append DEFAULT_CSV_OPTIONS[:converters]
|
31
|
+
# to your Array of converters.
|
32
|
+
#
|
33
|
+
def initialize(query, csv_opts: {})
|
34
|
+
super(query)
|
35
|
+
@csv_opts = DEFAULT_CSV_OPTIONS.merge(csv_opts)
|
36
|
+
end
|
37
|
+
|
11
38
|
def delete_empty_columns!
|
12
39
|
table.by_col!.delete_if { |c, vals| vals.all?(&:nil?) }
|
13
40
|
end
|
@@ -24,14 +51,6 @@ module Ddr::Index
|
|
24
51
|
@table ||= CSV.parse(data, csv_opts)
|
25
52
|
end
|
26
53
|
|
27
|
-
def csv_opts
|
28
|
-
{ headers: csv_headers,
|
29
|
-
converters: [convert_semicolons, convert_escaped_newlines],
|
30
|
-
return_headers: false,
|
31
|
-
write_headers: true,
|
32
|
-
}
|
33
|
-
end
|
34
|
-
|
35
54
|
def solr_csv_opts
|
36
55
|
{ "csv.mv.separator" => CSV_MV_SEPARATOR,
|
37
56
|
"csv.header" => solr_csv_header?,
|
@@ -44,10 +63,6 @@ module Ddr::Index
|
|
44
63
|
query.fields.map { |f| f.respond_to?(:heading) ? f.heading : f.to_s }
|
45
64
|
end
|
46
65
|
|
47
|
-
def csv_headers
|
48
|
-
:first_row
|
49
|
-
end
|
50
|
-
|
51
66
|
def solr_csv_header?
|
52
67
|
query.fields.empty?
|
53
68
|
end
|
@@ -72,13 +87,5 @@ module Ddr::Index
|
|
72
87
|
Connection.get("select", params: solr_csv_params)
|
73
88
|
end
|
74
89
|
|
75
|
-
def convert_semicolons
|
76
|
-
lambda { |f| f.gsub(/\\#{CSV_MV_SEPARATOR}/, CSV_MV_SEPARATOR) rescue f }
|
77
|
-
end
|
78
|
-
|
79
|
-
def convert_escaped_newlines
|
80
|
-
lambda { |f| f.gsub(/\\r/, "\r").gsub(/\\n/, "\n") rescue f }
|
81
|
-
end
|
82
|
-
|
83
90
|
end
|
84
91
|
end
|
data/lib/ddr/index/fields.rb
CHANGED
@@ -16,6 +16,7 @@ module Ddr::Index
|
|
16
16
|
ASPACE_ID = Field.new :aspace_id, :stored_sortable
|
17
17
|
ATTACHED_FILES_HAVING_CONTENT = Field.new :attached_files_having_content, :symbol
|
18
18
|
ATTACHED_TO_ID = Field.new :attached_to_id, :symbol
|
19
|
+
AVAILABLE = Field.new :available, :symbol
|
19
20
|
BIBLICAL_BOOK_FACET = Field.new :biblical_book_facet, :facetable
|
20
21
|
BOX_NUMBER_FACET = Field.new :box_number_facet, :facetable
|
21
22
|
CATEGORY_FACET = Field.new :category_facet, :facetable
|
@@ -29,6 +30,7 @@ module Ddr::Index
|
|
29
30
|
CONTENT_CREATE_DATE = Field.new :content_create_date, :stored_sortable, type: :date
|
30
31
|
CONTENT_SIZE = Field.new :content_size, solr_name: "content_size_lsi"
|
31
32
|
CONTENT_SIZE_HUMAN = Field.new :content_size_human, :symbol
|
33
|
+
CONTENTDM_ID = Field.new :contentdm_id, :stored_sortable
|
32
34
|
CONTRIBUTOR_FACET = Field.new :contributor_facet, :facetable
|
33
35
|
CREATOR_FACET = Field.new :creator_facet, :facetable
|
34
36
|
DATE_FACET = Field.new :date_facet, :facetable
|
@@ -16,9 +16,9 @@ module Ddr::Index
|
|
16
16
|
|
17
17
|
values do
|
18
18
|
attribute :field, FieldAttribute
|
19
|
-
attribute :value, String
|
20
|
-
attribute :quote_value, Boolean, default:
|
21
|
-
attribute :template, String, default:
|
19
|
+
attribute :value, String, required: true
|
20
|
+
attribute :quote_value, Boolean, default: false
|
21
|
+
attribute :template, String, default: STANDARD_QUERY
|
22
22
|
end
|
23
23
|
|
24
24
|
def to_s
|
@@ -46,7 +46,7 @@ module Ddr::Index
|
|
46
46
|
alias_method :id, :unique_key
|
47
47
|
|
48
48
|
def where(field, value)
|
49
|
-
|
49
|
+
values = Array(value)
|
50
50
|
if values.size > 1
|
51
51
|
disjunction(field, values)
|
52
52
|
else
|
data/lib/ddr/vocab/asset.rb
CHANGED
@@ -47,5 +47,9 @@ module Ddr::Vocab
|
|
47
47
|
label: "Nested Path",
|
48
48
|
comment: "The nested/tree path to the object to be reflected in structural metadata."
|
49
49
|
|
50
|
+
property "contentdmId",
|
51
|
+
label: "CONTENTdm ID"
|
52
|
+
comment: "The CONTENTdm reference corresponding to the object."
|
53
|
+
|
50
54
|
end
|
51
55
|
end
|
data/lib/ddr/workflow.rb
CHANGED
metadata
CHANGED
@@ -1,17 +1,17 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ddr-core
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jim Coble
|
8
8
|
- David Chandek-Stark
|
9
9
|
- Ayse Durmaz
|
10
10
|
- Hugh Cayless
|
11
|
-
autorequire:
|
11
|
+
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date: 2020-
|
14
|
+
date: 2020-10-27 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: activeresource
|
@@ -89,14 +89,14 @@ dependencies:
|
|
89
89
|
requirements:
|
90
90
|
- - "~>"
|
91
91
|
- !ruby/object:Gem::Version
|
92
|
-
version: 2.
|
92
|
+
version: 2.1.0
|
93
93
|
type: :runtime
|
94
94
|
prerelease: false
|
95
95
|
version_requirements: !ruby/object:Gem::Requirement
|
96
96
|
requirements:
|
97
97
|
- - "~>"
|
98
98
|
- !ruby/object:Gem::Version
|
99
|
-
version: 2.
|
99
|
+
version: 2.1.0
|
100
100
|
- !ruby/object:Gem::Dependency
|
101
101
|
name: grouper-rest-client
|
102
102
|
requirement: !ruby/object:Gem::Requirement
|
@@ -308,6 +308,7 @@ files:
|
|
308
308
|
- app/controllers/users/sessions_controller.rb
|
309
309
|
- app/models/concerns/ddr/captionable.rb
|
310
310
|
- app/models/concerns/ddr/describable.rb
|
311
|
+
- app/models/concerns/ddr/embargoable.rb
|
311
312
|
- app/models/concerns/ddr/governable.rb
|
312
313
|
- app/models/concerns/ddr/has_admin_metadata.rb
|
313
314
|
- app/models/concerns/ddr/has_attachments.rb
|
@@ -352,6 +353,7 @@ files:
|
|
352
353
|
- lib/ddr/auth/ability_definitions/attachment_ability_definitions.rb
|
353
354
|
- lib/ddr/auth/ability_definitions/collection_ability_definitions.rb
|
354
355
|
- lib/ddr/auth/ability_definitions/component_ability_definitions.rb
|
356
|
+
- lib/ddr/auth/ability_definitions/embargo_ability_definitions.rb
|
355
357
|
- lib/ddr/auth/ability_definitions/item_ability_definitions.rb
|
356
358
|
- lib/ddr/auth/ability_definitions/lock_ability_definitions.rb
|
357
359
|
- lib/ddr/auth/ability_definitions/publication_ability_definitions.rb
|
@@ -439,7 +441,7 @@ licenses:
|
|
439
441
|
- BSD-3-Clause
|
440
442
|
metadata:
|
441
443
|
allowed_push_host: https://rubygems.org
|
442
|
-
post_install_message:
|
444
|
+
post_install_message:
|
443
445
|
rdoc_options: []
|
444
446
|
require_paths:
|
445
447
|
- lib
|
@@ -455,7 +457,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
455
457
|
version: '0'
|
456
458
|
requirements: []
|
457
459
|
rubygems_version: 3.0.6
|
458
|
-
signing_key:
|
460
|
+
signing_key:
|
459
461
|
specification_version: 4
|
460
462
|
summary: Models used in the Duke Digital Repository
|
461
463
|
test_files: []
|