Top Level Namespace

Defined Under Namespace

Modules: Accountable, Adapters, Apps, AsyncProcessing, AsyncRequest, AsyncTransaction, Auth, AuthenticationAndSSOConcerns, Authorization, BB, BGS, BGSDependents, BID, BenefitsClaims, BenefitsDocuments, BenefitsIntakeService, BenefitsReferenceData, BipClaims, Breakers, CARMA, Caseflow, CentralMail, Chip, ClaimFastTracking, ClaimLetterTestData, ClaimStatusTool, ClaimsApi, ClaimsServiceProvider, Common, ConfigHelper, ConvertFileType, CopayNotifications, CoreExtensions, CypressViewportUpdater, DebtManagementCenter, DecisionReview, DecisionReviewV1, DirectDeposit, DisabilityCompensation, EMIS, EMISRedis, EVSS, EducationForm, Efolder, ExceptionHandling, ExternalServicesRedis, Facilities, FacilitiesQuery, FailedRequestLoggable, Faraday, FaradayAdapterSocks, FeatureFlipper, Filterable, Flipper, FlipperExtensions, Form1010Ezr, Form1010cg, Form1095, Form526BackupSubmission, Form526ClaimFastTrackingConcern, FormAttachmentCreate, FormDurations, Formatters, Forms, GI, Gibft, GithubAuthentication, HCA, Headers, IAMSSOeOAuth, IHub, Identity, IgnoreNotFound, IncomeLimits, InheritedProofing, Instrumentation, IntentToFileProvider, JsonMarshal, JsonSchema, KmsEncryptedModelPatch, KmsKeyRotation, LGY, Lighthouse, LoadTest, LogMetrics, Logging, Login, MAP, MDOT, MHV, MHVAC, MHVControllerConcerns, MHVLogging, MPI, MailAutomation, MedicalCopays, MedicalRecords, ModuleHelper, OIDC, Okta, OktaRedis, OliveBranch, OliveBranchMiddlewareExtension, PDFUtilities, PHRMgr, PPIUProvider, PagerDuty, PdfFill, PdfInfo, PensionBurial, Preneeds, RatedDisabilitiesProvider, RedisCaching, RedisForm, ReencodeImages, Reports, Requests, Rx, SAML, SFTPWriter, SM, Salesforce, Search, SearchClickTracking, SearchTypeahead, Sentry, SentryControllerLogging, SentryLogging, SetAWSConfig, SetGuid, Sidekiq, SidekiqStatsInstrumentation, SignIn, SimpleFormsApiSubmission, Slack, StringHelpers, StructuredData, Swagger, TempFormValidation, TermsOfUse, TestUserDashboard, TokenValidation, Traceable, Types, UploaderVirusScan, Users, V0, V1, VA0873, VA0994, VA1010Forms, VA10203, VA1990s, VA21686c, VA526ez, VAProfile, VAProfileRedis, VBMS, VBS, VEText, VIC, VRE, ValidatePdf, Vet360, VeteranVerification, VirtualRegionalOffice, Webhooks Classes: AcceptableVerifiedCredentialAdoptionService, Account, AccountLoginStat, AccountLoginStatisticsJob, AddressSerializer, Aes256CbcEncryptor, AllTriageTeams, ApiProviderFactory, AppealSerializer, AppealSubmission, AppealSubmissionUpload, AppealsBaseController, AppealsBaseControllerV1, AppealsPolicy, ApplicationController, ApplicationMailer, ApplicationRecord, AppointmentSerializer, Attachment, AttachmentSerializer, BBController, BGSPolicy, BackendServices, BackendStatus, BackendStatusSerializer, BackendStatusesSerializer, BankName, BaseFacility, BenefitsIntakeStatusJob, Category, CategorySerializer, CemeterySerializer, CentralMailClaim, CentralMailSubmission, CentralMailSubmissionSerializer, Ch31Error, Ch31NilClaimError, Ch31SubmissionsReportMailer, Ch33BankAccountSerializer, Ch33DdPolicy, ClaimsBaseController, CoePolicy, CollectionSerializer, CommunicationGroupsSerializer, CommunicationPreferencesPolicy, ContactSerializer, ControllerCreateException, ControllerException, CountriesSerializer, CreateDailySpoolFilesMailer, CreateStagingSpoolFilesMailer, CredentialAdoptionEmailRecord, DebtLettersPolicy, DebtPolicy, DecisionReviewEvidenceAttachment, DecisionReviewEvidenceAttachmentSerializer, DecisionReviewEvidenceAttachmentUploader, DeleteAttachmentJob, DeleteOldPiiLogsJob, DeleteOldTransactionsJob, DemographicsPolicy, DependentsApplication, DependentsApplicationFailureMailer, DependentsApplicationSerializer, DependentsSerializer, DependentsVerificationsSerializer, DeprecatedUserAccount, DirectDepositEmailJob, DirectDepositMailer, DisabilityCompensationsSerializer, DisabilityContention, DisabilityContentionSerializer, DrivetimeBand, EVSSClaim, EVSSClaimBaseSerializer, EVSSClaimDetailSerializer, EVSSClaimDocument, EVSSClaimDocumentUploader, EVSSClaimDocumentUploaderBase, EVSSClaimListSerializer, EVSSClaimService, EVSSClaimServiceAsync, EVSSClaimsSyncStatusTracker, EVSSPolicy, EVSSSeparationLocationSerializer, EducationBenefitsClaim, EducationBenefitsClaimSerializer, EducationBenefitsSubmission, EducationStemAutomatedDecision, EducationStemClaimStatusSerializer, EligibleDataClass, EligibleDataClassesSerializer, EmailSerializer, EvssClaimsServiceProvider, EvssIntentToFileProvider, EvssPPIUProvider, EvssRatedDisabilitiesProvider, ExpiryScanner, ExportBreakerStatus, ExternalServicesStatusJob, ExtractStatus, ExtractStatusSerializer, FacilitiesController, FacilityDentalService, FacilityMentalHealth, FacilitySatisfaction, FacilityWaitTime, FailedClaimsReportMailer, FeatureCleanerJob, FeatureToggleEvent, FlipperController, Folder, FolderNameConventionValidator, FolderSerializer, Form1095B, Form1095Policy, Form526ConfirmationEmailJob, Form526JobStatus, Form526JobStatusSerializer, Form526Submission, Form526SubmissionFailedEmailJob, Form5655Submission, FormAddress, FormAttachment, FormContactInformation, FormDate, FormFullName, FormIdentityInformation, FormMilitaryInformation, FormProfile, FormSubmission, FormSubmissionAttempt, FullNameSerializer, GIBillFeedback, GIBillFeedbackSerializer, GIBillFeedbackSubmissionJob, GIDSController, GIDSRedis, GenderIdentitySerializer, GetContestableIssuesSchemaValidationError, GibsNotFoundUser, HCAAttachment, HCAAttachmentSerializer, HCAAttachmentUploader, HCADisabilityRatingPolicy, HCARatingInfoSerializer, HCASubmissionFailureMailer, HealthCareApplication, HealthCareApplicationSerializer, HlrContestableIssuesControllerIndexException, HttpMethodNotAllowed, IAMSession, IAMUser, IAMUserIdentity, IdCardAnnouncementSubscription, IdCardAttributes, IdentifierIndex, InProgressForm, InProgressFormCleaner, InProgressFormSerializer, InheritedProofVerifiedUserAccount, InheritedProofingController, IntentToFileSerializer, InvalidLetterAddressEdipi, LetterBeneficiarySerializer, LettersSerializer, LighthouseClaimsServiceProvider, LighthouseDocument, LighthouseDocumentUploader, LighthouseDocumentUploaderBase, LighthouseIntentToFileProvider, LighthousePPIUProvider, LighthousePolicy, LighthouseRatedDisabilitiesProvider, LighthouseRatingInfoSerializer, MHVAccountTypeService, MHVHealthRecordsPolicy, MHVLoggingService, MHVMessagingPolicy, MHVOptInFlag, MHVPrescriptionsPolicy, MPIData, MPIPolicy, MaintenanceWindow, MaintenanceWindowSerializer, MebPolicy, MedicalCopaysPolicy, Message, MessageDraft, MessageSearch, MessageSerializer, MessageThread, MessageThreadDetails, MessagesSerializer, MessagingPreference, MessagingPreferenceSerializer, ModuleComponentGenerator, ModuleGenerator, OktaAppSerializer, OldEmail, OnsiteNotification, OnsiteNotificationSerializer, OpenidUser, OpenidUserIdentity, PPIUPolicy, PPIUSerializer, PaymentHistory, PaymentHistorySerializer, PciuAddressLineValidator, PermissionSerializer, PersistentAttachment, PersistentAttachmentSerializer, PersonalInformationLog, PersonalInformationSerializer, PhoneNumberSerializer, PiiLog, Post911GIBillStatusSerializer, PowerOfAttorney, PreferredNameSerializer, PreneedAttachmentSerializer, PreneedAttachmentUploader, PreneedsController, Prescription, PrescriptionDetails, PrescriptionPreference, PrescriptionPreferenceSerializer, PrescriptionSerializer, ProcessFileJob, ProfilePhotoAttachmentSerializer, RateLimitedSearch, RatedDisabilitiesSerializer, RatingInfoSerializer, ReceiveApplicationSerializer, RrdAlertMailer, RrdMasNotificationMailer, RxController, SAMLRequestTracker, SMController, SavedClaim, SavedClaimSerializer, SchemaCamelizer, SchoolCertifyingOfficialsMailer, ScrubbedString, SearchSerializer, SentryJob, ServiceHistorySerializer, Session, ShellCommand, Shrine, SidekiqStatsJob, SingleLogoutRequest, Spool10203SubmissionsReportMailer, SpoolFileEvent, SpoolSubmissionsReportMailer, StatesSerializer, StatsDMetric, StatsdMiddleware, StemApplicantConfirmationMailer, StemApplicantDenialMailer, StemApplicantScoMailer, SubmitDisabilityFormSerializer, SupportingDocumentationAttachmentSerializer, SupportingEvidenceAttachment, SupportingEvidenceAttachmentSerializer, SupportingEvidenceAttachmentUploader, TermsOfUseAgreement, TimeArg, TokenUtil, Tracking, TrackingSerializer, TransactionNotification, TransactionalEmailAnalyticsJob, TransactionalEmailMailer, TriageTeam, TriageTeamSerializer, User, UserAcceptableVerifiedCredential, UserAccount, UserCredentialEmail, UserIdentity, UserProfileAttributeService, UserProfileAttributes, UserRelationship, UserSerializer, UserSessionForm, UserVerification, VANotifyDdEmailJob, VANotifyEmailJob, VAProfilePolicy, ValidVAFileNumberSerializer, Vet360Policy, VeteranReadinessEmploymentMailer, VetsShrine, YearToDateReportMailer, ZipcodesSerializer

Constant Summary collapse

PERIODIC_JOBS =

rubocop:disable Metrics/BlockLength

lambda { |mgr|
  mgr.tz = ActiveSupport::TimeZone.new('America/New_York')

  mgr.register('*/15 * * * *', 'CovidVaccine::ScheduledBatchJob')
  mgr.register('*/15 * * * *', 'CovidVaccine::ExpandedScheduledSubmissionJob')
  mgr.register('*/30 * * * *', 'SidekiqAlive::CleanupQueues')

  mgr.register('5 * * * *', 'AppealsApi::HigherLevelReviewUploadStatusBatch')
  # Update HigherLevelReview statuses with their Central Mail status
  mgr.register('10 * * * *', 'AppealsApi::NoticeOfDisagreementUploadStatusBatch')
  # Update NoticeOfDisagreement statuses with their Central Mail status
  mgr.register('15 * * * *', 'AppealsApi::SupplementalClaimUploadStatusBatch')
  # Update SupplementalClaim statuses with their Central Mail status
  mgr.register('45 0 * * *', 'AppealsApi::HigherLevelReviewCleanUpWeekOldPii')
  # Remove PII of HigherLevelReviews that have 1) reached one of the 'completed' statuses and 2) are a week old
  mgr.register('45 0 * * *', 'AppealsApi::NoticeOfDisagreementCleanUpWeekOldPii')
  # Remove PII of NoticeOfDisagreements that have 1) reached one of the 'completed' statuses and 2) are a week old
  mgr.register('45 0 * * *', 'AppealsApi::SupplementalClaimCleanUpPii')
  # Ensures that appeal evidence received "late" (after the appeal has reached "success") is submitted to Central Mail
  mgr.register('30 * * * *', 'AppealsApi::EvidenceSubmissionBackup')
  # Remove PII of SupplementalClaims that have 1) reached one of the 'completed' statuses and 2) are a week old
  mgr.register('0 23 * * 1-5', 'AppealsApi::DecisionReviewReportDaily')
  # Daily report of appeals submissions
  mgr.register('0 23 * * 1-5', 'AppealsApi::DailyErrorReport')
  # Daily report of appeals errors
  mgr.register('0 8 * * 1-5', 'AppealsApi::DailyStuckRecordsReport')
  # Daily report of all stuck appeals submissions
  mgr.register('0 23 * * 7', 'AppealsApi::DecisionReviewReportWeekly')
  # Weekly report of appeals submissions
  mgr.register('0 5 * * 1', 'AppealsApi::WeeklyErrorReport')
  # Weekly CSV report of errored appeal submissions
  mgr.register('0 0 1 * *', 'AppealsApi::MonthlyStatsReport')
  # Email a decision reviews stats report for the past month to configured recipients first of the month
  mgr.register('0 2,9,16 * * 1-5', 'AppealsApi::FlipperStatusAlert')
  # Checks status of Flipper features expected to be enabled and alerts to Slack if any are not enabled

  mgr.register('0 0 * * *', 'BenefitsIntakeStatusJob')
  # Updates status of FormSubmissions per call to Lighthouse Benefits Intake API

  # mgr.register('0 0 * * *', 'VRE::CreateCh31SubmissionsReportJob')

  mgr.register('0 0 * * *', 'EducationForm::DeleteOldApplications')
  # Clear out processed 22-1990 applications that are older than 1 month

  mgr.register('20 0 * * *', 'TestUserDashboard::DailyMaintenance')
  # Checks in TUD users that weren't properly checked in.
  mgr.register('0 0 1 */3 *', 'IncomeLimits::GmtThresholdsImport')
  # Import income limit data CSVs from S3
  mgr.register('0 0 1 */3 *', 'IncomeLimits::StdCountyImport')
  # Import income limit data CSVs from S3
  mgr.register('0 0 1 */3 *', 'IncomeLimits::StdIncomeThresholdImport')
  # Import income limit data CSVs from S3
  mgr.register('0 0 1 */3 *', 'IncomeLimits::StdStateImport')
  # Import income limit data CSVs from S3
  mgr.register('0 0 1 */3 *', 'IncomeLimits::StdZipcodeImport')
  # Import income limit data CSVs from S3

  mgr.register('0 2 * * *', 'EVSS::DeleteOldClaims')
  # Clear out EVSS disability claims that have not been updated in 24 hours
  mgr.register('20 2 * * *', 'DeleteOldPiiLogsJob')
  # Clear out old personal information logs
  mgr.register('0 3 * * MON-FRI', 'EducationForm::CreateDailySpoolFiles')

  mgr.register('0 3 * * *', 'DeleteOldTransactionsJob')
  # Deletes old, completed AsyncTransaction records

  mgr.register('30 3 * * 1', 'EVSS::FailedClaimsReport')
  # Notify developers about EVSS claims which could not be uploaded

  mgr.register('0 4 * * *', 'EducationForm::CreateDailyFiscalYearToDateReport')
  # Send the daily report to VA stakeholders about Education Benefits submissions
  mgr.register('5 4 * * 1-5', 'EducationForm::CreateSpoolSubmissionsReport')
  # Send the daily report to the call center about spool file submissions
  mgr.register('10 4 * * *', 'Facilities::DentalServiceReloadJob')
  # Download and cache facility access-to-care metric data
  mgr.register('25 4 * * *', 'Facilities::MentalHealthReloadJob')
  # Download and cache facility mental health phone number data
  mgr.register('35 4 * * 1-5', 'EducationForm::Create10203SpoolSubmissionsReport')
  # Send the daily 10203 report to the call center about spool file submissions
  mgr.register('45 4 * * *', 'Facilities::AccessDataDownload')
  # Download and cache facility access-to-care metric data
  mgr.register('55 4 * * *', 'Facilities::PSSGDownload')
  # Download and store drive time bands

  mgr.register('0 6 * * *', 'AccountLoginStatisticsJob')
  # Gather account login statistics for statsd

  mgr.register('0 6-18/6 * * *', 'EducationForm::Process10203Submissions')

  mgr.register('* 7 * * *', 'SignIn::DeleteExpiredSessionsJob')
  # Delete expired sessions

  mgr.register('0 12 3 * *', 'CypressViewportUpdater::UpdateCypressViewportsJob')
  # Updates Cypress files in vets-website with data from Google Analytics.
  mgr.register('0 13 * * 1', 'Mobile::V0::WeeklyMaintenanceWindowLogger')
  # Weekly logs of maintenance windows
  mgr.register('0 20 * * *', 'ClaimsApi::ClaimAuditor')
  # Daily alert of pending claims longer than acceptable threshold
  mgr.register('15 23 * * *', 'ClaimsApi::ReportUnsuccessfulSubmissions')
  # Weekly report of unsuccessful claims submissions
  mgr.register('15 23 1 * *', 'ClaimsApi::ReportMonthlySubmissions')
  # Weekly report of unsuccessful claims submissions

  mgr.register('30 2 * * *', 'Identity::UserAcceptableVerifiedCredentialTotalsJob')

  # VAForms Module
  mgr.register('0 2 * * *', 'VAForms::FormReloader')
  # Fetches latest VA forms from Drupal database and updates vets-api forms database
  mgr.register('0 2,9,16 * * 1-5', 'VAForms::FlipperStatusAlert')
  # Checks status of Flipper features expected to be enabled and alerts to Slack if any are not enabled

  mgr.register('0 16 * * *', 'VANotify::InProgressForms')
  mgr.register('0 1 * * *', 'VANotify::ClearStaleInProgressRemindersSent')
  mgr.register('0 * * * *', 'VANotify::InProgress1880Form')

  mgr.register('0 * * * *', 'CovidVaccine::ExpandedSubmissionStateJob')

  mgr.register('0 * * * *', 'PagerDuty::CacheGlobalDowntime')
  mgr.register('*/3 * * * *', 'PagerDuty::PollMaintenanceWindows')

  mgr.register('0 2 * * *', 'InProgressFormCleaner')
  mgr.register('0 */4 * * *', 'MHV::AccountStatisticsJob')
  mgr.register('0 3 * * *', 'Form1095::New1095BsJob')
  mgr.register('0 2 * * *', 'Veteran::VSOReloader')
  mgr.register('15 2 * * *', 'Preneeds::DeleteOldUploads')

  mgr.register('* * * * *', 'ExternalServicesStatusJob')
  mgr.register('* * * * *', 'ExportBreakerStatus')

  # Disable FeatureCleanerJob. https://github.com/department-of-veterans-affairs/va.gov-team/issues/53538
  # mgr.register('0 0 * * *', 'FeatureCleanerJob')
  mgr.register('0 0 * * *', 'Form1010cg::DeleteOldUploadsJob')
  mgr.register('0 1 * * *', 'TransactionalEmailAnalyticsJob')

  # VBADocuments Module
  mgr.register('45 * * * *', 'VBADocuments::UploadStatusBatch')
  # Request updated statuses for benefits intake submissions
  mgr.register('5 */2 * * *', 'VBADocuments::RunUnsuccessfulSubmissions')
  # Run VBADocuments::UploadProcessor for submissions that are stuck in uploaded status
  mgr.register('*/2 * * * *', 'VBADocuments::UploadScanner')
  # Poll upload bucket for unprocessed uploads
  mgr.register('*/2 * * * *', 'VBADocuments::UploadRemover')
  # Clean up submitted documents from S3
  mgr.register('0 0 * * 1-5', 'VBADocuments::ReportUnsuccessfulSubmissions')
  # Daily/weekly report of unsuccessful benefits intake submissions
  mgr.register('0 2 1 * *', 'VBADocuments::ReportMonthlySubmissions')
  # Monthly report of benefits intake submissions
  mgr.register('0 2,9,16 * * 1-5', 'VBADocuments::SlackNotifier')
  # Notifies slack channel if certain benefits states get stuck
  mgr.register('0 2,9,16 * * 1-5', 'VBADocuments::FlipperStatusAlert')
  # Checks status of Flipper features expected to be enabled and alerts to Slack if any are not enabled

  # Rotates Lockbox/KMS record keys and _ciphertext fields every October 12th (when the KMS key auto-rotate)
  mgr.register('0 3 * * *', 'KmsKeyRotation::BatchInitiatorJob')

  # Updates veteran representatives and organizations address attributes (including lat, long, location)
  # Updates veteran representatives email address
  mgr.register('0 3 * * *', 'RepOrgAddresses::QueueAddressUpdates')
}
Q =
PersonalInformationLogQueryBuilder
TIME_ARGS_ARRAY_BUILDER =
lambda do |array_for_collecting_time_args|
  # closure for array_for_collecting_time_args
  lambda do |arg|
    if array_for_collecting_time_args.length == 2
      raise "can only specify a start and a stop time. extra time param: #{arg.inspect}"
    end

    time_arg = case arg
               when nil
                 TimeArg.new type: :open
               when String, Symbol
                 string = arg.to_s.downcase
                 case string
                 when 'now'
                   TimeArg.new time: Time.zone.now, type: :time
                 when 'yesterday', 'today', 'tomorrow'
                   TimeArg.new time: Time.zone.send(string), type: :date
                 else
                   parsed = if string.include?(':')
                              begin
                                { time: string.in_time_zone, type: :time }
                              rescue
                                nil
                              end
                            else
                              begin
                                { time: string.to_date, type: :date }
                              rescue
                                nil
                              end
                            end
                   return false unless parsed

                   TimeArg.new(**parsed)
                 end
               else
                 if arg.respond_to?(:strftime)
                   TimeArg.new time: arg, type: arg.respond_to?(:min) ? :time : :date
                 elsif arg.is_a?(ActiveSupport::Duration)
                   TimeArg.new time: arg, type: :duration
                 else
                   return false
                 end
               end

    array_for_collecting_time_args << time_arg
    true
  end
