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

pulibrary / pdc_discovery / 5c8f78ec-7ed2-40cf-b5a0-80a009270825

17 Jun 2026 07:04PM UTC coverage: 78.246% (-18.2%) from 96.464%
5c8f78ec-7ed2-40cf-b5a0-80a009270825

Pull #951

circleci

leefaisonr
Additional work for withdrawn works landing page
Co-authored-by: Carolyn Cole <carolyncole@users.noreply.github.com>
Pull Request #951: adding withdrawn json with updated metadata

2 of 4 new or added lines in 2 files covered. (50.0%)

150 existing lines in 5 files now uncovered.

2435 of 3112 relevant lines covered (78.25%)

4.82 hits per line

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

86.39
/app/controllers/catalog_controller.rb
1
# frozen_string_literal: true
2

3
class CatalogController < ApplicationController
1✔
4
  include Blacklight::Catalog
1✔
5
  include Blacklight::Configurable
1✔
6
  include Blacklight::SearchContext
1✔
7
  include BlacklightRangeLimit::ControllerOverride
1✔
8

9
  include Blacklight::Marc::Catalog
1✔
10

11
  around_action :retry_on_exception
1✔
12

13
  rescue_from Blacklight::Exceptions::RecordNotFound do
1✔
14
    error_page = Rails.env.production? || Rails.env.staging? ? '/discovery/errors/not_found' : '/errors/not_found'
×
15
    redirect_to error_page
×
16
  end
17

18
  def retry_on_exception
1✔
19
    yield
13✔
20
  rescue BlacklightRangeLimit::InvalidRange
21
    # This error is usually the result of a bot request and therefore we don't send it to Honeybadger,
22
    # but we log it just in case.
23
    Rails.logger.warn("Invalid Range Limit, params: #{params}")
×
24
    error_page = Rails.env.production? || Rails.env.staging? ? '/discovery/errors/range_limit_error' : '/errors/range_limit_error'
×
25
    redirect_to error_page
×
26
  rescue Blacklight::Exceptions::ECONNREFUSED, RSolr::Error::ConnectionRefused
27
    # If the Solr service is available, retry the HTTP request
28
    if search_service.repository.ping
2✔
29
      retry
×
30
    else
31
      error_page = Rails.env.production? || Rails.env.staging? ? '/discovery/errors/network_error' : '/errors/network_error'
2✔
32
      redirect_to error_page
2✔
33
    end
34
  end
35

36
  configure_blacklight do |config|
1✔
37
    ## Class for sending and receiving requests from a search index
38
    # config.repository_class = Blacklight::Solr::Repository
39
    #
40
    ## Class for converting Blacklight's url parameters to into request parameters for the search index
41
    # config.search_builder_class = ::SearchBuilder
42
    #
43
    ## Model that maps search index responses to the blacklight response model
44
    # config.response_model = Blacklight::Solr::Response
45
    #
46
    ## Should the raw solr document endpoint (e.g. /catalog/:id/raw) be enabled
47
    config.raw_endpoint.enabled = true
1✔
48

49
    ## Default parameters to send to solr for all search-like requests. See also SearchBuilder#processed_parameters
50
    config.default_solr_params = {
1✔
51
      rows: 10
52
    }
53

54
    # solr path which will be added to solr base url before the other solr params.
55
    # config.solr_path = 'select'
56
    # config.document_solr_path = 'get'
57

58
    # items to show per page, each number in the array represent another option to choose from.
59
    # config.per_page = [10,20,50,100]
60

61
    # solr field configuration for search results/index views
62
    config.index.title_field = 'title_tesim'
1✔
63
    # config.index.display_type_field = 'format'
64
    # config.index.thumbnail_field = 'thumbnail_path_ss'
65

66
    config.add_results_document_tool(:bookmark, partial: 'bookmark_control', if: :render_bookmarks_control?)
1✔
67

68
    config.add_results_collection_tool(:sort_widget)
1✔
69
    config.add_results_collection_tool(:per_page_widget)
