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

pulibrary / orangelight / 00dbc10b-d747-4ad7-b211-7b26d753abbb

14 Aug 2025 01:25PM UTC coverage: 0.483% (-94.9%) from 95.343%
00dbc10b-d747-4ad7-b211-7b26d753abbb

push

circleci

web-flow
Merge pull request #5181 from pulibrary/dependabot/bundler/activestorage-7.2.2.2

Bump activestorage from 7.2.2.1 to 7.2.2.2

47 of 9721 relevant lines covered (0.48%)

0.01 hits per line

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

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

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

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

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

22
  field_semantics.merge!(
×
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)
×
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)
×
46

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

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

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

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

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

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

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

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

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

79
  def identifiers
×
80
    @identifiers ||= identifier_keys.flat_map do |key|
×
81
      fetch(key, []).map do |value|
×
82
        SolrDocument::Identifier.new(key, value)
×
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
×
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
×
98
    string_values = first('electronic_access_1display') || '{}'
×
99
    JSON.parse(string_values).delete_if { |k, _v| k == 'iiif_manifest_paths' }
×
100
  end
×
101

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

109
  # Parse IIIF Manifest links from the electronic access information
110
  # @return [Hash] IIIF Manifests information
111
  def iiif_manifests
×
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
×
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
×
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
×
134
    @related_bibs_iiif_manifest ||= begin
×
135
      string_values = first('electronic_access_1display') || '{}'
×
136
      values = JSON.parse(string_values)
×
137
      mms_ids = values.keys.map { |key| key[/https\:\/\/catalog.princeton.edu\/catalog\/(\d*)#view/, 1] }.compact.uniq
×
138
      mms_ids.map { |id| ensure_voyager_to_alma_id(id) }.select { |mms_id| mms_id != id }
×
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)
×
147
    return id if id.length > 7 && id.start_with?("99")
×
148
    "99#{id}3506421"
×
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'])
×
156
    sibling_ids = clean_ids(Array.wrap(fetch(field, [])))
×
157
    root_id = fetch(:id)
×
158
    LinkedDocumentResolver::LinkedDocuments.new(siblings: sibling_ids,
×
159
                                                root: root_id,
×
160
                                                solr_field: query_field,
×
161
                                                maximum_records:)
×
162
  end
×
163

164
  def full_arks
×
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
×
171
    sibling_documents.flat_map(&:electronic_portfolios)
×
172
  end
×
173

174
  def solr_document_id
×
175
    self["id"]
×
176
  end
×
177

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

182
  def bound_with?
×
183
    return true if host_id.present?
×
184
    false
×
185
  end
×
186

187
  def numismatics_record?
×
188
    solr_document_id&.start_with? 'coin'
×
189
  end
×
190

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

195
    JSON.parse(holdings_1display)
×
196
        &.values
×
197
        &.any? do |holding|
×
198
          location_code = holding['location_code']
×
199
          Bibdata.holding_locations.dig(location_code, 'aeon_location') if location_code
×
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)
×
207
    host_id.each do |id|
×
208
      host_solr_document = doc_by_id(id)
×
209
      host_holdings = host_solr_document&.dig("holdings_1display")
×
210
      host_holdings_parse = JSON.parse(host_holdings || '{}')
×
211
      next if host_holdings_parse.blank? # do not merge an empty holding
×
212
      host_holding_id = host_holdings_parse.first[0]
×
213
      # append the host_id as mms_id in the host_holdings
214
      host_holdings_parse[host_holding_id]["mms_id"] = id
×
215

216
      holdings.merge!(host_holdings_parse)
×
217
    end
×
218
    holdings
×
219
  end
×
220

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

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

235
  def physical_holding?
×
236
    holdings_all_display.length.positive?
×
237
  end
×
238

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

243
  private
×
244

245
    def electronic_access_uris
×
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
×
259
      full_arks.first
×
260
    end
×
261

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

268
    def identifier_keys
×
269
      %w[
×
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
×
278
      sibling_ids = clean_ids(Array.wrap(fetch('other_version_s', [])))
×
279
      root_id = fetch(:id)
×
280
      linked_documents = LinkedDocumentResolver::LinkedDocuments.new(siblings: sibling_ids,
×
281
                                                                     root: root_id,
×
282
                                                                     solr_field: 'other_version_s')
×
283
      linked_documents.siblings
×
284
    end
×
285

286
    def doc_by_id(id)
×
287
      params = { q: "id:#{RSolr.solr_escape(id)}" }
×
288
      solr_response = Blacklight.default_index.connection.get('select', params:)
×
289
      solr_response["response"]["docs"].first
×
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