berkeley_library-av-core 0.4.0

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 (104) hide show
  1. checksums.yaml +7 -0
  2. data/.dockerignore +391 -0
  3. data/.github/workflows/build.yml +30 -0
  4. data/.gitignore +388 -0
  5. data/.idea/av_core.iml +146 -0
  6. data/.idea/codeStyles/Project.xml +12 -0
  7. data/.idea/codeStyles/codeStyleConfig.xml +5 -0
  8. data/.idea/go.imports.xml +6 -0
  9. data/.idea/inspectionProfiles/Project_Default.xml +37 -0
  10. data/.idea/misc.xml +6 -0
  11. data/.idea/modules.xml +8 -0
  12. data/.idea/vcs.xml +6 -0
  13. data/.rubocop.yml +241 -0
  14. data/.ruby-version +1 -0
  15. data/.simplecov +8 -0
  16. data/CHANGES.md +38 -0
  17. data/Gemfile +3 -0
  18. data/Jenkinsfile +16 -0
  19. data/LICENSE.md +21 -0
  20. data/README.md +20 -0
  21. data/Rakefile +20 -0
  22. data/av_core.gemspec +49 -0
  23. data/lib/berkeley_library/av/config.rb +238 -0
  24. data/lib/berkeley_library/av/constants.rb +30 -0
  25. data/lib/berkeley_library/av/core/module_info.rb +18 -0
  26. data/lib/berkeley_library/av/core.rb +7 -0
  27. data/lib/berkeley_library/av/marc/util.rb +114 -0
  28. data/lib/berkeley_library/av/marc.rb +52 -0
  29. data/lib/berkeley_library/av/metadata/README.md +5 -0
  30. data/lib/berkeley_library/av/metadata/field.rb +110 -0
  31. data/lib/berkeley_library/av/metadata/fields.rb +130 -0
  32. data/lib/berkeley_library/av/metadata/link.rb +28 -0
  33. data/lib/berkeley_library/av/metadata/readers/alma.rb +54 -0
  34. data/lib/berkeley_library/av/metadata/readers/base.rb +53 -0
  35. data/lib/berkeley_library/av/metadata/readers/tind.rb +52 -0
  36. data/lib/berkeley_library/av/metadata/readers.rb +2 -0
  37. data/lib/berkeley_library/av/metadata/source.rb +93 -0
  38. data/lib/berkeley_library/av/metadata/tind_html_metadata_da.json +2076 -0
  39. data/lib/berkeley_library/av/metadata/value.rb +121 -0
  40. data/lib/berkeley_library/av/metadata.rb +103 -0
  41. data/lib/berkeley_library/av/record.rb +86 -0
  42. data/lib/berkeley_library/av/record_id.rb +121 -0
  43. data/lib/berkeley_library/av/record_not_found.rb +7 -0
  44. data/lib/berkeley_library/av/restrictions.rb +36 -0
  45. data/lib/berkeley_library/av/track.rb +132 -0
  46. data/lib/berkeley_library/av/types/duration.rb +67 -0
  47. data/lib/berkeley_library/av/types/file_type.rb +84 -0
  48. data/lib/berkeley_library/av/util.rb +65 -0
  49. data/rakelib/bundle.rake +8 -0
  50. data/rakelib/coverage.rake +11 -0
  51. data/rakelib/gem.rake +54 -0
  52. data/rakelib/rubocop.rake +18 -0
  53. data/rakelib/spec.rake +12 -0
  54. data/spec/.rubocop.yml +116 -0
  55. data/spec/data/10.23.19.JessieLaCavalier.02.mrc +3 -0
  56. data/spec/data/alma/991005939359706532-sru.xml +123 -0
  57. data/spec/data/alma/991034756419706532-sru.xml +162 -0
  58. data/spec/data/alma/991047179369706532-sru.xml +210 -0
  59. data/spec/data/alma/991054360089706532-sru.xml +186 -0
  60. data/spec/data/alma/b11082434-sru.xml +165 -0
  61. data/spec/data/alma/b18538031-sru.xml +123 -0
  62. data/spec/data/alma/b20786580-sru.xml +123 -0
  63. data/spec/data/alma/b22139647-sru.xml +171 -0
  64. data/spec/data/alma/b22139658-sru.xml +282 -0
  65. data/spec/data/alma/b23161018-sru.xml +182 -0
  66. data/spec/data/alma/b23305522-sru.xml +144 -0
  67. data/spec/data/alma/b24071548-sru.xml +136 -0
  68. data/spec/data/alma/b24659129-sru.xml +210 -0
  69. data/spec/data/alma/b25207857-sru.xml +217 -0
  70. data/spec/data/alma/b25716973-sru.xml +186 -0
  71. data/spec/data/alma/b25742488-sru.xml +246 -0
  72. data/spec/data/record-(cityarts)00002.xml +78 -0
  73. data/spec/data/record-(cityarts)00773.xml +94 -0
  74. data/spec/data/record-(clir)00020.xml +153 -0
  75. data/spec/data/record-(miscmat)00615.xml +45 -0
  76. data/spec/data/record-(pacradio)00107.xml +85 -0
  77. data/spec/data/record-(pacradio)01469.xml +82 -0
  78. data/spec/data/record-empty-result.xml +4 -0
  79. data/spec/data/record-multiple-998s-disordered.xml +178 -0
  80. data/spec/data/record-multiple-998s.xml +178 -0
  81. data/spec/data/record-physcolloquia-bk00169017b.xml +78 -0
  82. data/spec/data/record-ragged-998-subfields.xml +122 -0
  83. data/spec/data/record-ragged-998s-multiple-fields.xml +160 -0
  84. data/spec/data/record-redirect-to-login.html +288 -0
  85. data/spec/data/record_id/bibs_with_check_digits.txt +151 -0
  86. data/spec/data/search-1993.xml +158 -0
  87. data/spec/data/search-b23305516.xml +81 -0
  88. data/spec/lib/berkeley_library/av/av_spec.rb +12 -0
  89. data/spec/lib/berkeley_library/av/config_spec.rb +250 -0
  90. data/spec/lib/berkeley_library/av/marc/util_spec.rb +150 -0
  91. data/spec/lib/berkeley_library/av/marc_spec.rb +62 -0
  92. data/spec/lib/berkeley_library/av/metadata/field_spec.rb +81 -0
  93. data/spec/lib/berkeley_library/av/metadata/fields_spec.rb +180 -0
  94. data/spec/lib/berkeley_library/av/metadata/metadata_spec.rb +274 -0
  95. data/spec/lib/berkeley_library/av/metadata/source_spec.rb +261 -0
  96. data/spec/lib/berkeley_library/av/metadata/value_spec.rb +29 -0
  97. data/spec/lib/berkeley_library/av/record_id_spec.rb +72 -0
  98. data/spec/lib/berkeley_library/av/record_spec.rb +284 -0
  99. data/spec/lib/berkeley_library/av/track_spec.rb +335 -0
  100. data/spec/lib/berkeley_library/av/types/duration_spec.rb +91 -0
  101. data/spec/lib/berkeley_library/av/types/file_type_spec.rb +98 -0
  102. data/spec/lib/berkeley_library/av/util_spec.rb +30 -0
  103. data/spec/spec_helper.rb +63 -0
  104. metadata +499 -0
