ddr-core 1.1.1 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/app/models/concerns/ddr/#search_builder_behavior.rb# +10 -0
  4. data/app/models/concerns/ddr/describable.rb +8 -12
  5. data/app/models/concerns/ddr/has_admin_metadata.rb +6 -0
  6. data/app/models/concerns/ddr/has_parent.rb +14 -2
  7. data/app/models/concerns/ddr/search_builder_behavior.rb~ +9 -0
  8. data/app/models/concerns/ddr/solr_document_behavior.rb +3 -0
  9. data/app/models/ddr/#admin_set.rb# +26 -0
  10. data/app/models/ddr/#auxiliary_resource_cache.rb# +34 -0
  11. data/app/models/ddr/auxiliary_resource.rb~ +13 -0
  12. data/app/models/ddr/cacheable_auxiliary_resource.rb~ +20 -0
  13. data/app/models/ddr/collection.rb +5 -4
  14. data/app/models/ddr/component.rb +8 -0
  15. data/app/models/ddr/finding_aid.rb +13 -21
  16. data/app/models/ddr/resource.rb +6 -0
  17. data/config/locales/ddr-core.en.yml +2 -0
  18. data/db/migrate/20200207194453_add_default_to_lock_version.rb +6 -0
  19. data/lib/ddr/auth/#duke_person.rb# +9 -0
  20. data/lib/ddr/auth/ability_definitions/publication_ability_definitions.rb +8 -1
  21. data/lib/ddr/auth/ability_definitions/superuser_ability_definitions.rb +3 -0
  22. data/lib/ddr/auth/duke_directory.rb~ +7 -0
  23. data/lib/ddr/auth/effective_roles.rb +1 -1
  24. data/lib/ddr/auth/permissions.rb +14 -11
  25. data/lib/ddr/auth/role_based_access_controls_enforcement.rb +1 -1
  26. data/lib/ddr/auth/roles.rb +15 -3
  27. data/lib/ddr/auth/roles/role.rb +27 -24
  28. data/lib/ddr/auth/roles/role_types.rb +13 -6
  29. data/lib/ddr/auth/web_auth_context.rb +6 -2
  30. data/lib/ddr/core.rb +5 -0
  31. data/lib/ddr/core/version.rb +1 -1
  32. data/lib/ddr/index/csv_query_result.rb +27 -20
  33. data/lib/ddr/index/fields.rb +1 -0
  34. data/lib/ddr/index/query_clause.rb +4 -4
  35. data/lib/ddr/vocab/asset.rb +4 -0
  36. data/lib/ddr/workflow.rb +1 -0
  37. metadata +14 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 88184d5957fb569466c8769d0cce46369c6c41a2dae430c526001740ed1bc830
4
- data.tar.gz: e8afa358d6fc130b20c3e834307cca249f7522e53730643a365ebfe36b92c093
3
+ metadata.gz: 7019ec71b3e1a704835530a69ff24d0df878f8bd35912c1382d9f919397c0af1
4
+ data.tar.gz: 81689f7ce034a586b44eede21c541ba06f9f9f67a29294088f24717d5b52ecd5
5
5
  SHA512:
6
- metadata.gz: 18f0a25afb0fce38a6fc7bcc4d1b34cd285b8d7e9b67b5d1d1f5b2d0a8a23835967b44e9be6e9e7b04b875738e70cf872a72e9a9d623147cce2f71676790d623
7
- data.tar.gz: bb9e4403c36dda3116aa493c7d0b44d9bbbf687ad058395f097bd46e2438c11b833396ebd1b171b726e33d8b5848c90b6b20d475db514b940c43060dc0180802
6
+ metadata.gz: 5ba7058499d29ee97c27ae8480b82a0c5d8edc3a8cff1365a0de3f16ded3d72b60e83bc31d9badc892083d6920379b5c6c98941ea1adb29b36626d9e6bf2865b
7
+ data.tar.gz: da5e331dd1770446db047867cb4e4c32fbb6488cffedb35c61df8230ad82d2e20fe565bb7000b2d4da88c9b1949c5fffc19471c1956dec4e5ea827cc958ae81d
data/README.md CHANGED
@@ -6,7 +6,7 @@ A port of ddr-models based on Valkyrie.
6
6
 
7
7
  Install docker (Docker for Mac includes all the required components).
8
8
 
