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

Min/APPPEALS-42711 #21285

Merged
merged 17 commits into from
Apr 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
72166d7
APPEALS-42711 adjusted query for webex recordings list
minhazur9 Mar 26, 2024
f0e205c
APPEALS-42711 added rspec tests for webex_conference_link
minhazur9 Mar 27, 2024
b14a68f
APPEALS-42711 some code climate refactors
minhazur9 Mar 27, 2024
979a056
APPEALS-42711 fixed code climate issues and webex service argument re…
minhazur9 Mar 27, 2024
926c8e0
APPEALS-42711 fixed som broken rspec tests
minhazur9 Mar 27, 2024
3709abf
APPEALS-42711 fixed a few code climate issues with mailer
minhazur9 Mar 28, 2024
ce970b9
APPEALS-42711 refactored more code climate issues with mailer and web…
minhazur9 Mar 28, 2024
c31d36a
APPEALS-42711 fixed broken rspec tests and finishing up with clearing…
minhazur9 Mar 28, 2024
2ebd4cd
APPEALS-42711 fixed some broken rspec tests and more code climate issues
minhazur9 Mar 29, 2024
a6ce066
Merge branch 'feature/APPEALS-25121' into min/APPEALS-42711
minhazur9 Mar 29, 2024
7d86c07
APPEALS-42711 changed names of classes and methods to fix code climat…
minhazur9 Mar 29, 2024
3d4325f
APPEALS-42711 changed names of classes and methods to fix code climat…
minhazur9 Mar 29, 2024
9c296c0
APPEALS-42711 changed names of classes and methods to fix code climat…
minhazur9 Mar 29, 2024
8b23f80
APPEALS-42711 added max value back in to webex recordings
minhazur9 Apr 1, 2024
1e3d2bf
APPEALS-42711 added max value back in to webex recordings
minhazur9 Apr 1, 2024
d853be7
min/APPEALS-42711 adjusted query
minhazur9 Apr 1, 2024
04008ad
APPEALS-42711 refactored some code
minhazur9 Apr 2, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions app/controllers/hearings/transcription_files_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ class Hearings::TranscriptionFilesController < ApplicationController

# Downloads file and sends to user's local computer
def download_transcription_file
tmp_location = file.download_from_s3
File.open(tmp_location, "r") { |f| send_data f.read, filename: file.file_name }
tmp_location = file.fetch_file_from_s3!
File.open(tmp_location, "r") { |stream| send_data stream.read, filename: file.file_name }
file.clean_up_tmp_location
end

Expand Down
58 changes: 37 additions & 21 deletions app/jobs/hearings/download_transcription_file_job.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,25 +19,43 @@ class FileDownloadError < StandardError; end
class HearingAssociationError < StandardError; end

retry_on(FileDownloadError, wait: 5.minutes) do |job, exception|
details = build_error_details("retrieve", "vtt", "from", "Webex", "download_file_to_tmp!", exception)
action_hash = {
action: "retrieve",
direction: "from",
filetype: "vtt",
call: "download_file_to_tmp!"
}
details = build_error_details(action_hash, "Webex", exception)
TranscriptFileIssuesMailer.send_issue_details(details, appeal_id)
job.log_error(exception)
end

retry_on(UploadTranscriptionFileToS3::FileUploadError, wait: :exponentially_longer) do |job, exception|
retry_on(TranscriptionFileUpload::FileUploadError, wait: :exponentially_longer) do |job, exception|
job.transcription_file.clean_up_tmp_location
job.log_error(exception)
end

retry_on(TranscriptionTransformer::FileConversionError, wait: 10.seconds) do |job, exception|
job.transcription_file.clean_up_tmp_location
details = build_error_details("convert", "vtt", "to", "rtf", "convert_to_rtf_and_upload_to_s3!", exception)
action_hash = {
action: "convert",
direction: "to",
filetype: "vtt",
call: "convert_to_rtf_and_upload_to_s3!"
}
details = build_error_details(action_hash, "rtf", exception)
TranscriptFileIssuesMailer.send_issue_details(details, appeal_id)
job.log_error(exception)
end

