@Test
  public void testGetAddressLabelsFiltersByCoachId()
      throws IOException, ObjectNotFoundException, JRException {

    final Person dennisRitchie = personService.get(Stubs.PersonFixture.DMR.id());
    final Person kevinSmith = personService.get(Stubs.PersonFixture.KEVIN_SMITH.id());
    dennisRitchie.setCoach(kevinSmith);
    personService.save(dennisRitchie);
    sessionFactory.getCurrentSession().flush();

    final MockHttpServletResponse response = new MockHttpServletResponse();
    // Alan Turing, i.e. the coach assigned to our test student users
    // in our standard fixture
    final UUID coachId = Stubs.PersonFixture.ADVISOR_0.id();
    controller.getAddressLabels(
        response, null, coachId, null, null, null, null, null, null, null, null, null, null, null,
        null, null, "csv");

    // "body" is the actual results and the header that describes its columns.
    // This is as opposed to rows which precede the header, which describe
    // the filtering criteria
    final List<String> expectedReportBodyLines = new ArrayList<String>(4);
    // same as in testGetAddressLabelsReturnsAllStudentsIfNoFiltersSet(), but
    // Dennis Ritchie is missing
    expectedReportBodyLines.add(
        "FIRST,MIDDLE,LAST, ID,TYPE,ADDRESS,CITY,ST,PHONE(H),EMAIL(SCHOOL),EMAIL(ALTERNATE)");
    expectedReportBodyLines.add(
        "James,A,Gosling,student0,ILP,444 West Third Street ,San Francisco,CA,908-123-4567,[email protected],[email protected]");
    expectedReportBodyLines.add(
        "Kenneth,L,Thompson,ken.1,CAP,444 West Third Street ,Murray Hill,NJ,908-123-4567,[email protected],[email protected]");

    expectReportBodyLines(expectedReportBodyLines, response, null);
  }
 // Faculty names are not added to the external courses by default
 // this method should fix ssp-3041 - Scody
 private void updateFactultyNames(ExternalStudentRecordsTO recordTO) {
   List<ExternalStudentTranscriptCourseTO> courses = recordTO.getTerms();
   if (courses != null) {
     for (ExternalStudentTranscriptCourseTO course : courses) {
       try {
         Person person =
             !StringUtils.isNotBlank(course.getFacultySchoolId())
                 ? null
                 : personService.getInternalOrExternalPersonBySchoolId(
                     course.getFacultySchoolId(),
                     false); // TODO: getInternalOrExternalPersonBySchoolId is slow refactor?
         if (person != null) {
           course.setFacultyName(person.getFullName());
         }
       } catch (ObjectNotFoundException e) {
         course.setFacultyName("None Listed");
         LOGGER.debug(
             "FACULTY SCHOOL ID WAS NOT RESOLVED WHILE LOADING TRANSCRIPT RECORD.  Faculty School_id: "
                 + course.getFacultySchoolId()
                 + " Student ID: "
                 + course.getSchoolId()
                 + " Course: "
                 + course.getFormattedCourse());
       }
     }
   }
 }
예제 #3
0
  static List<Person> getCoaches(
      final UUID coachId, String homeDepartment, PersonService personService)
      throws ObjectNotFoundException {
    List<Person> coaches;
    if (coachId != null) {
      Person coach = personService.get(coachId);
      coaches = new ArrayList<Person>();
      coaches.add(coach);
    } else {
      coaches =
          new ArrayList<Person>(
              personService.getAllCurrentCoaches(Person.PERSON_NAME_AND_ID_COMPARATOR));

      if (homeDepartment != null && homeDepartment.length() > 0) {
        List<Person> homeCoaches = new ArrayList<Person>();
        for (Person coach : coaches) {
          if (coach.getStaffDetails() != null
              && coach.getStaffDetails().getDepartmentName() != null
              && coach.getStaffDetails().getDepartmentName().equals(homeDepartment))
            homeCoaches.add(coach);
        }
        coaches = homeCoaches;
      }
    }

    return coaches;
  }
