diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 04fc72582..a3a7af7f4 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -29,13 +29,10 @@ jobs: ruby-version: 2.7.2 bundler-cache: true - - name: Use Node.js 14.x + - name: Use Node.js 16.x uses: actions/setup-node@v2 with: - node-version: 14.x - - - name: Use latest npm - run: npm install -g npm + node-version: 16.x - name: Install bundler & bundle-audit run: | @@ -89,13 +86,10 @@ jobs: ruby-version: 2.7.2 bundler-cache: true - - name: Use Node.js 14.x + - name: Use Node.js 16.x uses: actions/setup-node@v2 with: - node-version: 14.x - - - name: Use latest npm - run: npm install -g npm + node-version: 16.x - name: Install bundler & bundle-audit run: | diff --git a/Dockerfile b/Dockerfile index dbedccb76..4013a65f7 100644 --- a/Dockerfile +++ b/Dockerfile @@ -14,7 +14,7 @@ RUN bash -lc "rvm install ruby-${RUBY_VERSION} && rvm --default use ruby-${RUBY_ RUN rm -f /etc/service/nginx/down \ && rm -f /etc/nginx/sites-enabled/default \ && apt update \ - && curl -fsSL https://deb.nodesource.com/setup_14.x | bash - \ + && curl -fsSL https://deb.nodesource.com/setup_20.x | bash - \ && apt-get install -y nodejs \ && npm install -g npm@latest \ && apt-get install shared-mime-info -y diff --git a/Gemfile.lock b/Gemfile.lock index 5b1418d40..bd7909454 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,6 +1,6 @@ GIT remote: https://github.com/projecttacoma/cqm-parsers.git - revision: 7fcb3c10ae648b137c668bffbf148088baee4cc4 + revision: 358658c5d88406c3d2da4a0d756cd5a1977a2945 branch: bonnie-on-fhir specs: cqm-parsers (0.2.1.1) diff --git a/app/controllers/api_v1/measures_controller.rb b/app/controllers/api_v1/measures_controller.rb index 76dcb8031..44cf24252 100644 --- a/app/controllers/api_v1/measures_controller.rb +++ b/app/controllers/api_v1/measures_controller.rb @@ -81,8 +81,6 @@ def description param :population_titles, Array, of: String, :required => false, :desc => "The titles of the populations. If this is not included, populations will assume default values. i.e. \"Population 1\", \"Population 2\", etc." param :calculate_sdes, %w[true false], :required => false, :desc => "Should Supplemental Data Elements be included in calculations. Defaults to 'false' if not supplied." - param :vsac_tgt, String, :required => true, :desc => "VSAC ticket granting ticket. See https://www.nlm.nih.gov/vsac/support/" - param :vsac_tgt_expires_at, Integer, :required => true, :desc => "VSAC ticket granting ticket expiration time in seconds since epoch." param :vsac_query_type, %w[release profile], :required => false, :desc => "The type of VSAC query, either 'release', or 'profile'. Default to 'profile' if not supplied." param :vsac_query_include_draft, %w[true false], :required => false, :desc => "If VSAC should fetch draft value sets. Defaults to 'true' if not supplied." param :vsac_query_release, String, :required => false, :desc => "The program release used to retrieve value sets. Defaults to latest release for the eCQM program." diff --git a/app/controllers/measures_controller.rb b/app/controllers/measures_controller.rb index ffe4da9b7..74b8a32f8 100644 --- a/app/controllers/measures_controller.rb +++ b/app/controllers/measures_controller.rb @@ -29,7 +29,7 @@ def create begin scan_for_viruses(params[:measure_file]) - vsac_tgt = obtain_ticket_granting_ticket + set_vsac_api_key rescue VirusFoundError => e logger.error "VIRSCAN: error message: #{e.message}" raise MeasurePackageVirusFoundError.new @@ -41,13 +41,11 @@ def create raise convert_vsac_error_into_shared_error(e) end - params[:vsac_tgt] = vsac_tgt[:ticket] - params[:vsac_tgt_expires_at] = vsac_tgt[:expires] persist_measure(params[:measure_file], params.permit!.to_h, current_user) redirect_to "#{root_path}##{params[:redirect_route]}" rescue StandardError => e - # also clear the ticket granting ticket in the session if it was a VSACTicketExpiredError - session[:vsac_tgt] = nil if e.is_a?(VSACTicketExpiredError) + # also clear the vsac api key in the session if it was a VSACInvalidCredentialsError + session[:vsac_api_key] = nil if e.is_a?(VSACInvalidCredentialsError) flash[:error] = turn_exception_into_shared_error_if_needed(e).front_end_version redirect_to "#{root_path}##{params[:redirect_route]}" end @@ -131,6 +129,15 @@ def retrieve_measure_details(params) } end + def set_vsac_api_key + if session[:vsac_api_key].nil? + raise Util::VSAC::VSACNoCredentialsError.new if params[:vsac_api_key].nil? + session[:vsac_api_key] = params[:vsac_api_key] + else + params[:vsac_api_key] = session[:vsac_api_key] + end + end + def shift_years(measure, year_shift) return true # TODO: not implemented for patients and data elements yet @@ -173,33 +180,4 @@ def shift_birth_datetime(birth_datetime, year_shift) birth_datetime.change(year: year_shift + birth_datetime.year) end end - - def obtain_ticket_granting_ticket - # Retrieve a (possibly) existing ticket granting ticket - ticket_granting_ticket = session[:vsac_tgt] - - # If the ticket granting ticket doesn't exist (or has expired), get a new one - if ticket_granting_ticket.nil? - # The user could open a second browser window and remove their ticket_granting_ticket in the session after they - # prepared a measure upload assuming ticket_granting_ticket in the session in the first tab - - # First make sure we have credentials to attempt getting a ticket with. Throw an error if there are no credentials. - if params[:vsac_api_key].nil? - raise Util::VSAC::VSACNoCredentialsError.new - end - - # Retrieve a new ticket granting ticket by creating the api class. - api = Util::VSAC::VSACAPI.new(config: APP_CONFIG['vsac'], api_key: params[:vsac_api_key]) - ticket_granting_ticket = api.ticket_granting_ticket - - # Create a new ticket granting ticket session variable - session[:vsac_tgt] = ticket_granting_ticket - return ticket_granting_ticket - - # If it does exist, let the api test it - else - api = Util::VSAC::VSACAPI.new(config: APP_CONFIG['vsac'], ticket_granting_ticket: ticket_granting_ticket) - return api.ticket_granting_ticket - end - end end diff --git a/app/controllers/vsac_util_controller.rb b/app/controllers/vsac_util_controller.rb index 32c439f51..1a1734bc0 100644 --- a/app/controllers/vsac_util_controller.rb +++ b/app/controllers/vsac_util_controller.rb @@ -51,26 +51,20 @@ def program_release_names ## # GET /vsac_util/auth_valid # - # Gets the status of the ticket_granting_ticket in the session. Returns JSON: - # { valid: boolean, expires: DateTime } + # Gets the status of the API KEY in the session. Returns JSON: + # { valid: boolean } def auth_valid - # If VSAC TGT is still valid, return its expiration date/time - ticket_granting_ticket = session[:vsac_tgt] + vsac_api_key = session[:vsac_api_key] - # If there is no VSAC ticket granting ticket then return false. - if ticket_granting_ticket.nil? || ticket_granting_ticket.empty? - session[:vsac_tgt] = nil - render :json => {valid: false} - - # If it exists then check it using the API + if vsac_api_key.nil? || vsac_api_key.empty? + session[:vsac_api_key] = nil + render :json => {valid:false} else begin - Util::VSAC::VSACAPI.new(config: APP_CONFIG['vsac'], ticket_granting_ticket: ticket_granting_ticket) - render :json => {valid: true, expires: ticket_granting_ticket[:expires]} - - # API will throw an error if it has expired - rescue Util::VSAC::VSACTicketExpiredError - session[:vsac_tgt] = nil + Util::VSAC::VSACAPI.new(config: APP_CONFIG['vsac'], api_key: vsac_api_key) + render :json => {valid: true} + rescue Util::VSAC::VSACInvalidCredentialsError + session[:vsac_api_key] = nil render :json => {valid: false} end end @@ -79,10 +73,10 @@ def auth_valid ## # POST /vsac_util/auth_expire # - # Dumps the ticket_granting_ticket in the user session if there is one. Always returns JSON {}. + # Sets the vsac_api_key in the user session to nil. Always returns JSON {}. def auth_expire # Force expire the VSAC session - session[:vsac_tgt] = nil + session[:vsac_api_key] = nil render :json => {} end end diff --git a/app/helpers/measure_helper.rb b/app/helpers/measure_helper.rb index b614b97de..5cf97faeb 100644 --- a/app/helpers/measure_helper.rb +++ b/app/helpers/measure_helper.rb @@ -253,11 +253,9 @@ def retrieve_vasc_options(params, get_defaults_from_vsac = false) end def build_vs_loader(params, get_defaults_from_vsac) - vsac_tgt_object = {ticket: params[:vsac_tgt], expires: Time.at(params[:vsac_tgt_expires_at].to_i)} if params[:vsac_tgt].present? && params[:vsac_tgt_expires_at].present? - - return Measures::VSACValueSetLoader.new( + Measures::VSACValueSetLoader.new( options: retrieve_vasc_options(params, get_defaults_from_vsac), - ticket_granting_ticket: vsac_tgt_object + vsac_api_key: params[:vsac_api_key] ) end diff --git a/config/bonnie.yml b/config/bonnie.yml index 09ea370b8..cfffdd3e6 100644 --- a/config/bonnie.yml +++ b/config/bonnie.yml @@ -38,7 +38,7 @@ defaults: &defaults # DEV # Spreadsheet Example: https://docs.google.com/spreadsheets/d/15Tje3oiUfYgU24RiX-fUs-hH08dFOvW7_ysyAN8vxuc/edit#gid=0 # Spreadsheet's JSON: https://spreadsheets.google.com/feeds/list/15Tje3oiUfYgU24RiX-fUs-hH08dFOvW7_ysyAN8vxuc/od6/public/values?alt=json - spreadsheet_location: 'https://spreadsheets.google.com/feeds/list/15Tje3oiUfYgU24RiX-fUs-hH08dFOvW7_ysyAN8vxuc/od6/public/values?alt=json' + spreadsheet_location: 'http://127.0.0.1:5555/codeset_values.json' development: <<: *defaults diff --git a/doc/apipie_examples.json b/doc/apipie_examples.json index 39ecc5314..2c4b0b47f 100644 --- a/doc/apipie_examples.json +++ b/doc/apipie_examples.json @@ -1,34 +1,4 @@ { - "home#index": [ - { - "verb": "GET", - "path": "/", - "versions": [ - - ], - "query": "", - "request_data": null, - "response_data": "\n\n \n \n \n \n Bonnie v6.1.1\n \n \n \n \n\n\n \n\n \n Skip to main content\n \n
\n
\n
\n Bonnie\n
\n \n
\n\n
\n\n
\n
\n \n
loading
\n
\n
\n \n

