Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

akonhilas/APPEALS-38906 #20664

Merged
merged 10 commits into from
Feb 8, 2024
54 changes: 54 additions & 0 deletions app/jobs/hearings/get_webex_recordings_list_job.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# frozen_string_literal: true

# This job will retrieve a list of webex hearing recordings and details
# in a 24 hours period from the previous day

class Hearings::GetWebexRecordingsListJob < CaseflowJob
include Hearings::EnsureCurrentUserIsSet

queue_with_priority :low_priority
application_attr :hearing_schedule

retry_on(Caseflow::Error::WebexApiError, wait: :exponentially_longer) do |job, exception|
# TO IMPLEMENT: SEND EMAIL TO VA OPS TEAM
job.log_error(exception)
end

def perform
ensure_current_user_is_set
get_recordings_list.ids.each do |n|
get_recording_details(n)
end
end

def log_error(error)
Rails.logger.error("Retrying #{self.class.name} because failed with error: #{error}")
extra = {
application: self.class.name,
job_id: job_id
}
Raven.capture_exception(error, extra: extra)
end

private

def get_recordings_list
from = CGI.escape(2.days.ago.in_time_zone("America/New_York").end_of_day.iso8601)
to = CGI.escape(1.day.ago.in_time_zone("America/New_York").end_of_day.iso8601)
query = { "from": from, "to": to }

WebexService.new(
host: ENV["WEBEX_HOST_MAIN"],
port: ENV["WEBEX_PORT"],
aud: ENV["WEBEX_ORGANIZATION"],
apikey: ENV["WEBEX_BOTTOKEN"],
domain: ENV["WEBEX_DOMAIN_MAIN"],
api_endpoint: ENV["WEBEX_API_MAIN"],
query: query
).get_recordings_list
end

def get_recording_details(id)
nil
end
end
3 changes: 2 additions & 1 deletion app/jobs/virtual_hearings/conference_client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ def client(virtual_hearing)
aud: ENV["WEBEX_ORGANIZATION"],
apikey: ENV["WEBEX_BOTTOKEN"],
domain: ENV["WEBEX_DOMAIN_IC"],
api_endpoint: ENV["WEBEX_API_IC"]
api_endpoint: ENV["WEBEX_API_IC"],
query: nil
)
else
msg = "Conference Provider for the Virtual Hearing Not Found"
Expand Down
34 changes: 27 additions & 7 deletions app/services/external_api/webex_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@
require "json"

class ExternalApi::WebexService
def initialize(host:, port:, aud:, apikey:, domain:, api_endpoint:)
def initialize(host:, port:, aud:, apikey:, domain:, api_endpoint:, query:)
@host = host
@port = port
@aud = aud
@apikey = apikey
@domain = domain
@api_endpoint = api_endpoint
@query = query
end

def create_conference(conferenced_item)
Expand All @@ -25,7 +26,9 @@ def create_conference(conferenced_item)
"verticalType": "gen"
}

resp = send_webex_request(body)
method = "POST"

resp = send_webex_request(body, method)
return if resp.nil?

ExternalApi::WebexService::CreateResponse.new(resp)
Expand All @@ -43,30 +46,47 @@ def delete_conference(conferenced_item)
"provideShortUrls": true,
"verticalType": "gen"
}
resp = send_webex_request(body)

method = "POST"

resp = send_webex_request(body, method)
return if resp.nil?

ExternalApi::WebexService::DeleteResponse.new(resp)
end

def get_recordings_list
body = nil
method = "GET"
resp = send_webex_request(body, method)
return if resp.nil?

ExternalApi::WebexService::RecordingsListResponse.new(resp)
end

private

# :nocov:
def send_webex_request(body = nil)
def send_webex_request(body, method)
url = "https://#{@host}#{@domain}#{@api_endpoint}"
request = HTTPI::Request.new(url)
request.open_timeout = 300
request.read_timeout = 300
request.body = body.to_json unless body.nil?

request.query = @query
request.headers = { "Authorization": "Bearer #{@apikey}", "Content-Type": "application/json" }

MetricsService.record(
"#{@host} POST request to #{url}",
"#{@host} #{method} request to #{url}",
service: :webex,
name: @api_endpoint
) do
HTTPI.post(request)
case method
when "POST"
HTTPI.post(request)
when "GET"
HTTPI.get(request)
end
end
end
# :nocov:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# frozen_string_literal: true

class ExternalApi::WebexService::RecordingsListResponse < ExternalApi::WebexService::Response
def data
JSON.parse(resp.raw_body)
end

def ids
data["items"].pluck("id")
end
end
3 changes: 2 additions & 1 deletion config/initializers/scheduled_jobs.rb
Original file line number Diff line number Diff line change
Expand Up @@ -52,5 +52,6 @@
"cannot_delete_contention_remediation_job" => CannotDeleteContentionRemediationJob,
"contention_not_found_remediation_job" => ContentionNotFoundRemediationJob,
"process_notification_status_updates_job" => ProcessNotificationStatusUpdatesJob,
"stuck_job_scheduler_job" => StuckJobSchedulerJob
"stuck_job_scheduler_job" => StuckJobSchedulerJob,
"get_webex_recordings_list_job" => Hearings::GetWebexRecordingsListJob
}.freeze
97 changes: 97 additions & 0 deletions lib/fakes/webex_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,103 @@ def delete_conference(virtual_hearing)
)
end

