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,7 @@
1
+ module Ddr::Auth
2
+ class DukeDirectory
3
+
4
+
5
+
6
+ end
7
+ end
@@ -1,7 +1,8 @@
1
1
  module Ddr::Auth
2
2
  class EffectivePermissions
3
3
 
4
- # @param obj [Object] an object that receives :roles and returns a RoleSet
4
+ # @param obj [Object] an object that receives :roles and returns an Array
5
+ # of Ddr::Auth::Roles::Role.
5
6
  # @param agents [String, Array<String>] agent(s) to match roles
6
7
  # @return [Array<Symbol>]
7
8
  def self.call(obj, agents)
@@ -1,8 +1,12 @@
1
1
  module Ddr::Auth
2
2
  class EffectiveRoles
3
3
 
4
- def self.call(obj, agents)
5
- ( obj.resource_roles | obj.inherited_roles ).select { |r| agents.include?(r.agent) }
4
+ def self.call(obj, agents = nil)
5
+ ( obj.roles | obj.inherited_roles ).tap do |roles|
6
+ if agents
7
+ roles.select! { |r| agents.include?(r.agent) }
8
+ end
9
+ end
6
10
  end
7
11
 
8
12
  end
@@ -5,7 +5,7 @@ module Ddr
5
5
  def respond
6
6
  if scope == :user && Ddr::Auth.require_shib_user_authn
7
7
  store_location!
8
- redirect_to user_omniauth_authorize_path(:shibboleth)
8
+ redirect_to user_shibboleth_omniauth_authorize_path
9
9
  else
10
10
  super
11
11
  end
@@ -25,7 +25,7 @@ module Ddr
25
25
 
26
26
  # List of all grouper groups for the repository
27
27
  def repository_groups(raw = false)
28
- repo_groups = groups(REPOSITORY_GROUP_FILTER)
28
+ repo_groups = groups(Ddr::Auth.repository_group_filter)
29
29
  if ok?
30
30
  return repo_groups if raw
31
31
  repo_groups.map do |g|
@@ -52,7 +52,7 @@ module Ddr
52
52
  result = response["WsGetGroupsResults"]["results"].first
53
53
  # Have to manually filter results b/c Grouper WS version 1.5 does not support filter parameter
54
54
  if result && result["wsGroups"]