예제 #4
0
  /**
   * Returns an html page valid for printing
   *
   * <p>
   *
   * @param obj instance to print.
   * @return html text strem
   * @throws ObjectNotFoundException If specified object could not be found.
   * @throws SendFailedException
   */
  @PreAuthorize("hasRole('ROLE_PERSON_READ') or hasRole('ROLE_PERSON_MAP_READ')")
  @RequestMapping(value = "/emailCurrent", method = RequestMethod.POST)
  public @ResponseBody String email(
      final HttpServletResponse response,
      final @PathVariable UUID personId,
      @RequestBody final PlanOutputTO planOutputDataTO)
      throws ObjectNotFoundException {

    Plan currentPlan = service.getCurrentForStudent(personId);
    PlanTO planTO = getFactory().from(currentPlan);
    planOutputDataTO.setPlan(planTO);

    SubjectAndBody messageText = service.createOutput(planOutputDataTO);
    if (messageText == null) return null;
    Person person = personService.get(UUID.fromString(planOutputDataTO.getPlan().getPersonId()));
    Set<String> watcherAddresses = new HashSet<String>(person.getWatcherEmailAddresses());
    watcherAddresses.addAll(
        org.springframework.util.StringUtils.commaDelimitedListToSet(
            planOutputDataTO.getEmailCC()));

    messageService.createMessage(
        planOutputDataTO.getEmailTo(),
        org.springframework.util.StringUtils.arrayToCommaDelimitedString(
            watcherAddresses.toArray(new String[watcherAddresses.size()])),
        messageText);

    return "Map Plan has been queued.";
  }
예제 #5
0
 private PlanTO validatePlan(PlanTO plan) throws ObjectNotFoundException {
   String schoolId = null;
   if (StringUtils.isNotBlank(plan.getPersonId())) {
     Person student = personService.get(UUID.fromString(plan.getPersonId()));
     schoolId = student.getSchoolId();
   }
   return getService().validate(plan);
 }