def get_recordings_list
if error?
return ExternalApi::WebexService::RecordingsListResponse.new(
HTTPI::Response.new(@status_code, {}, error_response)
)
end

ExternalApi::WebexService::RecordingsListResponse.new(
HTTPI::Response.new(
200,
{},
fake_recordings_list_data.to_json
)
)
end

# rubocop:disable Metrics/MethodLength
def fake_recordings_list_data
{
"items": [
{
"id": "4f914b1dfe3c4d11a61730f18c0f5387",
"meetingId": "f91b6edce9864428af084977b7c68291_I_166641849979635652",
"scheduledMeetingId": "f91b6edce9864428af084977b7c68291_20200713T121500Z",
"meetingSeriesId": "f91b6edce9864428af084977b7c68291",
"topic": "200103-61110_2000061110_Appeal",
"createTime": "2020-07-13T17:11:35Z",
"timeRecorded": "2020-07-13T17:05:35Z",
"siteUrl": "site4-example.webex.com",
"downloadUrl": "https://site4-example.webex.com/site4/lsr.php?RCID=b91990e37417bda24986e46cf43345ab",
"playbackUrl": "https://site4-example.webex.com/site4/ldr.php?RCID=69201a61d1d94a84aca18817261d1a73",
"password": "BgJep@43",
"format": "ARF",
"serviceType": "MeetingCenter",
"durationSeconds": 18_416,
"sizeBytes": 168_103,
"shareToMe": false,
"integrationTags": [
"dbaeceebea5c4a63ac9d5ef1edfe36b9",
"85e1d6319aa94c0583a6891280e3437d",
"27226d1311b947f3a68d6bdf8e4e19a1"
],
"status": "available"
},
{
"id": "3324fb76946249cfa07fc30b3ccbf580",
"meetingId": "f91b6edce9864428af084977b7c68291_I_166641849979635652",
"scheduledMeetingId": "f91b6edce9864428af084977b7c68291_20200713T121500Z",
"meetingSeriesId": "f91b6edce9864428af084977b7c68291",
"topic": "150000248290335_343_LegacyAppeal",
"createTime": "2020-07-13T17:11:34Z",
"timeRecorded": "2020-07-13T17:05:35Z",
"siteUrl": "site4-example.webex.com",
"downloadUrl": "https://site4-example.webex.com/site4/lsr.php?RCID=8a763939dec1fa26c565700d628fcb98",
"playbackUrl": "https://site4-example.webex.com/site4/ldr.php?RCID=b05e9c4f773745e7b88725cc97bc3161",
"password": "BgJep@43",
"format": "ARF",
"serviceType": "MeetingCenter",
"durationSeconds": 181_562,
"sizeBytes": 199_134,
"shareToMe": false,
"integrationTags": [
"dbaeceebea5c4a63ac9d5ef1edfe36b9",
"85e1d6319aa94c0583a6891280e3437d",
"27226d1311b947f3a68d6bdf8e4e19a1"
],
"status": "available"
},
{
"id": "42b80117a2a74dcf9863bf06264f8075",
"meetingId": "f91b6edce9864428af084977b7c68291_I_166641849979635652",
"scheduledMeetingId": "f91b6edce9864428af084977b7c68291_20200713T121500Z",
"meetingSeriesId": "f91b6edce9864428af084977b7c68291",
"topic": "231207-1177_1177_Appeal",
"createTime": "2020-07-13T17:11:33Z",
"timeRecorded": "2020-07-13T17:05:35Z",
"siteUrl": "site4-example.webex.com",
"downloadUrl": "https://site4-example.webex.com/site4/lsr.php?RCID=0edd48adbb183e7da97884a0a984e877",
"playbackUrl": "https://site4-example.webex.com/site4/ldr.php?RCID=b64b28ebf70e4645954420c295a9fcad",
"password": "BgJep@4",
"format": "ARF",
"serviceType": "MeetingCenter",
"durationSeconds": 181_562,
"sizeBytes": 199_134,
"shareToMe": true,
"integrationTags": [
"dbaeceebea5c4a63ac9d5ef1edfe36b9",
"85e1d6319aa94c0583a6891280e3437d",
"27226d1311b947f3a68d6bdf8e4e19a1"
],
"status": "available"
}
]
}
end
# rubocop:enable Metrics/MethodLength

private

def build_meeting_response
Expand Down
30 changes: 30 additions & 0 deletions spec/jobs/hearings/get_webex_recordings_list_job_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# frozen_string_literal: true

describe Hearings::GetWebexRecordingsListJob, type: :job do
include ActiveJob::TestHelper

subject { described_class.perform_now }

it "Returns the correct array of ids" do
expect(subject).to eq(%w[4f914b1dfe3c4d11a61730f18c0f5387 3324fb76946249cfa07fc30b3ccbf580 42b80117a2a74dcf9863bf06264f8075])
end

context "job errors" do
before do
allow_any_instance_of(WebexService)
.to receive(:get_recordings_list)
.and_raise(Caseflow::Error::WebexApiError.new(code: 400, message: "Fake Error"))
end

it "Successfully catches errors and adds retry to queue" do
subject
expect(enqueued_jobs.size).to eq(1)
end

it "retries and logs errors" do
subject
expect(Rails.logger).to receive(:error).with(/Retrying/)
perform_enqueued_jobs { described_class.perform_later }
end
end
end
Loading
Loading