• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

pulibrary / orangelight / 4c391e0e-519a-40cb-8ad3-354445f4ce03

12 Aug 2025 08:47PM UTC coverage: 85.348% (-10.0%) from 95.335%
4c391e0e-519a-40cb-8ad3-354445f4ce03

push

circleci

web-flow
[#5143] Use access restriction note as Aeon ItemInfo1 if available (#5173)

With this commit, if a user visits a record with an access
restrictions note and presses the Reading Room Request
button, they will get to an Aeon form with the 'Restrictions'
field pre-filled with the restriction note.

If the record does not have an access restrictions note,
the field will be pre-filled with 'Reading Room Access Only',
as it has been previously.

Closes #5143

5493 of 6436 relevant lines covered (85.35%)

251.82 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

84.73
/app/models/solr_document.rb
1
# frozen_string_literal: true
2
require_relative 'solr_document/identifier'
1✔
3

4
class SolrDocument
1✔
5
  include Blacklight::Solr::Document
1✔
6
  include Orangelight::Document::Export
1✔
7
  include Orangelight::Document::Alma
1✔
8
  include Orangelight::Document::Scsb
1✔
9
  include Orangelight::Document::StandardNumbers
1✔
10

11
  # Explicitly required for sneakers
12
  include Blacklight::Document::Extensions
1✔
13
  include Blacklight::Document::SemanticFields
1✔
14

15
  # The following shows how to setup this blacklight document to display marc documents
16
  extension_parameters[:marc_source_field] = :id
1✔
17
  extension_parameters[:marc_format_type] = :marcxml
1✔
18
  use_extension(Blacklight::Marc::DocumentExtension) do |document|
1✔
19
    document.key?(:id)
752✔
20
  end
21

22
  field_semantics.merge!(
1✔
23
    title: 'title_citation_display',
24
    creator: 'author_citation_display',
25
    language: 'language_facet',
26
    format: 'format',
27
    description: 'summary_note_display',
28
    date: 'pub_date_start_sort',
29
    publisher: 'pub_created_display',
30
    subject: 'subject_facet',
31
    type: 'format',
32
    identifier: 'isbn_s'
33
  )
34

35
  # self.unique_key = 'id'
36

37
  # Email uses the semantic field mappings below to generate the body of an email.
38
  SolrDocument.use_extension(Blacklight::Document::Email)
1✔
39

40
  # DublinCore uses the semantic field mappings below to assemble an OAI-compliant Dublin Core
41
  # document Semantic mappings of solr stored fields. Fields may be multi or single valued.
42
  # See Blacklight::Solr::Document::ExtendableClassMethods#field_semantics and
43
  # Blacklight::Solr::Document#to_semantic_values.
44
  # Recommendation: Use field names from Dublin Core
45
  use_extension(Blacklight::Document::DublinCore)
1✔
46

47
  ## Adds RIS
48
  use_extension(Blacklight::Document::Ris)
1✔
49

50
  ## Adds JSON-LD
51
  use_extension(Blacklight::Document::JsonLd)
1✔
52

53
  ## Adds the methods needed for CiteProc citations,
54
  # Including MLA, APA, and Chicago
55
  use_extension(Blacklight::Document::CiteProc)
1✔
56

57
  ## Adds MLA html
58
  use_extension(Blacklight::Document::Mla)
1✔
59

60
  # Adds APA html
61
  use_extension(Blacklight::Document::Apa)
1✔
62

63
  # Adds Chicago Author Date html
64
  use_extension(Blacklight::Document::ChicagoAuthorDate)
1✔
65

66
  # Adds Chicago Note Bibliography html
67
  use_extension(Blacklight::Document::ChicagoNotesBibliography)
1✔
68

69
  def identifier_data
1✔
70
    values = identifiers.each_with_object({}) do |identifier, hsh|
193✔
71
      hsh[identifier.data_key.to_sym] ||= []
262✔
72
      hsh[identifier.data_key.to_sym] << identifier.value
262✔
73
    end
74

75
    values[:'bib-id'] = id unless id.nil?
193✔
76
    values
193✔
77
  end
78

79
  def identifiers
1✔
80
    @identifiers ||= identifier_keys.flat_map do |key|
386✔
81
      fetch(key, []).map do |value|
386✔
82
        SolrDocument::Identifier.new(key, value)
262✔
83
      end
84
    end.compact
85
  end
86

87
  # Retrieve the value of the ARK identifier
88
  # @return [String] the ARK for the resource
89
  def ark
1✔
90
    return unless full_ark
×
91
    m = /.*(ark:(.*))/.match(full_ark)
×
92
    m[1]
×
93
  end
94

95
  # Retrieve the electronic access information
96
  # @return [String] electronic access value
97
  def doc_electronic_access
1✔
98
    string_values = first('electronic_access_1display') || '{}'
193✔
99
    JSON.parse(string_values).delete_if { |k, _v| k == 'iiif_manifest_paths' }
238✔
100
  end
101

102
  # Retrieve electronic portfolio values and parse
103
  # @return [Array<Hash>] array of electronic portfolio hashes
104
  def electronic_portfolios
1✔
105
    values = fetch('electronic_portfolio_s', [])
553✔
106
    values.map { |v| JSON.parse(v) }
751✔
107
  end
108

109
  # Parse IIIF Manifest links from the electronic access information
110
  # @return [Hash] IIIF Manifests information
111
  def iiif_manifests
1✔
112
    string_values = first('electronic_access_1display') || '{}'
×
113
    values = JSON.parse(string_values)
×
114
    values.fetch('iiif_manifest_paths', {})
×
115
  end
116

117
  # IIIF Manifest URIs from the electronic access information
118
  # @return [Array<String>] URIs to IIIF Manifests
119
  def iiif_manifest_uris
1✔
120
    iiif_manifests.values
×
121
  end
122

123
  # The default IIIF Manifest URI from the electronic access information
124
  # @return [String] URIs to IIIF Manifests
125
  def iiif_manifest_uri
1✔
126
    iiif_manifest_uris.first
×
127
  end
128

129
  # Returns the MMS_IDs found in the electronic_access_1display display for URLs that follow the
130
  # pattern https://catalog.princeton.edu/catalog\{mms_id}#view except the one for the current ID.
131
  # These URLs are found when the Figgy manifest is registered for another (related) MMS_ID rather
132
  # than for the current one.
133
  def related_bibs_iiif_manifest
1✔
134
    @related_bibs_iiif_manifest ||= begin
29✔
135
      string_values = first('electronic_access_1display') || '{}'
29✔
136
      values = JSON.parse(string_values)
29✔
137
      mms_ids = values.keys.map { |key| key[/https\:\/\/catalog.princeton.edu\/catalog\/(\d*)#view/, 1] }.compact.uniq
48✔
138
      mms_ids.map { |id| ensure_voyager_to_alma_id(id) }.select { |mms_id| mms_id != id }
39✔
139
    end
140
  rescue => ex
141
    Rails.logger.error "Error calculating related_bibs_iiif_manifest for #{id}: #{ex.message}"
×
142
    []
×
143
  end
144

145
  # Makes sure an ID is an Alma ID or converts it to one if it is not.
146
  def ensure_voyager_to_alma_id(id)
1✔
147
    return id if id.length > 7 && id.start_with?("99")
5✔
148
    "99#{id}3506421"
5✔
149
  end
150

151
  # Retrieve the set of documents linked to this Object using a Solr Field
152
  # @param field [String] the field for this Object which contains the foreign document keys
153
  # @param query_field [String] the field in the linked documents to use as a key
154
  # @return [LinkedDocumentResolver::LinkedDocuments]
155
  def linked_records(field:, query_field: 'id', maximum_records: Orangelight.config['show_page']['linked_documents']['maximum'])
1✔
156
    sibling_ids = clean_ids(Array.wrap(fetch(field, [])))
32✔
157
    root_id = fetch(:id)
32✔
158
    LinkedDocumentResolver::LinkedDocuments.new(siblings: sibling_ids,
32✔
159
                                                root: root_id,
160
                                                solr_field: query_field,
161
                                                maximum_records:)
162
  end
163

164
  def full_arks
1✔
165
    electronic_access_uris.select { |x| x.include?('ark:') }
×
166
  end
167

168
  # Retrieves electronic portfolio values from sibling documents
169
  # @return [Array<Hash>] array of electronic portfolio hashes
170
  def sibling_electronic_portfolios
1✔
171
    sibling_documents.flat_map(&:electronic_portfolios)
29✔
172
  end
173

174
  def solr_document_id
1✔
175
    self["id"]
1,118✔
176
  end
177

178
  def host_id
1✔
179
    self["contained_in_s"].reject(&:empty?) if self["contained_in_s"].present?
994✔
180
  end
181

182
  def bound_with?
1✔
183
    return true if host_id.present?
318✔
184
    false
302✔
185
  end
186

187
  def numismatics_record?
1✔
188
    solr_document_id&.start_with? 'coin'
392✔
189
  end
190

191
  def in_a_special_collection?
1✔
192
    holdings_1display = self['holdings_1display']
193✔
193
    return true unless holdings_1display
193✔
194

195
    JSON.parse(holdings_1display)
168✔
196
        &.values
197
        &.any? do |holding|
198
          location_code = holding['location_code']
215✔
199
          Bibdata.holding_locations.dig(location_code, 'aeon_location') if location_code
215✔
200
        end
201
  end
202

203
  # host_id an Array of host id(s)
204
  # appends the host_id in each host_holding
205
  # merges host_holding in holdings
206
  def holdings_with_host_id(holdings)
1✔
207
    host_id.each do |id|
29✔
208
      host_solr_document = doc_by_id(id)
45✔
209
      host_holdings = host_solr_document&.dig("holdings_1display")
45✔
210
      host_holdings_parse = JSON.parse(host_holdings || '{}')
45✔
211
      next if host_holdings_parse.blank? # do not merge an empty holding
45✔
212
      host_holding_id = host_holdings_parse.first[0]
30✔
213
      # append the host_id as mms_id in the host_holdings
214
      host_holdings_parse[host_holding_id]["mms_id"] = id
30✔
215

216
      holdings.merge!(host_holdings_parse)
30✔
217
    end
218
    holdings
29✔
219
  end
220

221
  # Returns the holdings_1display of the record plus the holdings_1display of the host record
222
  def holdings_all_display
1✔
223
    holdings = JSON.parse(self["holdings_1display"] || '{}')
618✔
224

225
    holdings.each do |k, _val|
618✔
226
      # append the solr document id in each holding
227
      holdings[k].merge!("mms_id" => solr_document_id) if holdings[k].present?
736✔
228
    end
229
    return holdings if host_id.blank?
618✔
230
    # Append the host_id in the host_holdings
231
    # merge the host_holdings in holdings
232
    holdings_with_host_id(holdings)
29✔
233
  end
234

235
  def physical_holding?
1✔
236
    holdings_all_display.length.positive?
164✔
237
  end
238

239
  def electronic_access?
1✔
240
    (doc_electronic_access.length + electronic_portfolios.length).positive?
164✔
241
  end
242

243
  private
1✔
244

245
    def electronic_access_uris
1✔
246
      electronic_access = first('electronic_access_1display')
×
247
      values = JSON.parse(electronic_access)
×
248
      uris = values.keys
×
249
      if values['iiif_manifest_paths']
×
250
        uris.delete('iiif_manifest_paths')
×
251
        uris += values['iiif_manifest_paths'].keys
×
252
      end
253
      uris
×
254
    rescue
255
      []
×
256
    end
257

258
    def full_ark
1✔
259
      full_arks.first
×
260
    end
261

262
    def clean_ids(id_values)
1✔
263
      out = id_values.map { |id| id.delete('#') }
168✔
264
      # Strip all non-ascii characters from ids
265
      out.map { |id| id.gsub(/[^[:ascii:]]/, "") }
168✔
266
    end
267

268
    def identifier_keys
1✔
269
      %w[
193✔
270
        isbn_s
271
        oclc_s
272
      ]
273
    end
274

275
    # Retrieves sibling documents linked by values on the other_version_s field
276
    # @return [Array<SolrDocument>] array of sibling solr documents
277
    def sibling_documents
1✔
278
      sibling_ids = clean_ids(Array.wrap(fetch('other_version_s', [])))
29✔
279
      root_id = fetch(:id)
29✔
280
      linked_documents = LinkedDocumentResolver::LinkedDocuments.new(siblings: sibling_ids,
29✔
281
                                                                     root: root_id,
282
                                                                     solr_field: 'other_version_s')
283
      linked_documents.siblings
29✔
284
    end
285

286
    def doc_by_id(id)
1✔
287
      params = { q: "id:#{RSolr.solr_escape(id)}" }
45✔
288
      solr_response = Blacklight.default_index.connection.get('select', params:)
45✔
289
      solr_response["response"]["docs"].first
45✔
290
    end
291
end
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc