dor-rights-auth 1.2.0 → 1.7.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 5cf8440dedbe7f16ab7b4c9e6ddb7b2915469fed
4
- data.tar.gz: f9af60728a4c488eebfd37f4812cedc90f243675
2
+ SHA256:
3
+ metadata.gz: 411e5433cabba2ab3f47558c514c1c2c8093c0c9803a8a81987ae47736f13523
4
+ data.tar.gz: 7658e3e17dd9933ca60e76f1a26933722e4b5aa5e296623124923e006a087aad
5
5
  SHA512:
6
- metadata.gz: 318fbc547f7abd9bd91dc0199b3f5acd71985c04324cb2cdf7ebee64e324e10687ec727475a4ecb9e5523ba8e970ef55904fc9a63133dc7f2fce8454d9255e15
7
- data.tar.gz: df90d1277ddf87928a34ab995bbb596faaeb0c56b86f79f316a8589eb08e37154277b688dd69229dc98e0033c470c68242b7329aeb143364505fa0a2f9bed2dd
6
+ metadata.gz: 422dc8fe2ffe4974595f552dd289cd362779d0234e73d91200f468e96e4ad13883e685d00c17f892292261bb3527cf256ec462e6ccec5ee3b5e0302b77a44f9f
7
+ data.tar.gz: cac9eaf44ae089b5b61350c72a5e873e37c1b13bc9d7735af0d78ced1e7071307dea827fbe3e8e7b94fafd72c6f9bc26aff950d3b763249f2946a75b5a1679c7
@@ -1 +1,3 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'dor/rights_auth'
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'nokogiri'
2
4
  require 'time'
3
5
 
@@ -8,7 +10,7 @@ module Dor
8
10
  Rights = Struct.new(:value, :rule)
9
11
 
10
12
  # Rights for an object or File
11
- EntityRights = Struct.new(:world, :group, :agent, :location)
13
+ EntityRights = Struct.new(:world, :group, :agent, :location, :controlled_digital_lending)
12
14
  # class EntityRights
13
15
  # @world = #Rights
14
16
  # @group {
@@ -18,6 +20,7 @@ module Dor
18
20
  # 'app1' => #Rights,
19
21
  # 'app2' => #Rights
20
22
  # }
23
+ # @controlled_digital_lending = false
21
24
  # end
22
25
 
23
26
  # class Dor::RightsAuth
@@ -31,11 +34,12 @@ module Dor
31
34
  # read rights_xml only once and create query-able methods for rights info
32
35
  class RightsAuth
33
36
 
34
- CONTAINS_STANFORD_XPATH = "contains(translate(text(), 'STANFORD', 'stanford'), 'stanford')".freeze
37
+ CONTAINS_STANFORD_XPATH = "contains(translate(text(), 'STANFORD', 'stanford'), 'stanford')"
38
+ NO_DOWNLOAD_RULE = 'no-download'
35
39
 
36
40
  attr_accessor :obj_lvl, :file, :embargoed, :index_elements
37
41
 
38
- # note: index_elements is only valid for the xml as parsed, not after subsequent manipulation
42
+ # NOTE: index_elements is only valid for the xml as parsed, not after subsequent manipulation
39
43
 
40
44
  def initialize
41
45
  @file = {}
@@ -48,12 +52,36 @@ module Dor
48
52
  @embargoed
49
53
  end
50
54
 
55
+ # summary level rights info is mostly used for object-level indexing/faceting.
56
+ # thus, we currently only calculate it when parsing object rights for indexing.
57
+ # to keep from having to refactor or duplicate code right now, we'll just leverage
58
+ # what we've got, checking whether index_elements is populated, and raising an error
59
+ # if the object wasn't instantiated in a way that makes those calculations.
60
+ def check_index_elements_calculated!
61
+ unless index_elements.size > 0
62
+ raise "primary access rights not calculated. instantiate by calling '.parse(xml, forindex = true)'."
63
+ end
64
+ end
65
+
66
+ # this is just a convenience method for asking whether an object's rights would
67
+ # classify it as 'dark'.
68
+ def dark?
69
+ check_index_elements_calculated!
70
+ index_elements[:primary] == 'dark'
71
+ end
72
+
73
+ # this is just a convenience method for asking whether an object's rights would
74
+ # classify it as 'citation only'.
75
+ def citation_only?
76
+ check_index_elements_calculated!
77
+ index_elements[:primary] == 'citation'
78
+ end
79
+
51
80
  # Returns true if the object is world readable AND has no rule attribute