\n
\n\n \n \n \n\n", - "code": "200", - "show_in_doc": 1, - "recorded": true - } - ], - "home#show": [ - { - "verb": "GET", - "path": "/", - "versions": [ - - ], - "query": "", - "request_data": null, - "response_data": "\n\n \n \n \n Bonnie v6.1.1\n \n \n \n \n \n\n\n \n \n
\n
\n
\n
\n

BONNIE

\n

A tool for testing electronic clinical quality measures

\n
\n
\n login\n
\n
\n
\n
\n
\n
\n User Guide\n Release Notes\n User Group\n API Guide\n Report Bug\n
\n
\n
\n
\n
\n

streamlined and efficient

\n \n

pretesting for eCQMs

\n
\n
\n

developer empowerment

\n \n

provides specific feedback on the behavior of the CQM logic

\n
\n
\n

quality
reporting

\n \n

supports the CMS Quality Reporting Programs

\n
\n
\n
\n

Bonnie is a tool for testing electronic clinical quality measures (eCQMs) designed to support streamlined and efficient pre-testing of eCQMs, particularly those used in the CMS Quality Reporting Programs.

\n
\n
\n
\n

Current Version 6.1.1

\n

The version 6.1.1 release of Bonnie adds support for testing measures using CQL 1.4 and the FHIR 4.0.1 model

