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

pulibrary / bibdata / 1dcebae2-3318-4e77-bc53-82276e293354

02 May 2025 04:45PM UTC coverage: 28.256% (-63.9%) from 92.189%
1dcebae2-3318-4e77-bc53-82276e293354

push

circleci

sandbergja
Add basic infrastructure for compiling rust code

* Add a rake compile task to compile
* Run the rake task in CI
* Run the rake task before rspec tests with the rust tag, to provide quick feedback on rust changes in TDD cycles

2 of 7 new or added lines in 2 files covered. (28.57%)

2467 existing lines in 97 files now uncovered.

1089 of 3854 relevant lines covered (28.26%)

0.29 hits per line

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

20.51
/app/controllers/bibliographic_controller.rb
1
class BibliographicController < ApplicationController
1✔
2
  include FormattingConcern
1✔
3

4
  def adapter
1✔
UNCOV
5
    @adapter ||= AlmaAdapter.new
×
6
  end
7

8
  def index
1✔
UNCOV
9
    if params[:bib_id]
×
UNCOV
10
      if params.fetch(:holdings_only, '0') == '1'
×
UNCOV
11
        redirect_to action: :bib_holdings, bib_id: sanitized_bibid, status: :moved_permanently
×
UNCOV
12
      elsif params.fetch(:items_only, '0') == '1'
×
UNCOV
13
        redirect_to action: :bib_items, bib_id: sanitized_bibid, status: :moved_permanently
×
14
      else
UNCOV
15
        redirect_to action: :bib, bib_id: sanitized_bibid, status: :moved_permanently
×
16
      end
17
    else
UNCOV
18
      render plain: 'Record please supply a bib id', status: :not_found
×
19
    end
20
  end
21

22
  # Returns availability for a single ID
23
  # Client: This endpoint is used by orangelight to render status on the catalog
24
  #   show page
25
  def availability
1✔
UNCOV
26
    id = params[:bib_id]
×
UNCOV
27
    availability = adapter.get_availability_one(id:, deep_check: (params[:deep] == 'true'))
×
UNCOV
28
    respond_to do |wants|
×
UNCOV
29
      wants.json { render json: availability }
×
30
    end
31
  rescue StandardError => e
UNCOV
32
    handle_alma_exception(exception: e, message: "Failed to retrieve availability for ID: #{id}")
×
33
  end
34

35
  # Returns availability for multiple IDs
36
  # Client: This endpoint is used by orangelight to render status on the catalog
37
  #   search results page
38
  def availability_many
1✔
UNCOV
39
    ids = (params[:bib_ids] || '').split(',')
×
UNCOV
40
    availability = adapter.get_availability_many(ids:, deep_check: ActiveModel::Type::Boolean.new.cast(params[:deep]))
×
UNCOV
41
    respond_to do |wants|
×
UNCOV
42
      wants.json { render json: availability }
×
43
    end
44
  rescue StandardError => e
UNCOV
45
    handle_alma_exception(exception: e, message: "Failed to retrieve availability for IDs: #{ids}")
×
46
  end
47

48
  # Returns availability for a single holding in a bib record
49
  # Client: This endpoint is used by Requests to populate a request form and
50
  #   submit requests to the ILS
51
  def availability_holding
1✔
UNCOV
52
    if params[:bib_id] && params[:holding_id]
×
UNCOV
53
      availability = adapter.get_availability_holding(id: params[:bib_id], holding_id: params[:holding_id])
×
UNCOV
54
      respond_to do |wants|
×
UNCOV
55
        wants.json { render json: availability, status: availability.nil? ? 404 : 200 }
×
56
      end
57
    else
58
      render plain: 'Please supply a bib id and a holding id', status: :not_found
×
59
    end
60
  rescue StandardError => e
UNCOV
61
    handle_alma_exception(exception: e, message: "Failed to retrieve holdings for: #{params[:bib_id]}/#{params[:holding_id]}")
×
62
  end
63

64
  # Client: This endpoint is used by orangelight to present the staff view
65
  #   and sometimes by individuals to pull records from the ILS
66
  def bib
1✔
67
    opts = {
UNCOV
68
      holdings: params.fetch('holdings', 'true') == 'true',
×
69
      holdings_in_bib: params.fetch('holdings_in_bib', 'true') == 'true'
70
    }
71

72
    begin
UNCOV
73
      records = adapter.get_bib_record(sanitized_bibid)
×
UNCOV
74
      records.strip_non_numeric! unless opts[:holdings]
×
75
    rescue StandardError => e
UNCOV
76
      return handle_alma_exception(exception: e, message: "Failed to retrieve the record using the bib. ID: #{sanitized_bibid}")
×
77
    end
78

UNCOV
79
    if records.nil?
×
80
      render plain: "Record #{params[:bib_id]} not found or suppressed", status: :not_found
×
81
      Rails.logger.error "Record #{params[:bib_id]} not found or suppressed"
×
82
    else
UNCOV
83
      respond_to do |wants|
×
UNCOV
84
        wants.json  do
×
85
          json = MultiJson.dump(pass_records_through_xml_parser(records))
×
86
          render json:
×
87
        end
UNCOV
88
        wants.xml do
×
UNCOV
89
          xml = records_to_xml_string(records)
×
UNCOV
90
          render xml:
×
91
        end
92
      end
93
    end
94
  end
95

96
  # Client: Used by firestone_locator to pull bibliographic data
97
  #   Also used to pull orangelight and pul_solr test fixtures
98
  def bib_solr
1✔
99
    opts = {
UNCOV
100
      holdings: params.fetch('holdings', 'true') == 'true',
×
101
      holdings_in_bib: params.fetch('holdings_in_bib', 'true') == 'true'
102
    }
UNCOV
103
    records = adapter.get_bib_record(sanitized_bibid)
×
104
    if records.nil?
×
105
      render plain: "Record #{params[:bib_id]} not found or suppressed", status: :not_found
×
106
    else
107
      solr_doc = indexer.map_record(records)
×
108
      render json: solr_doc
×
109
    end
110
  rescue StandardError => e
111
    handle_alma_exception(exception: e, message: "Failed to retrieve the holding records for the bib. ID: #{sanitized_bibid}")
×
112
  end
113

114
  # Client: No known use cases
115
  def bib_holdings
1✔
UNCOV
116
    records = adapter.get_holding_records(sanitized_bibid)
×
UNCOV
117
    if records.empty?
×
118
      render plain: "Record #{params[:bib_id]} not found or suppressed", status: :not_found
×
119
    else
UNCOV
120
      respond_to do |wants|
×
UNCOV
121
        wants.json  do
×
122
          json = MultiJson.dump(pass_records_through_xml_parser(records))
×
123
          render json:
×
124
        end
UNCOV
125
        wants.xml do
×
UNCOV
126
          xml = records_to_xml_string(records)
×
UNCOV
127
          render xml:
×
128
        end
129
      end
130
    end
131
  rescue StandardError => e
UNCOV
132
    handle_alma_exception(exception: e, message: "Failed to retrieve the holding records for the bib. ID: #{sanitized_bibid}")
×
133
  end
134

135
  # bibliographic/:bib_id/items
136
  # Client: Used by figgy to check CDL status. Used by firestone_locator for
137
  #   call number and location data
138
  def bib_items
1✔
UNCOV
139
    item_keys = %w[id pid perm_location temp_location]
×
UNCOV
140
    holding_summary = adapter.get_items_for_bib(sanitized_bibid).holding_summary(item_key_filter: item_keys)
×
141

UNCOV
142
    respond_to do |wants|
×
UNCOV
143
      wants.json  { render json: MultiJson.dump(add_locator_call_no(holding_summary)) }
×
UNCOV
144
      wants.xml { render xml: '<todo but="You probably want JSON anyway" />' }
×
145
    end
146
  rescue Alma::BibItemSet::ResponseError
UNCOV
147
    render_not_found(params[:bib_id])
×
148
  rescue StandardError => e
