diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 62ccb2d3b8..9231b35e33 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -1,6 +1,6 @@ # This configuration was generated by # `rubocop --auto-gen-config --auto-gen-only-exclude --exclude-limit 1000` -# on 2024-04-24 16:19:07 UTC using RuboCop version 1.63.3. +# on 2024-05-21 08:38:48 UTC using RuboCop version 1.63.5. # The point is for the user to remove these configuration records # one by one as the offenses are removed from the code base. # Note that changes in the inspected code, or installation of new @@ -244,10 +244,11 @@ Metrics/AbcSize: - 'spec/support/seed_helpers.rb' - 'spec/support/validation_helpers.rb' -# Offense count: 19 +# Offense count: 20 # Configuration parameters: CountComments, Max, CountAsOne. Metrics/ClassLength: Exclude: + - 'app/controllers/case_workers/claims_controller.rb' - 'app/controllers/external_users/claims_controller.rb' - 'app/interfaces/api/entities/search_result.rb' - 'app/interfaces/api/v1/dropdown_data.rb' diff --git a/Gemfile b/Gemfile index 778453978e..517b82bd42 100644 --- a/Gemfile +++ b/Gemfile @@ -61,6 +61,7 @@ gem 'active_storage_validations' gem 'faraday', '~> 2.10' gem 'faraday-follow_redirects', '~> 0.3' gem 'puma' +gem 'oauth2' group :development, :test do gem 'annotate' diff --git a/Gemfile.lock b/Gemfile.lock index 55701b5854..ac93069d1f 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -381,6 +381,8 @@ GEM msgpack (1.7.2) multi_json (1.15.0) multi_test (1.1.0) + multi_xml (0.7.1) + bigdecimal (~> 3.1) multipart-post (2.4.1) mustermann (3.0.0) ruby2_keywords (~> 0.0.1) @@ -407,6 +409,13 @@ GEM racc (~> 1.4) notifications-ruby-client (6.2.0) jwt (>= 1.5, < 3) + oauth2 (2.0.9) + faraday (>= 0.17.3, < 3.0) + jwt (>= 1.0, < 3.0) + multi_xml (~> 0.5) + rack (>= 1.2, < 4) + snaky_hash (~> 2.0) + version_gem (~> 1.1) orm_adapter (0.5.0) paper_trail (15.1.0) activerecord (>= 6.1) @@ -597,6 +606,9 @@ GEM capybara (~> 3.32) site_prism-all_there (> 2, < 5) site_prism-all_there (3.0.5) + snaky_hash (2.0.1) + hashie + version_gem (~> 1.1, >= 1.1.1) sprockets (4.2.1) concurrent-ruby (~> 1.0) rack (>= 2.2.4, < 4) @@ -637,6 +649,7 @@ GEM activesupport vcr (6.3.0) base64 + version_gem (1.1.4) virtus (2.0.0) axiom-types (~> 0.1) coercible (~> 1.0) @@ -725,6 +738,7 @@ DEPENDENCIES net-smtp net-ssh (~> 7.2) nokogiri (~> 1.16) + oauth2 paper_trail (~> 15.1.0) parallel_tests pg (~> 1.5.7) diff --git a/app/controllers/case_workers/claims_controller.rb b/app/controllers/case_workers/claims_controller.rb index 6061416712..92813f3808 100644 --- a/app/controllers/case_workers/claims_controller.rb +++ b/app/controllers/case_workers/claims_controller.rb @@ -16,6 +16,7 @@ class ClaimsController < CaseWorkers::ApplicationController before_action :filter_archived_claims, only: [:archived] before_action :sort_claims, only: %i[index archived] before_action :set_claim, only: %i[show messages download_zip] + before_action :set_show_maat_details include ReadMessages include MessageControlsDisplay @@ -131,5 +132,14 @@ def sort_claims def criteria_params { sorting: sort_column, direction: sort_direction, page: current_page, limit: page_size, search: search_terms } end + + def set_show_maat_details + if params[:maat_details].present? + @show_maat_details = params[:maat_details] == 'on' + current_user.save_setting!(maat_details: @show_maat_details) + else + @show_maat_details = current_user.setting?(:maat_details) || false + end + end end end diff --git a/app/services/maat_service.rb b/app/services/maat_service.rb index 8ac57929a5..bd3db05341 100644 --- a/app/services/maat_service.rb +++ b/app/services/maat_service.rb @@ -11,7 +11,8 @@ def call { case_number: data['caseId'], - representation_order_date: data['crownRepOrderDate'] + representation_order_date: data['crownRepOrderDate'], + asn: data['arrestSummonsNo'] } end end diff --git a/app/services/maat_service/connection.rb b/app/services/maat_service/connection.rb index be84ccd3b3..d96335a249 100644 --- a/app/services/maat_service/connection.rb +++ b/app/services/maat_service/connection.rb @@ -3,35 +3,22 @@ class Connection include Singleton def fetch(maat_reference) - JSON.parse(client.get("assessment/rep-orders/#{maat_reference}").body) - rescue Faraday::ConnectionFailed + JSON.parse(access.get("assessment/rep-orders/#{maat_reference}").body) + rescue OAuth2::Error {} end private - def client - @client ||= Faraday.new(Settings.maat_api_url, request: { timeout: 2 }) do |conn| - conn.headers['Authorization'] = "Bearer #{oauth_token}" - end - end - - def oauth_token - response = Faraday.post(Settings.maat_api_oauth_url, request_params, request_headers) - JSON.parse(response.body)['access_token'] - end + def access = @access ||= client.client_credentials.get_token - def request_params - { - client_id: Settings.maat_api_oauth_client_id, - client_secret: Settings.maat_api_oauth_client_secret, - scope: Settings.maat_api_oauth_scope, - grant_type: 'client_credentials' - } - end - - def request_headers - { content_type: 'application/x-www-form-urlencoded' } + def client + @client ||= OAuth2::Client.new( + Settings.maat_api_oauth_client_id, + Settings.maat_api_oauth_client_secret, + site: Settings.maat_api_url, + token_url: Settings.maat_api_oauth_url + ) end end end diff --git a/app/views/shared/_claim.html.haml b/app/views/shared/_claim.html.haml index bbca000b72..d07e073df9 100644 --- a/app/views/shared/_claim.html.haml +++ b/app/views/shared/_claim.html.haml @@ -84,7 +84,12 @@ %h3.govuk-heading-m = t('.defendants') - = render partial: 'shared/claim_defendants', locals: {defendants: claim.defendants } + - if @show_maat_details + = govuk_link_to t('.disable_maat_details'), '?maat_details=off' + = render partial: 'shared/claim_defendants_with_maat', locals: {defendants: claim.defendants } + - else + = govuk_link_to t('.enable_maat_details'), '?maat_details=on' + = render partial: 'shared/claim_defendants', locals: {defendants: claim.defendants } - else .govuk-grid-row diff --git a/app/views/shared/_claim_defendant_details_with_maat.html.haml b/app/views/shared/_claim_defendant_details_with_maat.html.haml new file mode 100644 index 0000000000..8b0fcf95f4 --- /dev/null +++ b/app/views/shared/_claim_defendant_details_with_maat.html.haml @@ -0,0 +1,37 @@ +.app-card--defendant + %h4.govuk-heading-s + = t('.defendant', context: index) + + = govuk_summary_list do + = govuk_summary_list_row_collection( t('external_users.claims.defendants.defendant_fields.full_name') ) { defendant.name } + + - if defendant.date_of_birth.present? + = govuk_summary_list_row_collection( t('external_users.claims.defendants.defendant_fields.date_of_birth') ) { defendant.date_of_birth.strftime(Settings.date_format) rescue '' } + + - unless @claim.lgfs? && @claim.interim? + = govuk_summary_list_row_collection( t('external_users.claims.defendants.defendant_fields.judical_apportionment') ) { defendant.order_for_judicial_apportionment == true ? t('global_yes') : t('global_no') } + + + - if defendant.representation_orders.any? + = govuk_table do + = govuk_table_caption do + = t('shared.claim.reporders') + + = govuk_table_thead_collection [t('.date'), + t('external_users.claims.defendants.representation_order_fields.maat_reference_number'), + t('.asn')] + + = govuk_table_tbody do + - defendant.representation_orders.each do | representation_order | + = govuk_table_row do + = govuk_table_td('data-label': t('.date')) do + = representation_order.representation_order_date.strftime(Settings.date_format) rescue '' + + = govuk_table_td('data-label': t('external_users.claims.defendants.representation_order_fields.maat_reference_number')) do + = representation_order.maat_reference + + = govuk_table_td('data-label': t('.asn')) do + = representation_order.maat_details[:asn] + + - else + = govuk_inset_text(t('.no_reporder')) diff --git a/app/views/shared/_claim_defendants.html.haml b/app/views/shared/_claim_defendants.html.haml index 7d89a46759..699acc6d4d 100644 --- a/app/views/shared/_claim_defendants.html.haml +++ b/app/views/shared/_claim_defendants.html.haml @@ -1,3 +1,3 @@ - defendants.each_with_index do | defendant, index | .govuk-grid-column-one-half - = render partial: 'shared/claim_defendant_details', locals: { defendant: present(defendant, CaseWorkers::DefendantPresenter), index: index += 1 } + = render partial: 'shared/claim_defendant_details', locals: { defendant:, index: index += 1 } diff --git a/app/views/shared/_claim_defendants_with_maat.html.haml b/app/views/shared/_claim_defendants_with_maat.html.haml new file mode 100644 index 0000000000..836880bfb4 --- /dev/null +++ b/app/views/shared/_claim_defendants_with_maat.html.haml @@ -0,0 +1,3 @@ +- defendants.each_with_index do | defendant, index | + .govuk-grid-column-one-half + = render partial: 'shared/claim_defendant_details_with_maat', locals: { defendant: present(defendant, CaseWorkers::DefendantPresenter), index: index += 1 } diff --git a/config/locales/en.yml b/config/locales/en.yml index dc9786dd45..fbecafae6e 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -2026,11 +2026,20 @@ en: banner_paragraph: This is to enable routine maintenance work to be carried out. Please save and close any work before this time. claim_defendants: defendants: Defendants + enable_maat_details: Enable MAAT details (experimental) + disable_maat_details: Disable MAAT details (experimental) claim_defendant_details: caption: 'Defendant: Additional information' date: Order date defendant: Defendant %{context} no_reporder: No representation orders have been supplied for this defendant. + claim_defendant_details_with_maat: + caption: 'Defendant: Additional information' + date: Order date + defendant: Defendant %{context} + no_reporder: No representation orders have been supplied for this defendant. + case_number_from_maat: Case number from MAAT (experimental) + asn: ASN (experimental) evidence_checklist: caption: 'Supporting evidence checklist' summary: 'Note: To best navigate this table, step down the second column' @@ -2100,6 +2109,8 @@ en: submit_date: Claim submitted trial_concluded: Trial concluded prosecution_evidence: Prosecution evidence + enable_maat_details: Enable MAAT details (experimental) + disable_maat_details: Disable MAAT details (experimental) claims: interim_claim_info: fields: *interim_claim_info_fields diff --git a/config/settings.yml b/config/settings.yml index 1144f96cc6..0ca38be721 100644 --- a/config/settings.yml +++ b/config/settings.yml @@ -234,7 +234,6 @@ maat_regexp: !ruby/regexp <%= ENV['MAAT_REGEXP'] || '/^[2-9][0-9]{6}$/' %> maat_api_url: <%= ENV['MAAT_API_URL'] %> maat_api_oauth_client_id: <%= ENV['OAUTH_CLIENT_ID'] %> maat_api_oauth_client_secret: <%= ENV['OAUTH_CLIENT_SECRET'] %> -maat_api_oauth_scope: <%=ENV['OAUTH_SCOPE'] %> maat_api_oauth_url: <%=ENV['OAUTH_URL']%> secret_key_base: <%= ENV["SECRET_KEY_BASE"] %> diff --git a/spec/services/maat_service_spec.rb b/spec/services/maat_service_spec.rb index 6b89974ffa..3d8e0c999f 100644 --- a/spec/services/maat_service_spec.rb +++ b/spec/services/maat_service_spec.rb @@ -1,8 +1,21 @@ RSpec.describe MaatService do before do - allow(Settings).to receive_messages(maat_api_url: 'https://example.com', maat_api_oauth_url: 'https://example.com/oauth') - stub_request(:post, 'https://example.com/oauth') - .to_return(body: { access_token: 'test_token' }.to_json) + allow(OAuth2::Client).to receive(:new).and_return( + OAuth2::Client.new( + Settings.maat_api_oauth_client_id, + Settings.maat_api_oauth_client_secret, + site: 'https://example.com', + token_url: 'https://example.com/oauth' + ) + ) + stub_request(:post, 'https://example.com/oauth').to_return( + body: { + access_token: 'test-token', + expires_in: 3600, + token_type: 'Bearer' + }.to_json, + headers: { 'content-type': 'application/json' } + ) end describe '.call' do @@ -14,10 +27,16 @@ context 'with a valid MAAT reference' do before do stub_request(:get, "https://example.com/assessment/rep-orders/#{maat_reference}") - .to_return(body: { caseId: 'TEST12345678', crownRepOrderDate: '2024-03-28' }.to_json) + .to_return( + body: { + caseId: 'TEST12345678', + crownRepOrderDate: '2024-03-28', + arrestSummonsNo: 'ABCDEF' + }.to_json + ) end - it { is_expected.to eq({ case_number: 'TEST12345678', representation_order_date: '2024-03-28' }) } + it { is_expected.to eq({ case_number: 'TEST12345678', representation_order_date: '2024-03-28', asn: 'ABCDEF' }) } end context 'with a valid MAAT reference with no date' do @@ -26,7 +45,7 @@ .to_return(body: { caseId: 'TEST12345678' }.to_json) end - it { is_expected.to eq({ case_number: 'TEST12345678', representation_order_date: nil }) } + it { is_expected.to eq({ case_number: 'TEST12345678', representation_order_date: nil, asn: nil }) } end context 'with an unknown MAAT reference' do @@ -35,7 +54,7 @@ .to_return(status: 404, body: { message: "No Rep Order found for ID: #{maat_reference}" }.to_json) end - it { is_expected.to eq({ case_number: nil, representation_order_date: nil }) } + it { is_expected.to eq({ case_number: nil, representation_order_date: nil, asn: nil }) } end context 'when unauthorized' do @@ -44,18 +63,20 @@ .to_return(status: 401, body: { message: 'Unauthorized' }.to_json) end - it { is_expected.to eq({ case_number: nil, representation_order_date: nil }) } + it { is_expected.to eq({ case_number: nil, representation_order_date: nil, asn: nil }) } end context 'when the OAuth settings are not correct' do before do stub_request(:post, 'https://example.com/oauth') - .to_return(status: 400, body: { error: 'invalid_client' }.to_json) - stub_request(:get, "https://example.com/assessment/rep-orders/#{maat_reference}") - .to_return(status: 401, body: { message: 'Unauthorized' }.to_json) + .to_return( + status: 400, + body: { error: 'invalid_client' }.to_json, + headers: { 'content-type': 'application/json' } + ) end - it { is_expected.to eq({ case_number: nil, representation_order_date: nil }) } + it { is_expected.to eq({ case_number: nil, representation_order_date: nil, asn: nil }) } end end end