9
- Change to the `.docker` directory.
9
+ Change to the `.docker` directory.
10
10
 
11
11
  Start the *development* stack:
12
12
 
@@ -0,0 +1,10 @@
1
+ module Ddr
2
+ module SearchBuilderBehavior
3
+
4
+ def effective_role_filter(agents)
5
+ # https://lucene.apache.org/solr/guide/7_7/other-parsers.html#term-query-parser
6
+ "{!terms f=#{Ddr::Index::Fields::EFFECTIVE_ROLE} method=booleanQuery}#{agents.join(',')}"
7
+ end
8
+
9
+ end
10
+ end
@@ -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
- attribute term_name, Valkyrie::Types::Set
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
@@ -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 parent_id
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
- parent&.published? || false
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
@@ -0,0 +1,9 @@
1
+ module Ddr
2
+ module SearchBuilderBehavior
3
+
4
+ def effective_role_filter
5
+
6
+ end
7
+
8
+ end
9
+ 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
@@ -0,0 +1,26 @@
1
+ module Ddr
2
+ class AdminSet < AuxiliaryResource
3
+
4
+ def self.call(obj)
5
+ find_by_code(obj.admin_set)
6
+ rescue ActiveResource::ResourceNotFound => e
7
+ raise Ddr::NotFoundError, e
8
+ end
9
+
10
+ def self.find_by_code(code)
11
+ return unless code
12
+ new get(:find, code: code)
13
+ end
14
+
15
+ def self.keys
16
+ with_cache("keys") do
17
+ all.map(&:code)
18
+ end
19
+ end
20
+
21
+ def to_s
22
+ title
23
+ end
24
+
25
+ end
26
+ end
@@ -0,0 +1,34 @@
1
+ require 'active_resource'
2
+
3
+ module Ddr
4
+ class AuxiliaryResourceCache < ActiveSupport::Cache::MemoryStore
5
+
6
+ def initialize
7
+ @_cache =
8
+ end
9
+
10
+ def with(key, &block)
11
+ begin
12
+ cache.set(key, block.call)
13
+ rescue ActiveResource::ServerError => e
14
+ if cache.key?(key)
15
+ Rails.logger.error(e)
16
+ cache.get(key)
17
+ else
18
+ raise
19
+ end
20
+ end
21
+ end
22
+
23
+ private
24
+
25
+ def get(key)
26
+ @_cache[key]
27
+ end
28
+
29
+ def set(key, value)
30
+ @_cache[key] = value
31
+ end
32
+
33
+ end
34
+ end
@@ -0,0 +1,13 @@
1
+ require 'active_resource'
2
+
3
+ module Ddr
4
+ #
5
+ # Abstract superclass for resources bound to ddr-aux API data
6
+ #
7
+ class AuxiliaryResource < ActiveResource::Base
8
+
9
+ # ActiveResource freezes `site` in subclasses
10
+ self.site = Ddr.ddr_aux_api_url
11
+
12
+ end
13
+ end
@@ -0,0 +1,20 @@
1
+ module Ddr
2
+ module CacheableAuxiliaryResource
3
+
4
+ def with_cache(key, &block)
5
+ block.call.tap { |value| cache.write(key, value) }
6
+ rescue ActiveResource::ServerError => e
7
+ if value = cache.fetch(key)
8
+ logger.error(e) if logger
9
+ value
10
+ else
11
+ raise
12
+ end
13
+ end
14
+
15
+ def cache
16
+ @cache ||= ActiveSupport::Cache::MemoryStore.new
17
+ end
18
+
19
+ end
20
+ end
@@ -16,12 +16,13 @@ module Ddr
16
16
  query.docs
17
17
  end
18
18
 
19
- def targets
20
- Ddr.query_service.find_inverse_references_by(resource: self, property: 'for_collection_id')
19
+ # Collection resources are publishable unless they have been marked nonpublishable
20
+ def publishable?
21
+ !nonpublishable?
21
22
  end
22
23
 
23
- def publishable?
24
- true
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
@@ -29,5 +29,13 @@ module Ddr
29
29
  Ddr.query_service.find_by(id: target_id) if target_id
30
30
  end
31
31
 
32
+ def inherited_roles
33
+ if has_parent?
34
+ super | parent.policy_roles
35
+ else
36
+ super
37
+ end
38
+ end
39
+
32
40
  end
