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,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