149
    handle_alma_exception(exception: e, message: "Failed to retrieve items for bib ID: #{sanitized_bibid}")
×
150
  end
151

152
  private
1✔
153

154
    def render_not_found(id)
1✔
UNCOV
155
      render plain: "Record #{id} not found or suppressed", status: :not_found
×
156
    end
157

158
    # Ensure that the client is authenticated and the user is a catalog administrator
159
    def protect
1✔
160
      if user_signed_in?
×
161
        render plain: 'You are unauthorized', status: :forbidden if !current_user.catalog_admin?
×
162
      else
163
        redirect_to user_cas_omniauth_authorize_path
×
164
      end
165
    end
166

167
    # Generate the options for retrieving bib. records from Voyager
168
    # @return [Hash]
169
    def voyager_opts
1✔
170
      {
171
        holdings: params.fetch('holdings', 'true') == 'true',
×
172
        holdings_in_bib: params.fetch('holdings_in_bib', 'true') == 'true'
173
      }
174
    end
175

176
    # Access the URL helpers for the application
177
    # @return [Array<ActionDispatch::Routing::RouteSet::NamedRouteCollection::UrlHelper>]
178
    def url_helpers
1✔
179
      Rails.application.routes.url_helpers
×
180
    end
181

182
    # Access the global Traject Object
183
    # @return [Traject::Indexer::MarcIndexer] the Traject indexer
184
    def indexer
1✔
185
      TRAJECT_INDEXER
×
186
    end
187

188
    # Generate the URL for the application root
189
    # @return [String] the root URL
190
    def root_url
1✔
191
      url_helpers.root_url(host: request.host_with_port)
×
192
    end
193

194
    # Generates the URL for the bibliographic record
195
    # @return [String] the URL
196
    def bib_id_url
1✔
197
      url_helpers.show_bib_url(params[:bib_id], host: request.host_with_port)
×
198
    end
199

200
    # Sanitizes the bib_id HTTP parameter
201
    # @return [String]
202
    def sanitized_bibid
1✔
UNCOV
203
      CGI.escape(params[:bib_id])
×
204
    end
205

206
    def add_locator_call_no(records)
1✔
UNCOV
207
      records.each do |location, holdings|
×
UNCOV
208
        next unless location == 'firestone$stacks'
×
209

UNCOV
210
        holdings.each do |holding|
×
UNCOV
211
          holding['sortable_call_number'] = sortable_call_number(holding['call_number'])
×
212
        end
213
      end
214
    end
215

216
    def sortable_call_number(call_no)
1✔
UNCOV
217
      return call_no unless /^[A-Za-z]/.match?(call_no)
×
218

UNCOV
219
      call_no = make_sortable_call_number(call_no)
×
UNCOV
220
      lsort_result = Lcsort.normalize(call_no)
×
UNCOV
221
      return lsort_result.gsub('..', '.') unless lsort_result.nil?
×
222

223
      force_number_part_to_have_4_digits(call_no)
×
224
    rescue StandardError
225
      call_no
×
226
    end
227

228
    def make_sortable_call_number(call_no)
1✔
UNCOV
229
      tokens = call_no.split(' ')
×
UNCOV
230
      needs_adjustment = %w[oversize folio].include? tokens.first.downcase
×
UNCOV
231
      return call_no unless needs_adjustment
×
232

233
      # Move the first token (e.g. Oversize or Folio) to the end
UNCOV
234
      (tokens[1..] << tokens[0]).join(' ')
×
235
    end
236

237
    # This routine adjust something from "A53.blah" to "A0053.blah" for sorting purposes
238
    #
239
    def force_number_part_to_have_4_digits(call_no)
1✔
240
      dot_parts = call_no.tr(',', '.').split('.')
×
241
      return call_no if dot_parts.count <= 1
×
242

243
      parts = dot_parts[0].scan(/[A-Za-z]+|\d+/)
×
244
      parts[1] = parts[1].rjust(4, '0')
×
245
      dot_parts[0] = parts.join('.')
×
246
      dot_parts.join('.')
×
247
    end
248
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