예제 #6
0
 private Person findEnabledPersonByUsernameOrFail(String username)
     throws ObjectNotFoundException, UserNotEnabledException {
   Person person = personService.personFromUsername(username);
   if (person.isDisabled()) {
     throw new UserNotEnabledException("User '" + username + "' is disabled.");
   }
   return person;
 }
 private UUID[] personCollectionToUuidAray(Collection<Person> personCollection) {
   UUID[] uuidArray = new UUID[personCollection.size()];
   int i = 0;
   for (Person person : personCollection) {
     uuidArray[i] = person.getId();
     i++;
   }
   return uuidArray;
 }
  @RequestMapping(value = "/transcript/currentcourses", method = RequestMethod.GET)
  @PreAuthorize(Permission.SECURITY_PERSON_READ)
  public @ResponseBody List<ExternalStudentTranscriptCourseTO> loadCurrentCourses(
      final @PathVariable UUID id) throws ObjectNotFoundException {
    String schoolId = getStudentId(id);

    Term currentTerm;
    try {
      currentTerm = termService.getCurrentTerm();
    } catch (ObjectNotFoundException e) {
      currentTerm = new Term();
      LOGGER.error(
          "CURRENT TERM NOT SET, org.jasig.ssp.web.api.external.ExternalStudentRecordsController.loadCurrentCourses(UUID) is being called but will not function properly");
    }
    List<ExternalStudentTranscriptCourseTO> courses =
        externalStudentTranscriptCourseFactory.asTOList(
            externalStudentTranscriptCourseService.getTranscriptsBySchoolIdAndTermCode(
                schoolId, currentTerm.getCode()));
    Collection<EnrollmentStatus> mappings = statusCodeMappings();

    String defaultStatusCode = getDefaultStatusCode(mappings);

    for (ExternalStudentTranscriptCourseTO course : courses) {
      try {
        Person person =
            !StringUtils.isNotBlank(course.getFacultySchoolId())
                ? null
                : personService.getInternalOrExternalPersonBySchoolId(
                    course.getFacultySchoolId(),
                    false); // TODO: getInternalOrExternalPersonBySchoolId is slow refactor?
        if (person != null) {
          course.setFacultyName(person.getFullName());
        }
      } catch (ObjectNotFoundException e) {
        course.setFacultyName("None Listed");
        LOGGER.debug(
            "FACULTY SCHOOL ID WAS NOT RESOLVED WHILE LOADING TRANSCRIPT RECORD.  Factulty School_id: "
                + course.getFacultySchoolId()
                + " Student ID: "
                + course.getSchoolId()
                + " Course: "
                + course.getFormattedCourse());
      }

      if (StringUtils.isBlank(course.getStatusCode())) {
        course.setStatusCode(defaultStatusCode);
      } else if (mappings != null && !mappings.isEmpty()) {
        for (EnrollmentStatus enrollmentStatus : mappings) {
          if (enrollmentStatus.getCode().equals(course.getStatusCode())) {
            course.setStatusCode(enrollmentStatus.getName());
          }
        }
      }
    }
    return courses;
  }
  @Test
  public void testGetAllCurrentCoachesFiltersDuplicates() throws ObjectNotFoundException {
    final Person jamesDoe = person(JAMES_DOE);
    final Person advisor0 = person(ADVISOR_0);
    jamesDoe.setCoach(advisor0);
    personService.save(jamesDoe);
    sessionFactory.getCurrentSession().flush();

    final SortedSet<Person> result = personService.getAllCurrentCoaches(null);
    assertEquals(2, result.size());
  }
예제 #10
0
  @Override
  public EarlyAlert create(@NotNull final EarlyAlert earlyAlert)
      throws ObjectNotFoundException, ValidationException {
    // Validate objects
    if (earlyAlert == null) {
      throw new IllegalArgumentException("EarlyAlert must be provided.");
    }

    if (earlyAlert.getPerson() == null) {
      throw new ValidationException("EarlyAlert Student data must be provided.");
    }

    final Person student = earlyAlert.getPerson();

    // Figure student advisor or early alert coordinator
    final UUID assignedAdvisor = getEarlyAlertAdvisor(earlyAlert);
    if (assignedAdvisor == null) {
      throw new ValidationException(
          "Could not determine the Early Alert Advisor for student ID " + student.getId());
    }

    if (student.getCoach() == null || assignedAdvisor.equals(student.getCoach().getId())) {
      student.setCoach(personService.get(assignedAdvisor));
    }

    ensureValidAlertedOnPersonStateNoFail(student);

    // Create alert
    final EarlyAlert saved = getDao().save(earlyAlert);

    // Send e-mail to assigned advisor (coach)
    try {
      sendMessageToAdvisor(saved, earlyAlert.getEmailCC());
    } catch (final SendFailedException e) {
      LOGGER.warn("Could not send Early Alert message to advisor.", e);
      throw new ValidationException(
          "Early Alert notification e-mail could not be sent to advisor. Early Alert was NOT created.",
          e);
    }

    // Send e-mail CONFIRMATION to faculty
    try {
      sendConfirmationMessageToFaculty(saved);
    } catch (final SendFailedException e) {
      LOGGER.warn("Could not send Early Alert confirmation to faculty.", e);
      throw new ValidationException(
          "Early Alert confirmation e-mail could not be sent. Early Alert was NOT created.", e);
    }

    return saved;
  }