55
- groups = result["wsGroups"].select { |g| g["name"] =~ /^#{REPOSITORY_GROUP_FILTER}/ }
55
+ groups = result["wsGroups"].select { |g| g["name"] =~ /^#{Ddr::Auth.repository_group_filter}/ }
56
56
  end
57
57
  end
58
58
  rescue StandardError => e
@@ -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
@@ -1,11 +1,5 @@
1
1
  module Ddr
2
2
  module Auth
3
- #
4
- # Hydra controller mixin for role-based access control
5
- #
6
- # Overrides Hydra::AccessControlsEnforcement#gated_discovery_filters
7
- # to apply role filters instead of permissions filters.
8
- #
9
3
  module RoleBasedAccessControlsEnforcement
10
4
 
11
5
  def self.included(controller)
@@ -17,38 +11,8 @@ module Ddr
17
11
  @current_ability ||= AbilityFactory.call(current_user, request.env)
18
12
  end
19
13
 
20
- # List of URIs for policies on which any of the current user's agent has a role in policy scope
21
- def policy_role_policies
22
- @policy_role_policies ||= Array.new.tap do |uris|
23
- filters = current_ability.agents.map do |agent|
24
- "#{Ddr::Index::Fields::POLICY_ROLE}:\"#{agent}\""
25
- end.join(" OR ")
26
- query = "#{Ddr::Index::Fields::ACTIVE_FEDORA_MODEL}:Collection AND (#{filters})"
27
- results = ActiveFedora::SolrService.query(query, rows: Collection.count, fl: Ddr::Index::Fields::INTERNAL_URI)
28
- results.each_with_object(uris) { |r, memo| memo << r[Ddr::Index::Fields::INTERNAL_URI] }
29
- end
30
- end
31
-
32
- def policy_role_filters
33
- if policy_role_policies.present?
34
- rels = policy_role_policies.map { |pid| [:is_governed_by, pid] }
35
- ActiveFedora::SolrService.construct_query_for_rel(rels, "OR")
36
- end
37
- end
38
-
39
- def resource_role_filters
40
- current_ability.agents.map do |agent|
41
- ActiveFedora::SolrService.raw_query(Ddr::Index::Fields::RESOURCE_ROLE, agent)
42
- end.join(" OR ")
43
- end
44
-
45
- def gated_discovery_filters
46
- [resource_role_filters, policy_role_filters].compact
47
- end
48
-
49
- # Overrides Hydra::AccessControlsEnforcement
50
14
  def enforce_show_permissions
51
- authorize! :read, params[:id]
15
+ authorize! Permissions::DISCOVER, params[:id]
52
16
  end
53
17
 
54
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,67 +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)))
13
-
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
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)
14
+
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
- ###############
40
- # FIXME or remove serialization/deserialization
41
- ###############
42
- #
43
- # # Deserialize a Role from JSON
44
- # # @param json [String] the JSON string
45
- # # @return [Role] the role
46
- # def from_json(json)
47
- # build JSON.parse(json)
48
- # end
49
-
50
- # alias_method :deserialize, :from_json
51
-
52
- private
53
-
54
- #
55
- # DELETEME
56
- #
57
- # def build_attributes(args={})
58
- # # symbolize keys and stringify values
59
- # attrs = args.each_with_object({}) do |(k, v), memo|
60
- # memo[k.to_sym] = Array(v).first.to_s
61
- # end
62
- # # set default scope if necessary
63
- # attrs[:scope] ||= DEFAULT_SCOPE
64
- # # accept :type key for role_type attribute
65
- # if attrs.key?(:type)
66
- # attrs[:role_type] = attrs.delete(:type)
67
- # end
68
- # attrs
69
- # end
35
+ attribute :agent, ValidAgent
36
+ attribute :role_type, ValidRoleType
37
+ attribute :scope, ValidScope
70
38
 
71
- end # class << self
39
+ # DEPRECATED: Use constructor
40
+ def self.build(args={})
41
+ new(args)
42
+ end
72
43
 
73
44
  # Roles are considered equal (==) if they
74
45
  # are of the same type and have the same agent and scope.
@@ -96,19 +67,6 @@ module Ddr
96
67
  "agent=#{agent.inspect}, scope=#{scope.inspect}>"
97
68
  end
98
69
 
99
- # TODO refactor up?
100
- def proper_attributes
101
- attributes.slice(self.class.fields - self.class.reserved_attributes)
102
- end
103
-
104
- ###############
105
- # FIXME or remove serialization/deserialization
106
- ###############
107
- #
108
- # delegate :to_json, to: :proper_attributes
109
- #
110
- # alias_method :serialize, :to_json
111
-
112
70
  # Returns the permissions associated with the role
113
71
  # @return [Array<Symbol>] the permissions
114
72
  def permissions
@@ -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
@@ -9,6 +9,7 @@ module Ddr
9
9
  autoload :Files
10
10
  autoload :NotFoundError, 'ddr/error'
11
11
  autoload :Fits
12
+ autoload :FindingAid
12
13
  autoload :Index
13
14
  autoload :Managers
14
15
  autoload :Utils
@@ -103,6 +104,14 @@ module Ddr
103
104
  false
104
105
  end
105
106
 
107
+ mattr_accessor :ddr_aux_api_url do
108
+ ENV["DDR_AUX_API_URL"]
109
+ end
110
+
111
+ mattr_accessor :ead_xml_base_url do
112
+ ENV["EAD_XML_BASE_URL"]
113
+ end
114
+
106
115
  module Core
107
116
 
108
117
  end
@@ -1,5 +1,5 @@
1
1
  module Ddr
2
2
  module Core
3
- VERSION = '0.3.0'
3
+ VERSION = '1.2.0.rc1'
4
4
  end
