ddr-core 0.3.0 → 1.2.0.rc1

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.
Files changed (52) 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 +13 -65
  6. data/app/models/concerns/ddr/has_children.rb +8 -0
  7. data/app/models/concerns/ddr/has_content.rb +1 -0
  8. data/app/models/concerns/ddr/has_parent.rb +14 -2
  9. data/app/models/concerns/ddr/search_builder_behavior.rb~ +9 -0
  10. data/app/models/concerns/ddr/solr_document_behavior.rb +11 -90
  11. data/app/models/ddr/#admin_set.rb# +26 -0
  12. data/app/models/ddr/#auxiliary_resource_cache.rb# +34 -0
  13. data/app/models/ddr/admin_set.rb +3 -7
  14. data/app/models/ddr/alert.rb +16 -0
  15. data/app/models/ddr/auxiliary_resource.rb +24 -0
  16. data/app/models/ddr/auxiliary_resource.rb~ +13 -0
  17. data/app/models/ddr/cacheable_auxiliary_resource.rb~ +20 -0
  18. data/app/models/ddr/collection.rb +5 -4
  19. data/app/models/ddr/component.rb +8 -0
  20. data/app/models/ddr/contact.rb +1 -5
  21. data/app/models/ddr/finding_aid.rb +61 -0
  22. data/app/models/ddr/item.rb +0 -14
  23. data/app/models/ddr/language.rb +1 -6
  24. data/app/models/ddr/resource.rb +14 -0
  25. data/app/models/ddr/rights_statement.rb +2 -6
  26. data/config/locales/ddr-core.en.yml +4 -1
  27. data/db/migrate/20200207194453_add_default_to_lock_version.rb +6 -0
  28. data/lib/ddr/auth/#duke_person.rb# +9 -0
  29. data/lib/ddr/auth/ability_definitions/publication_ability_definitions.rb +7 -0
  30. data/lib/ddr/auth/ability_definitions/role_based_ability_definitions.rb +2 -2
  31. data/lib/ddr/auth/ability_definitions/superuser_ability_definitions.rb +3 -0
  32. data/lib/ddr/auth/duke_directory.rb~ +7 -0
  33. data/lib/ddr/auth/effective_permissions.rb +2 -1
  34. data/lib/ddr/auth/effective_roles.rb +6 -2
  35. data/lib/ddr/auth/failure_app.rb +1 -1
  36. data/lib/ddr/auth/grouper_gateway.rb +2 -2
  37. data/lib/ddr/auth/permissions.rb +14 -11
  38. data/lib/ddr/auth/role_based_access_controls_enforcement.rb +1 -37
  39. data/lib/ddr/auth/roles.rb +15 -3
  40. data/lib/ddr/auth/roles/role.rb +27 -69
  41. data/lib/ddr/auth/roles/role_types.rb +13 -6
  42. data/lib/ddr/core.rb +9 -0
  43. data/lib/ddr/core/version.rb +1 -1
  44. data/lib/ddr/fits.rb +0 -91
  45. data/lib/ddr/index.rb +2 -2
  46. data/lib/ddr/index/csv_query_result.rb +27 -20
  47. data/lib/ddr/index/fields.rb +5 -0
  48. data/lib/ddr/managers/technical_metadata_manager.rb +9 -4
  49. data/lib/ddr/structure.rb +2 -1
  50. data/lib/ddr/vocab/asset.rb +4 -0
  51. data/lib/ddr/workflow.rb +1 -0
  52. metadata +35 -9
@@ -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
@@ -1,9 +1,5 @@
1
- require "active_resource"
2
-
3
1
  module Ddr
4
- class AdminSet < ActiveResource::Base
5
-
6
- self.site = ENV["DDR_AUX_API_URL"]
2
+ class AdminSet < AuxiliaryResource
7
3
 
8
4
  def self.call(obj)
9
5
  find_by_code(obj.admin_set)
@@ -13,11 +9,11 @@ module Ddr
13
9
 
14
10
  def self.find_by_code(code)
15
11
  return unless code