예제 #11
0
 private void setInitialSelectedCourse(ModelMap model, final PortletRequest req)
     throws ObjectNotFoundException {
   String formattedCourse = req.getParameter("formattedCourse");
   String sectionCode = req.getParameter("sectionCode");
   String termCode = req.getParameter("termCode");
   Person user = (Person) model.get("user");
   if (user == null) {
     throw new EarlyAlertPortletControllerRuntimeException(
         "Missing or deactivated account for current user.");
   }
   FacultyCourse course =
       getCourse(
           model,
           new SearchFacultyCourseTO(user.getSchoolId(), termCode, sectionCode, formattedCourse));
   if (course != null) model.put("initialSelectedCourse", getCourseSectionKey(course));
 }
예제 #12
0
  private void ensureValidAlertedOnPersonStateOrFail(Person person)
      throws ObjectNotFoundException, ValidationException {

    if (person.getObjectStatus() != ObjectStatus.ACTIVE) {
      person.setObjectStatus(ObjectStatus.ACTIVE);
    }

    final ProgramStatus programStatus = programStatusService.getActiveStatus();
    if (programStatus == null) {
      throw new ObjectNotFoundException(
          "Unable to find a ProgramStatus representing \"activeness\".", "ProgramStatus");
    }

    Set<PersonProgramStatus> programStatuses = person.getProgramStatuses();
    if (programStatuses == null || programStatuses.isEmpty()) {
      PersonProgramStatus personProgramStatus = new PersonProgramStatus();
      personProgramStatus.setEffectiveDate(new Date());
      personProgramStatus.setProgramStatus(programStatus);
      personProgramStatus.setPerson(person);
      programStatuses.add(personProgramStatus);
      person.setProgramStatuses(programStatuses);
      // save should cascade, but make sure custom create logic fires
      personProgramStatusService.create(personProgramStatus);
    }

    if (person.getStudentType() == null) {
      StudentType studentType = studentTypeService.get(StudentType.EAL_ID);
      if (studentType == null) {
        throw new ObjectNotFoundException(
            "Unable to find a StudentType representing an early " + "alert-assigned type.",
            "StudentType");
      }
      person.setStudentType(studentType);
    }
  }
예제 #13
0
 private void ensureValidAlertedOnPersonStateNoFail(Person person) {
   try {
     ensureValidAlertedOnPersonStateOrFail(person);
   } catch (Exception e) {
     LOGGER.error(
         "Unable to set a program status or student type on "
             + "person '{}'. This is likely to prevent that person "
             + "record from appearing in caseloads, student searches, "
             + "and some reports.",
         person.getId(),
         e);
   }
 }
예제 #14
0
 /**
  * Return plan status for given student.
  *
  * @param personId Explicit personId to the instance to persist.
  * @return The current plan status of the student.
  */
 @DynamicPermissionChecking
 @RequestMapping(value = "/planstatus", method = RequestMethod.GET)
 public @ResponseBody ExternalPersonPlanStatusTO getPlanStatus(
     final HttpServletRequest request,
     final HttpServletResponse response,
     @PathVariable final UUID personId)
     throws ObjectNotFoundException {
   assertStandardMapReadApiAuthorization(request);
   if (personId == null) {
     return null;
   }
   String schoolId = null;
   Person student = personService.get(personId);
   schoolId = student.getSchoolId();
   // TODO not the cleanest way to handle but clientside generates 500 error in console
   // Currently plan status is not required.
   try {
     return planStatusFactory.from(externalPlanStatusService.getBySchoolId(schoolId));
   } catch (Exception exp) {
     return null;
   }
 }
  @Test
  public void testGetAllCurrentCoachesFiltersDuplicatesByIdNotName()
      throws ObjectNotFoundException {
    final String duplicatePersonSchoolId = ADVISOR_0.schoolId() + "_foo";
    this.createExternalPerson(
        duplicatePersonSchoolId,
        ADVISOR_0.username() + "_foo",
        ADVISOR_0.firstName(), // everything else the same
        ADVISOR_0.lastName(),
        ADVISOR_0.middleName(),
        ADVISOR_0.primaryEmailAddress());

    // this should create the person record
    Person duplicatePerson = personService.getBySchoolId(duplicatePersonSchoolId, true);
    assertNotNull(duplicatePerson); // sanity check
    final Person jamesDoe = person(JAMES_DOE);
    jamesDoe.setCoach(duplicatePerson);
    personService.save(jamesDoe);
    sessionFactory.getCurrentSession().flush();

    final SortedSet<Person> result = personService.getAllCurrentCoaches(null);
    assertEquals(3, result.size());
  }