discard_on(FileNameError) do |job, error|
details = build_error_details("retrieve", "vtt", "from", "Webex", "parse_hearing", error)
action_hash = {
action: "retrieve",
direction: "from",
filetype: "vtt",
call: "parse_hearing"
}
details = build_error_details(action_hash, "Webex", error)
TranscriptFileIssuesMailer.send_issue_details(details, appeal_id)
Rails.logger.error("#{job.class.name} (#{job.job_id}) discarded with error: #{error}")
end
Expand All @@ -48,7 +66,7 @@ class HearingAssociationError < StandardError; end
def perform(download_link:, file_name:)
ensure_current_user_is_set
@file_name = file_name
@transcription_file = find_or_create_transcription_file
@transcription_file ||= find_or_create_transcription_file
ensure_hearing_held

download_file_to_tmp!(download_link)
Expand Down Expand Up @@ -84,16 +102,17 @@ def log_error(error)
#
# Returns: Updated @transcription_file
def download_file_to_tmp!(link)
return if File.exist?(@transcription_file.tmp_location)
transcription_file = @transcription_file
return if File.exist?(transcription_file.tmp_location)

URI(link).open do |download|
IO.copy_stream(download, @transcription_file.tmp_location)
IO.copy_stream(download, transcription_file.tmp_location)
end
@transcription_file.update_status!(process: :retrieval, status: :success)
transcription_file.update_status!(process: :retrieval, status: :success)
log_info("File #{file_name} successfully downloaded from Webex. Uploading to S3...")
rescue OpenURI::HTTPError => error
@transcription_file.update_status!(process: :retrieval, status: :failure)
@transcription_file.clean_up_tmp_location
transcription_file.update_status!(process: :retrieval, status: :failure)
transcription_file.clean_up_tmp_location
raise FileDownloadError, "Webex temporary download link responded with error: #{error}"
end

Expand Down Expand Up @@ -153,7 +172,8 @@ def find_or_create_transcription_file(file_name_arg = file_name)
# Returns: integer value of 1 if tmp file deleted after successful upload
def convert_to_rtf_and_upload_to_s3!
log_info("Converting file #{file_name} to rtf...")
file_paths = @transcription_file.convert_to_rtf!
transcription_file = @transcription_file
file_paths = transcription_file.convert_to_rtf!
file_paths.each do |file_path|
output_file_name = file_path.split("/").last
output_file = find_or_create_transcription_file(output_file_name)
Expand Down Expand Up @@ -181,26 +201,23 @@ def log_info(message)
Rails.logger.info(message)
end

# rubocop:disable Metrics/ParameterLists
# Purpose: Builds object detailing error for mail template
# Params:
# action - string, the action that the job was doing
# action_hash - object, hash object for describing the action that was attempted
# filetype - string, the filetype that was getting worked on
# direction - string, either to/from in relative to provider
# provider - string, either the destination or starting point
# call - string, the method call where the error occured
# error - Exception - the error that was raised
#
# Returns: The hash for details on the error
def build_error_details(action, filetype, direction, provider, call, error)
def build_error_details(action_hash, provider, error)
{
action: action,
filetype: filetype,
direction: direction,
action: action_hash[:action],
filetype: action[:filetype],
direction: action_hash[:direction],
provider: provider,
error: error,
docket_number: hearing.docket_number,
api_call: call
api_call: action_hash[:call]
}
end

Expand All @@ -209,5 +226,4 @@ def build_error_details(action, filetype, direction, provider, call, error)
def appeal_id
hearing.appeal.external_id
end
# rubocop:enable Metrics/ParameterLists
end
18 changes: 8 additions & 10 deletions app/jobs/hearings/fetch_webex_recordings_details_job.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ class Hearings::FetchWebexRecordingsDetailsJob < CaseflowJob

# rubocop:disable Layout/LineLength
retry_on(Caseflow::Error::WebexApiError, wait: :exponentially_longer) do |job, exception|
file_name = job.arguments&.first&.[](:file_name)
file_name = @file_name || job.arguments&.first&.[](:file_name)
docket_number, hearing_id, class_name = file_name.split("_")
hearing = if class_name == "Hearing"
Hearing.find_by(id: hearing_id)
Expand All @@ -34,9 +34,9 @@ class Hearings::FetchWebexRecordingsDetailsJob < CaseflowJob
end
# rubocop:enable Layout/LineLength

# rubocop:disable Lint/UnusedMethodArgument
def perform(id:, file_name:)
ensure_current_user_is_set
@file_name ||= file_name
data = fetch_recording_details(id)
topic = data.topic