5
5
  end
@@ -94,96 +94,5 @@ module Ddr
94
94
  xpath('//fits:fits', fits: FITS_XMLNS).first
95
95
  end
96
96
 
97
- ### DDRevo ##########################################
98
- # From Ddr::Datastreams::FitsDatastream. Code above accounts for proxy terms from below and has a private 'root'
99
- # method but does not (yet) provide methods for all the terms in the terminology. Thought it was better to wait
100
- # and see which ones are actually needed.
101
- ### DDRevo ##########################################
102
- # set_terminology do |t|
103
- # t.root(path: "fits",
104
- # xmlns: FITS_XMLNS,
105
- # schema: FITS_SCHEMA)
106
- # t.version(path: {attribute: "version"})
107
- # t.timestamp(path: {attribute: "timestamp"})
108
- # t.identification {
109
- # t.identity {
110
- # t.mimetype(path: {attribute: "mimetype"})
111
- # t.format_label(path: {attribute: "format"})
112
- # t.version
113
- # t.externalIdentifier
114
- # t.pronom_identifier(path: "externalIdentifier", attributes: {type: "puid"})
115
- # }
116
- # }
117
- # t.fileinfo {
118
- # t.created
119
- # t.creatingApplicationName
120
- # t.creatingos
121
- # t.filename
122
- # t.filepath
123
- # t.fslastmodified
124
- # t.lastmodified
125
- # t.md5checksum
126
- # t.size
127
- # }
128
- # t.filestatus {
129
- # t.valid
130
- # t.well_formed(path: "well-formed")
131
- # }
132
- # t.metadata {
133
- # t.image {
134
- # t.imageWidth
135
- # t.imageHeight
136
- # t.colorSpace
137
- # t.iccProfileName
138
- # t.iccProfileVersion
139
- # }
140
- # t.document {
141
- # # TODO - configure to get from Tika?
142
- # # t.encoding
143
- # }
144
- # t.text
145
- # t.audio
146
- # t.video
147
- # }
148
- #
149
- # ## proxy terms
150
- #
151
- # # identification / identity
152
- # t.format_label proxy: [:identification, :identity, :format_label]
153
- # t.format_version proxy: [:identification, :identity, :version]
154
- # t.media_type proxy: [:identification, :identity, :mimetype]
155
- # t.pronom_identifier proxy: [:identification, :identity, :pronom_identifier]
156
- #
157
- # # filestatus
158
- # t.valid proxy: [:filestatus, :valid]
159
- # t.well_formed proxy: [:filestatus, :well_formed]
160
- #
161
- # # fileinfo
162
- # t.created proxy: [:fileinfo, :created]
163
- # t.creating_application proxy: [:fileinfo, :creatingApplicationName]
164
- # t.extent proxy: [:fileinfo, :size]
165
- # t.md5 proxy: [:fileinfo, :md5checksum]
166
- #
167
- # # image metadata
168
- # t.color_space proxy: [:metadata, :image, :colorSpace]
169
- # t.icc_profile_name proxy: [:metadata, :image, :iccProfileName]
170
- # t.icc_profile_version proxy: [:metadata, :image, :iccProfileVersion]
171
- # t.image_height proxy: [:metadata, :image, :imageHeight]
172
- # t.image_width proxy: [:metadata, :image, :imageWidth]
173
- # end
174
- #
175
- # def self.xml_template
176
- # builder = Nokogiri::XML::Builder.new do |xml|
177
- # xml.fits("xmlns"=>FITS_XMLNS,
178
- # "xmlns:xsi"=>"http://www.w3.org/2001/XMLSchema-instance",
179
- # "xsi:schemaLocation"=>"http://hul.harvard.edu/ois/xml/ns/fits/fits_output http://hul.harvard.edu/ois/xml/xsd/fits/fits_output.xsd")
180
- # end
181
- # builder.doc
182
- # end
183
- #
184
- # def prefix
185
- # "fits__"
186
- # end
187
-
188
97
  end
189
98
  end