cocina-models 0.67.0 → 0.69.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +12 -0
  3. data/README.md +19 -0
  4. data/cocina-models.gemspec +4 -1
  5. data/lib/cocina/generator/generator.rb +15 -12
  6. data/lib/cocina/generator/vocab.rb +46 -42
  7. data/lib/cocina/models/access.rb +3 -3
  8. data/lib/cocina/models/admin_policy.rb +1 -1
  9. data/lib/cocina/models/{admin_policy_default_access.rb → admin_policy_access_template.rb} +4 -4
  10. data/lib/cocina/models/admin_policy_administrative.rb +1 -1
  11. data/lib/cocina/models/administrative.rb +0 -3
  12. data/lib/cocina/models/citation_only_access.rb +3 -3
  13. data/lib/cocina/models/collection.rb +5 -5
  14. data/lib/cocina/models/collection_access.rb +1 -1
  15. data/lib/cocina/models/controlled_digital_lending_access.rb +3 -3
  16. data/lib/cocina/models/dark_access.rb +3 -3
  17. data/lib/cocina/models/dro.rb +15 -15
  18. data/lib/cocina/models/dro_access.rb +4 -4
  19. data/lib/cocina/models/dro_rights_description_builder.rb +67 -0
  20. data/lib/cocina/models/embargo.rb +3 -3
  21. data/lib/cocina/models/file.rb +1 -1
  22. data/lib/cocina/models/file_access.rb +3 -3
  23. data/lib/cocina/models/file_set.rb +16 -16
  24. data/lib/cocina/models/file_set_type.rb +25 -0
  25. data/lib/cocina/models/license.rb +10 -0
  26. data/lib/cocina/models/location_based_access.rb +3 -3
  27. data/lib/cocina/models/location_based_download_access.rb +3 -3
  28. data/lib/cocina/models/object_type.rb +31 -0
  29. data/lib/cocina/models/request_admin_policy.rb +1 -1
  30. data/lib/cocina/models/request_administrative.rb +14 -0
  31. data/lib/cocina/models/request_collection.rb +6 -6
  32. data/lib/cocina/models/request_dro.rb +16 -16
  33. data/lib/cocina/models/request_file.rb +1 -1
  34. data/lib/cocina/models/request_file_set.rb +16 -16
  35. data/lib/cocina/models/rights_description_builder.rb +81 -0
  36. data/lib/cocina/models/stanford_access.rb +3 -3
  37. data/lib/cocina/models/title_builder.rb +203 -0
  38. data/lib/cocina/models/version.rb +1 -1
  39. data/lib/cocina/models/vocabulary.rb +30 -0
  40. data/lib/cocina/models/world_access.rb +3 -3
  41. data/lib/cocina/models.rb +26 -7
  42. data/lib/cocina/rspec/matchers.rb +103 -0
  43. data/lib/cocina/rspec.rb +14 -0
  44. data/openapi.yml +132 -124
  45. metadata +39 -10
  46. data/lib/cocina/models/vocab.rb +0 -162
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 14a49c375a660bd05882ee93aeaf458dddb883e88ea55ed4e80bb48b2458446b
4
- data.tar.gz: ef9426b29aedcfc6cbc1cb55118de413f7bd64f9df9234f5203d2f67eee19583
3
+ metadata.gz: e198b8822ac577fc855cf1c4f9b41c4d675ea0cc26f9f34be5a2336d490f8bae
4
+ data.tar.gz: 85b616f47c334c92b236a72afb5d3614556055e85e2dd59bb195c0cf6ab6c3f7
5
5
  SHA512:
6
- metadata.gz: 25aed0abff20bc69292031adf1eee12b4b6ca528525ad9898e0baf464ec1e99c6c0e518a7585fdab4dc63651175da88e5f179dfdb1ef35e79ba1d1087cf1efbc
7
- data.tar.gz: babf7508c4aab20689bfd7d7618711b51a254405bd111117dd9a758b6dc556f571af9f90fb50929f515698a22a35c36275a26641ee5c93a3d51faa658a92481a
6
+ metadata.gz: c71aae2c9278daf30c101163fce072e584898c0726332d2bd09fb888649aae68b5fe5e32bb028c8e06f8dd22f30abaf81662f1fdcb989af448209427025bd243
7
+ data.tar.gz: f3b60727a439c71abbbbc41405797a34c0363526ef19296c067f562b4bab3341f6d3a9a5e31a55f146d705bed0e4ff17a2dec1a0d3cc285995c5ea76b5123664
data/.rubocop.yml CHANGED
@@ -78,6 +78,7 @@ Metrics/BlockLength:
78
78
  Exclude:
79
79
  - cocina-models.gemspec
80
80
  - spec/cocina/**/*
81
+ - lib/cocina/rspec/matchers.rb
81
82
 