Expand All @@ -49,31 +49,29 @@ def perform(id:, file_name:)
mp3_link = data.mp3_link
send_file(topic, "mp3", mp3_link)
end
# rubocop:enable Lint/UnusedMethodArgument

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)
super(error, extra: extra)
end

private

def fetch_recording_details(id)
query = { "id": id }

WebexService.new(
config = {
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
).fetch_recording_details
query: { "id": id }
}

WebexService.new(config: config).fetch_recording_details
end

def create_file_name(topic, extension)
Expand Down
28 changes: 12 additions & 16 deletions app/jobs/hearings/fetch_webex_recordings_list_job.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
# 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
# This job will retrieve a list of webex hearing recordings and details every hour

class Hearings::FetchWebexRecordingsListJob < CaseflowJob
include Hearings::EnsureCurrentUserIsSet
Expand All @@ -10,9 +9,10 @@ class Hearings::FetchWebexRecordingsListJob < CaseflowJob
application_attr :hearing_schedule

retry_on(Caseflow::Error::WebexApiError, wait: :exponentially_longer) do |job, exception|
from = 2.days.ago.in_time_zone("America/New_York").end_of_day
to = 1.day.ago.in_time_zone("America/New_York").end_of_day
query = "?from=#{CGI.escape(from.iso8601)}?to=#{CGI.escape(to.iso8601)}"
from = 2.hours.ago.in_time_zone("America/New_York")
to = 1.hour.ago.in_time_zone("America/New_York")
max = 100
query = "?max=#{max}?from=#{CGI.escape(from.iso8601)}?to=#{CGI.escape(to.iso8601)}"
details = {
action: "retrieve",
filetype: "vtt",
Expand All @@ -33,27 +33,23 @@ def perform
response = fetch_recordings_list
topics = response.topics
topic_num = 0
response.ids.each do |n|
Hearings::FetchWebexRecordingsDetailsJob.perform_later(id: n, topic: topics[topic_num])
response.ids.each do |id|
Hearings::FetchWebexRecordingsDetailsJob.perform_later(id: id, topic: topics[topic_num])
topic_num += 1
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)
super(error, extra: { application: self.class.name, job_id: job_id })
end

private

def fetch_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 }
from = CGI.escape(2.hours.ago.in_time_zone("America/New_York").iso8601)
to = CGI.escape(1.hour.ago.in_time_zone("America/New_York").iso8601)
max = 100
query = { "from": from, "to": to, "max": max }

WebexService.new(
host: ENV["WEBEX_HOST_MAIN"],
Expand Down
5 changes: 3 additions & 2 deletions app/jobs/virtual_hearings/conference_client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,16 @@ def client(virtual_hearing)
client_host: ENV["PEXIP_CLIENT_HOST"]
)
when "webex"
@client ||= WebexService.new(
config = {
host: ENV["WEBEX_HOST_IC"],
port: ENV["WEBEX_PORT"],
aud: ENV["WEBEX_ORGANIZATION"],
apikey: ENV["WEBEX_BOTTOKEN"],
domain: ENV["WEBEX_DOMAIN_IC"],
api_endpoint: ENV["WEBEX_API_IC"],
query: nil
)
}
@client ||= WebexService.new(config: config)
else
msg = "Conference Provider for the Virtual Hearing Not Found"
fail Caseflow::Error::MeetingTypeNotFoundError, message: msg
Expand Down
51 changes: 26 additions & 25 deletions app/mailers/transcript_file_issues_mailer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,50 +9,51 @@ class TranscriptFileIssuesMailer < ActionMailer::Base
# off the template to the above recipients
def send_issue_details(details, appeal_id)
@details = details
@case_link = case Rails.deploy_env
when :demo
"https://demo.appeals.va.gov/appeals/#{appeal_id}"
when :uat
"https://appeals.cf.uat.ds.va.gov/queue/appeals/#{appeal_id}"
when :prod
"https://appeals.cf.ds.va.gov/queue/appeals/#{appeal_id}"
when :prodtest
"https://appeals.cf.prodtest.ds.va.gov/queue/appeals/#{appeal_id}"
when :preprod
"https://appeals.cf.preprod.ds.va.gov/queue/appeals/#{appeal_id}"
else
"localhost:3000/queue/appeals/#{appeal_id}"
end
@config = mailer_config(appeal_id)
@case_link = @config[:link]
@subject = "File #{details[:action]} Error - #{details[:provider]} #{details[:docket_number]}"
mail(subject: @subject, to: to_email_address, cc: cc_email_address) do |format|
mail(subject: @subject, to: @config[:to_email_address], cc: @config[:cc_email_address]) do |format|
format.html { render "layouts/transcript_file_issues" }
end
end

# Handles specifically the transcript recording list issues
def webex_recording_list_issues(details)
@details = details
@config = mailer_config(nil)
@subject = "File #{details[:action]} Error - #{details[:provider]}"
mail(subject: @subject, to: to_email_address, cc: cc_email_address) do |format|
mail(subject: @subject, to: @config[:to_email_address], cc: @config[:cc_email_address]) do |format|
format.html { render "layouts/transcript_file_issues" }
end
end

# The email address to send mail to
def to_email_address
def mailer_config(appeal_id)
case Rails.deploy_env
when :demo, :development, :test
"Caseflow@test.com"
when :development, :demo, :test
{ link: non_external_link(appeal_id), to_email_address: "Caseflow@test.com" }
when :uat
"BID_Appeals_UAT@bah.com"
{
link: "https://appeals.cf.uat.ds.va.gov/queue/appeals/#{appeal_id}",
to_email_address: "BID_Appeals_UAT@bah.com"
}
when :prodtest
{ link: "https://appeals.cf.prodtest.ds.va.gov/queue/appeals/#{appeal_id}" }
when :preprod
{ link: "https://appeals.cf.preprod.ds.va.gov/queue/appeals/#{appeal_id}" }
when :prod
"BVAHearingTeam@VA.gov"
{
link: "https://appeals.cf.ds.va.gov/queue/appeals/#{appeal_id}",
to_email_address: "BVAHearingTeam@VA.gov",
cc_email_address: "OITAppealsHelpDesk@va.gov"
}
end
end

# The email address to cc
def cc_email_address
"OITAppealsHelpDesk@va.gov" if Rails.deploy_env == :prod
# The link for the case details page when not in prod or uat
def non_external_link(appeal_id)
return "https://demo.appeals.va.gov/appeals/#{appeal_id}" if Rails.deploy_env == :demo

"localhost:3000/queue/appeals/#{appeal_id}"
end
end

Expand Down
2 changes: 1 addition & 1 deletion app/models/concerns/hearing_concern.rb
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ def calculate_submission_window
# Associate hearing with transcription files across multiple dockets and order accordingly
def transcription_files_by_docket_number
# Remove hyphen in case of counter at end of file name to allow for alphabetical sort
transcription_files.sort_by { |f| f.file_name.split("-").join }.group_by(&:docket_number).values
transcription_files.sort_by { |file| file.file_name.split("-").join }.group_by(&:docket_number).values
end

# Group transcription files by docket number before mapping through nested array and serializing
Expand Down
4 changes: 2 additions & 2 deletions app/models/hearings/transcription_file.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,14 @@ class TranscriptionFile < CaseflowRecord

# Purpose: Fetches file from S3
# Return: The temporary save location of the file
def download_from_s3
def fetch_file_from_s3!
S3Service.fetch_file(aws_link, tmp_location)
tmp_location
end

# Purpose: Uploads transcription file to its corresponding location in S3
def upload_to_s3!
UploadTranscriptionFileToS3.new(self).call
TranscriptionFileUpload.new(self).call
end

# Purpose: Converts transcription file from vtt to rtf
Expand Down
6 changes: 4 additions & 2 deletions app/models/hearings/webex_conference_link.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,16 @@ def guest_link
def generate_conference_information
meeting_type.update!(service_name: "webex")

conference_response = WebexService.new(
config = {
host: ENV["WEBEX_HOST_IC"],
port: ENV["WEBEX_PORT"],
aud: ENV["WEBEX_ORGANIZATION"],
apikey: ENV["WEBEX_BOTTOKEN"],
domain: ENV["WEBEX_DOMAIN_IC"],
api_endpoint: ENV["WEBEX_API_IC"]
).create_conference(hearing)
}

conference_response = WebexService.new(config: config).create_conference(hearing)

update!(
host_link: conference_response.host_link,
Expand Down
Loading
Loading