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

pulibrary / tigerdata-app / 7291b10e-eaa3-4284-9371-5a980ceebf59

24 Nov 2025 07:18PM UTC coverage: 87.613% (-3.7%) from 91.333%
7291b10e-eaa3-4284-9371-5a980ceebf59

push

circleci

web-flow
Adds breadcrumb to Wizard (#2231)

Adds the breadcrumb to the Wizard and the functionality to allow the
user to save their changes before leaving the Wizard when clicking on
the "Dashboard" link in the breadcrumbs.

Closes #2102

5 of 12 new or added lines in 11 files covered. (41.67%)

904 existing lines in 36 files now uncovered.

2801 of 3197 relevant lines covered (87.61%)

360.23 hits per line

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

96.67
/app/models/mediaflux/request.rb
1
# frozen_string_literal: true
2
module Mediaflux
4✔
3
    class Request
4✔
4

5
      # As this is an abstract class, this should be overridden to specify the Mediaflux API service
6
      def self.service
4✔
7
        raise(NotImplementedError, "#{self} is an abstract class, please override #{self}.service")
1✔
8
      end
9

10
      # The default request URL path for the Mediaflux API
11
      # @return [String]
12
      def self.request_path
4✔
13
        "/__mflux_svc__"
6,047✔
14
      end
15

16
      def self.uri
4✔
17
        # Setting the URI to the Ansible build or Docker build of mediaflux depending on the environment
18
        URI("#{Connection.transport}://#{Connection.host}:#{Connection.port}#{request_path}")
3,037✔
19
      end
20

21
      # Constructs a new HTTP POST request for usage with the Mediaflux API
22
      # @return [Net::HTTP::Post]
23
      def self.build_post_request
4✔
24
        Net::HTTP::Post.new(request_path)
3,010✔
25
      end
26

27
      # The default XML namespace which should be used for building the XML
28
      #   Document transmitted in the body of the HTTP request
29
      # @return [String]
30
      def self.default_xml_namespace
4✔
31
        "tigerdata"
24✔
32
      end
33

34
      def self.default_xml_namespace_uri
4✔
35
        "http://tigerdata.princeton.edu"
24✔
36
      end
37

38
      # Constructs and memoizes a new instance of the Net::HTTP::Persistent object at the level of the Class
39
      # @returns http_client [Net::HTTP::Persistent] HTTP client for transmitting requests to the Mediaflux server API
40
      def self.find_or_create_http_client
4✔
41
        HttpConnection.instance.http_client
3,017✔
42
      end
43

44
      attr_reader :session_token
4✔
45

46
      # Constructor
47
      # @param file [File] any upload file required for the POST request
48
      # @param session_token [String] the API token for the authenticated session
49
      # @param http_client [Net::HTTP::Persistent] HTTP client for transmitting requests to the Mediaflux server API
50
      def initialize(file: nil, session_token: nil, http_client: nil)
4✔
51
        @http_client = http_client || self.class.find_or_create_http_client
3,017✔
52
        @file = file
3,017✔
53
        @session_token = session_token
3,017✔
54
      end
55

56
      # Resolves the HTTP request against the Mediaflux API
57
      # @return [Net::HTTP]
58
      def resolve
4✔
59
        start_time = ::Time.zone.now
3,018✔
60
        @http_response = @http_client.request self.class.uri, http_request
3,018✔
61
        log_elapsed(start_time)
3,017✔
62
        if response_error.present?
3,017✔
63
          Rails.logger.error "Mediaflux error: #{response_error[:title]}, #{response_error[:message]}"
19✔
64
        end
65
        @http_response
3,013✔
66
      end
67

68
      # Determines whether or not the request has been resolved
69
      # @return [Boolean]
70
      def resolved?
4✔
71
        @http_response.present?
6,960✔
72
      end
73

74
      # Resolves the HTTP request, and returns the XML Document parsed from the response body
75
      # @return [Nokogiri::XML::Document]
76
      def response_xml
4✔
77
        resolve unless resolved?
6,958✔
78
        Rails.logger.debug(response_body)
6,954✔
79
        @response_xml ||= Nokogiri::XML.parse(response_body)
6,954✔
80
        Rails.logger.debug(@response_xml)
6,954✔
81
        if @response_xml.xpath("//message").text == "session is not valid"
6,954✔
UNCOV
82
          raise Mediaflux::SessionExpired, "Session expired for token #{session_token}"
4✔
83
        end
84

85
        @response_xml
6,950✔
86
      end
87

88
      # The response body of the mediaflux call
89
      def response_body
4✔
90
        @response_body ||= http_response.body
9,983✔
91
      end
92

93
      def error?
4✔
94
        response_error.present?
795✔
95
      end
96

97
      def response_error
4✔
98
        xml = response_xml
3,864✔
99
        return nil if xml.xpath("/response/reply/error").count == 0
3,860✔
100
        error = {
101
          title: xml.xpath("/response/reply/error").text,
79✔
102
          message: xml.xpath("/response/reply/message").text
103
        }
104
        error
79✔
105
      end
106

107
      delegate :to_s, to: :response_xml
4✔
108

109
      def xml_payload( name: self.class.service)
4✔
110
        body = build_http_request_body(name: )
6,022✔
111
        xml_payload = body.to_xml
6,022✔
112
      end
113

114
      # The output of this routine can be passed to xtoshell in aterm.  The output of which can be sent to service.execute
115
      # @param [String] name name of the service this request will send
116
      # @return [String] xml that can be passed to xtoshell without manipulation
117
      def xtoshell_xml( name: self.class.service)
4✔
118
        xml_builder = build_http_request_body(name: )
1✔
119
        xml_builder.doc.xpath("//request/service/@session").remove
1✔
120
        xml = xml_builder.to_xml(:save_with => Nokogiri::XML::Node::SaveOptions::AS_XML | Nokogiri::XML::Node::SaveOptions::NO_DECLARATION)
1✔
121
        xml.strip.gsub("\"","'").gsub("<args>","").gsub("</args>","")
1✔
122
      end
123

124
      # This method is used for transforming iso8601 dates to dates that MediaFlux likes
125
      # Take a string like "2024-02-26T10:33:11-05:00" and convert this string to "22-FEB-2024 13:57:19"
126
      def self.format_date_for_mediaflux(iso8601_date)
4✔
127
        return if iso8601_date.nil?
×
128
        Time.format_date_for_mediaflux(iso8601_date)
×
129
      end
130

131
      private
4✔
132

133
        def http_request
4✔
134
          @http_request ||= build_http_request(name: self.class.service, form_file: @file)
3,018✔
135
        end
136

137
        def http_response
4✔
138
          @http_response ||= resolve
3,018✔
139
        end
140

141
        def build_http_request_body(name:)
4✔
142
          args = { name: name }
6,023✔
143
                                                # must use @session_token here instead of session_token
144
                                                #  for login to not go into an infinaite loop
145
          args[:session] = session_token unless @session_token.nil?
6,023✔
146

147
          Nokogiri::XML::Builder.new(namespace_inheritance: false) do |xml|
6,023✔
148
            xml.request do
6,023✔
149
              xml.service(**args) do
6,023✔
150
                yield xml if block_given?
6,023✔
151
              end
152
            end
153
          end
154
        end
155

156
        # rubocop:disable Metrics/MethodLength
157
        def build_http_request(name:, form_file: nil)
4✔
158
          request = self.class.build_post_request
3,010✔
159

160
          log_xml_request(xml_payload)
3,010✔
161
          if form_file.nil?
3,010✔
162
            request["Content-Type"] = "text/xml; charset=utf-8"
3,009✔
163
            request.body = xml_payload(name:)
3,009✔
164
          else
165
            request["Content-Type"] = "multipart/form-data"
1✔
166
            request.set_form({ "request" => xml_payload,
1✔
167
                               "nb-data-attachments" => "1",
168
                               "file_0" => form_file },
169
                          "multipart/form-data",
170
                          "charset" => "UTF-8")
171
          end
172

173
          request
3,010✔
174
        end
175
      # rubocop:enable Metrics/MethodLength
176

177
      def log_xml_request(xml_payload)
4✔
178
        password_element = xml_payload.match(/\<password\>.*\<\/password\>/)
3,010✔
179
        if password_element.nil?
3,010✔
180
          Rails.logger.debug(xml_payload)
1,544✔
181
        else
182
          # Don't log the password
183
          Rails.logger.debug(xml_payload.gsub(password_element.to_s, "<password>***</password>"))
1,466✔
184
        end
185
      end
186

187
      # Logs as warning Mediaflux requests that take longer than 3 seconds.
188
      #
189
      # We could eventually also send to Honeybadger long requests but
190
      # let's wait until we have a benchmark of what is considered slow
191
      # in Mediaflux.
192
      def log_elapsed(start_time)
4✔
193
        elapsed_time = ::Time.zone.now - start_time
3,017✔
194
        timing_info = "#{format('%.2f', elapsed_time)} s"
3,017✔
195
        if elapsed_time > 3.0
3,017✔
196
          Rails.logger.warn "Slow Mediaflux request: #{self.class}, #{timing_info}"
×
197
        end
198
      end
199
    end
200
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