ddr-core 0.3.0 → 1.2.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
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