1✔
70
    config.add_results_collection_tool(:view_type_group)
1✔
71

72
    config.add_show_tools_partial(:bookmark, partial: 'bookmark_control', if: :render_bookmarks_control?)
1✔
73
    config.add_show_tools_partial(:email, callback: :email_action, validator: :validate_email_params)
1✔
74
    config.add_show_tools_partial(:sms, if: :render_sms_action?, callback: :sms_action, validator: :validate_sms_params)
1✔
75
    config.add_show_tools_partial(:citation)
1✔
76

77
    config.add_nav_action(:bookmark, partial: 'blacklight/nav/bookmark', if: :render_bookmarks_control?)
1✔
78
    config.add_nav_action(:search_history, partial: 'blacklight/nav/search_history')
1✔
79

80
    # solr field configuration for document/show views
81
    # config.show.display_type_field = 'format'
82
    # config.show.thumbnail_field = 'thumbnail_path_ss'
83

84
    # solr fields that will be treated as facets by the blacklight application
85
    #   The ordering of the field names is the order of the display
86
    #
87
    # Setting a limit will trigger Blacklight's 'more' facet values link.
88
    # * If left unset, then all facet values returned by solr will be displayed.
89
    # * If set to an integer, then "f.somefield.facet.limit" will be added to
90
    # solr request, with actual solr request being +1 your configured limit --
91
    # you configure the number of items you actually want _displayed_ in a page.
92
    # * If set to 'true', then no additional parameters will be sent to solr,
93
    # but any 'sniffed' request limit parameters will be used for paging, with
94
    # paging at requested limit -1. Can sniff from facet.limit or
95
    # f.specific_field.facet.limit solr request params. This 'true' config
96
    # can be used if you set limits in :default_solr_params, or as defaults
97
    # on the solr side in the request handler itself. Request handler defaults
98
    # sniffing requires solr requests to be made with "echoParams=all", for
99
    # app code to actually have it echo'd back to see it.
100
    #
101
    # :show may be set to false if you don't want the facet to be drawn in the
102
    # facet bar
103
    #
104
    # set :index_range to true if you want the facet pagination view to have facet prefix-based navigation
105
    #  (useful when user clicks "more" on a large facet and wants to navigate alphabetically across a large set of results)
106
    # :index_range can be an array or range of prefixes that will be used to create the navigation (note: It is case sensitive when searching values)
107

108
    # config.add_facet_field 'example_pivot_field', label: 'Pivot Field', pivot: %w[format language_ssim], collapsing: true
109

110
    # config.add_facet_field 'example_query_facet_field', label: 'Publish Date', query: {
111
    #   years_5: { label: 'within 5 Years', fq: "pub_date_ssim:[#{Time.zone.now.year - 5} TO *]" },
112
    #   years_10: { label: 'within 10 Years', fq: "pub_date_ssim:[#{Time.zone.now.year - 10} TO *]" },
113
    #   years_25: { label: 'within 25 Years', fq: "pub_date_ssim:[#{Time.zone.now.year - 25} TO *]" }
114
    # }
115

116
    # TODO: When we upgrade to Blacklight 8
117
    #  We can remove the `component: Blacklight::FacetFieldListComponent` from the `add_facet_field` lines
118
    #  It is only present to remove a deprecation warning in Blacklight 7 that ironically is not needed for Blacklight 8
119
    #
120
    config.add_facet_field 'domain_ssim', label: 'Domain', limit: 5, component: Blacklight::FacetFieldListComponent
1✔
121
    config.add_facet_field 'communities_ssim', label: 'Community', limit: 5, component: Blacklight::FacetFieldListComponent
1✔
122
    config.add_facet_field 'subcommunities_ssim', label: 'Subcommunity', limit: 5, component: Blacklight::FacetFieldListComponent
1✔
123

124
    config.add_facet_field 'collection_tag_ssim', label: 'Collection Tags', limit: 5, component: Blacklight::FacetFieldListComponent
1✔
125
    config.add_facet_field 'authors_affiliation_ssim', label: 'Affiliation', limit: 5, component: Blacklight::FacetFieldListComponent
1✔
126

127
    config.add_facet_field 'genre_ssim', label: 'Type', limit: 5, component: Blacklight::FacetFieldListComponent
1✔
128
    config.add_facet_field 'year_available_itsi', label: 'Year Published', range: true
1✔
129

130
    # Notice that is facet is not shown. Yet facet searches by this field do work
131
    # and we use them when users click on the "Keywords" links in the Show page.
132
    config.add_facet_field 'subject_all_ssim', label: 'Keywords', show: false
1✔
133

134
    # Have BL send all facet field names to Solr, which has been the default
135
    # previously. Simply remove these lines if you'd rather use Solr request
136
    # handler defaults, or have no facets.
137
    config.add_facet_fields_to_solr_request!
1✔
138

139
    # solr fields to be displayed in the index (search results) view
140
    #   The ordering of the field names is the order of the display
141

142
    # Notice that for the author field we key of the `author_tesim` field but in reality
143
    # we render a different value (see the helper). We use `author_tesim` in here because
144
    # that is a common field between all our records, the ones coming from DataSpace
145
    # and the ones coming from PDC Describe.
146
    config.add_index_field 'author_tesim', label: 'Author(s)', helper_method: :authors_search_results_helper
1✔
147

148
    config.add_index_field 'format', label: 'Format'
1✔
149
    config.add_index_field 'abstract_tsim', label: 'Abstract'
1✔
150
    config.add_index_field 'published_ssim', label: 'Published'
1✔
151
    config.add_index_field 'published_vern_ssim', label: 'Published'
1✔
152
    config.add_index_field 'genre_ssim', label: 'Type'
1✔
153
    config.add_index_field 'issue_date_ssim', label: 'Issue Date'
1✔
154
    config.add_index_field 'version_number_ssi', label: 'Version'
1✔
155

156
    # solr fields to be displayed in the show (single result) view
157
    #   The ordering of the field names is the order of the display
158
    config.add_show_field 'author_tesim', label: 'Author'
1✔
159
    config.add_show_field 'format', label: 'Format'
1✔
160
    config.add_show_field 'url_fulltext_ssim', label: 'URL'
1✔
161
    config.add_show_field 'url_suppl_ssim', label: 'More Information'
1✔
162
    config.add_show_field 'language_ssim', label: 'Language'
1✔
163
    config.add_show_field 'published_ssim', label: 'Published'
1✔
164
    config.add_show_field 'published_vern_ssim', label: 'Published'
1✔
165
    config.add_show_field 'lc_callnum_ssim', label: 'Call number'
1✔
166
    config.add_show_field 'isbn_ssim', label: 'ISBN'
1✔
167
    config.add_show_field 'handle_ssim', label: 'Handle'
1✔
168

169
    config.add_show_field 'abstract_tsim', label: 'Abstract'
1✔
170
    config.add_show_field 'contributor_tsim', label: 'Author'
1✔
171
    config.add_show_field 'description_tsim', label: 'Description'
1✔
172
    config.add_show_field 'issue_date_ssim', label: 'Issued Date'
1✔
173
    config.add_show_field 'methods_tsim', label: 'Methods'
1✔
174

175
    # "fielded" search configuration. Used by pulldown among other places.
176
    # For supported keys in hash, see rdoc for Blacklight::SearchFields
177
    #
178
    # Search fields will inherit the :qt solr request handler from
179
    # config[:default_solr_parameters], OR can specify a different one
180
    # with a :qt key/value. Below examples inherit, except for subject
181
    # that specifies the same :qt as default for our own internal
182
    # testing purposes.
183
    #
184
    # The :key is what will be used to identify this BL search field internally,
185
    # as well as in URLs -- so changing it after deployment may break bookmarked
186
    # urls.  A display label will be automatically calculated from the :key,
187
    # or can be specified manually to be different.
188

189
    # This one uses all the defaults set by the solr request handler. Which
190
    # solr request handler? The one set in config[:default_solr_parameters][:qt],
191
    # since we aren't specifying it otherwise.
192

193
    config.add_search_field 'all_fields', label: 'All Fields'
1✔
194

195
    # Now we see how to over-ride Solr request handler defaults, in this
196
    # case for a BL "search field", which is really a dismax aggregate
197
    # of Solr search fields.
198

199
    config.add_search_field('title') do |field|
1✔
200
      # solr_parameters hash are sent to Solr as ordinary url query params.
201
      field.solr_parameters = {
1✔
202
        'spellcheck.dictionary': 'title',
203
        qf: '${title_qf}',
204
        pf: '${title_pf}'
205
      }
206
    end
207

208
    config.add_search_field('author') do |field|
1✔
209
      field.solr_parameters = {
1✔
210
        'spellcheck.dictionary': 'author',
211
        qf: '${author_qf}',
212
        pf: '${author_pf}'
213
      }
214
    end
215

216
    config.add_search_field('orcid') do |field|
1✔
217
      field.label = "ORCID"
1✔
218
      field.solr_parameters = {
1✔
219
        qf: 'authors_orcid_ssim',
220
        pf: 'authors_orcid_ssim'
221
      }
222
    end
223

224
    # Specifying a :qt only to show it's possible, and so our internal automated
225
    # tests can test it. In this case it's the same as
226
    # config[:default_solr_parameters][:qt], so isn't actually neccesary.
227
    config.add_search_field('subject') do |field|
1✔
228
      field.qt = 'search'
1✔
229
      field.solr_parameters = {
1✔
230
        'spellcheck.dictionary': 'subject',
231
        qf: '${subject_qf}',
232
        pf: '${subject_pf}'
233
      }
234
    end
235

236
    # "sort results by" select (pulldown)
237
    # label in pulldown is followed by the name of the Solr field to sort by and
238
    # whether the sort is ascending or descending (it must be asc or desc
239
    # except in the relevancy case). Add the sort: option to configure a
240
    # custom Blacklight url parameter value separate from the Solr sort fields.
241
    config.add_sort_field 'relevance', sort: 'score desc, issue_date_strict_ssi desc, title_si asc', label: 'relevance'
1✔
242
    config.add_sort_field 'year', sort: 'issue_date_strict_ssi desc, title_si asc', label: 'year'
1✔
243
    config.add_sort_field 'author', sort: 'author_si asc, title_si asc', label: 'author'
1✔
244
    config.add_sort_field 'title', sort: 'title_si asc, issue_date_strict_ssi desc', label: 'title'
1✔
245

246
    # If there are more than this many search results, no spelling ("did you
247
    # mean") suggestion is offered.
248
    config.spell_max = 5
1✔
249

250
    # # Configuration for autocomplete suggester
251
    # config.autocomplete_enabled = true
252
    # config.autocomplete_path = 'suggest'
253
    # # if the name of the solr.SuggestComponent provided in your solrconfig.xml is not the
254
    # # default 'mySuggester', uncomment and provide it below
255
    # # config.autocomplete_suggester = 'mySuggester'
256
    config.search_state_fields = config.search_state_fields + [
1✔
257
      :doi, :ark, :id,
258
      :a # this is in the search parameters becuase the search bar is shown on the error page
259
    ]
260

261
    # Sets up Blacklight crawler detection
262
    config.crawler_detector = lambda { |request|
1✔
263
      return true if request.env['HTTP_USER_AGENT'].blank?
5✔
264
      request.bot?
×
265
    }
266
  end
267

268
  def show
1✔
269
    @render_links = !agent_is_crawler?
5✔
270
    super
5✔
271
    if params["format"] == "json"
3✔
272
      render json: DocumentExport.new(@document)
1✔
273
    else
274
      case @document["state_ssi"]
2✔
275
      when "approved"
NEW
276
        render :show
×
277
      when "draft"
