• 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/helpers/blacklight_helper.rb
1
# frozen_string_literal: false
2

3
require 'library_stdnums'
×
4

5
module BlacklightHelper
×
6
  include Blacklight::BlacklightHelperBehavior
×
7
  require './lib/orangelight/string_functions'
×
8

9
  def json_field?(field)
×
10
    field[:hash]
×
11
  end
×
12

13
  def linked_record_field?(field)
×
14
    field[:link_field]
×
15
  end
×
16

17
  # Escape all whitespace characters within Solr queries specifying left anchor query facets
18
  # Ends all left-anchor searches with wildcards for matches that begin with search string
19
  # @param solr_parameters [Blacklight::Solr::Request] the parameters for the Solr query
20
  def prepare_left_anchor_search(solr_parameters)
×
21
    return unless left_anchor_search?(solr_parameters)
×
22
    solr_parameters.dig('json', 'query', 'bool').each_value do |value|
×
23
      value.select { |boolean_query| boolean_query_searches_left_anchored_field?(boolean_query) }.map! do |clause|
×
24
        query = escape_left_anchor_query(clause.dig(:edismax, :query).dup)
×
25
        query = add_wildcard(query)
×
26
        clause.dig(:edismax)[:query] = query
×
27
      end
×
28
    end
×
29
  end
×
30

31
  def left_anchor_search?(solr_parameters)
×
32
    return false unless solr_parameters.dig('json', 'query', 'bool')
×
33
    has_left_anchor = solr_parameters.dig('json', 'query', 'bool')
×
34
                                     .values
×
35
                                     .any? { |value| value.select { |clause| boolean_query_searches_left_anchored_field?(clause) } }
×
36
    return false unless has_left_anchor
×
37

38
    true
×
39
  end
×
40

41
  # Escape all whitespace characters within Solr queries specifying left anchor query facets
42
  def escape_left_anchor_query(query)
×
43
    query.gsub!(/(\s)/, '\\\\\1')
×
44
    query.gsub!(/(["\{\}\[\]\^\~])/, '\\\\\1')
×
45
    query.gsub!(/[\(\)]/, '')
×
46
    query
×
47
  end
×
48

49
  # Ends all left-anchor searches with wildcards for matches that begin with search string
50
  def add_wildcard(query)
×
51
    query.end_with?('*') ? query : query + '*'
×
52
  end
×
53

54
  def pul_holdings(solr_parameters)
×
55
    return unless blacklight_params[:f_inclusive] && blacklight_params[:f_inclusive][:advanced_location_s]&.include?('pul')
×
56
    solr_parameters[:fq].map! { |fq| fq.gsub '"pul"', '*' }
×
57
                        .reject! { |fq| fq == '{!term f=advanced_location_s}pul' }
×
58
    solr_parameters[:fq] << '-id:SCSB*'
×
59
  end
×
60

61
  def series_title_results(solr_parameters)
×
62
    return unless includes_series_search?
×
63
    solr_parameters[:fl] = 'id,score,author_display,marc_relator_display,format,pub_created_display,'\
×
64
                           'title_display,title_vern_display,isbn_s,oclc_s,lccn_s,holdings_1display,'\
×
65
                           'electronic_access_1display,electronic_portfolio_s,cataloged_tdt,series_display'
×
66
  end
×
67

68
  def includes_series_search?
×
69
    blacklight_params['clause'].map { |clause| clause[1]["field"] }.include?('series_title' || 'in_series') if blacklight_params['clause'].present?
×
70
  end
×
71

72
  # only fetch facets when an html page is requested
73
  def html_facets(solr_parameters)
×
74
    return if blacklight_params[:format].nil? || blacklight_params[:format] == 'html' ||
×
75
              blacklight_params[:format] == 'json'
×
76
    solr_parameters[:facet] = false
×
77
  end
×
78

79
  # Adapted from http://discovery-grindstone.blogspot.com/2014/01/cjk-with-solr-for-libraries-part-12.html
80
  def cjk_mm(solr_parameters)
×
81
    if blacklight_params && blacklight_params[:q].present?
×
82
      q_str = blacklight_params[:q]
×
83
      number_of_unigrams = cjk_unigrams_size(q_str)
×
84
      if number_of_unigrams > 2
×
85
        num_non_cjk_tokens = q_str.scan(/[[:alnum]]+/).size
×
86
        if num_non_cjk_tokens.positive?
×
87
          lower_limit = cjk_mm_val[0].to_i
×
88
          mm = (lower_limit + num_non_cjk_tokens).to_s + cjk_mm_val[1, cjk_mm_val.size]
×
89
          solr_parameters['mm'] = mm
×
90
        else
×
91
          solr_parameters['mm'] = cjk_mm_val
×
92
        end
×
93
      end
×
94
    end
×
95
  end
×
96

97
  def cjk_unigrams_size(str)
×
98
    if str&.is_a?(String)
×
99
      str.scan(/\p{Han}|\p{Katakana}|\p{Hiragana}|\p{Hangul}/).size
×
100
    else
×
101
      0
×
102
    end
×
103
  end
×
104

105
  def cjk_mm_val
×
106
    '3<86%'
×
107
  end
×
108

109
  def browse_related_name_hash(name)
×
110
    link_to(name, "/?f[author_s][]=#{CGI.escape name}", class: 'search-related-name', 'data-original-title' => "Search: #{name}") + '  ' +
×
111
      link_to('[Browse]', "/browse/names?q=#{CGI.escape name}", class: 'browse-related-name', 'data-original-title' => "Search: #{name}")
×
112
  end
×
113

114
  # render_document_heading from Blacklight v7.23.0.1
115
  # https://github.com/projectblacklight/blacklight/blob/242880eacb1c73a2a6a3d7cdf4e24cec151179f8/app/helpers/blacklight/blacklight_helper_behavior.rb#L245
116
  def render_document_heading(*args)
×
117
    options = args.extract_options!
×
118
    document = args.first
×
119
    tag = options.fetch(:tag, :h4)
×
120
    document ||= @document
×
121
    content_tag(tag, document_presenter(document).heading, itemprop: "name", lang: language_iana)
×
122
  end
×
123

124
  ##
125
  # Render the heading partial for a document
126
  #
127
  # @param [SolrDocument]
128
  # @return [String]
129
  def render_document_heading_partial(_document = @document)
×
130
    render partial: 'show_header_default'
×
131
  end
×
132

133
  # Generates markup for a <span> elements containing icons given a string value
134
  # @param value [String] value used for the CSS class
135
  # @return [String] markup for the <span> element
136
  def render_icon(var)
×
137
    "<span class='icon icon-#{var.parameterize}' aria-hidden='true'></span>".html_safe
×
138
  end
×
139

140
  # Generate the link to "start over" searches
141
  # @param path [String] the URL path for the link
142
  # @return [String] the markup for the link
143
  def render_start_over_link(path)
×
144
    child = "<span class=\"icon-refresh\" aria-hidden=\"true\"></span> <span>#{t('blacklight.search.start_over')}</span>"
×
145
    link_to(child.html_safe, path, class: 'catalog_startOverLink btn btn-primary', id: 'startOverLink')
×
146
  end
×
147

148
  # Generate the link to citations for Documents
149
  # @param path [String] the URL path for the link
150
  # @return [String] the markup for the link
151
  def render_cite_link(path)
×
152
    child = "<span class=\"icon-cite\" aria-hidden=\"true\"></span> #{t('blacklight.search.cite')}"
×
153
    link_to(child.html_safe, path, id: 'citeLink', data: { blacklight_modal: 'trigger' }, class: 'btn btn-default')
×
154
  end
×
155

156
  # Retrieve an instance of the FacetedQueryService
157
  # @return [FacetedQueryService] an instance of the service object
158
  def faceted_query_service
×
159
    @faceted_query_service ||= FacetedQueryService.new(Blacklight)
×
160
  end
×
161

162
  def oclc_resolve(oclc)
×
163
    oclc_norm = StringFunctions.oclc_normalize(oclc)
×
164
    unless oclc_norm.nil?
×
165
      fq = "oclc_s:#{oclc_norm}"
×
166
      resp = faceted_query_service.get_fq_solr_response(fq)
×
167
      req = JSON.parse(resp.body)
×
168
    end
×
169
    if oclc_norm.to_i.zero? || req['response']['docs'].empty?
×
170
      "/catalog?q=#{oclc}"
×
171
    else
×
172
      "/catalog/#{req['response']['docs'].first['id']}"
×
173
    end
×
174
  end
×
175

176
  def isbn_resolve(isbn)
×
177
    isbn_norm = StdNum::ISBN.normalize(isbn)
×
178
    unless isbn_norm.nil?
×
179
      fq = "isbn_s:#{isbn_norm}"
×
180
      resp = faceted_query_service.get_fq_solr_response(fq)
×
181
      req = JSON.parse(resp.body)
×
182
    end
×
183
    if isbn_norm.nil? || req['response']['docs'].empty?
×
184
      "/catalog?q=#{isbn}"
×
185
    else
×
186
      "/catalog/#{req['response']['docs'].first['id']}"
×
187
    end
×
188
  end
×
189

190
  def issn_resolve(issn)
×
191
    issn_norm = StdNum::ISSN.normalize(issn)
×
192
    unless issn_norm.nil?
×
193
      fq = "issn_s:#{issn_norm}"
×
194
      resp = faceted_query_service.get_fq_solr_response(fq)
×
195
      req = JSON.parse(resp.body)
×
196
    end
×
197
    if issn_norm.nil? || req['response']['docs'].empty?
×
198
      "/catalog?q=#{issn}"
×
199
    else
×
200
      "/catalog/#{req['response']['docs'].first['id']}"
×
201
    end
×
202
  end
×
203

204
  def lccn_resolve(lccn)
×
205
    lccn_norm = StdNum::LCCN.normalize(lccn)
×
206
    unless lccn_norm.nil?
×
207
      fq = "lccn_s:#{lccn_norm}"
×
208
      resp = faceted_query_service.get_fq_solr_response(fq)
×
209
      req = JSON.parse(resp.body)
×
210
    end
×
211
    if lccn_norm.nil? || req['response']['docs'].empty?
×
212
      "/catalog?q=#{lccn}"
×
213
    else
×
214
      "/catalog/#{req['response']['docs'].first['id']}"
×
215
    end
×
216
  end
×
217

218
  # Links to correct advanced search page based on advanced_type parameter value
219
  def edit_search_link
×
220
    url = advanced_path(params.permit!.except(:controller, :action).to_h)
×
221
    if params[:advanced_type] == 'numismatics'
×
222
      url.gsub('/advanced', '/numismatics')
×
223
    else
×
224
      url
×
225
    end
×
226
  end
×
227

228
  def link_back_to_catalog_safe(opts = { label: nil })
×
229
    link_back_to_catalog(opts)
×
230
  rescue ActionController::UrlGenerationError
×
231
    # This exception is triggered if the user's session has information that results in an
232
    # invalid back to catalog link. In that case, rather than blowing up on the user, we
233
    # render a valid link. This link does not preserve the user's previous setings and that is
234
    # OK because very likely their session is corrupted.
235
    link_to "Back to search", root_url
×
236
  end
×
237

238
    private
×
239

240
      def boolean_query_searches_left_anchored_field?(boolean_query)
×
241
        ["${left_anchor_qf}", "${in_series_qf}"].include? boolean_query.dig(:edismax, :qf)
×
242
      end
×
243
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