ddr-core 1.1.2 → 1.3.0
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/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: []
|