33
41
  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
- doc.css("eadid").attr("url").text
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.css("titleproper").children.first.text.strip
15
+ doc.fetch('normalized_title_ssm',[])&.first
20
16
  end
21
17
 
22
18
  def repository
23
- collection.xpath('ead:did/ead:repository/ead:corpname', ead: EAD_XMLNS).text
19
+ doc.fetch('repository_ssm',[])&.first
24
20
  end
25
21
 
26
22
  def collection_date_span
27
- collection.xpath('ead:did/ead:unitdate[@type="inclusive"]', ead: EAD_XMLNS).text
23
+ doc.fetch('normalized_date_ssm',[])&.first
28
24
  end
29
25
 
30
26
  def collection_number
31
- collection.xpath('ead:did/ead:unitid', ead: EAD_XMLNS).text
27
+ doc.fetch('unitid_ssm',[])&.first
32
28
  end
33
29
 
34
30
  def collection_title
35
- collection.xpath('ead:did/ead:unittitle', ead: EAD_XMLNS).text
31
+ doc.fetch('title_ssm',[])&.first
36
32
  end
37
33
 
38
34
  def extent
39
- collection.xpath('ead:did/ead:physdesc/ead:extent', ead: EAD_XMLNS).map(&:text).join("; ")
35
+ doc.fetch('extent_ssm',[]).join("; ")
40
36
  end
41
37
 
42
38
  def abstract
43
- collection.xpath('ead:did/ead:abstract', ead: EAD_XMLNS).text
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 ||= Nokogiri::XML(open(ead_xml_url))
46
+ @doc ||= JSON.parse(open(arclight_collection_data_url).read)
55
47
  end
56
48
 
57
- def ead_xml_url
58
- Ddr.ead_xml_base_url + ead_id + ".xml"
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
@@ -1,6 +1,8 @@
1
1
  module Ddr
2
2
  class Resource < Valkyrie::Resource
3
3
 
4
+ enable_optimistic_locking
5
+
4
6
  include Describable
5
7
  include Governable
6
8
  include HasAdminMetadata
@@ -88,6 +90,10 @@ module Ddr
88
90
  send(f)&.file_identifier.present?
89
91
  end
90
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.
91
97
  def publishable?
92
98
  false
93
99
  end
@@ -18,6 +18,8 @@ en:
18
18
  common_model_name:
19
19
  label: Model
20
20
  heading: model
21
+ contentdm_id:
22
+ label: "CONTENTdm ID"
21
23
  doi:
22
24
  label: DOI
23
25
  ead_id:
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+ class AddDefaultToLockVersion < ActiveRecord::Migration[5.2]
3
+ def change
4
+ change_column_default :orm_resources, :lock_version, from: nil, to: 0
5
+ end
6
+ end
@@ -0,0 +1,9 @@
1
+ module Ddr::Auth
2
+ class DukePerson
3
+
4
+ def self.get(user)
5
+
6
+ end
7
+
8
+ end
9
+ 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
@@ -0,0 +1,7 @@
1
+ module Ddr::Auth
2
+ class DukeDirectory
3
+
4
+
5
+
6
+ end
7
+ end
@@ -2,7 +2,7 @@ module Ddr::Auth
2
2
  class EffectiveRoles
3
3
 
4
4
  def self.call(obj, agents = nil)
5
- ( obj.resource_roles | obj.inherited_roles ).tap do |roles|
5
+ ( obj.roles | obj.inherited_roles ).tap do |roles|
6
6
  if agents
7
7
  roles.select! { |r| agents.include?(r.agent) }
8
8
  end
@@ -1,18 +1,21 @@
1
1
  module Ddr::Auth
2
2
  class Permissions
3
3
 
4
- READ = :read
5
- DOWNLOAD = :download
6
- ADD_CHILDREN = :add_children
7
- UPDATE = :update
8
- REPLACE = :replace
9
- ARRANGE = :arrange
10
- PUBLISH = :publish
11
- UNPUBLISH = :unpublish
12
- AUDIT = :audit
13
- GRANT = :grant
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, REPLACE, ARRANGE, PUBLISH, UNPUBLISH, AUDIT, GRANT ]
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
@@ -12,7 +12,7 @@ module Ddr
12
12
  end
13
13
 
14
14
  def enforce_show_permissions