end
TIMES_TO_WHERE_ARGS =
lambda do |times|
  a, b = times.map(&:time)
  types = times.map(&:type)

  start_time, stop_time = case types
                          when [], %i[open open]
                            [nil, nil]
                          when %i[date]
                            [a.beginning_of_day, a.end_of_day]
                          when %i[duration], %i[duration open]
                            [Time.zone.now - a, nil]
                          when %i[open]
                            raise "open-ended time range wasn't completed"
                          when %i[time]
                            if a.min.zero? && a.hour.zero?
                              [a.beginning_of_day, a.end_of_day]
                            elsif a.sec != 0
                              [a.beginning_of_minute, a.end_of_minute]
                            elsif a.min.zero?
                              [a.beginning_of_hour, a.end_of_hour]
                            elsif (a.min % 5).zero?
                              [a - 5.minutes, a + 5.minutes]
                            else
                              [a - 1.minute, a + 1.minute]
                            end
                          when %i[date date]
                            [a.beginning_of_day, b.end_of_day]
                          when %i[date duration]
                            start = a.beginning_of_day
                            [start, start + b]
                          when %i[date open]
                            [a.beginning_of_day, nil]
                          when %i[date time]
                            [a.beginning_of_day, b]
                          when %i[duration date]
                            stop = b.end_of_day
                            [stop - a, stop]
                          when %i[duration duration]
                            start = Time.zone.now - a
                            [start, start + b]
                          when %i[duration time]
                            [b - a, b]
                          when %i[open date]
                            [nil, b.end_of_day]
                          when %i[open duration]
                            [nil, Time.zone.now - a]
                          when %i[open time]
                            [nil, b]
                          when %i[time date]
                            [a, b.end_of_day]
                          when %i[time duration]
                            [a, a + b]
                          when %i[time open]
                            [a, nil]
                          when %i[time time]
                            [a, b]
                          else
                            raise "unknown types: #{types.inspect}"
                          end

  result_struct = Struct.new(:args, :kwargs, keyword_init: true)

  return result_struct.new unless start_time || stop_time
  return result_struct.new args: ['created_at >= ?', start_time] unless stop_time
  return result_struct.new args: ['created_at <= ?', stop_time] unless start_time

  result_struct.new kwargs: { created_at: [start_time..stop_time] }
end
PersonalInformationLogQueryBuilder =
lambda do |*args, **where_kwargs|
  query, args = if args.first.respond_to? :to_sql
                  [args.first, args[1..]]
                else
                  [PersonalInformationLog.all, args]
                end

  query = query.where(**where_kwargs) if where_kwargs.present?

  times = []
  # add_time is a lambda that takes in an arg
  # --if it's a time, adds it to times and returns true. otherwise returns false
  add_time = TIME_ARGS_ARRAY_BUILDER.call(times)

  error_class = []
  args.each do |arg|
    next if add_time.call(arg)

    case arg
    when String, Symbol
      error_class << "%#{arg}%"
    else
      raise "don't know what to do with arg: #{arg.inspect}"
    end
  end

  query = query.where('error_class ILIKE ANY (array[?])', error_class) if error_class.present?

  where_args = TIMES_TO_WHERE_ARGS.call(times)
  query = query.where(*where_args.args) if where_args.args
  query = query.where(**where_args.kwargs) if where_args.kwargs

  query
end

Instance Method Summary collapse

Instance Method Details

#_pObject



10
# File 'rakelib/decision_review_repl.rb', line 10

alias _p p

#_ppObject



11
# File 'rakelib/decision_review_repl.rb', line 11

alias _pp pp

#by_error_class(array) ⇒ Object

takes in an array of wrapped-PiiLogs and returns a hash where they’re sorted by error_class and then by error message category



383
384
385
386
387
388
389
390
391
392
393
# File 'rakelib/decision_review_repl.rb', line 383

def by_error_class(array)
  new_hash = Hash.new do |hash, key|
    hash[key] = Hash.new { |hash, key| hash[key] = [] }
  end

  array.each do |piilog|
    new_hash[piilog.error_class][piilog.error_message_category] << piilog
  end

  new_hash
end

#by_error_class_counts(array) ⇒ Object



410
411
412
# File 'rakelib/decision_review_repl.rb', line 410

def by_error_class_counts(array)
  counts by_error_class array
end

#by_error_message_category(array) ⇒ Object

takes in an array of wrapped-PiiLogs and returns a hash where they’re sorted by error message category



396
397
398
399
400
401
402
403
404
# File 'rakelib/decision_review_repl.rb', line 396

def by_error_message_category(array)
  new_hash = Hash.new { |hash, key| hash[key] = [] }

  array.each do |piilog|
    new_hash[piilog.error_message_category] << piilog
  end

  new_hash
end

#by_error_message_category_counts(array) ⇒ Object



422
423
424
# File 'rakelib/decision_review_repl.rb', line 422

def by_error_message_category_counts(array)
  counts by_error_message_category array
end

#counts(hash) ⇒ Object

recurses through a hash and, anytime an array is encountered, it’s replaced with its count



209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
# File 'rakelib/decision_review_repl.rb', line 209

def counts(hash)
  hash.reduce({}) do |acc, (k, v)|
    count = case v
            when Array
              v.count
            when Hash
              counts(v)
            else
              v
            end
    acc.merge k => count
  end.sort_by do |_k, v|
    -(v.is_a?(Hash) ? total_in_tree(v) : v)
  end.to_h
end

#moreObject



193
194
195
# File 'rakelib/decision_review_repl.rb', line 193

def more
  puts more_string
end

#more_stringObject



130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
# File 'rakelib/decision_review_repl.rb', line 130

def more_string
  <<~MORE


    # Q is an alias for the PersonalInformationLogQueryBuilder --a lambda that makes it easier to write
    # queries for PersonalInformationLog.

    logs = Q.(:hlr, 7.days)     # returns a PersonalInformationLog relation

    logs = Q.(:hlr, updated_at: nil)     # kwargs work just as they do with where

    logs = Q.(:hlr, :nod).where('updated_at > ?' Time.zone.yesterday)   # chainable. (that's HLR /or/ NOD PiiLogs)



    # PersonalInformationLogs are hard to wrangle because so much data gets dumped into their 'data' attributes.

    # In 'decision_review_repl.rb', there are a handful of PersonalInformationLog "wrapper classes" that add
    # helper methods for "specific types" of PersonalInformationLogs (PiiLogs recorded in the controller as
    # opposed to the service, for instance) (Note: I use PiiLog and PersonalInformationLog interchangeably
    # although there /is/ a PiiLog class). You can use '.helper_methods' on a PiiLog or scroll through
    # 'decision_review_repl.rb' to see what they offer, /BUT/, you do *not* need to explicitly call them. The
    # wrap command will /wrap/ a PersonalInformationLog (or Logs) with the appropriate wrapper class. With `wrap`,
    # you end up with an array of PersonalInformationLog /SimpleDelegator/ objects that are simply
    # PersonalInformationLogs with added methods --added methods that are appropriate for each PiiLog.
    # For instance, a PiiLog logged in a controller will have user info helper methods (as the 'data' attribute
    # has user info). If the PiiLog was recorded near the schema code in the Service class, the PiiLog will have
    # schema helper methods that help you navigate the PiiLog's data.

    logs = wrap Q.(:hlr)  # returns an array with helper methods added to each PersonalInformationLog
                          # depending on its type (was it thrown in a controller, the service, etc.)


    # There are a slew of methods that work with an array of wrapped PiiLogs.
    # for instance:

    hash = by_error_message_category(wrap(Q.call(:hlr, :yesterday))) # notice the "wrap" nestled in there

    # this will return a hash that organizes the array of PiiLogs by their error message category
    # if you pretty-print it, it will look something like:

    p hash

    # {"Outage..."=>
    #   [#<PersonalInformationLog:0x0000000000000000
    #     id: 0000000,
    #     data:
    #      {"user"=>
    #        {"icn"=> ...
    #         "ssn"=> ...
    #      ...
    #   [#<PersonalInformationLog:0x0000000000000000
    #      ...
    #  "Timeout"=> ...


    # see "spec/rakelib/piilog_repl/piilog_helpers_spec.rb" for more examples of using
    # the PersonalInformationLogQueryBuilder


  MORE
end

#p(object) ⇒ Object

Ruby pretty print that doesn’t echo the value after pretty printing it



198
199
200
201
# File 'rakelib/decision_review_repl.rb', line 198

def p(object)
  _pp object
  nil
end

#pp(object) ⇒ Object

pretty print using pretty_generate



204
205
206
# File 'rakelib/decision_review_repl.rb', line 204

def pp(object)
  puts JSON.pretty_generate object
end

#puts_by_error_class(array) ⇒ Object



406
407
408
# File 'rakelib/decision_review_repl.rb', line 406

def puts_by_error_class(array)
  puts by_error_class array
end

#puts_by_error_class_counts(array) ⇒ Object



414
415
416
# File 'rakelib/decision_review_repl.rb', line 414

def puts_by_error_class_counts(array)
  puts counts by_error_class array
end

#puts_by_error_message_category(array) ⇒ Object



418
419
420
# File 'rakelib/decision_review_repl.rb', line 418

def puts_by_error_message_category(array)
  puts by_error_message_category array
end

#puts_by_error_message_category_counts(array) ⇒ Object



426
427
428
# File 'rakelib/decision_review_repl.rb', line 426

def puts_by_error_message_category_counts(array)
  puts counts by_error_message_category array
end

#recipesObject



126
127
128
# File 'rakelib/decision_review_repl.rb', line 126

def recipes
  puts recipes_string
end

#recipes_stringObject



13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# File 'rakelib/decision_review_repl.rb', line 13

def recipes_string
  <<~RECIPES

    #############
    #  RECIPES  #
    #############



    # 🍝 get an HLR piilog that was created right now (roughly)

    logs = Q.(:hlr, :now)   # builds/returns a PersonalInformationLog relation
                            # this will give you the time range of the current minute.
                            # beside timestamp strings you can use :now, :today, :yesterday,
                            # :tomorrow as well as any time/date obj




    # 🍛 get all piilogs that have an error_class that includes either the string
    # "DocumentUploader" or "nod" (ILIKE) that was created between two dates

    logs = Q.('DocumentUploader', 'nod', '2021-03-14', '2021-03-15')   # you can pass up to 2 time arguments
                                                                       # which can be time, date, duration
                                                                       # or even nil (to express an open-ended
                                                                       # range)




    # 🌯 get all NOD piilogs that occurred on the day before yesterday

    logs = Q.(2.days.ago.to_date, :nod)   # Note the 'to_date'! Passing a single time arg that is a date means
                                          # everything on that date. When passing a single time arg that is a
                                          # Time class (with hour, min, sec), the resulting range depends on
                                          # how precise the time is. Examples: If the time is 00:00:00, then
                                          # time range of that date. If minutes and second are 0 (but hour is not),
                                          # the time range is that hour. If second is 0, time range is that minute.
                                          # And so on.. See TIMES_TO_WHERE_ARGS for the complete rules.
                                          # You can always use .to_sql to see the effect.




    # 🥗 get all DecisionReview piilogs that occurred in the past week

    logs = Q.(1.week, :nod, :hlr)   # Note: this will go back 1.week from the current moment.
                                    # You might want Q.(:nod, :hlr, 1.week.ago.to_date, nil)
                                    # Use `nil` for open-ended time ranges




    # 🍔 get the error counts for the last week of NOD errors

    # print the error counts by category:

      puts_by_error_message_category_counts wrap Q.(:nod, 7.days)

      #  {"Gateway timeout"=>7,
      #   "BackendServiceException [DR_422]"=>7,
      #   "Outage..."=>6,
      #   "BackendServiceException [DR_404]"=>2,
      #   "BackendServiceException [unmapped_service_exception]"=>1}

    # print the same counts, but first organize by where the exception occurred

      puts_by_error_class_counts wrap Q.(:nod, 7.days)

      #  {"V0::HigherLevelReviews::ContestableIssuesController#index exception Common::Exceptions::GatewayTimeout (HLR)"=>
      #    {"Gateway timeout"=>7},
      #   "V0::HigherLevelReviewsController#create exception DecisionReview::ServiceException (HLR)"=>
      #    {"BackendServiceException [DR_422]"=>7},
      #   "V0::HigherLevelReviews::ContestableIssuesController#index exception Breakers::OutageException (HLR)"=>
      #    {"Outage..."=>4},
      #   "V0::HigherLevelReviews::ContestableIssuesController#index exception DecisionReview::ServiceException (HLR)"=>
      #    {"BackendServiceException [DR_404]"=>2,
      #     "BackendServiceException [unmapped_service_exception]"=>1},
      #   "V0::HigherLevelReviewsController#create exception Breakers::OutageException (HLR)"=>
      #    {"Outage..."=>2}}

    # now you can see that some of those 6 outages occurred at the ContestableIssuesController#index and
    # some at HigherLevelReviewsController#create.

    # Notice the 'wrap' method? 'wrap' adds helper methods to PersonalInformationLog objects. Type 'more' for details.




    # 🍱 get the DecisionReview error counts for the past 15 days

    15.downto(1).each do |d|
      date = d.days.ago.to_date
      count = Q.(:hlr, :nod, date).count
      puts "%s  %s %3d" % [date.strftime('%A')[0..2], date, count]
    end



    # 🍕 what helper methods were added to my PiiLog?

    piilogs = wrap Q.(:hlr, 1.week)

    piilogs.first.helper_methods




    (type 'more' for more info)

  RECIPES
end

#total_in_tree(hash) ⇒ Object

given a hash, or subhash, adds up all of the integers encountered (recursive)



226
227
228
229
230
231
232
233
234
235
# File 'rakelib/decision_review_repl.rb', line 226

def total_in_tree(hash)
  hash.reduce(0) do |acc, (_k, v)|
    acc + case v
          when Array, Hash
            total_in_tree v
          else
            v.is_a?(Integer) ? v : 0
          end
  end
end

#wrap(value) ⇒ Object



371
372
373
374
375
376
377
# File 'rakelib/decision_review_repl.rb', line 371

def wrap(value)
  if value.is_a?(PersonalInformationLog)
    wrap_personal_information_log value
  else
    wrap_personal_information_logs value
  end
end

#wrap_personal_information_log(value, raise_if_no_suitable_wrapper_found: true) ⇒ Object

given a PersonalInformationLog, picks the correct wrapper class



347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
# File 'rakelib/decision_review_repl.rb', line 347

def wrap_personal_information_log(value, raise_if_no_suitable_wrapper_found: true)
  case
  when value.data.dig('schema', 'properties', 'data', 'items', 'properties', 'type', 'enum', 0) == 'contestableIssue'
    GetContestableIssuesSchemaValidationError
  when value.error_class.include?('HigherLevelReviews::ContestableIssuesController#index exception')
    HlrContestableIssuesControllerIndexException
  when value.error_class.include?('ContestableIssuesController#index exception')
    ControllerException
  when value.error_class.include?('HigherLevelReviewsController#create exception')
    ControllerCreateException
  when raise_if_no_suitable_wrapper_found
    raise "couldn't find a suitable wrapper for #{value.inspect}"
  else
    return value
  end.new value
end

#wrap_personal_information_logs(relation) ⇒ Object

takes a PersonalInformationLog relation and returns an array of wrapped PersonalInformationLogs



365
366
367
368
369
# File 'rakelib/decision_review_repl.rb', line 365

def wrap_personal_information_logs(relation)
  relation.map do |personal_information_log|
    wrap_personal_information_log personal_information_log
  end
end