52
81
  # @return [Boolean]
53
82
  def world_unrestricted?
54
83
  @obj_lvl.world.value && @obj_lvl.world.rule.nil?
55
84
  end
56
-
57
85
  alias_method :public_unrestricted?, :world_unrestricted?
58
86
 
59
87
  def readable?
@@ -61,20 +89,41 @@ module Dor
61
89
  public_unrestricted? || stanford_only_unrestricted?
62
90
  end
63
91
 
92
+ # Returns true if the object is readable AND allows download
93
+ # @return [Boolean]
94
+ def world_downloadable?
95
+ world_rule = @obj_lvl.world.rule
96
+ @obj_lvl.world.value && (world_rule.nil? || world_rule != NO_DOWNLOAD_RULE)
97
+ end
98
+ alias_method :public_downloadable?, :world_downloadable?
99
+
100
+ # Returns true if the object is enabled for controlled digital lending
101
+ # @return [Boolean]
102
+ def controlled_digital_lending?
103
+ @obj_lvl.controlled_digital_lending
104
+ end
105
+
64
106
  # Returns true if the object is stanford-only readable AND has no rule attribute
65
107
  # @return [Boolean]
66
108
  def stanford_only_unrestricted?
67
109
  @obj_lvl.group[:stanford].value && @obj_lvl.group[:stanford].rule.nil?
68
110
  end
69
111
 
112
+ # Returns true if the object is stanford-only readable AND allows download
113
+ # @return [Boolean]
114
+ def stanford_only_downloadable?
115
+ stanford_rule = @obj_lvl.group[:stanford].rule
116
+ @obj_lvl.group[:stanford].value && (stanford_rule.nil? || stanford_rule != NO_DOWNLOAD_RULE)
117
+ end
118
+
70
119
  # Returns true if the passed in agent (usually an application) is allowed access to the object without a rule
71
120
  # @param [String] agent_name Name of the agent that wants to access this object
72
121
  # @return [Boolean]
73
122
  def agent_unrestricted?(agent_name)
74
123
  return false unless @obj_lvl.agent.key? agent_name
124
+
75
125
  @obj_lvl.agent[agent_name].value && @obj_lvl.agent[agent_name].rule.nil?
76
126
  end
77
-
78
127
  alias_method :allowed_read_agent?, :agent_unrestricted?
79
128
 
80
129
  # Returns true if the file is stanford-only readable AND has no rule attribute
@@ -98,18 +147,44 @@ module Dor
98
147
 
99
148
  @file[file_name].world.value && @file[file_name].world.rule.nil?
100
149
  end
101
-
102
150
  alias_method :public_unrestricted_file?, :world_unrestricted_file?
103
151
 
152
+ # Returns true if the file is world readable AND either has no rule attribute or
153
+ # the rule attribute is not 'no-download'
154
+ # If world rights do not exist for this file, then object level rights are returned
155
+ # @see #world_downloadable?
156
+ # @param [String] file_name name of the file being tested
157
+ # @return (see #world_rights)
158
+ def world_downloadable_file?(file_name)
159
+ return world_downloadable? if @file[file_name].nil? || @file[file_name].world.nil?
160
+
161
+ world_rule = @file[file_name].world.rule
162
+ @file[file_name].world.value && (world_rule.nil? || world_rule != NO_DOWNLOAD_RULE)
163
+ end
164
+ alias_method :public_downloadable_file?, :world_downloadable_file?
165
+
166
+ def stanford_only_downloadable_file?(file_name)
167
+ return stanford_only_downloadable? if @file[file_name].nil? || @file[file_name].group[:stanford].nil?
168
+
169
+ stanford_rule = @file[file_name].group[:stanford].rule
170
+ @file[file_name].group[:stanford].value && (stanford_rule.nil? || stanford_rule != NO_DOWNLOAD_RULE)
171
+ end
172
+
173
+ def cdl_rights_for_file(file_name)
174
+ return controlled_digital_lending? if @file[file_name].nil? || @file[file_name].controlled_digital_lending.nil?
175
+
176
+ @file[file_name].controlled_digital_lending.value
177
+ end
178
+
104
179
  # Returns whether an object-level world node exists, and the value of its rule attribute
105
- # @return [Array<(Boolean, String)>] First value: existance of node. Second Value: rule attribute, nil otherwise
180
+ # @return [Array<(Boolean, String)>] First value: existence of node. Second Value: rule attribute, nil otherwise
106
181
  # @example Using multiple variable assignment to read both array elements