82
83
  Metrics/MethodLength:
83
84
  Max: 14
@@ -87,6 +88,12 @@ Metrics/MethodLength:
87
88
 
88
89
  # ----- RSpec ------
89
90
 
91
+ RSpec/BeEq: # new in 2.9.0
92
+ Enabled: true
93
+
94
+ RSpec/BeNil: # new in 2.9.0
95
+ Enabled: true
96
+
90
97
  RSpec/ExampleLength:
91
98
  Max: 18
92
99
  Exclude:
@@ -99,6 +106,9 @@ RSpec/MultipleExpectations:
99
106
  RSpec/StubbedMock: # (new in 1.44)
100
107
  Enabled: true
101
108
 
109
+ RSpec/MultipleMemoizedHelpers:
110
+ Max: 6
111
+
102
112
  # ----- Style ------
103
113
 
104
114
  Style/Documentation:
@@ -270,3 +280,5 @@ RSpec/FactoryBot/SyntaxMethods: # new in 2.7
270
280
  Enabled: true
271
281
  RSpec/Rails/AvoidSetupHook: # new in 2.4
272
282
  Enabled: true
283
+ Style/NestedFileDirname: # new in 1.26
284
+ Enabled: true
data/README.md CHANGED
@@ -26,6 +26,11 @@ exe/generator generate
26
26
  exe/generator generate_schema DRO