예제 #16
0
  /**
   * Persist any changes to the plan instance.
   *
   * @param id Explicit id to the instance to persist.
   * @param obj Full instance to persist.
   * @return The update data object instance.
   * @throws ObjectNotFoundException If specified object could not be found.
   * @throws ValidationException If the specified id is null.
   * @throws CloneNotSupportedException
   */
  @PreAuthorize("hasRole('ROLE_PERSON_MAP_WRITE')")
  @RequestMapping(value = "/{id}", method = RequestMethod.PUT)
  public @ResponseBody PlanTO save(
      @PathVariable final UUID id, @Valid @RequestBody final PlanTO obj)
      throws ValidationException, ObjectNotFoundException, CloneNotSupportedException {
    if (id == null) {
      throw new ValidationException(
          "You submitted without an id to the save method.  Did you mean to create?");
    }

    if (obj.getId() == null) {
      obj.setId(id);
    }
    final Plan oldPlan = getService().get(id);
    final Person oldOwner = oldPlan.getOwner();

    SspUser currentUser = getSecurityService().currentlyAuthenticatedUser();

    // If the currently logged in user is not the owner of this plan
    // we need to create a clone then save it.
    if (currentUser.getPerson().getId().equals(oldOwner.getId())) {
      final Plan model = getFactory().from(obj);
      Plan savedPlan = getService().save(model);
      if (null != model) {
        return validatePlan(new PlanTO(savedPlan));
      }
    } else {
      obj.setId(null);
      Plan model = getFactory().from(obj);
      final Plan clonedPlan = getService().copyAndSave(model);
      if (null != clonedPlan) {
        return validatePlan(new PlanTO(clonedPlan));
      }
    }

    return null;
  }
  @RequestMapping(value = "/studentactivity", method = RequestMethod.GET)
  @PreAuthorize(Permission.SECURITY_PERSON_READ)
  public @ResponseBody List<RecentActivityTO> loadRecentStudentActivity(final @PathVariable UUID id)
      throws ObjectNotFoundException {
    List<RecentActivityTO> recentActivities = new ArrayList<RecentActivityTO>();
    Person person = personService.get(id);
    SortingAndPaging sAndP =
        SortingAndPaging.createForSingleSortWithPaging(
            ObjectStatus.ACTIVE, 0, 1000, "createdDate", "DESC", "createdDate");

    PagingWrapper<EarlyAlert> earlyAlerts = earlyAlertService.getAllForPerson(person, sAndP);
    SspUser currentUser = securityService.currentUser();
    List<EarlyAlertTO> earlyAlertTOs = earlyAlertTOFactory.asTOList(earlyAlerts.getRows());

    PagingWrapper<JournalEntry> journalEntries =
        journalEntryService.getAllForPerson(person, currentUser, sAndP);

    List<JournalEntryTO> journalEntriesTOs =
        journalEntryTOFactory.asTOList(journalEntries.getRows());

    PagingWrapper<Task> actions = taskService.getAllForPerson(person, currentUser, sAndP);

    List<TaskTO> actionsTOs = taskTOFactory.asTOList(actions.getRows());

    PagingWrapper<Plan> plans =
        planService.getAllForStudent(
            SortingAndPaging.createForSingleSortWithPaging(
                ObjectStatus.ALL, 0, 1000, null, null, null),
            id);

    List<PlanTO> planTOs = planTOFactory.asTOList(plans.getRows());

    for (EarlyAlertTO earlyAlert : earlyAlertTOs) {
      if (earlyAlert.getClosedDate() != null) {
        recentActivities.add(
            new RecentActivityTO(
                earlyAlert.getClosedById(),
                earlyAlert.getClosedByName(),
                "Early Alert Closed",
                earlyAlert.getClosedDate()));
      } else {
        recentActivities.add(
            new RecentActivityTO(
                earlyAlert.getCreatedBy().getId(),
                getPersonLiteName(earlyAlert.getCreatedBy()),
                "Early Alert Created",
                earlyAlert.getCreatedDate()));
      }
    }

    for (JournalEntryTO journalEntry : journalEntriesTOs) {
      recentActivities.add(
          new RecentActivityTO(
              journalEntry.getCreatedBy().getId(),
              getPersonLiteName(journalEntry.getCreatedBy()),
              "Journal Entry",
              journalEntry.getEntryDate()));
    }

    for (TaskTO action : actionsTOs) {
      if (action.isCompleted()) {
        recentActivities.add(
            new RecentActivityTO(
                action.getModifiedBy().getId(),
                getPersonLiteName(action.getModifiedBy()),
                "Action Plan Task Created",
                action.getCompletedDate()));
      } else {
        recentActivities.add(
            new RecentActivityTO(
                action.getCreatedBy().getId(),
                getPersonLiteName(action.getCreatedBy()),
                "Action Plan Task Created",
                action.getCreatedDate()));
      }
    }

    for (PlanTO planTO : planTOs) {
      Date testDate = DateUtils.addDays(planTO.getCreatedDate(), 1);
      String planName = planTO.getName();
      if (planTO.getModifiedDate().before(testDate)) {
        recentActivities.add(
            new RecentActivityTO(
                planTO.getCreatedBy().getId(),
                getPersonLiteName(planTO.getCreatedBy()),
                "Map Plan (" + planName + ") Created",
                planTO.getModifiedDate()));
      } else {
        recentActivities.add(
            new RecentActivityTO(
                planTO.getModifiedBy().getId(),
                getPersonLiteName(planTO.getModifiedBy()),
                "Map Plan (" + planName + ") Updated",
                planTO.getModifiedDate()));
      }
    }

    if (person.getStudentIntakeCompleteDate() != null) {
      recentActivities.add(
          new RecentActivityTO(
              person.getCoach().getId(),
              person.getCoach().getFullName(),
              "Student Intake Completed",
              person.getStudentIntakeCompleteDate()));
    }
    if (person.getStudentIntakeRequestDate() != null) {
      recentActivities.add(
          new RecentActivityTO(
              person.getCoach().getId(),
              person.getCoach().getFullName(),
              "Student Intake Requested",
              person.getStudentIntakeRequestDate()));
    }

    Collections.sort(recentActivities, RecentActivityTO.RECENT_ACTIVITY_TO_DATE_COMPARATOR);
    return recentActivities;
  }