107
182
  # world_exists, world_rule = rights.world_rights
108
183
  def world_rights
109
184
  [@obj_lvl.world.value, @obj_lvl.world.rule]
110
185
  end
111
186
 
112
- # Returns whether and object-level group/stanford node exists, and the value of its rule attribute
187
+ # Returns whether an object-level group/stanford node exists, and the value of its rule attribute
113
188
  # @return (see #world_rights)
114
189
  # @example Using multiple variable assignment to read both array elements
115
190
  # su_only_exists, su_only_rule = rights.stanford_only_rights
@@ -135,8 +210,8 @@ module Dor
135
210
  # @return [Boolean] whether any location restrictions exist on the file or the
136
211
  # object itself (in the absence of file-level rights)
137
212
  def restricted_by_location?(file_name = nil)
138
- any_file_location = @file[file_name] && @file[file_name].location.any?
139
- any_object_location = @obj_lvl.location && @obj_lvl.location.any?
213
+ any_file_location = @file[file_name]&.location&.any?
214
+ any_object_location = @obj_lvl.location&.any?
140
215
 
141
216
  any_file_location || any_object_location
142
217
  end
@@ -149,6 +224,7 @@ module Dor
149
224
  # @note should be called after doing a check for world_unrestricted?
150
225
  def agent_rights(agent_name)
151
226
  return [false, nil] if @obj_lvl.agent[agent_name].nil?
227
+
152
228
  [@obj_lvl.agent[agent_name].value, @obj_lvl.agent[agent_name].rule]
153
229
  end
154
230
 
@@ -168,7 +244,7 @@ module Dor
168
244
  # Returns whether a file-level group/stanford node exists, and the value of its rule attribute
169
245
  # If a group/stanford node does not exist for this file, then object-level group/stanford rights are returned
170
246
  # @see #stanford_only_rights
171
- # @param (see #world_rights_for_file)
247
+ # @param [String] file_name name of the file being tested
172
248
  # @return (see #world_rights)
173
249
  # @example Using multiple variable assignment to read both array elements
174
250
  # su_only_exists, su_only_rule = rights.stanford_only_rights_for_file('somefile')
@@ -215,6 +291,7 @@ module Dor
215
291
  # @return [Array] list of things that are wrong with it
216
292
  def self.validate_lite(doc)
217
293
  return ['no_rightsMetadata'] if doc.nil? || doc.at_xpath('//rightsMetadata').nil?
294
+
218
295
  errors = []
219
296
  maindiscover = doc.at_xpath("//rightsMetadata/access[@type='discover' and not(file)]")
220
297
  mainread = doc.at_xpath("//rightsMetadata/access[@type='read' and not(file)]")
@@ -243,7 +320,10 @@ module Dor
243
320
  def self.extract_index_terms(doc)
244
321
  terms = []
245
322
  machine = doc.at_xpath("//rightsMetadata/access[@type='read' and not(file)]/machine")
246
- terms.push 'none_discover' if doc.at_xpath("//rightsMetadata/access[@type='discover']/machine/none")
323
+ if doc.at_xpath("//rightsMetadata/access[@type='discover']/machine/none") ||
324
+ doc.at_xpath("//rightsMetadata/access[@type='discover']/machine[not(*)]")
325
+ terms.push 'none_discover'
326
+ end
247
327
  terms.push 'world_discover' if doc.at_xpath("//rightsMetadata/access[@type='discover']/machine/world[not(@rule)]")
248
328
  return terms if machine.nil?
249
329
 
@@ -264,15 +344,15 @@ module Dor
264
344
  end
265
345
  end
266
346
 
267
- if doc.at_xpath("//rightsMetadata/access[@type='read' and file]/machine/none")
268
- terms.push "none_read_file"
269
- end
347
+ terms.push 'none_read_file' if doc.at_xpath("//rightsMetadata/access[@type='read' and file]/machine/none")
270
348
 
271
349
  if machine.at_xpath('./none')
272
350
  terms.push 'none_read'
273
351
  elsif machine.at_xpath('./world')
274
352
  terms.push 'world_read'
275
353
  terms.push "world|#{machine.at_xpath('./world/@rule').value.downcase}" if machine.at_xpath('./world/@rule')
354
+ elsif machine.at_xpath('./cdl')
355
+ terms.push 'cdl_none'
276
356
  end
277
357
 
278
358
  # now some statistical generation
@@ -307,23 +387,23 @@ module Dor
307
387
  def self.init_index_elements(doc)
308
388
  errors = validate_lite(doc)
309
389
  stuff = {
310
- :primary => nil,
311
- :errors => errors,
312
- :terms => [],
313
- :obj_groups => [],
314
- :obj_locations => [],
315
- :obj_agents => [],
316
- :file_groups => [],
317
- :file_locations => [],
318
- :file_agents => [],
319
- :obj_world_qualified => [],
320
- :obj_groups_qualified => [],
321
- :obj_locations_qualified => [],
322
- :obj_agents_qualified => [],
323
- :file_world_qualified => [],
324
- :file_groups_qualified => [],
390
+ :primary => nil,
391
+ :errors => errors,
392
+ :terms => [],
393
+ :obj_groups => [],
394
+ :obj_locations => [],
395
+ :obj_agents => [],
396
+ :file_groups => [],
397
+ :file_locations => [],
398
+ :file_agents => [],
399
+ :obj_world_qualified => [],
400
+ :obj_groups_qualified => [],
401
+ :obj_locations_qualified => [],
402
+ :obj_agents_qualified => [],
403
+ :file_world_qualified => [],
404
+ :file_groups_qualified => [],
325
405
  :file_locations_qualified => [],
326
- :file_agents_qualified => []
406
+ :file_agents_qualified => []
327
407
  }
328
408
 
329
409
  if errors.include? 'no_rightsMetadata'
@@ -345,6 +425,8 @@ module Dor
345
425
  has_rule = index_terms.include? 'has_rule'
346
426
  if index_terms.include?('none_discover')
347
427
  'dark'
428
+ elsif index_terms.include?('cdl_none')
429
+ 'controlled digital lending'
348
430
  elsif errors.include?('no_discover_access') || errors.include?('no_discover_machine')
349
431
  'dark'
350
432
  elsif errors.include?('no_read_machine') || index_terms.include?('none_read')
@@ -381,7 +463,14 @@ module Dor
381
463
  rights.obj_lvl.world.value = false
382
464
  end
383
465
 
384
- rights.obj_lvl.group = { :stanford => Rights.new }
466
+ # TODO: we should also look for the <group rule="no-download">stanford</group> node and parse as needed
467
+ if doc.at_xpath("//rightsMetadata/access[@type='read' and not(file)]/machine/cdl")
468
+ rights.obj_lvl.controlled_digital_lending = true
469
+ else
470
+ rights.obj_lvl.controlled_digital_lending = false
471
+ end
472
+
473
+ rights.obj_lvl.group = { :stanford => Rights.new }
385
474
  xpath = "//rightsMetadata/access[@type='read' and not(file)]/machine/group[#{CONTAINS_STANFORD_XPATH}]"
386
475
  if doc.at_xpath(xpath)
387
476
  rights.obj_lvl.group[:stanford].value = true
@@ -431,6 +520,7 @@ module Dor
431
520
  access_with_files.each do |access_node|
432
521
  stanford_access = Rights.new
433
522
  world_access = Rights.new
523
+ controlled_digital_lending = Rights.new
434
524
  if access_node.at_xpath("machine/group[#{CONTAINS_STANFORD_XPATH}]")
435
525
  stanford_access.value = true
436
526
  rule = access_node.at_xpath("machine/group[#{CONTAINS_STANFORD_XPATH}]/@rule")
@@ -444,6 +534,14 @@ module Dor
444
534
  stanford_access.value = false
445
535
  end
446
536
 
537
+ if access_node.at_xpath('machine/cdl')
538
+ controlled_digital_lending.value = true
539
+ rule = access_node.at_xpath('machine/cdl/@rule')
540
+ controlled_digital_lending.rule = rule.value if rule
541
+ else
542
+ controlled_digital_lending.value = false
543
+ end
544
+
447
545
  if access_node.at_xpath('machine/world')
448
546
  world_access.value = true
449
547
  rule = access_node.at_xpath('machine/world/@rule')
@@ -483,26 +581,26 @@ module Dor
483
581
  file_rights.group = { :stanford => stanford_access }
484
582
  file_rights.agent = file_agents
485
583
  file_rights.location = file_locations
486
-
584
+ file_rights.controlled_digital_lending = controlled_digital_lending
487
585
  rights.file[f.content] = file_rights
488
586
  end
489
587
  end
490
588
 
491
589
  if forindex