16
- new get(:find, code: code)
12
+ fetch(code) { new get(:find, code: code) }
17
13
  end
18
14
 
19
15
  def self.keys
20
- all.map(&:code)
16
+ fetch("codes") { all.map(&:code) }
21
17
  end
22
18
 
23
19
  def to_s
@@ -0,0 +1,16 @@
1
+ module Ddr
2
+ class Alert < AuxiliaryResource
3
+
4
+ ADMIN_SITE = 'admin'
5
+ PUBLIC_SITE = 'public'
6
+
7
+ # @param [String] the application ('admin' or 'public') for which to return active alerts
8
+ # @return [Array] the active alerts for the requested application site
9
+ def self.call(site)
10
+ get(:active, site: site).map { |resp| new(resp) }
11
+ rescue ActiveResource::ServerError => e
12
+ []
13
+ end
14
+
15
+ end
16
+ end
@@ -0,0 +1,24 @@
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
+ class_attribute :cache_expiry, instance_accessor: false
13
+ self.cache_expiry = 1.hour
14
+
15
+ def self.fetch(value_key, &block)
16
+ Rails.cache.fetch(cache_key(value_key), expires_in: cache_expiry, &block)
17
+ end
18
+
19
+ def self.cache_key(suffix)
20
+ [ model_name.cache_key, suffix ].join('/')
21
+ end
22
+
23
+ end
24
+ 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,9 +1,5 @@
1
- require 'activeresource'
2
-
3
1
  module Ddr
4
- class Contact < ActiveResource::Base
5
-
6
- self.site = ENV["DDR_AUX_API_URL"]
2
+ class Contact < AuxiliaryResource
7
3
 
8
4
  def self.call(slug)
9
5
  new get(:find, slug: slug)
@@ -0,0 +1,61 @@
1
+ # TODO: 'https://duldev.atlassian.net/browse/DDR-1755'
2
+
3
+ module Ddr
4
+ class FindingAid
5
+ attr_reader :ead_id
6
+
7
+ EAD_XMLNS = "urn:isbn:1-931666-22-9"
8
+
9
+ def initialize(ead_id)
10
+ @ead_id = ead_id
11
+ end
12
+
13
+ def url
14
+ doc.css("eadid").attr("url").text
15
+ end
16
+
17
+ # The finding aid title
18
+ def title
19
+ doc.css("titleproper").children.first.text.strip
20
+ end
21
+
22
+ def repository
23
+ collection.xpath('ead:did/ead:repository/ead:corpname', ead: EAD_XMLNS).text
24
+ end
25
+
26
+ def collection_date_span
27
+ collection.xpath('ead:did/ead:unitdate[@type="inclusive"]', ead: EAD_XMLNS).text
28
+ end
29
+
30
+ def collection_number
31
+ collection.xpath('ead:did/ead:unitid', ead: EAD_XMLNS).text
32
+ end
33
+
34
+ def collection_title
35
+ collection.xpath('ead:did/ead:unittitle', ead: EAD_XMLNS).text
36
+ end
37
+
38
+ def extent
39
+ collection.xpath('ead:did/ead:physdesc/ead:extent', ead: EAD_XMLNS).map(&:text).join("; ")
40
+ end
41
+
42
+ def abstract
43
+ collection.xpath('ead:did/ead:abstract', ead: EAD_XMLNS).text
44
+ end
45
+
46
+ private
47
+
48
+ def collection
49
+ doc.xpath('//ead:archdesc[@level="collection"]', ead: EAD_XMLNS)
50
+ end
51
+
52
+ # @raise [OpenURI::HTTPError] if 404, etc.
53
+ def doc
54
+ @doc ||= Nokogiri::XML(open(ead_xml_url))
55
+ end
56
+
57
+ def ead_xml_url
58
+ Ddr.ead_xml_base_url + ead_id + ".xml"
59
+ end
60
+ end
61
+ end
@@ -12,25 +12,11 @@ module Ddr
12
12
 
13
13
  self.parent_class = Ddr::Collection
14
14
 