278
        render :show_draft
×
279
      when "withdrawn"
280
        render :show_withdrawn
×
281
      else
282
        render :show_blank
2✔
283
      end
284
    end
285
  end
286

287
  # This endpoint is used to feed the AJAX call on the Show page for the file list and
288
  # therefore the return JSON must be something that DataTables can use.
289
  def file_list
1✔
290
    document = solr_find(params["id"])
×
291
    file_list = { data: document.files }
×
292

293
    render json: file_list.to_json
×
294
  end
295

296
  # Returns the raw BibTex citation information
297
  def bibtex
1✔
298
    @document = search_service.fetch(params[:id])
1✔
299
    citation = @document.cite("BibTeX")
1✔
300
    send_data citation, filename: "#{@document.bibtex_id}.bibtex", type: 'text/plain', disposition: 'attachment'
1✔
301
  end
302

303
  def resolve_doi
1✔
304
    raise Blacklight::Exceptions::RecordNotFound unless params.key?(:doi)
1✔
305

306
    doi_query = params[:doi]
1✔
307
    query = { q: "uri_ssim:*\"#{doi_query}\"" }
1✔
308

309
    solr_response = search_service.repository.search(**query)
1✔
310
    documents = solr_response.documents
1✔
311

312
    raise Blacklight::Exceptions::RecordNotFound if documents.empty?
1✔
313
    preferred = documents.select { |d| d.data_source == 'pdc_discovery' }
2✔
314
    document = if preferred.empty?
1✔
315
                 documents.first
1✔
316
               else
317
                 preferred.first
×
318
               end
319

320
    redirect_to(solr_document_path(id: document.id))
1✔
321
  end
322

323
  def resolve_ark
1✔
324
    raise Blacklight::Exceptions::RecordNotFound unless params.key?(:ark)
1✔
325

326
    ark = params[:ark]
1✔
327
    ark_query = "uri_ssim:*\"#{ark}\""
1✔
328
    query = { q: ark_query }
1✔
329

330
    solr_response = search_service.repository.search(**query)
1✔
331
    documents = solr_response.documents
1✔
332

333
    raise Blacklight::Exceptions::RecordNotFound if documents.empty?
1✔
334
    document = documents.first
1✔
335

336
    redirect_to(solr_document_path(id: document.id))
1✔
337
  end
338

339
  # Create an endpoint for PPPL / OSTI harvesting that provides full datacite records
340
  def pppl_reporting_feed
1✔
341
    # Limit to items from PPPL
342
    lucene_queries = ['data_source_ssi:pdc_describe', 'group_code_ssi:"PPPL"']
5✔
343
    lucene_expr = lucene_queries.join(" ")
5✔
344
    page = params["page"] || "1"
5✔
345
    per_page = params["per_page"] || "10"
5✔
346
    start = per_page.to_i * (page.to_i - 1)
5✔
347

348
    query_sort = 'internal_id_lsi desc'
5✔
349
    query_fl = 'pdc_describe_json_ss'
5✔
350
    query_format = 'json'
5✔
351
    query = {
352
      q: lucene_expr,
5✔
353
      fl: query_fl,
354
      format: query_format,
355
      sort: query_sort,
356
      rows: per_page,
357
      start: start
358
    }
359

360
    solr_response = search_service.repository.search(**query)
5✔
361

362
    @documents = solr_response.documents
5✔
363
    respond_to do |format|
5✔
364
      format.json { render json: @documents }
10✔
365
    end
366
  end
367

368
  private
1✔
369

370
  def solr_find(id)
1✔
371
    solr_url = Blacklight.default_configuration.connection_config[:url]
×
372
    solr = RSolr.connect(url: solr_url)
×
373
    solr_params = { q: "id:#{id}", fl: '*' }
×
374
    response = solr.get('select', params: solr_params)
×
375
    solr_doc = response["response"]["docs"][0]
×
376
    SolrDocument.new(solr_doc)
×
377
  end
378
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

© 2026 Coveralls, Inc