예제 #18
0
 @Override
 public PagingWrapper<EarlyAlert> getAllForPerson(
     final Person person, final SortingAndPaging sAndP) {
   return getDao().getAllForPersonId(person.getId(), sAndP);
 }
예제 #19
0
  /**
   * Send e-mail ({@link Message}) to the assigned advisor for the student.
   *
   * @param earlyAlert Early Alert
   * @param emailCC Email address to also CC this message
   * @throws ObjectNotFoundException
   * @throws SendFailedException
   * @throws ValidationException
   */
  private void sendMessageToAdvisor(
      @NotNull final EarlyAlert earlyAlert, // NOPMD
      final String emailCC)
      throws ObjectNotFoundException, SendFailedException, ValidationException {
    if (earlyAlert == null) {
      throw new IllegalArgumentException("Early alert was missing.");
    }

    if (earlyAlert.getPerson() == null) {
      throw new IllegalArgumentException("EarlyAlert Person is missing.");
    }

    final Person person = earlyAlert.getPerson().getCoach();
    final SubjectAndBody subjAndBody =
        messageTemplateService.createEarlyAlertAdvisorConfirmationMessage(
            fillTemplateParameters(earlyAlert));

    if (person == null) {
      LOGGER.warn(
          "Student {} had no coach when EarlyAlert {} was"
              + " created. Unable to send message to coach.",
          earlyAlert.getPerson(),
          earlyAlert);
    } else {
      // Create and queue the message
      final Message message = messageService.createMessage(person, emailCC, subjAndBody);
      LOGGER.info("Message {} created for EarlyAlert {}", message, earlyAlert);
    }

    // Send same message to all applicable Campus Early Alert routing
    // entries
    final PagingWrapper<EarlyAlertRouting> routes =
        earlyAlertRoutingService.getAllForCampus(
            earlyAlert.getCampus(), new SortingAndPaging(ObjectStatus.ACTIVE));
    if (routes.getResults() > 0) {
      for (final EarlyAlertRouting route : routes.getRows()) {
        // Check that route applies
        if (route.getEarlyAlertReason() == null) {
          throw new ObjectNotFoundException(
              "EarlyAlertRouting missing EarlyAlertReason.", "EarlyAlertReason");
        }

        // Only routes that are for any of the Reasons in this
        // EarlyAlert should be applied.
        if ((earlyAlert.getEarlyAlertReasonIds() == null)
            || !earlyAlert.getEarlyAlertReasonIds().contains(route.getEarlyAlertReason())) {
          continue;
        }

        // Send e-mail to specific person
        final Person to = route.getPerson();
        if ((to != null) && !StringUtils.isEmpty(to.getPrimaryEmailAddress())) {
          final Message message = messageService.createMessage(to, null, subjAndBody);
          LOGGER.info(
              "Message {} for EarlyAlert {} also routed to {}",
              new Object[] {message, earlyAlert, to}); // NOPMD
        }

        // Send e-mail to a group
        if (!StringUtils.isEmpty(route.getGroupName())
            && !StringUtils.isEmpty(route.getGroupEmail())) {
          final Message message =
              messageService.createMessage(route.getGroupEmail(), null, subjAndBody);
          LOGGER.info(
              "Message {} for EarlyAlert {} also routed to {}",
              new Object[] {
                message,
                earlyAlert, // NOPMD
                route.getGroupEmail()
              });
        }
      }
    }
  }
예제 #20
0
  @RenderMapping(params = "action=enterAlert")
  public ModelAndView showForm(
      final PortletRequest req,
      @RequestParam(required = false) final String schoolId,
      @RequestParam(required = false) final String formattedCourse,
      @RequestParam(required = false) final String studentUserName,
      @RequestParam(required = false) final String sectionCode,
      @RequestParam(required = false) final String termCode,
      ModelMap model) {
    // Do not use a @ModelAttribute-annotated argument to get the user
    // out of the model b/c Spring will attempt to set properties on it
    // by matching up request param names. This will overwrite user.schoolId
    // with the method param of that name, effectively copying the student's
    // school ID into the faculty user's record.
    if (!StringUtils.isNotBlank(schoolId) && !StringUtils.isNotBlank(studentUserName)) {
      throw new EarlyAlertPortletControllerRuntimeException("Missing student identifier.");
    }

    if (!StringUtils.isNotBlank(formattedCourse) && !StringUtils.isNotBlank(sectionCode)) {
      throw new EarlyAlertPortletControllerRuntimeException("Missing course identifier/s.");
    }
    Person user = (Person) model.get("user");
    if (user == null) {
      throw new EarlyAlertPortletControllerRuntimeException(
          "Missing or deactivated account for current user.");
    }
    FacultyCourse course = null;
    Person student = null;
    ExternalFacultyCourseRoster enrollment = null;
    try {
      // Should really always have a term code (see deprecation notes for
      // getCourseByFacultySchoolIdAndFormattedCourse) but we know at
      // least one real-world deployment (SPC) cannot/does not send term
      // codes when deep linking to the EA form *and* this just happens to
      // work b/c their formattedCourse values are globally unique. So
      // we preserve the option of not filtering by term code.
      course =
          facultyCourseService.getCourseBySearchFacultyCourseTO(
              new SearchFacultyCourseTO(
                  user.getSchoolId(), termCode, sectionCode, formattedCourse));

      if (course == null) {
        throw new EarlyAlertPortletControllerRuntimeException(
            buildErrorMesssage(
                "Course not found or current user is not listed as the instructor of record:",
                user.getSchoolId(),
                schoolId,
                studentUserName,
                formattedCourse,
                termCode,
                sectionCode));
      }

      /*
       * NB:  It's on us to translate from schoolId <-> studentId (SSP
       * UUID) at this point in the Early Alert process.  Previous APIs
       * user the former where following APIs use the later.
       */
      if (StringUtils.isNotBlank(schoolId)) {
        try {
          student = personService.getBySchoolId(schoolId, true); // TODO:  Handle error better??
          if (student == null) {
            throw new EarlyAlertPortletControllerRuntimeException(
                "Student not found by school ID: " + schoolId);
          }
        } catch (ObjectNotFoundException e) {
          throw new EarlyAlertPortletControllerRuntimeException(
              "Student not found by school ID: " + schoolId, e);
        }
      } else {
        try {
          student = personService.getByUsername(studentUserName, true);
          if (student == null) {
            throw new EarlyAlertPortletControllerRuntimeException(
                "Student not found by username: "******"Student not found by username: "******"Selected student has no school ID. Username: "******"Enrollment not found for: ",
                user.getSchoolId(),
                student.getSchoolId(),
                student.getUsername(),
                formattedCourse,
                termCode,
                sectionCode));
      }
    } catch (EarlyAlertPortletControllerRuntimeException e) {
      throw e;
    } catch (Exception e) {
      throw new RuntimeException(
          buildErrorMesssage(
              "System error looking up course or enrollment for: ",
              user.getSchoolId(),
              student == null ? schoolId : student.getSchoolId(),
              student == null ? studentUserName : student.getUsername(),
              formattedCourse,
              termCode,
              sectionCode),
          e);
    }
    /*
     *  SANITY CHECK (is this even necessary?  wanted?)
     *    - Confirm that the logged in user is the faculty of record on the
     *      course
     */
    if (!course.getFacultySchoolId().equals(user.getSchoolId())) {
      throw new EarlyAlertPortletControllerRuntimeException(
          buildErrorMesssage(
              "Current user is not listed as the instructor of record on the specified course: ",
              user.getSchoolId(),
              student.getSchoolId(),
              student.getUsername(),
              formattedCourse,
              termCode,
              sectionCode));
    }

    EarlyAlertSearchForm form = new EarlyAlertSearchForm();
    form.setAuthor(user);
    form.setStudent(student);

    form.setSortAndPage(buildSortAndPage(-1, 0));
    PagedResponse<EarlyAlertSearchResultTO> results = earlyAlertService.searchEarlyAlert(form);

    model.put(KEY_STUDENT_ID, student.getId()); // Student UUID
    model.put(KEY_COURSE, course);
    model.put(KEY_ENROLLMENT, enrollment);
    model.put(KEY_EARLY_ALERT_RESULTS, results.getRows());
    try {
      Term term = termService.getByCode(course.getTermCode());
      model.put(KEY_COURSE_TERM_NAME, term.getName());
    } catch (Exception exp) {
      model.put(KEY_COURSE_TERM_NAME, course.getTermCode());
    }

    return new ModelAndView("ea-form", model);
  }