From 5a806cf04b30fe6ea22a1be99c0518ba6595715a Mon Sep 17 00:00:00 2001 From: Janet Lu <93942793+j-n-t-l@users.noreply.github.com> Date: Thu, 20 Apr 2023 16:47:44 -0400 Subject: [PATCH 1/3] janet/APPEALS-20062 Create Webhook API (#18468) * APPEALS-20062 added controller and route * APPEALS-20062 updated controller + added rspec test * APPEALS-20062 did a migration and updated logic and rspec * APPEALS-20062 added in notification events to rspec * APPEALS-20062 updated controller and rspec * APPEALS-20062 updated error logging * APPEALS-20062 updated rspec * APPEALS-20062 added comments * APPEALS-20062 typo fix * APPEALS-20062 split up method into smaller ones * APPEALS-20062 created log_error method * APPEALS-20062 moved some methods to private * APPEALS-20062 added success json message * APPEALS-20062 code review changes * APPEALS-20062 added required params * APPEALS-20062 changed to deep_dup * APPEALS-20062 undid required params * APPEALS-20062 added a space * APPEALS-20062 added required_params * APPEALS-20062 alignment issue --------- Co-authored-by: Matthew Thornton --- .../api/v1/va_notify_controller.rb | 69 +++++++++ config/routes.rb | 1 + db/schema.rb | 7 +- .../api/v1/va_notify_controller_spec.rb | 132 ++++++++++++++++++ 4 files changed, 205 insertions(+), 4 deletions(-) create mode 100644 app/controllers/api/v1/va_notify_controller.rb create mode 100644 spec/controllers/api/v1/va_notify_controller_spec.rb diff --git a/app/controllers/api/v1/va_notify_controller.rb b/app/controllers/api/v1/va_notify_controller.rb new file mode 100644 index 00000000000..414e95eb37a --- /dev/null +++ b/app/controllers/api/v1/va_notify_controller.rb @@ -0,0 +1,69 @@ +# frozen_string_literal: true + +class Api::V1::VaNotifyController < Api::ApplicationController + # Purpose: POST request to VA Notify API to update status for a Notification entry + # + # Params: Params content can be found at https://vajira.max.gov/browse/APPEALS-21021 + # + # Response: Update corresponding Notification status + def notifications_update + if required_params[:type] == "email" + email_update + elsif required_params[:type] == "sms" + sms_update + end + end + + private + + # Purpose: Log error in Rails logger and gives 500 error + # + # Params: Notification type string, either "email" or "SMS" + # + # Response: json error message with uuid and 500 error + def log_error(type) + uuid = SecureRandom.uuid + error_msg = "An " + type + "notification with id " + required_params[:id] + + " could not be found. " + "Error ID: " + uuid + Rails.logger.error(error_msg) + render json: { message: error_msg }, status: :internal_server_error + end + + # Purpose: Finds and updates notification if type is email + # + # Params: Params content can be found at https://vajira.max.gov/browse/APPEALS-21021 + # + # Response: Update corresponding email Notification status + def email_update + # find notification through external id + notif = Notification.find_by(email_notification_external_id: required_params[:id]) + # log external id if notification doesn't exist + return log_error(required_params[:type]) unless notif + + # update notification if it exists + notif.update!(email_notification_status: required_params[:status]) + render json: { message: "Email notification successfully updated: ID " + required_params[:id] } + end + + # Purpose: Finds and updates notification if type is SMS + # + # Params: Params content can be found at https://vajira.max.gov/browse/APPEALS-21021 + # + # Response: Update corresponding SMS Notification status + def sms_update + # find notification through external id + notif = Notification.find_by(sms_notification_external_id: required_params[:id]) + # log external id if notification doesn't exist + return log_error(required_params[:type]) unless notif + + # update notification if it exists + notif.update!(sms_notification_status: params[:status]) + render json: { message: "SMS notification successfully updated: ID " + required_params[:id] } + end + + def required_params + id_param, type_param, status_param = params.require([:id, :type, :status]) + + { id: id_param, type: type_param, status: status_param } + end +end diff --git a/config/routes.rb b/config/routes.rb index 95e02eaea14..88c42e81d0d 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -26,6 +26,7 @@ resources :appeals, only: :index resources :jobs, only: :create post 'mpi', to: 'mpi#veteran_updates' + post 'va_notify_update', to: 'va_notify#notifications_update' end namespace :v2 do resources :appeals, only: :index diff --git a/db/schema.rb b/db/schema.rb index a3711114e08..eafc2b8ab21 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -91,7 +91,7 @@ t.boolean "appeal_docketed", default: false, null: false, comment: "When true, appeal has been docketed" t.bigint "appeal_id", null: false, comment: "AMA or Legacy Appeal ID" t.string "appeal_type", null: false, comment: "Appeal Type (Appeal or LegacyAppeal)" - t.datetime "created_at", null: false + t.datetime "created_at", null: false, comment: "Date and Time the record was inserted into the table" t.bigint "created_by_id", null: false, comment: "User id of the user that inserted the record" t.boolean "decision_mailed", default: false, null: false, comment: "When true, appeal has decision mail request complete" t.boolean "hearing_postponed", default: false, null: false, comment: "When true, appeal has hearing postponed and no hearings scheduled" @@ -100,7 +100,7 @@ t.boolean "privacy_act_complete", default: false, null: false, comment: "When true, appeal has a privacy act request completed" t.boolean "privacy_act_pending", default: false, null: false, comment: "When true, appeal has a privacy act request still open" t.boolean "scheduled_in_error", default: false, null: false, comment: "When true, hearing was scheduled in error and none scheduled" - t.datetime "updated_at" + t.datetime "updated_at", comment: "Date and time the record was last updated" t.bigint "updated_by_id", comment: "User id of the last user that updated the record" t.boolean "vso_ihp_complete", default: false, null: false, comment: "When true, appeal has a VSO IHP request completed" t.boolean "vso_ihp_pending", default: false, null: false, comment: "When true, appeal has a VSO IHP request pending" @@ -1275,7 +1275,7 @@ t.string "recipient_email", comment: "Participant's Email Address" t.string "recipient_phone_number", comment: "Participants Phone Number" t.text "sms_notification_content", comment: "Full SMS Text Content of Notification" - t.string "sms_notification_external_id", comment: "VA Notify Notification Id for the sms notification send through their API " + t.string "sms_notification_external_id" t.string "sms_notification_status", comment: "Status of SMS/Text Notification" t.datetime "updated_at", comment: "TImestamp of when Notification was Updated" t.index ["appeals_id", "appeals_type"], name: "index_appeals_notifications_on_appeals_id_and_appeals_type" @@ -1577,7 +1577,6 @@ t.boolean "national_cemetery_administration", default: false t.boolean "no_special_issues", default: false, comment: "Affirmative no special issues, added belatedly" t.boolean "nonrating_issue", default: false - t.boolean "pact_act", default: false, comment: "The Sergeant First Class (SFC) Heath Robinson Honoring our Promise to Address Comprehensive Toxics (PACT) Act" t.boolean "pension_united_states", default: false t.boolean "private_attorney_or_agent", default: false t.boolean "radiation", default: false diff --git a/spec/controllers/api/v1/va_notify_controller_spec.rb b/spec/controllers/api/v1/va_notify_controller_spec.rb new file mode 100644 index 00000000000..6b8165b7c9c --- /dev/null +++ b/spec/controllers/api/v1/va_notify_controller_spec.rb @@ -0,0 +1,132 @@ +# frozen_string_literal: true + +describe Api::V1::VaNotifyController, type: :controller do + before do + Seeds::NotificationEvents.new.seed! + end + let(:api_key) { ApiKey.create!(consumer_name: "API Consumer").key_string } + let!(:appeal) { create(:appeal) } + let!(:notification_email) do + create( + :notification, + appeals_id: appeal.uuid, + appeals_type: "Appeal", + event_date: "2023-02-27 13:11:51.91467", + event_type: "Quarterly Notification", + notification_type: "Email", + notified_at: "2023-02-28 14:11:51.91467", + email_notification_external_id: "3fa85f64-5717-4562-b3fc-2c963f66afa6", + email_notification_status: "No Claimant Found" + ) + end + let!(:notification_sms) do + create( + :notification, + appeals_id: appeal.uuid, + appeals_type: "Appeal", + event_date: "2023-02-27 13:11:51.91467", + event_type: "Quarterly Notification", + notification_type: "Email", + notified_at: "2023-02-28 14:11:51.91467", + sms_notification_external_id: "3fa85f64-5717-4562-b3fc-2c963f66afa6", + sms_notification_status: "Preferences Declined" + ) + end + let(:default_payload) do + { + id: "3fa85f64-5717-4562-b3fc-2c963f66afa6", + body: "string", + completed_at: "2023-04-17T12:38:48.699Z", + created_at: "2023-04-17T12:38:48.699Z", + created_by_name: "string", + email_address: "user@example.com", + line_1: "string", + line_2: "string", + line_3: "string", + line_4: "string", + line_5: "string", + line_6: "string", + phone_number: "+16502532222", + postage: "string", + postcode: "string", + reference: "string", + scheduled_for: "2023-04-17T12:38:48.699Z", + sent_at: "2023-04-17T12:38:48.699Z", + sent_by: "string", + status: "created", + subject: "string", + type: "" + } + end + context "email notification status is changed" do + let(:payload_email) do + default_payload.deep_dup.tap do |payload| + payload[:type] = "email" + end + end + it "updates status of notification" do + request.headers["Authorization"] = "Bearer #{api_key}" + post :notifications_update, params: payload_email + notification_email.reload + expect(notification_email.email_notification_status).to eq("created") + end + end + + context "sms notification status is changed" do + let(:payload_sms) do + default_payload.deep_dup.tap do |payload| + payload[:type] = "sms" + end + end + it "updates status of notification" do + request.headers["Authorization"] = "Bearer #{api_key}" + post :notifications_update, params: payload_sms + notification_sms.reload + expect(notification_sms.sms_notification_status).to eq("created") + end + end + context "notification does not exist" do + let(:payload_fake) do + { + "id": "fake", + "body": "string", + "completed_at": "2023-04-17T12:38:48.699Z", + "created_at": "2023-04-17T12:38:48.699Z", + "created_by_name": "string", + "email_address": "user@example.com", + "line_1": "string", + "line_2": "string", + "line_3": "string", + "line_4": "string", + "line_5": "string", + "line_6": "string", + "phone_number": "+16502532222", + "postage": "string", + "postcode": "string", + "recipient_identifiers": [ + { + "id_type": "VAPROFILEID", + "id_value": "string" + } + ], + "reference": "string", + "scheduled_for": "2023-04-17T12:38:48.699Z", + "sent_at": "2023-04-17T12:38:48.699Z", + "sent_by": "string", + "status": "created", + "subject": "string", + "template": { + "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", + "uri": "string", + "version": 0 + }, + "type": "sms" + } + end + it "updates status of notification" do + request.headers["Authorization"] = "Bearer #{api_key}" + post :notifications_update, params: payload_fake + expect(response.status).to eq(500) + end + end +end From 9e409a54a9e728c7d955e34cec7cbbe7d01296f8 Mon Sep 17 00:00:00 2001 From: Matthew Thornton <99351305+ThorntonMatthew@users.noreply.github.com> Date: Wed, 3 May 2023 14:19:22 -0400 Subject: [PATCH 2/3] type to notification_type (#18546) Co-authored-by: Matthew Thornton --- .../api/v1/va_notify_controller.rb | 18 ++--- .../api/v1/va_notify_controller_spec.rb | 69 ++++++++++--------- 2 files changed, 46 insertions(+), 41 deletions(-) diff --git a/app/controllers/api/v1/va_notify_controller.rb b/app/controllers/api/v1/va_notify_controller.rb index 414e95eb37a..b8d18399b27 100644 --- a/app/controllers/api/v1/va_notify_controller.rb +++ b/app/controllers/api/v1/va_notify_controller.rb @@ -7,9 +7,9 @@ class Api::V1::VaNotifyController < Api::ApplicationController # # Response: Update corresponding Notification status def notifications_update - if required_params[:type] == "email" + if required_params[:notification_type] == "email" email_update - elsif required_params[:type] == "sms" + elsif required_params[:notification_type] == "sms" sms_update end end @@ -21,10 +21,10 @@ def notifications_update # Params: Notification type string, either "email" or "SMS" # # Response: json error message with uuid and 500 error - def log_error(type) + def log_error(notification_type) uuid = SecureRandom.uuid - error_msg = "An " + type + "notification with id " + required_params[:id] + - " could not be found. " + "Error ID: " + uuid + error_msg = "An #{notification_type} notification with id #{required_params[:id]} could not be found. " \ + "Error ID: #{uuid}" Rails.logger.error(error_msg) render json: { message: error_msg }, status: :internal_server_error end @@ -38,7 +38,7 @@ def email_update # find notification through external id notif = Notification.find_by(email_notification_external_id: required_params[:id]) # log external id if notification doesn't exist - return log_error(required_params[:type]) unless notif + return log_error(required_params[:notification_type]) unless notif # update notification if it exists notif.update!(email_notification_status: required_params[:status]) @@ -54,7 +54,7 @@ def sms_update # find notification through external id notif = Notification.find_by(sms_notification_external_id: required_params[:id]) # log external id if notification doesn't exist - return log_error(required_params[:type]) unless notif + return log_error(required_params[:notification_type]) unless notif # update notification if it exists notif.update!(sms_notification_status: params[:status]) @@ -62,8 +62,8 @@ def sms_update end def required_params - id_param, type_param, status_param = params.require([:id, :type, :status]) + id_param, notification_type_param, status_param = params.require([:id, :notification_type, :status]) - { id: id_param, type: type_param, status: status_param } + { id: id_param, notification_type: notification_type_param, status: status_param } end end diff --git a/spec/controllers/api/v1/va_notify_controller_spec.rb b/spec/controllers/api/v1/va_notify_controller_spec.rb index 6b8165b7c9c..fccc5c094f1 100644 --- a/spec/controllers/api/v1/va_notify_controller_spec.rb +++ b/spec/controllers/api/v1/va_notify_controller_spec.rb @@ -55,15 +55,17 @@ sent_by: "string", status: "created", subject: "string", - type: "" + notification_type: "" } end + context "email notification status is changed" do let(:payload_email) do default_payload.deep_dup.tap do |payload| - payload[:type] = "email" + payload[:notification_type] = "email" end end + it "updates status of notification" do request.headers["Authorization"] = "Bearer #{api_key}" post :notifications_update, params: payload_email @@ -75,9 +77,10 @@ context "sms notification status is changed" do let(:payload_sms) do default_payload.deep_dup.tap do |payload| - payload[:type] = "sms" + payload[:notification_type] = "sms" end end + it "updates status of notification" do request.headers["Authorization"] = "Bearer #{api_key}" post :notifications_update, params: payload_sms @@ -85,44 +88,46 @@ expect(notification_sms.sms_notification_status).to eq("created") end end + context "notification does not exist" do let(:payload_fake) do { - "id": "fake", - "body": "string", - "completed_at": "2023-04-17T12:38:48.699Z", - "created_at": "2023-04-17T12:38:48.699Z", - "created_by_name": "string", - "email_address": "user@example.com", - "line_1": "string", - "line_2": "string", - "line_3": "string", - "line_4": "string", - "line_5": "string", - "line_6": "string", - "phone_number": "+16502532222", - "postage": "string", - "postcode": "string", - "recipient_identifiers": [ + id: "fake", + body: "string", + completed_at: "2023-04-17T12:38:48.699Z", + created_at: "2023-04-17T12:38:48.699Z", + created_by_name: "string", + email_address: "user@example.com", + line_1: "string", + line_2: "string", + line_3: "string", + line_4: "string", + line_5: "string", + line_6: "string", + phone_number: "+16502532222", + postage: "string", + postcode: "string", + recipient_identifiers: [ { - "id_type": "VAPROFILEID", - "id_value": "string" + id_type: "VAPROFILEID", + id_value: "string" } ], - "reference": "string", - "scheduled_for": "2023-04-17T12:38:48.699Z", - "sent_at": "2023-04-17T12:38:48.699Z", - "sent_by": "string", - "status": "created", - "subject": "string", - "template": { - "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", - "uri": "string", - "version": 0 + reference: "string", + scheduled_for: "2023-04-17T12:38:48.699Z", + sent_at: "2023-04-17T12:38:48.699Z", + sent_by: "string", + status: "created", + subject: "string", + template: { + id: "3fa85f64-5717-4562-b3fc-2c963f66afa6", + uri: "string", + version: 0 }, - "type": "sms" + notification_type: "sms" } end + it "updates status of notification" do request.headers["Authorization"] = "Bearer #{api_key}" post :notifications_update, params: payload_fake From 3fd33a80b0dd970ab545b626bdbb0c1bc9397397 Mon Sep 17 00:00:00 2001 From: Matthew Thornton <99351305+ThorntonMatthew@users.noreply.github.com> Date: Tue, 16 May 2023 09:26:54 -0400 Subject: [PATCH 3/3] lighthouse api update (#18568) (#18570) Co-authored-by: breedbah <123968373+breedbah@users.noreply.github.com> --- config/environments/test.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/environments/test.rb b/config/environments/test.rb index 739eeb2b3fb..a2953a63382 100644 --- a/config/environments/test.rb +++ b/config/environments/test.rb @@ -76,7 +76,7 @@ # Raises error for missing translations # config.action_view.raise_on_missing_translations = true - ENV["VA_DOT_GOV_API_URL"] = "https://staging-api.va.gov/" + ENV["VA_DOT_GOV_API_URL"] = "https://sandbox-api.va.gov/" # For testing uncertification methods ENV["TEST_USER_ID"] = "TEST_USER_ID"