27
27
  ```
28
28
 
29
+ ### Controlled vocabularies
30
+ ```
31
+ exe/generator generate_vocab
32
+ ```
33
+
29
34
  ## Testing
30
35
 
31
36
  The generator is tested via its output when run against `openapi.yml`, viz., the Cocina model classes. Thus, `generate` should be run after any changes to `openapi.yml`.
@@ -98,3 +103,17 @@ The following are the recommended naming conventions for code using Cocina model
98
103
  * `cocina_admin_policy`: `Cocina::Models::AdminPolicy` instance
99
104
  * `cocina_collection`: `Cocina::Models::Collection` instance
100
105
  * `cocina_object`: `Cocina::Models::DRO` or `Cocina::Models::AdminPolicy` or `Cocina::Models::Collection` instance
106
+
107
+ ## RSpec matchers
108
+
109
+ As of the 0.69.0 release, the `cocina-models` gem provides RSpec matchers for downstream apps to make it easier to compare Cocina data structures. The matchers provided include:
110
+
111
+ * `equal_cocina_model`: Compare a Cocina JSON string with a model instance. This matcher is especially valuable coupled with the `super_diff` gem (a dependency of `cocina-models` since the 0.69.0 release). Example usage:
112
+ * `expect(http_response_body_with_cocina_json).to equal_cocina_model(cocina_instance)`
113
+ * `cocina_object_with` (AKA `match_cocina_object_with`): Compare a Cocina model instance with a hash containining part of the structure of a Cocina object. Example usage:
114
+ * `expect(CocinaObjectStore).to have_received(:save).with(cocina_object_with(access: { view: 'world' }, structural: { contains: [...] }))`
115
+ * expect(updated_cocina_item).to match_cocina_object_with(structural: { hasMemberOrders: [] })
116
+ * `cocina_object_with_types`: Check a Cocina object's type information. Example usage:
117
+ * `expect(object_client).to have_received(:update).with(params: cocina_object_with_types(content_type: Cocina::Models::ObjectType.book, viewing_direction: 'left-to-right'))`
118
+ * `cocina_admin_policy_with_registration_collections`: Check a Cocina admin policy's collections. Example usage:
119
+ * `expect(object_client).to have_received(:update).with(params: cocina_admin_policy_with_registration_collections([collection_id]))`
@@ -28,7 +28,10 @@ Gem::Specification.new do |spec|
28
28
  spec.add_dependency 'dry-struct', '~> 1.0'
29
29
  spec.add_dependency 'dry-types', '~> 1.1'
30
30
  spec.add_dependency 'openapi3_parser' # Parsing openapi doc
31
- spec.add_dependency 'openapi_parser', '~> 1.0' # Validating openapi requests
31
+ # Match these version requirements to what committee wants,
32
+ # so that our client (non-committee) users have the same dependencies.
33
+ spec.add_dependency 'openapi_parser', '>= 0.11.1', '< 1.0'
34
+ spec.add_dependency 'super_diff'
32
35
  spec.add_dependency 'thor'
33
36
  spec.add_dependency 'zeitwerk', '~> 2.1'
34
37
 
@@ -42,12 +42,7 @@ module Cocina
42
42
 
43
43
  desc 'generate_vocab', 'generate vocab'
44
44
  def generate_vocab
45
- vocab = Vocab.new(schemas)
46
- filepath = "#{options[:output]}/#{vocab.filename}"
47
- FileUtils.rm_f(filepath)
48
-
49
- create_file filepath, vocab.generate
50
- run("rubocop -a #{filepath} > /dev/null")
45
+ Vocab.generate(schemas, output_dir: options[:output])
51
46
  end
52
47
 
53
48
  private
@@ -76,18 +71,26 @@ module Cocina
76
71
  run("rubocop -a #{filepath} > /dev/null")
77
72
  end
78
73
 
79
- # rubocop:disable Metrics/AbcSize
74
+ NO_CLEAN = [
75
+ 'checkable.rb',
76
+ 'dro_rights_description_builder.rb',
77
+ 'license.rb',
78
+ 'rights_description_builder.rb',
79
+ 'title_builder.rb',
80
+ 'validatable.rb',
81
+ 'validator.rb',
82
+ 'version.rb',
83
+ 'vocabulary.rb'
84
+ ].freeze
85
+
80
86
  def clean_output
81
87
  FileUtils.mkdir_p(options[:output])
82
88
  files = Dir.glob("#{options[:output]}/*.rb")
83
89
  # Leave alone
84
- files.delete("#{options[:output]}/version.rb")
85
- files.delete("#{options[:output]}/checkable.rb")
86
- files.delete("#{options[:output]}/validator.rb")
87
- files.delete("#{options[:output]}/validatable.rb")
90
+ NO_CLEAN.each { |filename| files.delete("#{options[:output]}/#{filename}") }
91
+
88
92
  FileUtils.rm_f(files)
89
93
  end
90
- # rubocop:enable Metrics/AbcSize
91
94
  end
92
95
  end
93
96
  end
@@ -4,36 +4,51 @@ module Cocina
4
4
  module Generator
5
5
  # Class for generating a vocab
6
6
  class Vocab
7
- def initialize(schemas)
8
- @schemas = schemas
7
+ CLASS_COMMENT = {
8
+ 'ObjectType' => 'This vocabulary defines the top level object type',
9
+ 'FileSetType' => 'This vocabulary defines the types of file sets'
10
+ }.freeze
11
+
12
+ def self.generate(schemas, output_dir:)
13
+ new(schemas, output_dir: output_dir).generate
9
14
  end
10
15
 
11
- def filename
12
- 'vocab.rb'
16
+ def initialize(schemas, output_dir:)
17
+ @schemas = schemas
18
+ @output_dir = output_dir
13
19
  end
14
20
 
15
21
  def generate
16
- <<~RUBY
17
- # frozen_string_literal: true
18
-
19
- module Cocina
20
- module Models
21
- # A digital repository object. See http://sul-dlss.github.io/cocina-models/maps/DRO.json
22
- class Vocab
22
+ names.each do |namespace, v|
23
+ filepath = File.join(output_dir, "#{namespace.underscore}.rb")
24
+ File.write(filepath, contents(namespace, v))
25
+ end
26
+ end
23
27
 
24
- #{vocab_methods}
28
+ def contents(namespace, methods)
29
+ <<~RUBY
30
+ # frozen_string_literal: true
25
31
 
26
- end
27
- end
32
+ module Cocina
33
+ module Models
34
+ # #{CLASS_COMMENT.fetch(namespace)}
35
+ class #{namespace} < Vocabulary('#{URIS.fetch(namespace)}')
36
+ #{draw_ruby_methods(methods, 6)}
37
+ end
38
+ end
28
39
  end
29
40
  RUBY
30
41
  end
31
42
 
32
43
  private
33
44
 
34
- attr_reader :schemas
45
+ attr_reader :schemas, :output_dir
35
46
 
36
- BASE = 'http://cocina.sul.stanford.edu/models/'
47
+ BASE = 'https://cocina.sul.stanford.edu/models/'
48
+ URIS = {
49
+ 'ObjectType' => BASE,
50
+ 'FileSetType' => "#{BASE}resources/"
51
+ }.freeze
37
52
 
38
53
  def vocabs
39
54
  type_properties = schemas.values.map { |schema| schema.properties['type'] }.compact
@@ -43,38 +58,27 @@ module Cocina
43
58
  .sort
44
59
  end
45
60
 
46
- def vocab_methods
47
- names = vocabs.each_with_object({}) do |vocab, object|
48
- # Note special handling of 3d
49
- namespaced = vocab.delete_prefix(BASE).delete_suffix('.jsonld')
50
- .gsub('-', '_').gsub('3d', 'three_dimensional')
51
- namespace, name = namespaced.include?('/') ? namespaced.split('/') : [:root, namespaced]
52
- object[namespace] ||= {}
53
- object[namespace][name] = vocab
61
+ def names
62
+ @names ||= vocabs.each_with_object({}) do |vocab, object|
63
+ namespaced = vocab.delete_prefix(BASE)
64
+ namespace, name = namespaced.include?('/') ? namespaced.split('/') : ['ObjectType', namespaced]
65
+ namespace = 'FileSetType' if namespace == 'resources'
66
+ object[namespace] ||= []
67
+ object[namespace] << name
54
68
  end
55
- draw_namespaced_methods(names)
56
69
  end
57
70
 
58
- def draw_namespaced_methods(names)
59
- names.flat_map do |namespace, methods|
60
- [].tap do |items|
61
- items << "class #{namespace.capitalize}" unless namespace == :root
62
- items << draw_ruby_methods(methods)
63
- items << 'end' unless namespace == :root
71
+ def draw_ruby_methods(methods, indent)
72
+ spaces = ' ' * indent
73
+ methods.map do |name|
74
+ if name == '3d'
75
+ "#{spaces}property :'3d', method_name: :three_dimensional"
76
+ else
77
+ name = "'#{name}'" if name.match?(/(^\d)|-/)
78
+ "#{spaces}property :#{name}"
64
79
  end
65
80
  end.join("\n")
66
81
  end
67
-
68
- def draw_ruby_methods(methods)
69
- methods.map do |name, vocab|
70
- <<~RUBY
71
- def self.#{name}
72
- "#{vocab}"
73
- end
74
-
75
- RUBY
76
- end.join("\n")
77
- end
78
82
  end
79
83
  end
80
84
  end
@@ -5,13 +5,13 @@ module Cocina
5
5
  class Access < Struct
6
6
  # Access level.
7
7
  # Validation of this property is relaxed. See the openapi for full validation.
8
- attribute :access, Types::Strict::String.optional.default('dark').meta(omittable: true)
8
+ attribute :view, Types::Strict::String.optional.default('dark').meta(omittable: true)
9
9
  # Download access level.
10
10
  # Validation of this property is relaxed. See the openapi for full validation.
11
11
  attribute :download, Types::Strict::String.optional.default('none').meta(omittable: true)
12
- # If access is "location-based", which location should have access.
12
+ # Not used for this access type, must be null.
13
13
  # Validation of this property is relaxed. See the openapi for full validation.
14
- attribute :readLocation, Types::Strict::String.optional.meta(omittable: true)
14
+ attribute :location, Types::Strict::String.optional.meta(omittable: true)
15
15
  # Validation of this property is relaxed. See the openapi for full validation.
16
16
  attribute :controlledDigitalLending, Types::Strict::Bool.optional.meta(omittable: true)
17
17
  end
@@ -7,7 +7,7 @@ module Cocina
7
7
 
8
8
  include Checkable
9
9
 
10
- TYPES = ['http://cocina.sul.stanford.edu/models/admin_policy.jsonld'].freeze
10
+ TYPES = ['https://cocina.sul.stanford.edu/models/admin_policy'].freeze
11
11
 
12
12
  # The version of Cocina with which this object conforms.
13
13
  # example: 1.2.3
@@ -2,8 +2,8 @@
2
2
 
3
3
  module Cocina
4
4
  module Models
5
- class AdminPolicyDefaultAccess < Struct
6
- attribute :access, Types::Strict::String.enum('world', 'stanford', 'location-based', 'citation-only', 'dark').meta(omittable: true)
5
+ class AdminPolicyAccessTemplate < Struct
6
+ attribute :view, Types::Strict::String.enum('world', 'stanford', 'location-based', 'citation-only', 'dark').meta(omittable: true)
7
7
  # Available for controlled digital lending.
8
8
  attribute :controlledDigitalLending, Types::Strict::Bool.meta(omittable: true)
9
9
  # The human readable copyright statement that applies
@@ -12,9 +12,9 @@ module Cocina
12
12
  # Download access level. This is used in the transition from Fedora as a way to set a default download level at registration that is copied down to all the files.
13
13
 
14
14
  attribute :download, Types::Strict::String.enum('world', 'stanford', 'location-based', 'none').meta(omittable: true)
15
- # If access is "location-based", which location should have access. This is used in the transition from Fedora as a way to set a default readLocation at registration that is copied down to all the files.
15
+ # If access or download is "location-based", this indicates which location should have access. This is used in the transition from Fedora as a way to set a default location at registration that is copied down to all the files.
16
16
 
17
- attribute :readLocation, Types::Strict::String.optional.enum('spec', 'music', 'ars', 'art', 'hoover', 'm&m').meta(omittable: true)
17
+ attribute :location, Types::Strict::String.optional.enum('spec', 'music', 'ars', 'art', 'hoover', 'm&m').meta(omittable: true)
18
18
  # The human readable use and reproduction statement that applies
19
19
  # example: Property rights reside with the repository. Literary rights reside with the creators of the documents or their heirs. To obtain permission to publish or reproduce, please contact the Public Services Librarian of the Dept. of Special Collections (http://library.stanford.edu/spc).
20
20
  attribute :useAndReproductionStatement, Types::Strict::String.optional.meta(omittable: true)
@@ -3,7 +3,7 @@
3
3
  module Cocina
4
4
  module Models
5
5
  class AdminPolicyAdministrative < Struct
6
- attribute(:defaultAccess, AdminPolicyDefaultAccess.default { AdminPolicyDefaultAccess.new })
6
+ attribute(:accessTemplate, AdminPolicyAccessTemplate.default { AdminPolicyAccessTemplate.new })
7
7
  attribute :registrationWorkflow, Types::Strict::Array.of(Types::Strict::String).default([].freeze)
8
8
  # An additional workflow to start for objects managed by this admin policy once the end-accession workflow step is complete
9
9
  # example: wasCrawlPreassemblyWF
@@ -6,9 +6,6 @@ module Cocina
6
6
  # example: druid:bc123df4567
7
7
  attribute :hasAdminPolicy, Types::Strict::String
8
8
  attribute :releaseTags, Types::Strict::Array.of(ReleaseTag).default([].freeze)
9
- # Administrative or Internal project this resource is a part of
10
- # example: Google Books
11
- attribute :partOfProject, Types::Strict::String.optional.meta(omittable: true)
12
9
  end
13
10
  end
14
11
  end
@@ -4,11 +4,11 @@ module Cocina
4
4
  module Models
5
5
  class CitationOnlyAccess < Struct
6
6
  # Access level.
7
- attribute :access, Types::Strict::String.enum('citation-only')
7
+ attribute :view, Types::Strict::String.enum('citation-only')
8
8
  # Download access level.
9
9
  attribute :download, Types::Strict::String.enum('none')
10
- # If access is "location-based", which location should have access.
11
- attribute :readLocation, Types::Strict::String.optional.enum('').meta(omittable: true)
10
+ # Not used for this access type, must be null.
11
+ attribute :location, Types::Strict::String.optional.enum('').meta(omittable: true)
12
12
  attribute :controlledDigitalLending, Types::Strict::Bool.enum(false).meta(omittable: true)
13
13
  end
14
14
  end
@@ -7,11 +7,11 @@ module Cocina
7
7
 
8
8
  include Checkable
9
9
 
10
- TYPES = ['http://cocina.sul.stanford.edu/models/collection.jsonld',
11
- 'http://cocina.sul.stanford.edu/models/curated-collection.jsonld',
12
- 'http://cocina.sul.stanford.edu/models/user-collection.jsonld',
13
- 'http://cocina.sul.stanford.edu/models/exhibit.jsonld',
14
- 'http://cocina.sul.stanford.edu/models/series.jsonld'].freeze
10
+ TYPES = ['https://cocina.sul.stanford.edu/models/collection',
11
+ 'https://cocina.sul.stanford.edu/models/curated-collection',
12
+ 'https://cocina.sul.stanford.edu/models/user-collection',
13
+ 'https://cocina.sul.stanford.edu/models/exhibit',
14
+ 'https://cocina.sul.stanford.edu/models/series'].freeze
15
15
 
16
16
  # The version of Cocina with which this object conforms.
17
17
  # example: 1.2.3
@@ -4,7 +4,7 @@ module Cocina
4
4
  module Models
5
5
  class CollectionAccess < Struct
6
6
  # Access level
7
- attribute :access, Types::Strict::String.default('dark').enum('world', 'dark').meta(omittable: true)
7
+ attribute :view, Types::Strict::String.default('dark').enum('world', 'dark').meta(omittable: true)
8
8
  # The human readable copyright statement that applies
9
9
  # example: Copyright World Trade Organization
10
10
  attribute :copyright, Types::Strict::String.optional.meta(omittable: true)
@@ -4,11 +4,11 @@ module Cocina
4
4
  module Models
5
5
  class ControlledDigitalLendingAccess < Struct
6
6
  # Access level.
7
- attribute :access, Types::Strict::String.enum('stanford')
7
+ attribute :view, Types::Strict::String.enum('stanford')
8
8
  # Download access level.
9
9
  attribute :download, Types::Strict::String.enum('none')
10
- # If access is "location-based", which location should have access.
11
- attribute :readLocation, Types::Strict::String.optional.enum('').meta(omittable: true)
10
+ # Not used for this access type, must be null.
11
+ attribute :location, Types::Strict::String.optional.enum('').meta(omittable: true)
12
12
  # Available for controlled digital lending.
13
13
  attribute :controlledDigitalLending, Types::Strict::Bool.default(false)
14
14
  end
@@ -4,11 +4,11 @@ module Cocina
4
4
  module Models
5
5
  class DarkAccess < Struct
6
6
  # Access level.
7
- attribute :access, Types::Strict::String.default('dark').enum('dark').meta(omittable: true)
7
+ attribute :view, Types::Strict::String.default('dark').enum('dark').meta(omittable: true)
8
8
  # Download access level.
9
9
  attribute :download, Types::Strict::String.default('none').enum('none').meta(omittable: true)
10
- # If access is "location-based", which location should have access.
11
- attribute :readLocation, Types::Strict::String.optional.enum('').meta(omittable: true)
10
+ # Not used for this access type, must be null.
11
+ attribute :location, Types::Strict::String.optional.enum('').meta(omittable: true)
12
12
  attribute :controlledDigitalLending, Types::Strict::Bool.enum(false).meta(omittable: true)
13
13
  end
14
14
  end
@@ -7,21 +7,21 @@ module Cocina
7
7
 
8
8
  include Checkable
9
9
 
10
- TYPES = ['http://cocina.sul.stanford.edu/models/object.jsonld',
11
- 'http://cocina.sul.stanford.edu/models/3d.jsonld',
12
- 'http://cocina.sul.stanford.edu/models/agreement.jsonld',
13
- 'http://cocina.sul.stanford.edu/models/book.jsonld',
14
- 'http://cocina.sul.stanford.edu/models/document.jsonld',
15
- 'http://cocina.sul.stanford.edu/models/geo.jsonld',
16
- 'http://cocina.sul.stanford.edu/models/image.jsonld',
17
- 'http://cocina.sul.stanford.edu/models/page.jsonld',
18
- 'http://cocina.sul.stanford.edu/models/photograph.jsonld',
19
- 'http://cocina.sul.stanford.edu/models/manuscript.jsonld',
20
- 'http://cocina.sul.stanford.edu/models/map.jsonld',
21
- 'http://cocina.sul.stanford.edu/models/media.jsonld',
22
- 'http://cocina.sul.stanford.edu/models/track.jsonld',
23
- 'http://cocina.sul.stanford.edu/models/webarchive-binary.jsonld',
24
- 'http://cocina.sul.stanford.edu/models/webarchive-seed.jsonld'].freeze
10
+ TYPES = ['https://cocina.sul.stanford.edu/models/object',
11
+ 'https://cocina.sul.stanford.edu/models/3d',
12
+ 'https://cocina.sul.stanford.edu/models/agreement',
13
+ 'https://cocina.sul.stanford.edu/models/book',
14
+ 'https://cocina.sul.stanford.edu/models/document',
15
+ 'https://cocina.sul.stanford.edu/models/geo',
16
+ 'https://cocina.sul.stanford.edu/models/image',
17
+ 'https://cocina.sul.stanford.edu/models/page',
18
+ 'https://cocina.sul.stanford.edu/models/photograph',
19
+ 'https://cocina.sul.stanford.edu/models/manuscript',
20
+ 'https://cocina.sul.stanford.edu/models/map',
21
+ 'https://cocina.sul.stanford.edu/models/media',
22
+ 'https://cocina.sul.stanford.edu/models/track',
23
+ 'https://cocina.sul.stanford.edu/models/webarchive-binary',
24
+ 'https://cocina.sul.stanford.edu/models/webarchive-seed'].freeze
25
25
 
26
26
  # The version of Cocina with which this object conforms.
27
27
  # example: 1.2.3
@@ -5,13 +5,13 @@ module Cocina
5
5
  class DROAccess < Struct
6
6
  # Access level.
7
7
  # Validation of this property is relaxed. See the openapi for full validation.
8
- attribute :access, Types::Strict::String.optional.default('dark').meta(omittable: true)
8
+ attribute :view, Types::Strict::String.optional.default('dark').meta(omittable: true)
9
9
  # Download access level.
10
10
  # Validation of this property is relaxed. See the openapi for full validation.
11
11
  attribute :download, Types::Strict::String.optional.default('none').meta(omittable: true)
12
- # If access is "location-based", which location should have access.
12
+ # Not used for this access type, must be null.
13
13
  # Validation of this property is relaxed. See the openapi for full validation.
14
- attribute :readLocation, Types::Strict::String.optional.meta(omittable: true)
14
+ attribute :location, Types::Strict::String.optional.meta(omittable: true)
15
15
  # Validation of this property is relaxed. See the openapi for full validation.
16
16
  attribute :controlledDigitalLending, Types::Strict::Bool.optional.meta(omittable: true)
17
17
  # The human readable copyright statement that applies
@@ -22,7 +22,7 @@ module Cocina
22
22
  # example: Property rights reside with the repository. Literary rights reside with the creators of the documents or their heirs. To obtain permission to publish or reproduce, please contact the Public Services Librarian of the Dept. of Special Collections (http://library.stanford.edu/spc).
23
23
  attribute :useAndReproductionStatement, Types::Strict::String.optional.meta(omittable: true)
24
24
  # The license governing reuse of the DRO. Should be an IRI for known licenses (i.e. CC, RightsStatement.org URI, etc.).
25
- attribute :license, Types::Strict::String.optional.enum('https://www.gnu.org/licenses/agpl.txt', 'https://www.apache.org/licenses/LICENSE-2.0', 'https://opensource.org/licenses/BSD-2-Clause', 'https://opensource.org/licenses/BSD-3-Clause', 'https://creativecommons.org/licenses/by/4.0/legalcode', 'https://creativecommons.org/licenses/by-nc/4.0/legalcode', 'https://creativecommons.org/licenses/by-nc-nd/4.0/legalcode', 'https://creativecommons.org/licenses/by-nc-sa/4.0/legalcode', 'https://creativecommons.org/licenses/by-nd/4.0/legalcode', 'https://creativecommons.org/licenses/by-sa/4.0/legalcode', 'https://creativecommons.org/publicdomain/zero/1.0/legalcode', 'https://opensource.org/licenses/cddl1', 'https://www.eclipse.org/legal/epl-2.0', 'https://www.gnu.org/licenses/gpl-3.0-standalone.html', 'https://www.isc.org/downloads/software-support-policy/isc-license/', 'https://www.gnu.org/licenses/lgpl-3.0-standalone.html', 'https://opensource.org/licenses/MIT', 'https://www.mozilla.org/MPL/2.0/', 'https://opendatacommons.org/licenses/by/1-0/', 'http://opendatacommons.org/licenses/odbl/1.0/', 'https://opendatacommons.org/licenses/odbl/1-0/', 'https://creativecommons.org/publicdomain/mark/1.0/', 'https://opendatacommons.org/licenses/pddl/1-0/', 'https://creativecommons.org/licenses/by/3.0/legalcode', 'https://creativecommons.org/licenses/by-sa/3.0/legalcode', 'https://creativecommons.org/licenses/by-nd/3.0/legalcode', 'https://creativecommons.org/licenses/by-nc/3.0/legalcode', 'https://creativecommons.org/licenses/by-nc-sa/3.0/legalcode', 'https://creativecommons.org/licenses/by-nc-nd/3.0/legalcode', 'http://cocina.sul.stanford.edu/licenses/none').meta(omittable: true)
25
+ attribute :license, Types::Strict::String.optional.enum('https://www.gnu.org/licenses/agpl.txt', 'https://www.apache.org/licenses/LICENSE-2.0', 'https://opensource.org/licenses/BSD-2-Clause', 'https://opensource.org/licenses/BSD-3-Clause', 'https://creativecommons.org/licenses/by/4.0/legalcode', 'https://creativecommons.org/licenses/by-nc/4.0/legalcode', 'https://creativecommons.org/licenses/by-nc-nd/4.0/legalcode', 'https://creativecommons.org/licenses/by-nc-sa/4.0/legalcode', 'https://creativecommons.org/licenses/by-nd/4.0/legalcode', 'https://creativecommons.org/licenses/by-sa/4.0/legalcode', 'https://creativecommons.org/publicdomain/zero/1.0/legalcode', 'https://opensource.org/licenses/cddl1', 'https://www.eclipse.org/legal/epl-2.0', 'https://www.gnu.org/licenses/gpl-3.0-standalone.html', 'https://www.isc.org/downloads/software-support-policy/isc-license/', 'https://www.gnu.org/licenses/lgpl-3.0-standalone.html', 'https://opensource.org/licenses/MIT', 'https://www.mozilla.org/MPL/2.0/', 'https://opendatacommons.org/licenses/by/1-0/', 'http://opendatacommons.org/licenses/odbl/1.0/', 'https://opendatacommons.org/licenses/odbl/1-0/', 'https://creativecommons.org/publicdomain/mark/1.0/', 'https://opendatacommons.org/licenses/pddl/1-0/', 'https://creativecommons.org/licenses/by/3.0/legalcode', 'https://creativecommons.org/licenses/by-sa/3.0/legalcode', 'https://creativecommons.org/licenses/by-nd/3.0/legalcode', 'https://creativecommons.org/licenses/by-nc/3.0/legalcode', 'https://creativecommons.org/licenses/by-nc-sa/3.0/legalcode', 'https://creativecommons.org/licenses/by-nc-nd/3.0/legalcode', 'https://cocina.sul.stanford.edu/licenses/none').meta(omittable: true)
26
26
  end
27
27
  end
28
28
  end
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Cocina
4
+ module Models
5
+ # Rights description builder for items
6
+ class DroRightsDescriptionBuilder < RightsDescriptionBuilder
7
+ # @param [Cocina::Models::DRO] cocina_item
8
+
9
+ # This overrides the superclass
10
+ # @return [Cocina::Models::DROAccess]
11
+ def object_access
12
+ @object_access ||= cocina.access
13
+ end
14
+
15
+ private
16
+
17
+ def object_level_access
18
+ super + access_level_from_files.uniq.map { |str| "#{str} (file)" }
19
+ end
20
+
21
+ def access_level_from_files
22
+ # dark access doesn't permit any file access
23
+ return [] if object_access.view == 'dark'
24
+
25
+ file_access_nodes.reject { |fa| same_as_object_access?(fa) }.flat_map do |fa|
26
+ file_access_from_file(fa)
27
+ end
28
+ end
29
+
30
+ # rubocop:disable Metrics/MethodLength
31
+ def file_access_from_file(file_access)
32
+ basic_access = if file_access[:view] == 'location-based'
33
+ "location: #{file_access[:location]}"
34
+ else
35
+ file_access[:view]
36
+ end
37
+
38
+ return [basic_access] if file_access[:view] == file_access[:download]
39
+
40
+ basic_access += ' (no-download)' if file_access[:view] != 'dark'
41
+
42
+ case file_access[:download]
43
+ when 'stanford'
44
+ [basic_access, 'stanford']
45
+ when 'location-based'
46
+ # Here we're using location to mean download location.
47
+ [basic_access, "location: #{file_access[:location]}"]
48
+ else
49
+ [basic_access]
50
+ end
51
+ end
52
+ # rubocop:enable Metrics/MethodLength
53
+
54
+ def same_as_object_access?(file_access)
55
+ (file_access[:view] == object_access.view && file_access[:download] == object_access.download) ||
56
+ (object_access.view == 'citation-only' && file_access[:view] == 'dark')
57
+ end
58
+
59
+ def file_access_nodes
60
+ Array(cocina.structural.contains)
61
+ .flat_map { |fs| Array(fs.structural.contains) }
62
+ .map { |file| file.access.to_h }
63
+ .uniq
64
+ end
65
+ end
66
+ end
67
+ end
@@ -5,13 +5,13 @@ module Cocina
5
5
  class Embargo < Struct
6
6
  # Access level.
7
7
  # Validation of this property is relaxed. See the openapi for full validation.
8
- attribute :access, Types::Strict::String.optional.default('dark').meta(omittable: true)
8
+ attribute :view, Types::Strict::String.optional.default('dark').meta(omittable: true)
9
9
  # Download access level.
10
10
  # Validation of this property is relaxed. See the openapi for full validation.
11
11
  attribute :download, Types::Strict::String.optional.default('none').meta(omittable: true)
12
- # If access is "location-based", which location should have access.
12
+ # Not used for this access type, must be null.
13
13
  # Validation of this property is relaxed. See the openapi for full validation.
14
- attribute :readLocation, Types::Strict::String.optional.meta(omittable: true)
14
+ attribute :location, Types::Strict::String.optional.meta(omittable: true)
15
15
  # Validation of this property is relaxed. See the openapi for full validation.
16
16
  attribute :controlledDigitalLending, Types::Strict::Bool.optional.meta(omittable: true)
17
17
  # Date when the Collection is released from an embargo.
@@ -5,7 +5,7 @@ module Cocina
5
5
  class File < Struct
6
6
  include Checkable
7
7
 
8
- TYPES = ['http://cocina.sul.stanford.edu/models/file.jsonld'].freeze
8
+ TYPES = ['https://cocina.sul.stanford.edu/models/file'].freeze
9
9
 
10
10
  # The content type of the File.
11
11
  attribute :type, Types::Strict::String.enum(*File::TYPES)
@@ -5,13 +5,13 @@ module Cocina
5
5
  class FileAccess < Struct
6
6
  # Access level.
7
7
  # Validation of this property is relaxed. See the openapi for full validation.
8
- attribute :access, Types::Strict::String.optional.default('dark').meta(omittable: true)
8
+ attribute :view, Types::Strict::String.optional.default('dark').meta(omittable: true)
9
9
  # Download access level.
10
10
  # Validation of this property is relaxed. See the openapi for full validation.
11
11
  attribute :download, Types::Strict::String.optional.default('none').meta(omittable: true)
12
- # If access is "location-based", which location should have access.
12
+ # Not used for this access type, must be null.
13
13
  # Validation of this property is relaxed. See the openapi for full validation.
14
- attribute :readLocation, Types::Strict::String.optional.meta(omittable: true)
14
+ attribute :location, Types::Strict::String.optional.meta(omittable: true)
15
15
  # Validation of this property is relaxed. See the openapi for full validation.
16
16
  attribute :controlledDigitalLending, Types::Strict::Bool.optional.meta(omittable: true)
17
17
  end