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

pulibrary / orangelight / a403a64b-87b2-431b-a8bc-82d253504741

30 Oct 2025 05:45PM UTC coverage: 95.355% (-0.07%) from 95.426%
a403a64b-87b2-431b-a8bc-82d253504741

Pull #5281

circleci

christinach
Remove flash_html -html fragments- and flash_messages_html from all
json reposnses in form_controller.rb
Json reponse includes only success, message and errors if present
In RequestHandler.js build a DOM element for the button and append it
in the success or error element

related to [#5264]
Pull Request #5281: Don't use Rails ujs for request form submission

44 of 45 new or added lines in 1 file covered. (97.78%)

5 existing lines in 2 files now uncovered.

6199 of 6501 relevant lines covered (95.35%)

1464.12 hits per line

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

95.96
/app/controllers/requests/form_controller.rb
1
# frozen_string_literal: true
2
require 'faraday'
3✔
3

4
include Requests::ApplicationHelper
3✔
5

6
module Requests
3✔
7
  class FormController < ApplicationController
3✔
8
    before_action :authenticate_user!, except: [:index], unless: -> { aeon? }
138✔
9

10
    def index
3✔
11
      redirect_to('/')
1✔
12
    end
13

14
    def generate
3✔
15
      # Patron can be slow to load, start loading it early
16
      @user = current_or_guest_user
87✔
17
      patron_request = Thread.new { Patron.authorize(user: @user) }
174✔
18

19
      system_id = sanitize(params[:system_id])
87✔
20
      mfhd = sanitize(params[:mfhd])
87✔
21
      params.require(:mfhd) unless system_id.starts_with?("SCSB") # there are not multiple locations for shared items so no MFHD is passed
87✔
22
      @back_to_record_url = BackToRecordUrl.new(params)
86✔
23

24
      @title = "Request ID: #{system_id}"
86✔
25

26
      # needed to see if we can suppress login for this item
27
      @request = FormDecorator.new(Requests::Form.new(system_id:, mfhd:, patron_request:), view_context, @back_to_record_url)
86✔
28
      @patron = patron_request.value
86✔
29
      patron_errors = @patron.errors
86✔
30
      flash.now[:error] = patron_errors.join(", ") if patron_errors.present?
86✔
31
    rescue ActionController::ParameterMissing
32
      render 'requests/form/no_location_specified'
1✔
33
    end
34

35
    def aeon?
3✔
36
      return true if params["aeon"] == 'true'
135✔
37

38
      false
134✔
39
    end
40

41
    # will post and a JSON document of selected "requestable" objects with selection parameters and
42
    # user information for further processing and distribution to various request endpoints.
43
    def submit
3✔
44
      @submission = Requests::Submission.new(sanitize_submission(params), Patron.new(user: current_or_guest_user))
45✔
45

46
      valid = @submission.valid?
45✔
47
      @services = @submission.process_submission if valid
45✔
48

49
      response_data = if valid && @submission.service_errors.blank?
45✔
50
                        respond_to_submit_success(@submission)
37✔
51
                      elsif valid # submission was valid, but service failed
8✔
52
                        respond_to_service_error(@services)
4✔
53
                      else
54
                        respond_to_validation_error(@submission)
4✔
55
                      end
56

57
      render json: response_data
45✔
58
    end
59

60
    private
3✔
61

62
      def mode
3✔
63
        return 'standard' if params[:mode].nil?
×
64
        sanitize(params[:mode])
×
65
      end
66

67
      # trusted params
68
      def request_params
3✔
69
        params.permit(:id, :system_id, :mfhd, :user_name, :email, :loc_code, :user, :requestable, :request, :barcode, :isbns).permit!
×
70
      end
71

72
      def sanitize_submission(params)
3✔
73
        params[:requestable].each do |requestable|
45✔
74
          params['user_supplied_enum'] = sanitize(requestable['user_supplied_enum']) if requestable.key? 'user_supplied_enum'
215✔
75
        end
76
        lparams = params.permit(bib: [:id, :title, :author, :isbn, :date])
45✔
77
        lparams[:requestable] = params[:requestable].map do |requestable|
45✔
78
          json_pick_up = requestable[:pick_up]
215✔
79
          requestable = requestable.merge(JSON.parse(json_pick_up)) if json_pick_up.present?
215✔
80
          requestable.permit!
215✔
81
        end
82
        lparams
45✔
83
      end
84

85
      # :reek:UncommunicativeVariableName { accept: ['e'] }
86
      # :reek:TooManyStatements
87
      def respond_to_submit_success(submission)
3✔
88
        success_message = submission.success_messages.join(' ')
37✔
89
        flash.now[:success] = success_message
37✔
90
        logger.info "Request Sent"
37✔
91

92
        {
37✔
93
          success: true,
94
          message: success_message
95
        }
96
      end
97

98
      # :reek:UncommunicativeVariableName { accept: ['e'] }
99
      def respond_to_service_error(services)
3✔
100
        errors = services.map(&:errors).flatten
4✔
101
        error_types = errors.pluck(:type).uniq
4✔
102
        flash_now_error = if error_types.include?("digitize")
4✔
103
                            errors[error_types.index("digitize")][:error]
3✔
104
                          else
105
                            I18n.t('requests.submit.service_error')
1✔
106
                          end
107
        flash.now[:error] = flash_now_error
4✔
108
        logger.error "Request Service Error"
4✔
109
        service_errors = services.map(&:error_hash).inject(:merge)
4✔
110
        send_error_email(service_errors, @submission)
4✔
111

112
        {
4✔
113
          success: false,
114
          message: flash_now_error,
115
          errors: service_errors
116
        }
117
      end
118

119
      # :reek:TooManyStatements
120
      def respond_to_validation_error(submission)
3✔
121
        error_message = I18n.t('requests.submit.error')
4✔
122
        error_messages = submission.errors.messages
4✔
123
        extract_specific_errors(error_messages)
4✔
124

125
        flash.now[:error] = error_message
4✔
126
        logger.error "Request Submission #{error_messages.as_json}"
4✔
127

128
        {
4✔
129
          success: false,
130
          message: error_message,
131
          errors: format_validation_errors(error_messages)
132
        }
133
      end
134

135
      def sanitize(str)
3✔
136
        str.gsub(/[^A-Za-z0-9@\-_\.]/, '') if str.is_a? String
182✔
137
        str
182✔
138
      end
139

140
      # :reek:NestedIterators
141
      # :reek:TooManyStatements
142
      # :reek:UtilityFunction
143
      def format_validation_errors(error_messages)
3✔
144
        formatted_errors = {}
7✔
145

146
        error_messages.each do |key, values|
7✔
147
          formatted_errors[key] = if key == :items
9✔
148
                                    # Handle special items field format
149
                                    values.map do |value|
6✔
150
                                      if value.is_a?(Hash)
6✔
151
                                        first_value = value.values.first
5✔
152
                                        {
153
                                          key: value.keys.first,
5✔
154
                                          type: first_value['type'],
155
                                          text: first_value['text']
156
                                        }
157
                                      else
158
                                        { text: value }
1✔
159
                                      end
160
                                    end
161
                                  else
162
                                    # Handle regular validation errors
163
                                    values
3✔
164
                                  end
165
        end
166
        formatted_errors
7✔
167
      end
168

169
      # :reek:NestedIterators
170
      # :reek:TooManyStatements
171
      # :reek:UtilityFunction
172
      def extract_specific_errors(error_messages)
3✔
173
        specific_errors = []
4✔
174
        error_messages.each do |key, values|
4✔
175
          if key == :items
5✔
176
            values.each do |value|
4✔
177
              if value.is_a?(Hash)
4✔
178
                first_value = value.values.first
4✔
179
                text_value = first_value['text']
4✔
180
                specific_errors << text_value if text_value
4✔
181
              else
NEW
182
                specific_errors << value
×
183
              end
184
            end
185
          else
186
            specific_errors.concat(values)
1✔
187
          end
188
        end
189
        specific_errors
4✔
190
      end
191

192
      # This has to be a utility function to prevent ActiveJob from trying to serialize too many objects
193
      # :reek:UtilityFunction
194
      def send_error_email(errors, submission)
3✔
195
        Requests::RequestMailer.send("service_error_email", errors, submission.to_h).deliver_later
4✔
196
      end
197
  end
198
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