\n
\n
\n

Capabilities V6.1.1

\n
    \n
  • Hybrid Measure Support
  • \n
  • Display CQL Definition Results
  • \n
  • VSAC Profile and Release Selection
  • \n
  • Custom Measurement Period
  • \n
  • Bonnie API
  • \n
  • CQL 1.4 Support
  • \n
  • FHIR 4.0.1 Model Support
  • \n
\n
\n
\n
\n
\n

\n This version of Bonnie supports CQL 1.4, FHIR 4.0.1 Based measures.
\n For CQL 1.4, QDM 5.5 Based measures, please use Bonnie-QDM.
\n For CQL 1.3, QDM 5.4 Based measures, please use Bonnie-QDM-Prior.\n

\n
\n\n
\n
\n \n \n\n", - "code": "200", - "show_in_doc": 1, - "recorded": true - } - ], "groups#index": [ { "verb": "GET", @@ -138,23 +108,100 @@ "measures#create": [ { "verb": "POST", - "path": "/measures", + "path": "/api_v1/measures", "versions": [ - + "1" ], "query": null, "request_data": { - "vsac_query_type": "profile", - "vsac_query_profile": "Latest eCQM", - "vsac_query_include_draft": "false", - "vsac_query_measure_defined": "true", - "vsac_api_key": "vcrpass", "measure_file": "", - "measure_type": "ep", - "calculation_type": "patient" + "calculation_type": "addition", + "vsac_api_key": "oof", + "vsac_query_type": "profile" }, - "response_data": "You are being redirected.", - "code": "302", + "response_data": { + "status": "error", + "messages": "Invalid parameter 'calculation_type': Must be one of: episode, patient." + }, + "code": "400", + "show_in_doc": 1, + "recorded": true + }, + { + "verb": "POST", + "path": "/api_v1/measures", + "versions": [ + "1" + ], + "query": null, + "request_data": { + "measure_file": "" + }, + "response_data": { + "status": "error", + "messages": "Missing parameter: calculation_type" + }, + "code": "400", + "show_in_doc": 1, + "recorded": true + }, + { + "verb": "POST", + "path": "/api_v1/measures", + "versions": [ + "1" + ], + "query": null, + "request_data": { + "measure_file": "not-a-file.gif", + "calculation_type": "episode", + "vsac_api_key": "oof", + "vsac_query_type": "profile" + }, + "response_data": { + "status": "error", + "messages": "Invalid parameter 'measure_file': Must be a valid MAT Export." + }, + "code": "400", + "show_in_doc": 1, + "recorded": true + }, + { + "verb": "POST", + "path": "/api_v1/measures", + "versions": [ + "1" + ], + "query": null, + "request_data": { + "measure_file": "", + "calculation_type": "episode", + "vsac_api_key": "oof", + "vsac_query_type": "profile" + }, + "response_data": { + "status": "error", + "messages": "Invalid parameter 'measure_file': Must be a valid MAT Export." + }, + "code": "400", + "show_in_doc": 1, + "recorded": true + }, + { + "verb": "POST", + "path": "/api_v1/measures", + "versions": [ + "1" + ], + "query": null, + "request_data": { + "calculation_type": "episode" + }, + "response_data": { + "status": "error", + "messages": "Missing parameter: measure_file" + }, + "code": "400", "show_in_doc": 1, "recorded": true } diff --git a/package-lock.json b/package-lock.json index 92a24cfdc..e260176d8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -437,11 +437,11 @@ "license": "MIT" }, "node_modules/cql-exec-fhir": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/cql-exec-fhir/-/cql-exec-fhir-2.1.3.tgz", - "integrity": "sha512-UxGpZlvQHCd1Pl47J+J01SsvxBucbRGF1pFqlITw62e2YT3PDDdV4s7ZNfQ1Yy2TigSwITmajnSH0tOZuT4mvQ==", + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/cql-exec-fhir/-/cql-exec-fhir-2.1.5.tgz", + "integrity": "sha512-rNseLFJ2IVAtQQqsa4hb6uPFzD1EJBi0Hs4yPZNPqeCuNEUfqvO4dldJ7Edl8IcGMbIrWoKy17dLW5KBKzrSpw==", "dependencies": { - "xml2js": "~0.4.23" + "xml2js": "^0.5.0" }, "peerDependencies": { "cql-execution": ">=1.3.0 || ^3.0.0-beta" @@ -1213,9 +1213,9 @@ "license": "MIT" }, "node_modules/luxon": { - "version": "1.28.0", - "resolved": "https://registry.npmjs.org/luxon/-/luxon-1.28.0.tgz", - "integrity": "sha512-TfTiyvZhwBYM/7QdAVDh+7dBTBA29v4ik0Ce9zda3Mnf8on1S5KJI8P2jKFZ8+5C0jhmr0KwJEO/Wdpm0VeWJQ==", + "version": "1.28.1", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-1.28.1.tgz", + "integrity": "sha512-gYHAa180mKrNIUJCbwpmD0aTu9kV0dREDrwNnuyFAsO1Wt0EVYSZelPnJlbj9HplzXX/YWXHFTL45kvZ53M0pw==", "engines": { "node": "*" } @@ -1906,9 +1906,9 @@ "license": "ISC" }, "node_modules/xml2js": { - "version": "0.4.23", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", - "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz", + "integrity": "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==", "dependencies": { "sax": ">=0.6.0", "xmlbuilder": "~11.0.0" @@ -2267,11 +2267,11 @@ "version": "1.0.3" }, "cql-exec-fhir": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/cql-exec-fhir/-/cql-exec-fhir-2.1.3.tgz", - "integrity": "sha512-UxGpZlvQHCd1Pl47J+J01SsvxBucbRGF1pFqlITw62e2YT3PDDdV4s7ZNfQ1Yy2TigSwITmajnSH0tOZuT4mvQ==", + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/cql-exec-fhir/-/cql-exec-fhir-2.1.5.tgz", + "integrity": "sha512-rNseLFJ2IVAtQQqsa4hb6uPFzD1EJBi0Hs4yPZNPqeCuNEUfqvO4dldJ7Edl8IcGMbIrWoKy17dLW5KBKzrSpw==", "requires": { - "xml2js": "~0.4.23" + "xml2js": "^0.5.0" } }, "cql-execution": { @@ -2391,7 +2391,7 @@ "requires": { "acorn-node": "^1.6.1", "defined": "^1.0.0", - "minimist": "^1.1.1" + "minimist": "^1.2.7" } }, "diffie-hellman": { @@ -2796,9 +2796,9 @@ "version": "3.0.4" }, "luxon": { - "version": "1.28.0", - "resolved": "https://registry.npmjs.org/luxon/-/luxon-1.28.0.tgz", - "integrity": "sha512-TfTiyvZhwBYM/7QdAVDh+7dBTBA29v4ik0Ce9zda3Mnf8on1S5KJI8P2jKFZ8+5C0jhmr0KwJEO/Wdpm0VeWJQ==" + "version": "1.28.1", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-1.28.1.tgz", + "integrity": "sha512-gYHAa180mKrNIUJCbwpmD0aTu9kV0dREDrwNnuyFAsO1Wt0EVYSZelPnJlbj9HplzXX/YWXHFTL45kvZ53M0pw==" }, "md5.js": { "version": "1.3.5", @@ -3296,9 +3296,9 @@ "version": "1.0.2" }, "xml2js": { - "version": "0.4.23", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", - "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz", + "integrity": "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==", "requires": { "sax": ">=0.6.0", "xmlbuilder": "~11.0.0" diff --git a/test/functional/api_v1/measures_controller_test.rb b/test/functional/api_v1/measures_controller_test.rb index d70950f2f..9b0d68957 100644 --- a/test/functional/api_v1/measures_controller_test.rb +++ b/test/functional/api_v1/measures_controller_test.rb @@ -57,9 +57,8 @@ class MeasuresControllerTest < ActionController::TestCase VCR.use_cassette('api_valid_vsac_response', @vcr_options) do # get ticket_granting_ticket - api = Util::VSAC::VSACAPI.new(config: APP_CONFIG['vsac'], api_key: ENV['VSAC_API_KEY']) - ticket = api.ticket_granting_ticket[:ticket] - post :create, params: {vsac_query_type: 'profile', vsac_query_profile: 'Latest eCQM', vsac_query_measure_defined: 'true', vsac_tgt: ticket, vsac_tgt_expires_at: @ticket_expires_at, measure_file: measure_file, calculation_type: 'patient'} + Util::VSAC::VSACAPI.new(config: APP_CONFIG['vsac'], api_key: ENV['VSAC_API_KEY']) + post :create, params: {vsac_query_type: 'profile', vsac_query_profile: 'Latest eCQM', vsac_query_measure_defined: 'true', vsac_api_key: 'oof', measure_file: measure_file, calculation_type: 'patient'} assert_response :success expected_response = { 'status' => 'success', 'url' => "/api_v1/measures/#{@test_set_id}"} assert_equal expected_response, JSON.parse(response.body) @@ -106,7 +105,7 @@ class MeasuresControllerTest < ActionController::TestCase test 'should return bad_request when measure_file is not a file' do @request.env['CONTENT_TYPE'] = 'multipart/form-data' - post :create, params: {measure_file: 'not-a-file.gif', calculation_type: 'episode', vsac_tgt: 'foo', vsac_tgt_expires_at: @ticket_expires_at, vsac_query_type: 'profile'} + post :create, params: {measure_file: 'not-a-file.gif', calculation_type: 'episode', vsac_api_key: 'oof', vsac_query_type: 'profile'} assert_response :bad_request expected_response = { 'status' => 'error', 'messages' => "Invalid parameter 'measure_file': Must be a valid MAT Export." } assert_equal expected_response, JSON.parse(response.body) @@ -115,7 +114,7 @@ class MeasuresControllerTest < ActionController::TestCase test 'should return bad_request when measure_file is not a zip' do @request.env['CONTENT_TYPE'] = 'multipart/form-data' not_zip_file = fixture_file_upload(File.join('test','fixtures','measures','CMS160v6','cqm_measures','CMS160v6.json')) - post :create, params: {measure_file: not_zip_file, calculation_type: 'episode', vsac_tgt: 'foo', vsac_tgt_expires_at: @ticket_expires_at, vsac_query_type: 'profile'} + post :create, params: {measure_file: not_zip_file, calculation_type: 'episode', vsac_api_key: 'oof', vsac_query_type: 'profile'} assert_response :bad_request expected_response = { 'status' => 'error', 'messages' => "Invalid parameter 'measure_file': Must be a valid MAT Export." } assert_equal expected_response, JSON.parse(response.body) @@ -136,7 +135,7 @@ class MeasuresControllerTest < ActionController::TestCase test 'should return bad_request when calculation_type is invalid' do measure_file = fixture_file_upload(File.join('test','fixtures/fhir_measures/CMS104/CMS104_v6_0_Artifacts.zip'),'application/zip') @request.env['CONTENT_TYPE'] = 'multipart/form-data' - post :create, params: {measure_file: measure_file, calculation_type: 'addition', vsac_tgt: 'foo', vsac_tgt_expires_at: @ticket_expires_at, vsac_query_type: 'profile'} + post :create, params: {measure_file: measure_file, calculation_type: 'addition', vsac_api_key: 'oof', vsac_query_type: 'profile'} assert_response :bad_request expected_response = { 'status' => 'error', 'messages' => "Invalid parameter 'calculation_type': Must be one of: episode, patient." } assert_equal expected_response, JSON.parse(response.body) @@ -161,9 +160,8 @@ class MeasuresControllerTest < ActionController::TestCase VCR.use_cassette('api_valid_vsac_response', @vcr_options) do # get ticket_granting_ticket - api = Util::VSAC::VSACAPI.new(config: APP_CONFIG['vsac'], api_key: ENV['VSAC_API_KEY']) - ticket = api.ticket_granting_ticket[:ticket] - post :create, params: {vsac_query_type: 'profile', vsac_query_profile: 'Latest eCQM', vsac_query_measure_defined: 'true', vsac_tgt: ticket, vsac_tgt_expires_at: @ticket_expires_at, measure_file: measure_file, calculation_type: 'patient'} + Util::VSAC::VSACAPI.new(config: APP_CONFIG['vsac'], api_key: ENV['VSAC_API_KEY']) + post :create, params: {vsac_query_type: 'profile', vsac_query_profile: 'Latest eCQM', vsac_query_measure_defined: 'true', vsac_api_key: 'oof', measure_file: measure_file, calculation_type: 'patient'} assert_response :success expected_response = { 'status' => 'success', 'url' => "/api_v1/measures/#{@test_set_id}"} assert_equal expected_response, JSON.parse(response.body) @@ -184,17 +182,15 @@ class MeasuresControllerTest < ActionController::TestCase # Permitting repeat playbacks since we are checking for duplicates. vcr_options[:allow_playback_repeats] = true VCR.use_cassette('api_valid_vsac_response', vcr_options) do - # get ticket_granting_ticket - api = Util::VSAC::VSACAPI.new(config: APP_CONFIG['vsac'], api_key: ENV['VSAC_API_KEY']) - ticket = api.ticket_granting_ticket[:ticket] - post :create, params: {vsac_query_type: 'profile', vsac_query_profile: 'Latest eCQM', vsac_query_measure_defined: 'true', vsac_tgt: ticket, vsac_tgt_expires_at: @ticket_expires_at, measure_file: measure_file, calculation_type: 'patient'} + Util::VSAC::VSACAPI.new(config: APP_CONFIG['vsac'], api_key: ENV['VSAC_API_KEY']) + post :create, params: {vsac_query_type: 'profile', vsac_query_profile: 'Latest eCQM', vsac_query_measure_defined: 'true', vsac_api_key: 'oof', measure_file: measure_file, calculation_type: 'patient'} assert_response :success expected_response = { 'status' => 'success', 'url' => "/api_v1/measures/#{@test_set_id}"} assert_equal expected_response, JSON.parse(response.body) # Attempting to re-use measure_file here caused a failure during Bonnie's measure parsing. Simply re-loading the same file to a different variable works. same_file = fixture_file_upload(@test_file, 'application/zip') - post :create, params: {vsac_query_type: 'profile', vsac_query_profile: 'Latest eCQM', vsac_query_measure_defined: 'true', vsac_tgt: ticket, vsac_tgt_expires_at: @ticket_expires_at, measure_file: same_file, calculation_type: 'patient'} + post :create, params: {vsac_query_type: 'profile', vsac_query_profile: 'Latest eCQM', vsac_query_measure_defined: 'true', vsac_api_key: 'oof', measure_file: same_file, calculation_type: 'patient'} assert_response :conflict expected_response = { 'status' => 'error', 'messages' => 'A measure with this Set ID already exists.', 'url' => "/api_v1/measures/#{@test_set_id}"} assert_equal expected_response, JSON.parse(response.body) @@ -207,10 +203,8 @@ class MeasuresControllerTest < ActionController::TestCase measure_file = fixture_file_upload(File.join('test','fixtures','fhir_measures','ContinuousFhir_v6_0_Artifacts.zip'),'application/zip') @request.env['CONTENT_TYPE'] = 'multipart/form-data' VCR.use_cassette('api_valid_vsac_response', @vcr_options) do - # get ticket_granting_ticket - api = Util::VSAC::VSACAPI.new(config: APP_CONFIG['vsac'], api_key: ENV['VSAC_API_KEY']) - ticket = api.ticket_granting_ticket[:ticket] - post :create, params: {vsac_query_type: 'profile', vsac_query_profile: 'Latest eCQM', vsac_query_measure_defined: 'true', vsac_tgt: ticket, vsac_tgt_expires_at: @ticket_expires_at, measure_file: measure_file, calculation_type: 'patient'} + Util::VSAC::VSACAPI.new(config: APP_CONFIG['vsac'], api_key: ENV['VSAC_API_KEY']) + post :create, params: {vsac_query_type: 'profile', vsac_query_profile: 'Latest eCQM', vsac_query_measure_defined: 'true', vsac_api_key: 'oof', measure_file: measure_file, calculation_type: 'patient'} assert_response :ok expected_response = { 'status' => 'success', 'url' => '/api_v1/measures/81AC1377-E54D-420F-ACA7-4D902EA01F9D'} assert_equal expected_response, JSON.parse(response.body) @@ -231,10 +225,8 @@ class MeasuresControllerTest < ActionController::TestCase measure_file = fixture_file_upload(File.join('test','fixtures','fhir_measures','ContinuousFhir_v6_0_Artifacts.zip'),'application/zip') @request.env['CONTENT_TYPE'] = 'multipart/form-data' VCR.use_cassette('api_valid_vsac_response_provided_titles', @vcr_options) do - # get ticket_granting_ticket - api = Util::VSAC::VSACAPI.new(config: APP_CONFIG['vsac'], api_key: ENV['VSAC_API_KEY']) - ticket = api.ticket_granting_ticket[:ticket] - post :create, params: {vsac_query_type: 'profile', vsac_query_profile: 'Latest eCQM', vsac_query_measure_defined: 'true', vsac_tgt: ticket, vsac_tgt_expires_at: @ticket_expires_at, measure_file: measure_file, calculation_type: 'episode', population_titles: ['First Pop', 'Second Pop', 'First Strat']} + Util::VSAC::VSACAPI.new(config: APP_CONFIG['vsac'], api_key: ENV['VSAC_API_KEY']) + post :create, params: {vsac_query_type: 'profile', vsac_query_profile: 'Latest eCQM', vsac_query_measure_defined: 'true', vsac_api_key: 'oof', measure_file: measure_file, calculation_type: 'episode', population_titles: ['First Pop', 'Second Pop', 'First Strat']} assert_response :ok expected_response = { 'status' => 'success', 'url' => '/api_v1/measures/116A8764-E871-472F-9503-CA27889114DE'} assert_equal expected_response, JSON.parse(response.body) @@ -255,9 +247,8 @@ class MeasuresControllerTest < ActionController::TestCase measure_file = fixture_file_upload(@test_file, 'application/zip') @request.env['CONTENT_TYPE'] = 'multipart/form-data' VCR.use_cassette('api_invalid_release_vsac_response', @vcr_options) do - api = Util::VSAC::VSACAPI.new(config: APP_CONFIG['vsac'], api_key: ENV['VSAC_API_KEY']) - ticket = api.ticket_granting_ticket[:ticket] - post :create, params: {vsac_query_type: 'release', vsac_query_release: 'Fake 1234', vsac_query_measure_defined: 'true', vsac_tgt: ticket, vsac_tgt_expires_at: @ticket_expires_at, measure_file: measure_file, calculation_type: 'episode'} + Util::VSAC::VSACAPI.new(config: APP_CONFIG['vsac'], api_key: ENV['VSAC_API_KEY']) + post :create, params: {vsac_query_type: 'release', vsac_query_release: 'Fake 1234', vsac_query_measure_defined: 'true', vsac_api_key: 'oof', measure_file: measure_file, calculation_type: 'episode'} assert_response :bad_request expected_response = {'status'=>'error', 'messages'=>'VSAC value set (2.16.840.1.114222.4.11.837) not found or is empty. Please verify that you are using the correct profile or release and have VSAC authoring permissions if you are requesting draft value sets.'} assert_equal expected_response, JSON.parse(response.body) @@ -269,8 +260,7 @@ class MeasuresControllerTest < ActionController::TestCase measure_file = fixture_file_upload(@test_file, 'application/zip') @request.env['CONTENT_TYPE'] = 'multipart/form-data' VCR.use_cassette('api_invalid_ticket_vsac_response', @vcr_options) do - ticket = 'foo' - post :create, params: {vsac_tgt: ticket, vsac_tgt_expires_at: @ticket_expires_at, measure_file: measure_file, calculation_type: 'episode'} + post :create, params: {vsac_api_key: 'oof', measure_file: measure_file, calculation_type: 'episode'} assert_response :bad_request expected_response = {'status'=>'error', 'messages'=>'VSAC session expired. Please try again.'} assert_equal expected_response, JSON.parse(response.body) @@ -282,9 +272,8 @@ class MeasuresControllerTest < ActionController::TestCase measure_file = fixture_file_upload(@test_file, 'application/zip') @request.env['CONTENT_TYPE'] = 'multipart/form-data' VCR.use_cassette('api_valid_vsac_response_non_exist_measure', @vcr_options) do - api = Util::VSAC::VSACAPI.new(config: APP_CONFIG['vsac'], api_key: ENV['VSAC_API_KEY']) - ticket = api.ticket_granting_ticket[:ticket] - put :update, params: {id: '762B1B52-40BF-4596-B34F-4963188E7FF7', vsac_query_type: 'profile', vsac_query_profile: 'Latest eCQM', vsac_query_measure_defined: 'true', vsac_tgt: ticket, vsac_tgt_expires_at: @ticket_expires_at, measure_file: measure_file, calculation_type: 'episode'} + Util::VSAC::VSACAPI.new(config: APP_CONFIG['vsac'], api_key: ENV['VSAC_API_KEY']) + put :update, params: {id: '762B1B52-40BF-4596-B34F-4963188E7FF7', vsac_query_type: 'profile', vsac_query_profile: 'Latest eCQM', vsac_query_measure_defined: 'true', vsac_api_key: 'oof', measure_file: measure_file, calculation_type: 'episode'} assert_response :not_found expected_response = { 'status' => 'error', 'messages' => 'No measure found for this Set ID.'} assert_equal expected_response, JSON.parse(response.body) @@ -300,16 +289,14 @@ class MeasuresControllerTest < ActionController::TestCase # Permitting repeat playbacks since we are checking for duplicates. vcr_options[:allow_playback_repeats] = true VCR.use_cassette('api_valid_vsac_response', vcr_options) do - api = Util::VSAC::VSACAPI.new(config: APP_CONFIG['vsac'], api_key: ENV['VSAC_API_KEY']) - ticket = api.ticket_granting_ticket[:ticket] - - post :create, params: {measure_file: measure_file, calculation_type: 'patient', vsac_tgt: ticket, vsac_tgt_expires_at: @ticket_expires_at, vsac_query_type: 'profile', vsac_query_profile: 'Latest eCQM'} + Util::VSAC::VSACAPI.new(config: APP_CONFIG['vsac'], api_key: ENV['VSAC_API_KEY']) + post :create, params: {measure_file: measure_file, calculation_type: 'patient', vsac_api_key: 'oof', vsac_query_type: 'profile', vsac_query_profile: 'Latest eCQM'} assert_response :success expected_response = { 'status' => 'success', 'url' => "/api_v1/measures/#{@test_set_id}"} assert_equal expected_response, JSON.parse(response.body) measure_update_file = fixture_file_upload(@test_file, 'application/zip') - put :update, params: {id: '42bf391f-38a3-4c0f-9ece-dcd47e9609d9', measure_file: measure_update_file, calculation_type: 'episode', vsac_tgt: ticket, vsac_tgt_expires_at: @ticket_expires_at, vsac_query_type: 'profile', vsac_query_profile: 'Latest eCQM'} + put :update, params: {id: '42bf391f-38a3-4c0f-9ece-dcd47e9609d9', measure_file: measure_update_file, calculation_type: 'episode', vsac_api_key: 'oof', vsac_query_type: 'profile', vsac_query_profile: 'Latest eCQM'} assert_response :not_found expected_response = { 'status' => 'error', 'messages' => 'No measure found for this Set ID.'} assert_equal expected_response, JSON.parse(response.body) @@ -321,9 +308,8 @@ class MeasuresControllerTest < ActionController::TestCase measure_file = fixture_file_upload(@test_file, 'application/zip') @request.env['CONTENT_TYPE'] = 'multipart/form-data' VCR.use_cassette('api_valid_vsac_response', @vcr_options) do - api = Util::VSAC::VSACAPI.new(config: APP_CONFIG['vsac'], api_key: ENV['VSAC_API_KEY']) - ticket = api.ticket_granting_ticket[:ticket] - post :create, params: {vsac_query_type: 'profile', vsac_query_profile: 'Latest eCQM', vsac_query_measure_defined: 'true', vsac_tgt: ticket, vsac_tgt_expires_at: @ticket_expires_at, measure_file: measure_file, calculation_type: 'episode', calculate_sdes: 'true'} + Util::VSAC::VSACAPI.new(config: APP_CONFIG['vsac'], api_key: ENV['VSAC_API_KEY']) + post :create, params: {vsac_query_type: 'profile', vsac_query_profile: 'Latest eCQM', vsac_query_measure_defined: 'true', vsac_api_key: 'oof', measure_file: measure_file, calculation_type: 'episode', calculate_sdes: 'true'} assert_response :success measure = CQM::Measure.where({set_id: @test_set_id}).first assert_equal true, measure.calculate_sdes @@ -335,9 +321,8 @@ class MeasuresControllerTest < ActionController::TestCase measure_file = fixture_file_upload(@test_file, 'application/zip') @request.env['CONTENT_TYPE'] = 'multipart/form-data' VCR.use_cassette('api_valid_vsac_response', @vcr_options) do - api = Util::VSAC::VSACAPI.new(config: APP_CONFIG['vsac'], api_key: ENV['VSAC_API_KEY']) - ticket = api.ticket_granting_ticket[:ticket] - post :create, params: {vsac_query_type: 'profile', vsac_query_profile: 'Latest eCQM', vsac_query_measure_defined: 'true', vsac_tgt: ticket, vsac_tgt_expires_at: @ticket_expires_at, measure_file: measure_file, calculation_type: 'episode', calculate_sdes: 'false'} + Util::VSAC::VSACAPI.new(config: APP_CONFIG['vsac'], api_key: ENV['VSAC_API_KEY']) + post :create, params: {vsac_query_type: 'profile', vsac_query_profile: 'Latest eCQM', vsac_query_measure_defined: 'true', vsac_api_key: 'oof', measure_file: measure_file, calculation_type: 'episode', calculate_sdes: 'false'} assert_response :success measure = CQM::Measure.where({set_id: @test_set_id}).first assert_equal false, measure.calculate_sdes @@ -359,8 +344,7 @@ class MeasuresControllerTest < ActionController::TestCase @request.env['CONTENT_TYPE'] = 'multipart/form-data' VCR.use_cassette('valid_vsac_response_composite_api_initial', @vcr_options) do - api = Util::VSAC::VSACAPI.new(config: APP_CONFIG['vsac'], api_key: ENV['VSAC_API_KEY']) - ticket = api.ticket_granting_ticket[:ticket] + Util::VSAC::VSACAPI.new(config: APP_CONFIG['vsac'], api_key: ENV['VSAC_API_KEY']) post :create, params: { vsac_query_type: 'profile', vsac_query_profile: 'eCQM Update 2020-05-07', @@ -383,8 +367,7 @@ class MeasuresControllerTest < ActionController::TestCase @request.env['CONTENT_TYPE'] = 'multipart/form-data' VCR.use_cassette('valid_vsac_response_composite_api_again', @vcr_options) do - api = Util::VSAC::VSACAPI.new(config: APP_CONFIG['vsac'], api_key: ENV['VSAC_API_KEY']) - ticket = api.ticket_granting_ticket[:ticket] + Util::VSAC::VSACAPI.new(config: APP_CONFIG['vsac'], api_key: ENV['VSAC_API_KEY']) post :update, params: { vsac_query_type: 'profile', id: '244B4F52-C9CA-45AA-8BDB-2F005DA05BFC', @@ -415,8 +398,7 @@ class << measure_file end @request.env['CONTENT_TYPE'] = 'multipart/form-data' VCR.use_cassette('valid_vsac_response_bad_composite_api', @vcr_options) do - api = Util::VSAC::VSACAPI.new(config: APP_CONFIG['vsac'], api_key: ENV['VSAC_API_KEY']) - ticket = api.ticket_granting_ticket[:ticket] + Util::VSAC::VSACAPI.new(config: APP_CONFIG['vsac'], api_key: ENV['VSAC_API_KEY']) post :create, params: { vsac_query_type: 'profile', vsac_query_profile: 'Latest eCQM', @@ -442,8 +424,7 @@ class << measure_file end @request.env['CONTENT_TYPE'] = 'multipart/form-data' VCR.use_cassette('valid_vsac_response_bad_composite_api', @vcr_options) do - api = Util::VSAC::VSACAPI.new(config: APP_CONFIG['vsac'], api_key: ENV['VSAC_API_KEY']) - ticket = api.ticket_granting_ticket[:ticket] + Util::VSAC::VSACAPI.new(config: APP_CONFIG['vsac'], api_key: ENV['VSAC_API_KEY']) post :create, params: { vsac_query_type: 'profile', vsac_query_profile: 'Latest eCQM', diff --git a/test/functional/vsac_util_controller_test.rb b/test/functional/vsac_util_controller_test.rb index 398486d0a..62208ae5a 100644 --- a/test/functional/vsac_util_controller_test.rb +++ b/test/functional/vsac_util_controller_test.rb @@ -54,37 +54,10 @@ class VsacUtilControllerTest < ActionController::TestCase test "vsac auth valid" do # The ticket field was taken from the vcr_cassettes/valid_vsac_response file - session[:vsac_tgt] = {ticket: "ST-67360-HgEfelIvwUQ3zz3X39fg-cas", expires: Time.now.utc + 27000} + session[:vsac_api_key] = 'somethingDecent' get :auth_valid assert_response :ok assert_equal true, JSON.parse(response.body)['valid'] end - - test "vsac auth invalid" do - # Time is past expired - # The ticket field was taken from the vcr_cassettes/valid_vsac_response file - session[:vsac_tgt] = {ticket: "ST-67360-HgEfelIvwUQ3zz3X39fg-cas", expires: Time.now.utc - 27000} - get :auth_valid - - assert_response :ok - assert_equal false, JSON.parse(response.body)['valid'] - end - - test "force expire vsac session" do - # The ticket field was taken from the vcr_cassettes/valid_vsac_response file - session[:vsac_tgt] = {ticket: "ST-67360-HgEfelIvwUQ3zz3X39fg-cas", expires: Time.now.utc + 27000} - post :auth_expire - - assert_response :ok - assert_equal "{}", response.body - - assert_nil session[:vsac_tgt] - - # Assert that vsac_auth_valid returns that vsac session is invalid - get :auth_valid - - assert_response :ok - assert_equal false, JSON.parse(response.body)['valid'] - end end