15
- ### DDRevo #####################
16
- # TODO: We may want to revisit this alternate implementation once ddr-core is more fully baked
17
- # or it may be fine just as it is
18
- ### DDRevo #####################
19
15
  def children_having_extracted_text
20
- # Ddr::Index::Query.build(self) do |item|
21
- # is_part_of item
22
- # where attached_files_having_content: "extractedText"
23
- # fields :id, :extracted_text
24
- # end
25
16
  children.select { |child| child.attached_files_having_content.include?(:extracted_text) }
26
17
  end
27
18
 
28
- ### DDRevo #####################
29
- # TODO: We may want to revisit this alternate implementation once ddr-core is more fully baked
30
- # or it may be fine just as it is
31
- ### DDRevo #####################
32
19
  def all_text
33
- # children_having_extracted_text.docs.map(&:extracted_text).flatten
34
20
  children_having_extracted_text.map { |child| child.extracted_text.content }.to_a.flatten
35
21
  end
36
22
 
@@ -1,9 +1,5 @@
1
- require "active_resource"
2
-
3
1
  module Ddr
4
- class Language < ActiveResource::Base
5
-
6
- self.site = ENV["DDR_AUX_API_URL"]
2
+ class Language < AuxiliaryResource
7
3
 
8
4
  def self.call(obj)
9
5
  obj.language.map do |lang|
@@ -28,4 +24,3 @@ module Ddr
28
24
 
29
25
  end
30
26
  end
31
-
@@ -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
@@ -47,6 +49,10 @@ module Ddr
47
49
  can_have_streamable_media?
48
50
  end
49
51
 
52
+ def self.canonical_model_name(model_name)
53
+ model_name.starts_with?('Ddr::') ? model_name : "Ddr::#{model_name}"
54
+ end
55
+
50
56
  def self.common_model_name
51
57
  name.split('::').last
52
58
  end
@@ -65,6 +71,10 @@ module Ddr
65
71
  alias_method :new_record?, :new_record
66
72
  alias_method :resource_model, :internal_resource
67
73
 
74
+ def rights_statement
75
+ RightsStatement.call(self)
76
+ end
77
+
68
78
  def title_display
69
79
  return title.first if title.present?
70
80
  return identifier.first if identifier.present?
@@ -80,6 +90,10 @@ module Ddr
80
90
  send(f)&.file_identifier.present?
81
91
  end
82
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.
83
97
  def publishable?
84
98
  false
85
99
  end
@@ -1,9 +1,5 @@
1
- require "active_resource"
2
-
3
1
  module Ddr
4
- class RightsStatement < ActiveResource::Base
5
-
6
- self.site = ENV["DDR_AUX_API_URL"]
2
+ class RightsStatement < AuxiliaryResource
7
3
 
8
4
  def self.call(obj)
9
5
  if obj.rights.present?
@@ -22,4 +18,4 @@ module Ddr
22
18
  end
23
19
 
24
20
  end
25
- end
21
+ end
@@ -16,7 +16,10 @@ en:
16
16
  aspace_id:
17
17
  label: "ArchivesSpace ID"
18
18
  common_model_name:
19
- label: "Common Model Name"
19
+ label: Model
20
+ heading: model
21
+ contentdm_id:
22
+ label: "CONTENTdm ID"
20
23
  doi:
21
24
  label: DOI
22
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,6 +2,10 @@ 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?
@@ -9,6 +13,9 @@ module Ddr
9
13
  cannot :unpublish, Ddr::Resource do |obj|
10
14
  !obj.published?
11
15
  end
16
+ cannot :make_nonpublishable, Ddr::Resource do |obj|
17
+ obj.published? || !obj.publishable?
18
+ end
12
19
  end
13
20
 
14
21
  end
@@ -30,8 +30,8 @@ module Ddr
30
30
  end
31
31
  end
32
32
 
33
- def cached_permissions(pid, &block)
34
- cache[pid] ||= block.call
33
+ def cached_permissions(id, &block)
34
+ cache[id] ||= block.call
35
35
  end
36
36
 
37
37
  end
@@ -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