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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f6a1052e5e437237006cf1412ac6505d0d21daee7ca0bdaa0755d985c91eee87
4
- data.tar.gz: 4722ee74f016efbca90f93a6bdff963db1a964cd180dbbc55e0febf8c861c67c
3
+ metadata.gz: 61fa03b921f6c0f3b15a68938f568c4547f324facd5f57bf753ca5b28ae756e2
4
+ data.tar.gz: e74b196e266a1d4a21c24c90490374d2f7054fb52921623adba198bbc9948eca
5
5
  SHA512:
6
- metadata.gz: d4352b429f24959b5c52388ba562724ff782c4a2e877c565ca0716c450965bbbbfde3d1c558ae2179064ec8963a4eb1f0fb6664656c7c1535cf1dc7acb02189f
7
- data.tar.gz: 7bf7a08bad7f10c1ff6049130e42d8c8584f925f845d83222aa74286b031dca008ee61a440d2989e4734e4e5539e14b2e252d679a0ff75bd0cbdbad6bf6a06f5
6
+ metadata.gz: 95ab554ea0873c8b6f8db7ae981f0d6336d180731f91bfd57d19f8806682142fdc47bce3fb09a8aae485bd41e7e9389e0c4cf16fdfa992406032335350085041
7
+ data.tar.gz: 5239037ba065ed2034951311c260d988b19cbd45f3d2c2f6f10e78e9cd311e866e9fc7ca49619fca3de2ec791dea19942b41b4b22863383b9442456ade3ff0ac
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
 
data/Rakefile CHANGED
@@ -28,3 +28,8 @@ begin
28
28
  task default: :spec
29
29
  rescue LoadError
30
30
  end
31
+
32
+ # This allows our s2i builder image to work more smoothly
33
+ task 'tmp:create' do
34
+ Rake::Task['app:tmp:create'].invoke
35
+ 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
@@ -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 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
@@ -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
- 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
@@ -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
- 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,7 @@
1
1
  module Ddr
2
2
  class Item < Resource
3
3
 
4
+ include Embargoable
4
5
  include HasChildren
5
6
  include HasParent
6
7
  include HasStructMetadata
@@ -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
@@ -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:
@@ -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
@@ -8,6 +8,7 @@ module Ddr
8
8
  ComponentAbilityDefinitions,
9
9
  AttachmentAbilityDefinitions,
10
10
  RoleBasedAbilityDefinitions,
11
+ EmbargoAbilityDefinitions,
11
12
  PublicationAbilityDefinitions,
12
13
  LockAbilityDefinitions,
13
14
  AdminSetAbilityDefinitions,
@@ -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
@@ -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,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::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,
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
- 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
@@ -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
@@ -1,5 +1,5 @@
1
1
  module Ddr
2
2
  module Core
3
- VERSION = '1.1.2'
3
+ VERSION = '1.3.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
@@ -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: 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,17 +1,17 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ddr-core
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.2
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-02-07 00:00:00.000000000 Z
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.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
@@ -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: []