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

pulibrary / orangelight / 4e01fe00-694b-47b4-8b30-2de4dc4acc66

31 Jul 2025 07:56PM UTC coverage: 92.891% (-2.5%) from 95.4%
4e01fe00-694b-47b4-8b30-2de4dc4acc66

Pull #4962

circleci

web-flow
Merge pull request #5130 from pulibrary/clean_up_scss_comments

Remove SCSS commented code.
Pull Request #4962: Orangelight pos workcycle 07-07-2025

193 of 197 new or added lines in 24 files covered. (97.97%)

161 existing lines in 35 files now uncovered.

5932 of 6386 relevant lines covered (92.89%)

1443.08 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'
2✔
3

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

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

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

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

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

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

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

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

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

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

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

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

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

79
  def identifiers
2✔
80
    @identifiers ||= identifier_keys.flat_map do |key|
1,245✔
81
      fetch(key, []).map do |value|
1,248✔
82
        SolrDocument::Identifier.new(key, value)
968✔
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
2✔
UNCOV
90
    return unless full_ark
×
UNCOV
91
    m = /.*(ark:(.*))/.match(full_ark)
×
UNCOV
92
    m[1]
×
93
  end
94

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

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

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

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

174
  def solr_document_id
2✔
175
    self["id"]
3,556✔
176
  end
177

178
  def host_id
2✔
179
    self["contained_in_s"].reject(&:empty?) if self["contained_in_s"].present?
3,211✔
180
  end
181

182
  def bound_with?
2✔
183
    return true if host_id.present?
1,072✔
184
    false
970✔
185
  end
186

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

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

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

216
      holdings.merge!(host_holdings_parse)
156✔
217
    end
218
    holdings
102✔
219
  end
220

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

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

235
  def physical_holding?
2✔
236
    holdings_all_display.length.positive?
518✔
237
  end
238

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

243
  private
2✔
244

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

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

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

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

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