492
- [:obj_groups,
493
- :obj_locations,
494
- :obj_agents,
495
- :file_groups,
496
- :file_locations,
497
- :file_agents,
498
- :obj_world_qualified,
499
- :obj_groups_qualified,
500
- :obj_locations_qualified,
501
- :obj_agents_qualified,
502
- :file_world_qualified,
503
- :file_groups_qualified,
504
- :file_locations_qualified,
505
- :file_agents_qualified].each { |index_elt| rights.index_elements[index_elt].uniq! }
590
+ %i[obj_groups
591
+ obj_locations
592
+ obj_agents
593
+ file_groups
594
+ file_locations
595
+ file_agents
596
+ obj_world_qualified
597
+ obj_groups_qualified
598
+ obj_locations_qualified
599
+ obj_agents_qualified
600
+ file_world_qualified
601
+ file_groups_qualified
602
+ file_locations_qualified
603
+ file_agents_qualified].each { |index_elt| rights.index_elements[index_elt].uniq! }
506
604
  end
507
605
 
508
606
  rights
metadata CHANGED
@@ -1,15 +1,17 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dor-rights-auth
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.0
4
+ version: 1.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Willy Mene
8
8
  - Joe Atzberger
9
+ - Johnathan Martin
10
+ - Naomi Dushay
9
11
  autorequire:
10
12
  bindir: bin
11
13
  cert_chain: []
12
- date: 2016-07-06 00:00:00.000000000 Z
14
+ date: 2021-01-07 00:00:00.000000000 Z
13
15
  dependencies:
14
16
  - !ruby/object:Gem::Dependency
15
17
  name: nokogiri
@@ -25,6 +27,34 @@ dependencies:
25
27
  - - ">="
26
28
  - !ruby/object:Gem::Version
27
29
  version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: codeclimate-test-reporter
32
+ requirement: !ruby/object:Gem::Requirement
33
+ requirements:
34
+ - - ">="
35
+ - !ruby/object:Gem::Version
36
+ version: '0'
37
+ type: :development
38
+ prerelease: false
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ - !ruby/object:Gem::Dependency
45
+ name: coveralls
46
+ requirement: !ruby/object:Gem::Requirement
47
+ requirements:
48
+ - - ">="
49
+ - !ruby/object:Gem::Version
50
+ version: '0'
51
+ type: :development
52
+ prerelease: false
53
+ version_requirements: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ version: '0'
28
58
  - !ruby/object:Gem::Dependency
29
59
  name: rake
30
60
  requirement: !ruby/object:Gem::Requirement
@@ -54,7 +84,7 @@ dependencies:
54
84
  - !ruby/object:Gem::Version
55
85
  version: '3.0'
56
86
  - !ruby/object:Gem::Dependency
57
- name: coveralls
87
+ name: rubocop
58
88
  requirement: !ruby/object:Gem::Requirement
59
89
  requirements:
60
90
  - - ">="
@@ -68,7 +98,7 @@ dependencies:
68
98
  - !ruby/object:Gem::Version
69
99
  version: '0'
70
100
  - !ruby/object:Gem::Dependency
71
- name: codeclimate-test-reporter
101
+ name: rubocop-rspec
72
102
  requirement: !ruby/object:Gem::Requirement
73
103
  requirements:
74
104
  - - ">="
@@ -97,8 +127,7 @@ dependencies:
97
127
  version: '0'
98
128
  description: Parses rightsMetadata xml into a useable object
99
129
  email:
100
- - wmene@stanford.edu
101
- - atz@stanford.edu
130
+ - dlss-infrastructure-team@lists.stanford.edu
102
131
  executables: []
103
132
  extensions: []
104
133
  extra_rdoc_files: []
@@ -121,19 +150,17 @@ require_paths:
121
150
  - lib
122
151
  required_ruby_version: !ruby/object:Gem::Requirement
123
152
  requirements:
124
- - - ">="
153
+ - - ">"
125
154
  - !ruby/object:Gem::Version
126
- version: '0'
155
+ version: '2.5'
127
156
  required_rubygems_version: !ruby/object:Gem::Requirement
128
157
  requirements:
129
158
  - - ">="
130
159
  - !ruby/object:Gem::Version
131
160
  version: 1.3.6
132
161
  requirements: []
133
- rubyforge_project:
134
- rubygems_version: 2.4.8
162
+ rubygems_version: 3.1.2
135
163
  signing_key:
136
164
  specification_version: 4
137
165
  summary: Parses rightsMetadata xml into a useable object
138
166
  test_files: []
139
- has_rdoc: