<commit_before>package hmda.api.http.institutions.submissions

import akka.actor.{ ActorRef, ActorSystem }
import akka.http.scaladsl.marshalling.ToResponseMarshallable
import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport._
import akka.http.scaladsl.model.{ StatusCodes, Uri }
import akka.http.scaladsl.server.Route
import akka.http.scaladsl.server.Directives._
import akka.pattern.ask
import akka.util.Timeout
import hmda.api.http.HmdaCustomDirectives
import hmda.api.model.ErrorResponse
import hmda.model.fi.{ Filing, Submission, SubmissionId }
import hmda.model.institution.Institution
import hmda.persistence.HmdaSupervisor.{ FindFilings, FindSubmissions }
import hmda.persistence.institutions.FilingPersistence.GetFilingByPeriod
import hmda.persistence.institutions.SubmissionPersistence.GetSubmissionById
import hmda.persistence.institutions.{ FilingPersistence, SubmissionPersistence }
import hmda.persistence.model.HmdaSupervisorActor.FindActorByName
import hmda.query.projections.institutions.InstitutionView
import hmda.query.projections.institutions.InstitutionView.GetInstitutionById

import scala.concurrent.{ ExecutionContext, Future }
import scala.util.{ Failure, Success }

trait RequestVerificationUtils extends HmdaCustomDirectives {

  implicit val system: ActorSystem
  implicit val timeout: Timeout

  /*
     If the institution, filing, and submission exist, complete the request.
     If any one does not exist, respond with 404 error, including an appropriate message.
   */
  def completeVerified(institutionId: String, period: String, seqNr: Int, uri: Uri)(completeRequest: Route)(implicit ec: ExecutionContext): Route = {
    onComplete(verifyRequest(institutionId, period, seqNr)) {
      case Success(None) => completeRequest
      case Success(Some(message)) =>
        val errorResponse = ErrorResponse(404, message, uri.path)
        complete(ToResponseMarshallable(StatusCodes.NotFound -> errorResponse))
      case Failure(error) => completeWithInternalError(uri, error)
    }
  }

  /*
     If the request is legal (i.e. the institution, period, and filing exist), return None.
     If any of the objects does not exist, return Some(message), where message describes the issue.
   */
  private def verifyRequest(institutionId: String, period: String, seqNr: Int)(implicit ec: ExecutionContext): Future[Option[String]] = {
    val submissionId = SubmissionId(institutionId, period, seqNr)

    val supervisor = system.actorSelection("/user/supervisor")
    val querySupervisor = system.actorSelection("/user/query-supervisor")

    val fInstitutionsActor = (querySupervisor ? FindActorByName(InstitutionView.name)).mapTo[ActorRef]
    val fFilingsActor = (supervisor ? FindFilings(FilingPersistence.name, institutionId)).mapTo[ActorRef]
    val fSubmissionsActor = (supervisor ? FindSubmissions(SubmissionPersistence.name, institutionId, period)).mapTo[ActorRef]

    for {
      ia <- fInstitutionsActor
      i <- (ia ? GetInstitutionById(institutionId)).mapTo[Institution]
      fa <- fFilingsActor
      f <- (fa ? GetFilingByPeriod(period)).mapTo[Filing]
      sa <- fSubmissionsActor
      s <- (sa ? GetSubmissionById(submissionId)).mapTo[Submission]
      msg <- getErrorMessage(i, f, s, institutionId, period, submissionId)
    } yield msg
  }

  private def getErrorMessage(i: Institution, f: Filing, s: Submission, iid: String, p: String, sid: SubmissionId)(implicit ec: ExecutionContext): Future[Option[String]] = Future {

    if (s.id == sid) None
    else if (f.period == p) Some(s"Submission ${sid.sequenceNumber} not found for $p filing")
    else if (i.id == iid) Some(s"$p filing not found for institution $iid")
    else Some(s"Institution $iid not found")
  }

}<commit_msg>STEP 1: clearer, more stringent logic for 404<commit_after>package hmda.api.http.institutions.submissions