data/.rubocop.yml ADDED
@@ -0,0 +1,241 @@
1
+ inherit_mode:
2
+ merge:
3
+ - Exclude
4
+ - Include
5
+
6
+ AllCops:
7
+ UseCache: false
8
+ # Exclude generated files
9
+ Exclude:
10
+ - 'bin/**/*'
11
+ - 'db/**/*'
12
+ - 'out/**/*'
13
+ # Exclude vendor files in GitHub build
14
+ - 'vendor/**/*'
15
+
16
+ # Allow one line around block body (Layout/EmptyLines will still disallow two or more)
17
+ Layout/EmptyLinesAroundBlockBody:
18
+ Enabled: false
19
+
20
+ # Allow one line around class body (Layout/EmptyLines will still disallow two or more)
21
+ Layout/EmptyLinesAroundClassBody:
22
+ Enabled: false
23
+
24
+ # Allow one line around module body (Layout/EmptyLines will still disallow two or more)
25
+ Layout/EmptyLinesAroundModuleBody:
26
+ Enabled: false
27
+
28
+ # Reasonable line-length check; it's too easy for the cure to be worse than the disease
29
+ Layout/LineLength:
30
+ Max: 150
31
+
32
+ # Make indents consistent regardless of the lengths of variables and method names and whatnot
33
+ Layout/MultilineMethodCallIndentation:
34
+ EnforcedStyle: indented
35
+
36
+ # Produces monsters
37
+ Layout/MultilineOperationIndentation:
38
+ Enabled: false
39
+
40
+ # We meant to do that
41
+ Naming/MemoizedInstanceVariableName:
42
+ Enabled: False
43
+
44
+ # It works in context, trust us
45
+ Naming/MethodParameterName:
46
+ Enabled: False
47
+
48
+ # Confusing and weird
49
+ Naming/VariableNumber:
50
+ Enabled: False
51
+
52
+ # Whether vertical or horizontal is more readable depends on context
53
+ Style/AccessorGrouping:
54
+ Enabled: false
55
+
56
+ # Do what's readable in the context you're in
57
+ Style/AccessModifierDeclarations:
58
+ Enabled: false
59
+
60
+ # 👎 to cultural imperialism
61
+ Style/AsciiComments:
62
+ Enabled: false
63
+
64
+ #
65
+ Style/ClassEqualityComparison:
66
+ Enabled: false
67
+
68
+ # Seriously?
69
+ Style/CommentedKeyword:
70
+ Enabled: False
71
+
72
+ # Disable problematic module documentation check (see https://github.com/bbatsov/rubocop/issues/947)
73
+ Style/Documentation:
74
+ Enabled: false
75
+
76
+ # Adding more line noise to format strings will not improve them
77
+ Style/FormatStringToken:
78
+ Enabled: false
79
+
80
+ # Putting '# frozen_string_literal: true' everywhere does not make the world a better place
81
+ Style/FrozenStringLiteralComment:
82
+ Enabled: false
83
+
84
+ # Requiring the lambda() method just makes wordy calls wordier
85
+ Style/Lambda:
86
+ EnforcedStyle: literal
87
+
88
+ # `foo.positive?` is cute, but it's not actually more readable than `foo > 0`
89
+ Style/NumericPredicate:
90
+ Enabled: false
91
+
92
+ # Don't be unnecessarily redundant
93
+ Style/ReturnNil:
94
+ Enabled: true
95
+ EnforcedStyle: return
96
+
97
+ # Unclear why it's a good idea to give parameters semantically meaningless names
98
+ Style/SingleLineBlockParams:
99
+ Enabled: false
100
+
101
+ # The semantics of `foo&.bar` are a lot less interchangeable with `foo && foo.bar` than RuboCop thinks
102
+ Style/SafeNavigation:
103
+ Enabled: false
104
+
105
+ ############################################################
106
+ # Enable newer cops
107
+
108
+ Style/HashEachMethods: # (new in 0.80)
109
+ Enabled: true
110
+ Style/HashTransformKeys: # (new in 0.80)
111
+ Enabled: true
112
+ Style/HashTransformValues: # (new in 0.80)
113
+ Enabled: true
114
+ Lint/RaiseException: # (new in 0.81)
115
+ Enabled: true
116
+ Lint/StructNewOverride: # (new in 0.81)
117
+ Enabled: true
118
+ Layout/SpaceAroundMethodCallOperator: # (new in 0.82)
119
+ Enabled: true
120
+ Style/ExponentialNotation: # (new in 0.82)
121
+ Enabled: false
122
+ Layout/EmptyLinesAroundAttributeAccessor: # (new in 0.83)
123
+ Enabled: true
124
+ Style/SlicingWithRange: # (new in 0.83)
125
+ Enabled: true
126
+ Lint/DeprecatedOpenSSLConstant: # (new in 0.84)
127
+ Enabled: true
128
+ Lint/MixedRegexpCaptureTypes: # (new in 0.85)
129
+ Enabled: true
130
+ Style/RedundantRegexpCharacterClass: # (new in 0.85)
131
+ Enabled: true
132
+ Style/RedundantRegexpEscape: # (new in 0.85)
133
+ Enabled: true
134
+ Style/RedundantFetchBlock: # (new in 0.86)
135
+ Enabled: true
136
+ Lint/DuplicateRegexpCharacterClassElement: # (new in 1.1)
137
+ Enabled: true
138
+ Lint/EmptyBlock: # (new in 1.1)
139
+ Enabled: true
140
+ Lint/ToEnumArguments: # (new in 1.1)
141
+ Enabled: true
142
+ Lint/UnmodifiedReduceAccumulator: # (new in 1.1)
143
+ Enabled: true
144
+ Style/ArgumentsForwarding: # (new in 1.1)
145
+ Enabled: true
146
+ Style/DocumentDynamicEvalDefinition: # (new in 1.1)
147
+ Enabled: true
148
+ Style/SwapValues: # (new in 1.1)
149
+ Enabled: true
150
+ Lint/NoReturnInBeginEndBlocks: # (new in 1.2)
151
+ Enabled: true
152
+ Style/CollectionCompact: # (new in 1.2)
153
+ Enabled: true
154
+ Style/NegatedIfElseCondition: # (new in 1.2)
155
+ Enabled: true
156
+ Lint/DuplicateBranch: # (new in 1.3)
157
+ Enabled: true
158
+ Lint/EmptyClass: # (new in 1.3)
159
+ Enabled: true
160
+ Style/NilLambda: # (new in 1.3)
161
+ Enabled: true
162
+ Style/RedundantArgument: # (new in 1.4)
163
+ Enabled: true
164
+ Lint/UnexpectedBlockArity: # (new in 1.5)
165
+ Enabled: true
166
+ Layout/SpaceBeforeBrackets: # (new in 1.7)
167
+ Enabled: true
168
+ Lint/AmbiguousAssignment: # (new in 1.7)
169
+ Enabled: true
170
+ Style/HashExcept: # (new in 1.7)
171
+ Enabled: true
172
+ Lint/DeprecatedConstants: # (new in 1.8)
173
+ Enabled: true
174
+ Lint/LambdaWithoutLiteralBlock: # (new in 1.8)
175
+ Enabled: true
176
+ Lint/RedundantDirGlobSort: # (new in 1.8)
177
+ Enabled: true
178
+ Style/EndlessMethod: # (new in 1.8)
179
+ Enabled: true
180
+ Lint/NumberedParameterAssignment: # (new in 1.9)
181
+ Enabled: true
182
+ Lint/OrAssignmentToConstant: # (new in 1.9)
183
+ Enabled: true
184
+ Lint/SymbolConversion: # (new in 1.9)
185
+ Enabled: true
186
+ Lint/TripleQuotes: # (new in 1.9)
187
+ Enabled: true
188
+ Style/IfWithBooleanLiteralBranches: # (new in 1.9)
189
+ Enabled: true
190
+ Gemspec/DateAssignment: # (new in 1.10)
191
+ Enabled: true
192
+ Style/HashConversion: # (new in 1.10)
193
+ Enabled: true
194
+ Style/StringChars: # (new in 1.12)
195
+ Enabled: true
196
+ Lint/EmptyInPattern: # (new in 1.16)
197
+ Enabled: true
198
+ Style/InPatternThen: # (new in 1.16)
199
+ Enabled: true
200
+ Style/MultilineInPatternThen: # (new in 1.16)
201
+ Enabled: true
202
+ Style/QuotedSymbols: # (new in 1.16)
203
+ Enabled: true
204
+ Layout/LineEndStringConcatenationIndentation: # (new in 1.18)
205
+ Enabled: true
206
+ Naming/InclusiveLanguage: # (new in 1.18)
207
+ Enabled: true
208
+ Lint/AmbiguousRange: # new in 1.19
209
+ Enabled: true
210
+ Style/RedundantSelfAssignmentBranch: # new in 1.19
211
+ Enabled: true
212
+ Lint/AmbiguousOperatorPrecedence: # new in 1.21
213
+ Enabled: true
214
+ Lint/IncompatibleIoSelectWithFiberScheduler: # new in 1.21
215
+ Enabled: true
216
+ Lint/RequireRelativeSelfPath: # new in 1.22
217
+ Enabled: true
218
+ Security/IoMethods: # new in 1.22
219
+ Enabled: true
220
+ Style/NumberedParameters: # new in 1.22
221
+ Enabled: true
222
+ Style/NumberedParametersLimit: # new in 1.22
223
+ Enabled: true
224
+ Style/SelectByRegexp: # new in 1.22
225
+ Enabled: true
226
+ Gemspec/RequireMFA: # new in 1.23
227
+ Enabled: true
228
+ Lint/UselessRuby2Keywords: # new in 1.23
229
+ Enabled: true
230
+ Style/OpenStructUse: # new in 1.23
231
+ Enabled: true
232
+ Naming/BlockForwarding: # new in 1.24
233
+ Enabled: true
234
+ Style/FileRead: # new in 1.24
235
+ Enabled: true
236
+ Style/FileWrite: # new in 1.24
237
+ Enabled: true
238
+ Style/MapToHash: # new in 1.24
239
+ Enabled: true
240
+ Style/NestedFileDirname: # new in 1.26
241
+ Enabled: true
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 3.1.3
data/.simplecov ADDED
@@ -0,0 +1,8 @@
1
+ require 'simplecov-rcov'
2
+
3
+ SimpleCov.start 'rails' do
4
+ add_filter 'module_info.rb'
5
+ coverage_dir 'artifacts'
6
+ formatter SimpleCov::Formatter::RcovFormatter
7
+ minimum_coverage 100
8
+ end
data/CHANGES.md ADDED
@@ -0,0 +1,38 @@
1
+ # 0.3.0 (2022-02-01)
2
+
3
+ - Rename `Record#ucb_access?` and `Metadata#ucb_access?` to `calnet_or_ip?` for clarity.
4
+ - Remove the following methods:
5
+ - `Record#player_link_text`
6
+ - `Metadata#player_link_text`
7
+ - `Metadata#player_url`
8
+ - Remove the following constants:
9
+ - `AV::Constants::RESTRICTIONS_CALNET`
10
+ - `AV::Constants::RESTRICTIONS_UCB_IP`
11
+ - `AV::Constants::RESTRICTIONS`
12
+ - `AV::Constants::RESTRICTIONS_NONE`
13
+
14
+ # 0.2.3 (2022-01-05)
15
+
16
+ - `Record#bib_number` and `Metadata#bib_number` now return nil instead of raising an
17
+ exception when the MARC field expected to contain a Millennium bib number contains
18
+ something else.
19
+
20
+ # 0.2.2 (2022-01-03)
21
+
22
+ - Add `Record#calnet_only?` in addition to `Record#ucb_access?`
23
+
24
+ # 0.2.1 (2021-11-08)
25
+
26
+ - Add `Metadata#calnet_only?` in addition to `Metadata#ucb_access?`
27
+ - Support declaring restrictions in 998$r as well as 95640$z (Alma) or 85642$y (TIND)
28
+
29
+ # 0.2.0 (2021-10-21)
30
+
31
+ - Add Alma support
32
+ - Remove Millennium support
33
+ - Switch to [`BerkeleyLibrary/logging`](https://github.com/BerkeleyLibrary/logging)
34
+
35
+ # 0.1.0 (2021-08-05)
36
+
37
+ - Initial prerelease
38
+ - Send a custom `User-Agent` header to deal with new TIND firewall rules.
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
data/Jenkinsfile ADDED
@@ -0,0 +1,16 @@
1
+ dockerComposePipeline(
2
+ commands: [
3
+ 'bundle exec rake coverage',
4
+ 'bundle exec rake rubocop',
5
+ 'bundle exec rake bundle:audit',
6
+ 'bundle exec rake gem'
7
+ ],
8
+ artifacts: [
9
+ junit: 'artifacts/rspec/**/*.xml',
10
+ html : [
11
+ 'Code Coverage': 'artifacts/rcov',
12
+ 'RuboCop' : 'artifacts/rubocop'
13
+ ],
14
+ raw : ['artifacts/**/*.gem']
15
+ ]
16
+ )
data/LICENSE.md ADDED
@@ -0,0 +1,21 @@
1
+ # The MIT License (MIT)
2
+
3
+ Copyright © 2023 The Regents of the University of California
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a
6
+ copy of this software and associated documentation files (the “Software”),
7
+ to deal in the Software without restriction, including without limitation
8
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
9
+ and/or sell copies of the Software, and to permit persons to whom the
10
+ Software is furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21
+ DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,20 @@
1
+ # BerkeleyLibrary::AV::Core
2
+
3
+ [![Build Status](https://github.com/BerkeleyLibrary/av-core/actions/workflows/build.yml/badge.svg?branch=main)](https://github.com/BerkeleyLibrary/av-core/actions/workflows/build.yml)
4
+ [![Gem Version](https://img.shields.io/gem/v/berkeley_library-av-core.svg)](https://rubygems.org/gems/berkeley_library-av-core)
5
+
6
+ Gem for UC Berkeley Library shared audio/video code.
7
+
8
+ ## Installation
9
+
10
+ In your Gemfile:
11
+
12
+ ```ruby
13
+ gem 'berkeley_library-av-core'
14
+ ```
15
+
16
+ In your code:
17
+
18
+ ```ruby
19
+ require 'berkeley_library/av/core'
20
+ ```
data/Rakefile ADDED
@@ -0,0 +1,20 @@
1
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('Gemfile', __dir__)
2
+ require 'bundler/setup' # Set up gems listed in the Gemfile.
3
+
4
+ # ------------------------------------------------------------
5
+ # Application code
6
+
7
+ File.expand_path('lib', __dir__).tap do |lib|
8
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
9
+ end
10
+
11
+ # ------------------------------------------------------------
12
+ # CI
13
+
14
+ ENV['RAILS_ENV'] = 'test' if ENV['CI']
15
+
16
+ # ------------------------------------------------------------
17
+ # Custom tasks
18
+
19
+ desc 'Run tests, check test coverage, check code style, check for vulnerabilities, build gem'
20
+ task default: %i[coverage rubocop bundle:audit gem]
data/av_core.gemspec ADDED
@@ -0,0 +1,49 @@
1
+ File.expand_path('lib', __dir__).tap do |lib|
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ end
4
+
5
+ ruby_version_file = File.expand_path('.ruby-version', __dir__)
6
+ ruby_version_exact = File.read(ruby_version_file).strip
7
+ ruby_minor_version = ruby_version_exact.gsub(/^(\d+\.\d+).*/, '\1')
8
+
9
+ require 'berkeley_library/av/core/module_info'
10
+
11
+ Gem::Specification.new do |spec|
12
+ spec.name = BerkeleyLibrary::AV::Core::ModuleInfo::NAME
13
+ spec.author = BerkeleyLibrary::AV::Core::ModuleInfo::AUTHOR
14
+ spec.email = BerkeleyLibrary::AV::Core::ModuleInfo::AUTHOR_EMAIL
15
+ spec.summary = BerkeleyLibrary::AV::Core::ModuleInfo::SUMMARY
16
+ spec.description = BerkeleyLibrary::AV::Core::ModuleInfo::DESCRIPTION
17
+ spec.license = BerkeleyLibrary::AV::Core::ModuleInfo::LICENSE
18
+ spec.version = BerkeleyLibrary::AV::Core::ModuleInfo::VERSION
19
+ spec.homepage = BerkeleyLibrary::AV::Core::ModuleInfo::HOMEPAGE
20
+
21
+ spec.files = `git ls-files -z -- ':!:Dockerfile' ':!:docker-compose.yml'`.split("\x0")
22
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
23
+ spec.require_paths = ['lib']
24
+
25
+ spec.required_ruby_version = ">= #{ruby_minor_version}"
26
+
27
+ spec.add_dependency 'berkeley_library-logging', '~> 0.2'
28
+ spec.add_dependency 'berkeley_library-marc', '~> 0.2', '>= 0.2.1'
29
+ spec.add_dependency 'berkeley_library-util', '~> 0.1', '>= 0.1.1'
30
+ spec.add_dependency 'ruby-marc-spec', '~> 0.1', '>= 0.1.3'
31
+ spec.add_dependency 'typesafe_enum', '~> 0.3'
32
+
33
+ spec.add_development_dependency 'brakeman', '~> 4.9'
34
+ spec.add_development_dependency 'bundle-audit', '~> 0.1'
35
+ spec.add_development_dependency 'ci_reporter_rspec', '~> 1.0'
36
+ spec.add_development_dependency 'colorize', '~> 0.8'
37
+ spec.add_development_dependency 'dotenv', '~> 2.7'
38
+ spec.add_development_dependency 'irb', '~> 1.2' # workaroundfor https://github.com/bundler/bundler/issues/6929
39
+ spec.add_development_dependency 'listen', '>= 3.0.5', '< 3.2'
40
+ spec.add_development_dependency 'rake', '~> 13.0'
41
+ spec.add_development_dependency 'rspec-support', '~> 3.9'
42
+ spec.add_development_dependency 'rubocop', '1.26.0'
43
+ spec.add_development_dependency 'rubocop-rake', '~> 0.6.0'
44
+ spec.add_development_dependency 'rubocop-rspec', '~> 2.4.0'
45
+ spec.add_development_dependency 'simplecov', '~> 0.21'
46
+ spec.add_development_dependency 'simplecov-rcov', '~> 0.2'
47
+ spec.add_development_dependency 'webmock', '~> 3.8'
48
+ spec.metadata['rubygems_mfa_required'] = 'true'
49
+ end
@@ -0,0 +1,238 @@
1
+ require 'berkeley_library/util/uris'
2
+
3
+ module BerkeleyLibrary
4
+ module AV
5
+ # rubocop:disable Metrics/ClassLength
6
+ class Config
7
+ REQUIRED_SETTINGS = %i[
8
+ avplayer_base_uri
9
+ alma_sru_host
10
+ alma_primo_host
11
+ alma_institution_code
12
+ alma_permalink_key
13
+ tind_base_uri
14
+ wowza_base_uri
15
+ ].freeze
16
+
17
+ class << self
18
+ include BerkeleyLibrary::Util
19
+
20
+ # Alma SRU hostname, e.g. UC Berkeley = berkeley.alma.exlibrisgroup.com
21
+ def alma_sru_host
22
+ @alma_sru_host ||= value_from_rails_config(:alma_sru_host)
23
+ end
24
+
25
+ # Alma institution code, e.g. UC Berkeley = 01UCS_BER
26
+ def alma_institution_code
27
+ @alma_institution_code ||= value_from_rails_config(:alma_institution_code)
28
+ end
29
+
30
+ # Alma Primo host, e.g. UC Berkeley = search.library.berkeley.edu
31
+ def alma_primo_host
32
+ @alma_primo_host ||= value_from_rails_config(:alma_primo_host)
33
+ end
34
+
35
+ # View state key to use when generating Alma permalinks, e.g. `iqob43`; see
36
+ # https://knowledge.exlibrisgroup.com/Primo/Knowledge_Articles/What_is_the_key_in_short_permalinks%3F
37
+ def alma_permalink_key
38
+ @alma_permalink_key ||= value_from_rails_config(:alma_permalink_key)
39
+ end
40
+
41
+ def alma_sru_base_uri
42
+ ensure_configured(:alma_sru_host, :alma_institution_code)
43
+
44
+ sru_base_uri_for(alma_sru_host, alma_institution_code)
45
+ end
46
+
47
+ def alma_permalink_base_uri
48
+ ensure_configured(:alma_primo_host, :alma_institution_code, :alma_permalink_key)
49
+
50
+ primo_permalink_base_uri_for(alma_primo_host, alma_institution_code, alma_permalink_key)
51
+ end
52
+
53
+ def avplayer_base_uri
54
+ @avplayer_base_uri ||= uri_from_rails_config(:avplayer_base_uri)
55
+ end
56
+
57
+ def tind_base_uri
58
+ @tind_base_uri ||= uri_from_rails_config(:tind_base_uri)
59
+ end
60
+
61
+ def wowza_base_uri
62
+ @wowza_base_uri ||= uri_from_rails_config(:wowza_base_uri)
63
+ end
64
+
65
+ # Sets the AV Player base URI
66
+ #
67
+ # @param [URI, String] uri the base URI
68
+ # @return [URI] the URI
69
+ # @raise URI::InvalidURIError if the URI cannot be parsed, or is not HTTP/HTTPS
70
+ def avplayer_base_uri=(uri)
71
+ @avplayer_base_uri = clean_uri(uri)
72
+ end
73
+
74
+ # Sets the Alma SRU hostname
75
+ #
76
+ # @param [String] hostname the hostname
77
+ # @return [String] the hostname
78
+ # @raise ArgumentError if the hostname is nil or empty
79
+ # @raise URI::InvalidURIError if the resulting SRU URI cannot be parsed
80
+ def alma_sru_host=(hostname)
81
+ raise ArgumentError, "Invalid hostname: #{hostname.inspect}" if hostname.nil? || hostname.empty?
82
+
83
+ sru_uri = sru_base_uri_for(hostname, '') # Catch bad URIs early
84
+ @alma_sru_host = sru_uri.host
85
+ end
86
+
87
+ # Sets the Alma Primo hostname
88
+ #
89
+ # @param [String] hostname the hostname
90
+ # @return [String] the hostname
91
+ # @raise ArgumentError if the hostname is nil or empty
92
+ # @raise URI::InvalidURIError if the resulting Primo permalink URI cannot be parsed
93
+ def alma_primo_host=(hostname)
94
+ raise ArgumentError, "Invalid hostname: #{hostname.inspect}" if hostname.nil? || hostname.empty?
95
+
96
+ primo_uri = primo_permalink_base_uri_for(hostname, 'XXX', 'abc123') # Catch bad URIs early
97
+ @alma_primo_host = primo_uri.host
98
+ end
99
+
100
+ # Sets the Alma SRU institution code
101
+ #
102
+ # @param [String] inst_code the institution code
103
+ # @return [String] the institution code
104
+ # @raise ArgumentError if the institution code is nil or empty
105
+ # @raise URI::InvalidURIError if the resulting SRU URI cannot be parsed
106
+ def alma_institution_code=(inst_code)
107
+ raise ArgumentError, "Invalid institution code: #{inst_code.inspect}" if inst_code.nil? || inst_code.empty?
108
+
109
+ sru_uri = sru_base_uri_for('example.org', inst_code) # Catch bad URIs early
110
+ @alma_institution_code = sru_uri.path.split('/').last
111
+ end
112
+
113
+ # Sets the Alma permalink key
114
+ #
115
+ # @param [String] permalink_key the permalink key
116
+ # @return [String] the permalink key
117
+ # @raise ArgumentError if the permalink key is nil or empty
118
+ # @raise URI::InvalidURIError if the resulting Primo permalink URI cannot be parsed
119
+ def alma_permalink_key=(permalink_key)
120
+ raise ArgumentError, "Invalid permalink key: #{permalink_key.inspect}" if permalink_key.nil? || permalink_key.empty?
121
+
122
+ sru_uri = primo_permalink_base_uri_for('example.org', 'XXX', permalink_key) # Catch bad URIs early
123
+ @alma_permalink_key = sru_uri.path.split('/').last
124
+ end
125
+
126
+ # Sets the TIND base URI
127
+ #
128
+ # @param [URI, String] uri the base URI
129
+ # @return [URI] the URI
130
+ # @raise URI::InvalidURIError if the URI cannot be parsed, or is not HTTP/HTTPS
131
+ def tind_base_uri=(uri)
132
+ @tind_base_uri = clean_uri(uri)
133
+ end
134
+
135
+ # Sets the Wowza base URI
136
+ #
137
+ # @param [URI, String] uri the base URI
138
+ # @return [URI] the URI
139
+ # @raise URI::InvalidURIError if the URI cannot be parsed, or is not HTTP/HTTPS
140
+ def wowza_base_uri=(uri)
141
+ @wowza_base_uri = clean_uri(uri)
142
+ end
143
+
144
+ # Returns the list of missing required settings.
145
+ # @return [Array<Symbol>] the missing settings.
146
+ def missing(*settings)
147
+ settings = REQUIRED_SETTINGS if settings.empty?
148
+ [].tap do |unset|
149
+ settings.each do |setting|
150
+ unset << setting unless set?(setting)
151
+ end
152
+ end
153
+ end
154
+
155
+ def ensure_configured(*settings)
156
+ return if (missing_settings = missing(*settings)).empty?
157
+
158
+ raise ArgumentError, "Missing AV configuration settings: #{missing_settings.join(', ')}"
159
+ end
160
+
161
+ private
162
+
163
+ def sru_base_uri_for(domain, inst_code)
164
+ URIs.append("https://#{domain}/view/sru/", inst_code)
165
+ end
166
+
167
+ def primo_permalink_base_uri_for(alma_primo_host, inst_code, key)
168
+ URIs.append("https://#{alma_primo_host}/", 'permalink', inst_code, key)
169
+ end
170
+
171
+ # Returns a URI
172
+ # @param [URI, String] url the base URL
173
+ # @return [URI] the URI
174
+ # @raise URI::InvalidURIError if the URI cannot be parsed, or is not HTTP/HTTPS
175
+ def clean_uri(url)
176
+ BerkeleyLibrary::Util::URIs.uri_or_nil(url).tap do |uri|
177
+ raise URI::InvalidURIError, 'url cannot be nil' unless uri
178
+ raise URI::InvalidURIError, 'URL must have a scheme' unless (scheme = uri.scheme)
179
+ raise URI::InvalidURIError, 'URL must be HTTP or HTTPS' unless scheme.start_with?('http')
180
+ end
181
+ end
182
+
183
+ def uri_from_rails_config(sym)
184
+ return unless (config = rails_config)
185
+
186
+ result = config.send(sym)
187
+ clean_uri(result)
188
+ end
189
+
190
+ # Gets the specified value from the Rails configuraiton
191
+ # @return [Object, nil] the value, or nil if there is no Rails configuration or the value is not set
192
+ def value_from_rails_config(sym)
193
+ return unless (config = rails_config)
194
+
195
+ config.send(sym)
196
+ end
197
+
198
+ def rails_config
199
+ return unless defined?(Rails)
200
+ return unless (application = Rails.application)
201
+
202
+ application.config
203
+ end
204
+
205
+ def set?(setting)
206
+ !Config.send(setting).nil?
207
+ end
208
+
209
+ def clear!
210
+ REQUIRED_SETTINGS.each do |attr|
211
+ ivar_name = "@#{attr}"
212
+ next unless instance_variable_defined?(ivar_name)
213
+
214
+ send(:remove_instance_variable, ivar_name)
215
+ end
216
+ end
217
+ end
218
+
219
+ private_class_method :new
220
+
221
+ end
222
+ # rubocop:enable Metrics/ClassLength
223
+
224
+ class << self
225
+ def config
226
+ AV::Config
227
+ end
228
+
229
+ def configure(&)
230
+ class_eval(&)
231
+ end
232
+
233
+ def configured?
234
+ Config.missing.empty?
235
+ end
236
+ end
237
+ end
238
+ end
@@ -0,0 +1,30 @@
1
+ module BerkeleyLibrary
2
+ module AV
3
+ module Constants
4
+ TAG_TITLE_FIELD = '245'.freeze
5
+ TAG_LINK_FIELD = '856'.freeze
6
+ TAG_TRACK_FIELD = '998'.freeze
7
+ TAG_TIND_ID = '001'.freeze
8
+
9
+ # TODO: use marc/spec
10
+ TAG_TIND_CATALOG_ID = '901'.freeze
11
+ SUBFIELD_CODE_TIND_BIB_NUMBER = 'm'.freeze
12
+
13
+ # TODO: use marc/spec
14
+ TAG_ALMA_MIGRATION_INFO = '996'.freeze
15
+ SUBFIELD_CODE_ALMA_BIB_NUMBER = 'a'.freeze
16
+
17
+ SUBFIELD_CODE_DURATION = :a
18
+ SUBFIELD_CODE_TITLE = :t
19
+ SUBFIELD_CODE_PATH = :g
20
+ SUBFIELD_CODES_TRACKS = [SUBFIELD_CODE_DURATION, SUBFIELD_CODE_TITLE, SUBFIELD_CODE_PATH].freeze
21
+
22
+ UNKNOWN_TITLE = 'Unknown title'.freeze
23
+
24
+ # '99' is the Alma prefix for a Metadata Management System ID
25
+ ALMA_RECORD_RE = /^(?<type>99)[0-9]{9,12}(?<institution>[0-9]{4})$/
26
+ MILLENNIUM_RECORD_RE = /^b(?<digits>[0-9]{8})(?<check>[0-9ax])?$/
27
+ OCLC_RECORD_RE = /^o[0-9]+$/
28
+ end
29
+ end
30
+ end