15
- authorize! :read, params[:id]
15
+ authorize! Permissions::DISCOVER, params[:id]
16
16
  end
17
17
 
18
18
  end
@@ -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
- @role_types ||= RoleTypes.constants(false).map { |const| RoleTypes.const_get(const) }
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
@@ -8,35 +8,38 @@ module Ddr
8
8
 
9
9
  DEFAULT_SCOPE = Roles::RESOURCE_SCOPE
10
10
 
11
- ValidScope = Valkyrie::Types::Strict::String.enum(*(Roles::SCOPES))
12
- ValidRoleType = Valkyrie::Types::Strict::String.enum(*(Roles::role_types.map(&:title)))
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
- attribute :agent, Valkyrie::Types::Strict::String.constrained(min_size: 1)
15
- attribute :role_type, ValidRoleType
16
- attribute :scope, ValidScope
17
-
18
- class << self
19
-
20
- # Build a Role instance from hash attributes
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
- role.scope ||= DEFAULT_SCOPE
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
- end # class << self
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,43 @@ 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::READ, Permissions::DOWNLOAD, Permissions::ADD_CHILDREN,
18
- Permissions::UPDATE, Permissions::REPLACE, Permissions::ARRANGE ]
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::READ, Permissions::DOWNLOAD, Permissions::UPDATE ]
26
+ [ Permissions::DISCOVER, Permissions::READ, Permissions::DOWNLOAD, Permissions::UPDATE ]
26
27
  )
27
28
 
28
29
  CONTRIBUTOR = RoleType.new(
29
30
  "Contributor",
30
31
  "The Contributor role conveys responsibility for adding related " \
31
32
  "resources to a resource, such as works to a collection.",
32
- [ Permissions::READ, Permissions::ADD_CHILDREN ]
33
+ [ Permissions::DISCOVER, Permissions::READ, Permissions::ADD_CHILDREN ]
33
34
  )
34
35
 
35
36
  DOWNLOADER = RoleType.new(
36
37
  "Downloader",
37
38
  "The Downloader role conveys access to the \"master\" file " \
38
39
  "(original content bitstream) of a resource.",
39
- [ Permissions::READ, Permissions::DOWNLOAD ]
40
+ [ Permissions::DISCOVER, Permissions::READ, Permissions::DOWNLOAD ]
40
41
  )
41
42
 
42
43
  VIEWER = RoleType.new(
43
44
  "Viewer",
44
45
  "The Viewer role conveys access to the description and \"access\" " \
45
46
  "files (e.g., derivative bitstreams) of a resource.",
46
- [ Permissions::READ ]
47
+ [ Permissions::DISCOVER, Permissions::READ ]
48
+ )
49
+
50
+ METADATA_VIEWER = RoleType.new(
51
+ "MetadataViewer",
52
+ "The MetadataViewer role coveys access to the description of a resource.",
53
+ [ Permissions::DISCOVER ]
47
54
  )
48
55
 
49
56
  end
@@ -11,12 +11,16 @@ module Ddr::Auth
11
11
 
12
12
  # @return [Array<String>]
13
13
  def affiliation
14
- split_env("affiliation").map { |a| a.sub(/@duke\.edu\z/, "") }
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
@@ -108,10 +108,15 @@ module Ddr
108
108
  ENV["DDR_AUX_API_URL"]
109
109
  end
110
110
 
111
+ # Deprecated in ddr-core 1.2.0. Remove in future.
111
112
  mattr_accessor :ead_xml_base_url do
112
113
  ENV["EAD_XML_BASE_URL"]
113
114
  end
114
115
 
116
+ mattr_accessor :finding_aid_base_url do
117
+ ENV["FINDING_AID_BASE_URL"] || 'https://archives.lib.duke.edu'
118
+ end
119
+
115
120
  module Core
116
121
 
117
122
  end
@@ -1,5 +1,5 @@
1
1
  module Ddr
2
2
  module Core
3
- VERSION = '1.1.1'
3
+ VERSION = '1.2.0'
4
4
  end
5
5
  end
@@ -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
@@ -29,6 +29,7 @@ module Ddr::Index
29
29
  CONTENT_CREATE_DATE = Field.new :content_create_date, :stored_sortable, type: :date
30
30
  CONTENT_SIZE = Field.new :content_size, solr_name: "content_size_lsi"
31
31
  CONTENT_SIZE_HUMAN = Field.new :content_size_human, :symbol
32
+ CONTENTDM_ID = Field.new :contentdm_id, :stored_sortable
32
33
  CONTRIBUTOR_FACET = Field.new :contributor_facet, :facetable
33
34
  CREATOR_FACET = Field.new :creator_facet, :facetable
34
35
  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: false
21
- attribute :template, String, default: STANDARD_QUERY
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
- values = Array(value)
49
+ values = Array(value)
50
50
  if values.size > 1
51
51
  disjunction(field, values)
52
52
  else
@@ -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
@@ -3,6 +3,7 @@ module Ddr
3
3
 
4
4
  PUBLISHED = 'published'
5
5
  UNPUBLISHED = 'unpublished'
6
+ NONPUBLISHABLE = 'nonpublishable'
6
7
 
7
8
  end
8
9
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ddr-core
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.1
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jim Coble
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2020-01-09 00:00:00.000000000 Z
14
+ date: 2020-07-15 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.0.0
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.0.0
99
+ version: 2.1.0
100
100
  - !ruby/object:Gem::Dependency
101
101
  name: grouper-rest-client
102
102
  requirement: !ruby/object:Gem::Requirement
@@ -306,6 +306,7 @@ files:
306
306
  - app/assets/config/ddr_core_manifest.js
307
307
  - app/controllers/users/omniauth_callbacks_controller.rb
308
308
  - app/controllers/users/sessions_controller.rb
309
+ - app/models/concerns/ddr/#search_builder_behavior.rb#
309
310
  - app/models/concerns/ddr/captionable.rb
310
311
  - app/models/concerns/ddr/describable.rb
311
312
  - app/models/concerns/ddr/governable.rb
@@ -319,12 +320,17 @@ files:
319
320
  - app/models/concerns/ddr/has_parent.rb
320
321
  - app/models/concerns/ddr/has_struct_metadata.rb
321
322
  - app/models/concerns/ddr/has_thumbnail.rb
323
+ - app/models/concerns/ddr/search_builder_behavior.rb~
322
324
  - app/models/concerns/ddr/solr_document_behavior.rb
323
325
  - app/models/concerns/ddr/streamable.rb
326
+ - app/models/ddr/#admin_set.rb#
327
+ - app/models/ddr/#auxiliary_resource_cache.rb#
324
328
  - app/models/ddr/admin_set.rb
325
329
  - app/models/ddr/alert.rb
326
330
  - app/models/ddr/attachment.rb
327
331
  - app/models/ddr/auxiliary_resource.rb
332
+ - app/models/ddr/auxiliary_resource.rb~
333
+ - app/models/ddr/cacheable_auxiliary_resource.rb~
328
334
  - app/models/ddr/collection.rb
329
335
  - app/models/ddr/component.rb
330
336
  - app/models/ddr/contact.rb
@@ -342,8 +348,10 @@ files:
342
348
  - config/routes.rb
343
349
  - db/migrate/20141104181418_create_users.rb
344
350
  - db/migrate/20141107124012_add_columns_to_user.rb
351
+ - db/migrate/20200207194453_add_default_to_lock_version.rb
345
352
  - lib/ddr-core.rb
346
353
  - lib/ddr/auth.rb
354
+ - lib/ddr/auth/#duke_person.rb#
347
355
  - lib/ddr/auth/ability.rb
348
356
  - lib/ddr/auth/ability_definitions.rb
349
357
  - lib/ddr/auth/ability_definitions/admin_set_ability_definitions.rb
@@ -364,6 +372,7 @@ files:
364
372
  - lib/ddr/auth/auth_context.rb
365
373
  - lib/ddr/auth/auth_context_factory.rb
366
374
  - lib/ddr/auth/detached_auth_context.rb
375
+ - lib/ddr/auth/duke_directory.rb~
367
376
  - lib/ddr/auth/dynamic_groups.rb
368
377
  - lib/ddr/auth/effective_permissions.rb
369
378
  - lib/ddr/auth/effective_roles.rb
@@ -453,7 +462,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
453
462
  - !ruby/object:Gem::Version
454
463
  version: '0'
455
464
  requirements: []
456
- rubygems_version: 3.0.6
465
+ rubygems_version: 3.0.8
457
466
  signing_key:
458
467
  specification_version: 4
459
468
  summary: Models used in the Duke Digital Repository