import akka.actor.{ ActorRef, ActorSystem }
import akka.http.scaladsl.marshalling.ToResponseMarshallable
import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport._
import akka.http.scaladsl.model.{ StatusCodes, Uri }
import akka.http.scaladsl.server.Route
import akka.http.scaladsl.server.Directives._
import akka.pattern.ask
import akka.util.Timeout
import hmda.api.http.HmdaCustomDirectives
import hmda.api.model.ErrorResponse
import hmda.model.fi.{ Filing, Submission, SubmissionId }
import hmda.model.institution.Institution
import hmda.persistence.HmdaSupervisor.{ FindFilings, FindSubmissions }
import hmda.persistence.institutions.FilingPersistence.GetFilingByPeriod
import hmda.persistence.institutions.SubmissionPersistence.GetSubmissionById
import hmda.persistence.institutions.{ FilingPersistence, SubmissionPersistence }
import hmda.persistence.model.HmdaSupervisorActor.FindActorByName
import hmda.query.projections.institutions.InstitutionView
import hmda.query.projections.institutions.InstitutionView.GetInstitutionById

import scala.concurrent.{ ExecutionContext, Future }
import scala.util.{ Failure, Success }

trait RequestVerificationUtils extends HmdaCustomDirectives {

  implicit val system: ActorSystem
  implicit val timeout: Timeout

  /*
     If the institution, filing, and submission exist, complete the request.
     If any one does not exist, respond with 404 error, including an appropriate message.
   */
  def completeVerified(institutionId: String, period: String, seqNr: Int, uri: Uri)(completeRequest: Route)(implicit ec: ExecutionContext): Route = {
    onComplete(verifyRequest(institutionId, period, seqNr)) {
      case Success(None) => completeRequest
      case Success(Some(message)) =>
        val errorResponse = ErrorResponse(404, message, uri.path)
        complete(ToResponseMarshallable(StatusCodes.NotFound -> errorResponse))
      case Failure(error) => completeWithInternalError(uri, error)
    }
  }

  /*
     If the request is legal (i.e. the institution, period, and filing exist), return None.
     If any of the objects does not exist, return Some(message), where message describes the issue.
   */
  private def verifyRequest(institutionId: String, period: String, seqNr: Int)(implicit ec: ExecutionContext): Future[Option[String]] = {
    val submissionId = SubmissionId(institutionId, period, seqNr)

    val supervisor = system.actorSelection("/user/supervisor")
    val querySupervisor = system.actorSelection("/user/query-supervisor")

    val fInstitutionsActor = (querySupervisor ? FindActorByName(InstitutionView.name)).mapTo[ActorRef]
    val fFilingsActor = (supervisor ? FindFilings(FilingPersistence.name, institutionId)).mapTo[ActorRef]
    val fSubmissionsActor = (supervisor ? FindSubmissions(SubmissionPersistence.name, institutionId, period)).mapTo[ActorRef]

    for {
      ia <- fInstitutionsActor
      i <- (ia ? GetInstitutionById(institutionId)).mapTo[Institution]
      fa <- fFilingsActor
      f <- (fa ? GetFilingByPeriod(period)).mapTo[Filing]
      sa <- fSubmissionsActor
      s <- (sa ? GetSubmissionById(submissionId)).mapTo[Submission]
      msg <- getErrorMessage(i, f, s, institutionId, period, submissionId)
    } yield msg
  }

  private def getErrorMessage(i: Institution, f: Filing, s: Submission, iid: String, p: String, sid: SubmissionId)(implicit ec: ExecutionContext): Future[Option[String]] = Future {
    val submissionFound: Boolean = s.id == sid
    val filingFound: Boolean = f.period == p
    val institutionFound: Boolean = i.id == iid

    if (submissionFound && filingFound && institutionFound) None
    else if (filingFound && institutionFound) Some(s"Submission ${sid.sequenceNumber} not found for $p filing")
    else if (institutionFound) Some(s"$p filing not found for institution $iid")
    else Some(s"Institution $iid not found")
  }

}
{'fraction_non_alphanumeric': 0.09748509204044595, 'fraction_numerical': 0.002074150894477573, 'mean_word_length': 4.9759876065065844, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1378008', 'n_tokens_mistral': 2341, 'n_tokens_neox': 2285, 'n_words': 556}