@Override
  public String getAnswerHtml(FeedbackQuestionDetails questionDetails) {
    FeedbackRubricQuestionDetails fqd = (FeedbackRubricQuestionDetails) questionDetails;
    StringBuilder html = new StringBuilder(100);
    for (int i = 0; i < answer.size(); i++) {
      int chosenIndex = answer.get(i);
      String chosenChoice = "";
      if (chosenIndex == -1) {
        chosenChoice =
            "<span class=\"color_neutral\"><i>"
                + Const.INSTRUCTOR_FEEDBACK_RESULTS_MISSING_RESPONSE
                + "</i></span>";
        html.append(
            StringHelper.integerToLowerCaseAlphabeticalIndex(i + 1) + ") " + chosenChoice + "<br>");
      } else {
        chosenChoice = Sanitizer.sanitizeForHtml(fqd.getRubricChoices().get(answer.get(i)));
        html.append(
            StringHelper.integerToLowerCaseAlphabeticalIndex(i + 1)
                + ") "
                + chosenChoice
                + " <span class=\"color_neutral\"><i>(Choice "
                + (chosenIndex + 1)
                + ")</i></span><br>");
      }
    }

    return html.toString();
  }
  /**
   * This method should be used by admin only since the previous searching does not restrict the
   * visibility according to the logged-in user's google ID. Therefore,This fromResults method does
   * not require a googleID as a parameter. Returned results bundle will contain information related
   * to matched instructors only.
   *
   * @param results
   * @return studentResultBundle containing information related to matched students only.
   */
  public InstructorSearchResultBundle getInstructorsfromResults(Results<ScoredDocument> results) {
    if (results == null) {
      return this;
    }

    cursor = results.getCursor();

    for (ScoredDocument doc : results) {
      InstructorAttributes instructor =
          JsonUtils.fromJson(
              doc.getOnlyField(Const.SearchDocumentField.INSTRUCTOR_ATTRIBUTE).getText(),
              InstructorAttributes.class);

      if (instructorsLogic.getInstructorForRegistrationKey(StringHelper.encrypt(instructor.key))
          == null) {
        instructorsLogic.deleteDocument(instructor);
        continue;
      }

      instructorList.add(instructor);
      numberOfResults++;
    }

    sortInstructorResultList();

    return this;
  }
 /**
  * This recovers a set of html-sanitized string to original encoding for appropriate display in
  * files such as csv file <br>
  * It restores encoding for < > \ / ' & <br>
  *
  * @param sanitized string set
  * @return recovered string set
  */
 public static Set<String> recoverFromSanitizedText(Set<String> textSet) {
   Set<String> textSetTemp = new HashSet<String>();
   for (String text : textSet) {
     textSetTemp.add(StringHelper.recoverFromSanitizedText(text));
   }
   return textSetTemp;
 }
 public String getRegistrationUrl() {
   return new Url(Config.APP_URL + Const.ActionURIs.STUDENT_COURSE_JOIN_NEW)
       .withRegistrationKey(StringHelper.encrypt(key))
       .withStudentEmail(email)
       .withCourseId(course)
       .toString();
 }
  public String toString(int indent) {
    String indentString = StringHelper.getIndent(indent);
    StringBuilder sb = new StringBuilder();
    sb.append(indentString + "Student:" + name + "[" + email + "]" + EOL);

    return sb.toString();
  }
  @Test
  public void testGetStudent() throws InvalidParametersException, EntityDoesNotExistException {
    int currentNumberOfStudent = studentsDb.getAllStudents().size();
    StudentAttributes s = createNewStudent();
    s.googleId = "validGoogleId";
    s.googleId = "validTeam";
    studentsDb.updateStudent(s.course, s.email, s.name, s.team, s.email, s.googleId, s.comments);

    ______TS("typical success case: existent");
    StudentAttributes retrieved = studentsDb.getStudentForEmail(s.course, s.email);
    assertNotNull(retrieved);
    assertNotNull(studentsDb.getStudentForRegistrationKey(retrieved.key));
    assertNotNull(studentsDb.getStudentForRegistrationKey(StringHelper.encrypt(retrieved.key)));
    assertNull(studentsDb.getStudentForRegistrationKey("notExistingKey"));
    ______TS("non existant student case");
    retrieved = studentsDb.getStudentForEmail("any-course-id", "*****@*****.**");
    assertNull(retrieved);

    StudentAttributes s2 = createNewStudent("*****@*****.**");
    s2.googleId = "validGoogleId2";
    studentsDb.updateStudent(
        s2.course, s2.email, s2.name, s2.team, s2.email, s2.googleId, s2.comments);
    studentsDb.deleteStudentsForGoogleId(s2.googleId);
    assertNull(studentsDb.getStudentForGoogleId(s2.course, s2.googleId));

    s2 = createNewStudent("*****@*****.**");
    assertEquals(
        true, studentsDb.getUnregisteredStudentsForCourse(s2.course).get(0).isEnrollInfoSameAs(s2));

    s2.googleId = null;
    studentsDb.updateStudent(
        s2.course, s2.email, s2.name, s2.team, s2.email, s2.googleId, s2.comments);
    assertEquals(
        true, studentsDb.getUnregisteredStudentsForCourse(s2.course).get(0).isEnrollInfoSameAs(s2));

    assertTrue(s.isEnrollInfoSameAs(studentsDb.getStudentsForGoogleId(s.googleId).get(0)));
    assertEquals(true, studentsDb.getStudentsForCourse(s.course).get(0).isEnrollInfoSameAs(s));
    assertEquals(
        true, studentsDb.getStudentsForTeam(s.team, s.course).get(0).isEnrollInfoSameAs(s));
    assertEquals(2 + currentNumberOfStudent, studentsDb.getAllStudents().size());

    ______TS("null params case");
    try {
      studentsDb.getStudentForEmail(null, "*****@*****.**");
      Assert.fail();
    } catch (AssertionError a) {
      assertEquals(Const.StatusCodes.DBLEVEL_NULL_INPUT, a.getMessage());
    }
    try {
      studentsDb.getStudentForEmail("any-course-id", null);
      Assert.fail();
    } catch (AssertionError a) {
      assertEquals(Const.StatusCodes.DBLEVEL_NULL_INPUT, a.getMessage());
    }
  }
 public StudentAttributes(
     String section, String team, String name, String email, String comment, String courseId) {
   this();
   this.section = Sanitizer.sanitizeTitle(section);
   this.team = Sanitizer.sanitizeTitle(team);
   this.lastName = Sanitizer.sanitizeName(StringHelper.splitName(name)[1]);
   this.name = Sanitizer.sanitizeName(name);
   this.email = Sanitizer.sanitizeEmail(email);
   this.comments = Sanitizer.sanitizeTextField(comment);
   this.course = Sanitizer.sanitizeTitle(courseId);
 }
  private void testInputValidation() {

    ______TS("Checking max-length enforcement by the text boxes");

    String maxLengthInstructorName =
        StringHelper.generateStringOfLength(FieldValidator.PERSON_NAME_MAX_LENGTH);
    String longInstructorName =
        StringHelper.generateStringOfLength(FieldValidator.PERSON_NAME_MAX_LENGTH + 1);

    courseEditPage.clickEditInstructorLink(1);
    courseEditPage.clickShowNewInstructorFormButton();

    // Add instructor
    assertEquals(
        maxLengthInstructorName, courseEditPage.fillNewInstructorName(maxLengthInstructorName));
    assertEquals(
        longInstructorName.substring(0, FieldValidator.PERSON_NAME_MAX_LENGTH),
        courseEditPage.fillNewInstructorName(longInstructorName));
    // Edit instructor
    assertEquals(
        maxLengthInstructorName, courseEditPage.editInstructorName(1, maxLengthInstructorName));
    assertEquals(
        longInstructorName.substring(0, FieldValidator.PERSON_NAME_MAX_LENGTH),
        courseEditPage.editInstructorName(1, longInstructorName));

    String maxLengthEmail = StringHelper.generateStringOfLength(FieldValidator.EMAIL_MAX_LENGTH);
    String longEmail = StringHelper.generateStringOfLength(FieldValidator.EMAIL_MAX_LENGTH + 1);

    // Add instructor
    assertEquals(maxLengthEmail, courseEditPage.fillNewInstructorEmail(maxLengthEmail));
    assertEquals(
        longEmail.substring(0, FieldValidator.EMAIL_MAX_LENGTH),
        courseEditPage.fillNewInstructorEmail(longEmail));
    // Edit instructor
    assertEquals(maxLengthEmail, courseEditPage.editInstructorEmail(1, maxLengthEmail));
    assertEquals(
        longEmail.substring(0, FieldValidator.EMAIL_MAX_LENGTH),
        courseEditPage.editInstructorEmail(1, longEmail));
  }
  @Test
  public void testExecuteAndPostProcess() throws Exception {
    InstructorsDb instrDb = new InstructorsDb();

    InstructorAttributes instructor = dataBundle.instructors.get("instructor1OfCourse1");
    instructor = instrDb.getInstructorForEmail(instructor.courseId, instructor.email);

    gaeSimulation.loginAsInstructor(instructor.googleId);

    ______TS("not enough parameters");

    verifyAssumptionFailure();

    ______TS("invalid key");

    String[] submissionParams = new String[] {Const.ParamsNames.REGKEY, "invalidKey"};

    InstructorCourseJoinAuthenticatedAction a = getAction(submissionParams);
    RedirectResult r = (RedirectResult) a.executeAndPostProcess();

    assertEquals(
        Const.ActionURIs.INSTRUCTOR_HOME_PAGE
            + "?message=You+have+used+an+invalid+join+link"
            + "%3A+%2Fpage%2FinstructorCourseJoin%3Fregkey%3DinvalidKey"
            + "&error=true&user="******"instructor already registered");

    submissionParams =
        new String[] {Const.ParamsNames.REGKEY, StringHelper.encrypt(instructor.key)};

    a = getAction(submissionParams);
    r = (RedirectResult) a.executeAndPostProcess();

    assertEquals(
        Const.ActionURIs.INSTRUCTOR_HOME_PAGE
            + "?message=idOfInstructor1OfCourse1+has+already+joined+this+course"
            + "&persistencecourse="
            + instructor.courseId
            + "&error=true&user="******"instructor object belongs to another account");

    InstructorAttributes instructor2 = dataBundle.instructors.get("instructor2OfCourse1");
    instructor2 = instrDb.getInstructorForGoogleId(instructor2.courseId, instructor2.googleId);

    submissionParams =
        new String[] {Const.ParamsNames.REGKEY, StringHelper.encrypt(instructor2.key)};

    a = getAction(submissionParams);
    r = (RedirectResult) a.executeAndPostProcess();

    assertEquals(
        Const.ActionURIs.INSTRUCTOR_HOME_PAGE
            + "?message=The+join+link+used+belongs+to+a+different+user"
            + "+whose+Google+ID+is+idOfInst..fCourse1"
            + "+%28only+part+of+the+Google+ID+is+shown+to+protect+privacy%29."
            + "+If+that+Google+ID+is+owned+by+you%2C+please+logout+and"
            + "+re-login+using+that+Google+account.+If+it+doesn%E2%80%99t"
            + "+belong+to+you%2C+please+%3Ca+href%3D%22mailto"
            + "%3Ateammates%40comp.nus.edu.sg%3Fbody%3D"
            + "Your+name%3A%250AYour+course%3A%250AYour+university%3A%22%3E"
            + "contact+us%3C%2Fa%3E+so+that+we+can+investigate."
            + "&persistencecourse="
            + instructor2.courseId
            + "&error=true&user="******"typical case");

    instructor =
        new InstructorAttributes(
            "ICJAAT.instr", instructor.courseId, "New Instructor", "*****@*****.**");
    InstructorsLogic.inst().addInstructor(instructor.courseId, instructor.name, instructor.email);

    AccountAttributes newInstructorAccount =
        new AccountAttributes(instructor.googleId, instructor.name, false, instructor.email, "NUS");
    AccountsLogic.inst().createAccount(newInstructorAccount);

    InstructorAttributes newInstructor =
        instrDb.getInstructorForEmail(instructor.courseId, instructor.email);

    gaeSimulation.loginUser(instructor.googleId);

    submissionParams =
        new String[] {Const.ParamsNames.REGKEY, StringHelper.encrypt(newInstructor.key)};

    a = getAction(submissionParams);
    r = (RedirectResult) a.executeAndPostProcess();

    assertEquals(
        Const.ActionURIs.INSTRUCTOR_HOME_PAGE
            + "?persistencecourse=idOfTypicalCourse1"
            + "&error=false&user=ICJAAT.instr",
        r.getDestinationWithParams());
    assertFalse(r.isError);

    InstructorAttributes retrievedInstructor =
        instrDb.getInstructorForEmail(instructor.courseId, instructor.email);
    assertEquals(instructor.googleId, retrievedInstructor.googleId);
  }
  @Override
  public ActionResult execute() throws EntityDoesNotExistException {
    String newCourseId = getRequestParamValue(Const.ParamsNames.COURSE_ID);
    Assumption.assertNotNull(newCourseId);
    String newCourseName = getRequestParamValue(Const.ParamsNames.COURSE_NAME);
    Assumption.assertNotNull(newCourseName);

    /* Check if user has the right to execute the action */
    new GateKeeper().verifyInstructorPrivileges(account);

    /* Create a new course in the database */
    data = new InstructorCoursesPageData(account);
    CourseAttributes newCourse = new CourseAttributes(newCourseId, newCourseName);
    createCourse(newCourse);

    /* Prepare data for the refreshed page after executing the adding action */
    List<CourseDetailsBundle> allCourses =
        new ArrayList<CourseDetailsBundle>(
            logic.getCourseSummariesForInstructor(data.account.googleId).values());
    CourseDetailsBundle.sortDetailedCoursesByCourseId(allCourses);
    List<CourseDetailsBundle> activeCourses =
        logic.extractActiveCourses(allCourses, data.account.googleId);
    List<CourseDetailsBundle> archivedCourses =
        logic.extractArchivedCourses(allCourses, data.account.googleId);

    String CourseIdToShowParam = "";
    String CourseNameToShowParam = "";

    if (isError) { // there is error in adding the course
      CourseIdToShowParam = Sanitizer.sanitizeForHtml(newCourse.id);
      CourseNameToShowParam = Sanitizer.sanitizeForHtml(newCourse.name);

      List<String> statusMessageTexts = new ArrayList<String>();

      for (StatusMessage msg : statusToUser) {
        statusMessageTexts.add(msg.getText());
      }

      statusToAdmin = StringHelper.toString(statusMessageTexts, "<br>");
    } else {
      statusToAdmin = "Course added : " + newCourse.id;
      statusToAdmin += "<br>Total courses: " + allCourses.size();
    }

    List<CourseAttributes> courseList = logic.getCoursesForInstructor(data.account.googleId);
    Map<String, InstructorAttributes> instructorsForCourses =
        new HashMap<String, InstructorAttributes>();
    for (CourseAttributes course : courseList) {
      instructorsForCourses.put(
          course.id, logic.getInstructorForGoogleId(course.id, data.account.googleId));
    }

    data.init(
        activeCourses,
        archivedCourses,
        instructorsForCourses,
        CourseIdToShowParam,
        CourseNameToShowParam);

    return createShowPageResult(Const.ViewURIs.INSTRUCTOR_COURSES, data);
  }
  @Override
  protected ActionResult execute() throws EntityDoesNotExistException {
    courseId = getRequestParamValue(Const.ParamsNames.COURSE_ID);
    feedbackSessionName = getRequestParamValue(Const.ParamsNames.FEEDBACK_SESSION_NAME);
    Assumption.assertPostParamNotNull(Const.ParamsNames.COURSE_ID, courseId);
    Assumption.assertPostParamNotNull(Const.ParamsNames.FEEDBACK_SESSION_NAME, feedbackSessionName);

    setAdditionalParameters();
    verifyAccesibleForSpecificUser();

    String userEmailForCourse = getUserEmailForCourse();
    String userTeamForCourse = getUserTeamForCourse();
    String userSectionForCourse = getUserSectionForCourse();
    data = new FeedbackSubmissionEditPageData(account, student);
    data.bundle = getDataBundle(userEmailForCourse);
    Assumption.assertNotNull(
        "Feedback session " + feedbackSessionName + " does not exist in " + courseId + ".",
        data.bundle);

    checkAdditionalConstraints();

    setStatusToAdmin();

    if (!isSessionOpenForSpecificUser(data.bundle.feedbackSession)) {
      isError = true;
      statusToUser.add(
          new StatusMessage(
              Const.StatusMessages.FEEDBACK_SUBMISSIONS_NOT_OPEN, StatusMessageColor.WARNING));
      return createSpecificRedirectResult();
    }

    int numOfQuestionsToGet = data.bundle.questionResponseBundle.size();
    for (int questionIndx = 1; questionIndx <= numOfQuestionsToGet; questionIndx++) {
      String totalResponsesForQuestion =
          getRequestParamValue(
              Const.ParamsNames.FEEDBACK_QUESTION_RESPONSETOTAL + "-" + questionIndx);

      if (totalResponsesForQuestion == null) {
        continue; // question has been skipped (not displayed).
      }

      List<FeedbackResponseAttributes> responsesForQuestion =
          new ArrayList<FeedbackResponseAttributes>();
      String questionId =
          HttpRequestHelper.getValueFromParamMap(
              requestParameters, Const.ParamsNames.FEEDBACK_QUESTION_ID + "-" + questionIndx);
      FeedbackQuestionAttributes questionAttributes = data.bundle.getQuestionAttributes(questionId);
      if (questionAttributes == null) {
        statusToUser.add(
            new StatusMessage(
                "The feedback session or questions may have changed while you were submitting. "
                    + "Please check your responses to make sure they are saved correctly.",
                StatusMessageColor.WARNING));
        isError = true;
        log.warning(
            "Question not found. (deleted or invalid id passed?) id: "
                + questionId
                + " index: "
                + questionIndx);
        continue;
      }

      FeedbackQuestionDetails questionDetails = questionAttributes.getQuestionDetails();

      int numOfResponsesToGet = Integer.parseInt(totalResponsesForQuestion);
      String qnId = "";

      Set<String> emailSet = data.bundle.getRecipientEmails(questionAttributes.getId());
      emailSet.add("");
      emailSet = StringHelper.recoverFromSanitizedText(emailSet);

      ArrayList<String> responsesRecipients = new ArrayList<String>();
      List<String> errors = new ArrayList<String>();

      for (int responseIndx = 0; responseIndx < numOfResponsesToGet; responseIndx++) {
        FeedbackResponseAttributes response =
            extractFeedbackResponseData(
                requestParameters, questionIndx, responseIndx, questionAttributes);

        if (response.feedbackQuestionType != questionAttributes.questionType) {
          errors.add(
              String.format(
                  Const.StatusMessages.FEEDBACK_RESPONSES_WRONG_QUESTION_TYPE, questionIndx));
        }

        qnId = response.feedbackQuestionId;

        boolean isExistingResponse = response.getId() != null;
        // test that if editing an existing response, that the edited response's id
        // came from the original set of existing responses loaded on the submission page
        if (isExistingResponse && !isExistingResponseValid(response)) {
          errors.add(
              String.format(Const.StatusMessages.FEEDBACK_RESPONSES_INVALID_ID, questionIndx));
          continue;
        }

        responsesRecipients.add(response.recipientEmail);
        // if the answer is not empty but the recipient is empty
        if (response.recipientEmail.isEmpty() && !response.responseMetaData.getValue().isEmpty()) {
          errors.add(
              String.format(
                  Const.StatusMessages.FEEDBACK_RESPONSES_MISSING_RECIPIENT, questionIndx));
        }

        if (response.responseMetaData.getValue().isEmpty()) {
          // deletes the response since answer is empty
          saveResponse(response);
        } else {
          response.giverEmail =
              questionAttributes.giverType.isTeam() ? userTeamForCourse : userEmailForCourse;
          response.giverSection = userSectionForCourse;
          responsesForQuestion.add(response);
        }
      }

      List<String> questionSpecificErrors =
          questionDetails.validateResponseAttributes(
              responsesForQuestion, data.bundle.recipientList.get(qnId).size());
      errors.addAll(questionSpecificErrors);

      if (!emailSet.containsAll(responsesRecipients)) {
        errors.add(
            String.format(Const.StatusMessages.FEEDBACK_RESPONSE_INVALID_RECIPIENT, questionIndx));
      }

      if (errors.isEmpty()) {
        for (FeedbackResponseAttributes response : responsesForQuestion) {
          saveResponse(response);
        }
      } else {
        List<StatusMessage> errorMessages = new ArrayList<StatusMessage>();

        for (String error : errors) {
          errorMessages.add(new StatusMessage(error, StatusMessageColor.DANGER));
        }

        statusToUser.addAll(errorMessages);
        isError = true;
      }
    }

    if (!isError) {
      statusToUser.add(
          new StatusMessage(
              Const.StatusMessages.FEEDBACK_RESPONSES_SAVED, StatusMessageColor.SUCCESS));
    }

    if (isUserRespondentOfSession()) {
      appendRespondant();
    } else {
      removeRespondant();
    }

    return createSpecificRedirectResult();
  }
 private boolean isMultipleFieldsEmpty() {
   int numEmptyFields =
       StringHelper.countEmptyStrings(shortName, email, nationality, moreInfo, pictureKey);
   return numEmptyFields > 1;
 }
  @Test
  public void testValidate() {
    EvaluationAttributes e = new EvaluationAttributes();

    e.courseId = "";
    e.name = "";
    e.instructions = new Text("Instruction to students.");
    e.startTime = TimeHelper.getDateOffsetToCurrentTime(1);
    e.endTime = TimeHelper.getDateOffsetToCurrentTime(2);
    e.activated = false;
    e.published = false;
    e.timeZone = 0.0;
    e.gracePeriod = 5;
    e.p2pEnabled = true;

    assertEquals("invalid values", false, e.isValid());
    String errorMessage =
        String.format(COURSE_ID_ERROR_MESSAGE, e.courseId, REASON_EMPTY)
            + EOL
            + String.format(EVALUATION_NAME_ERROR_MESSAGE, e.name, REASON_EMPTY);
    assertEquals("valid values", errorMessage, StringHelper.toString(e.getInvalidityInfo()));

    e.courseId = "valid-course";
    e.name = "valid name";
    e.instructions = new Text("valid instructions");
    assertTrue("valid, minimal properties", e.isValid());

    assertEquals("valid values", true, e.isValid());

    e.startTime = null;
    try {
      e.getInvalidityInfo();
      signalFailureToDetectException("null start time not detected");
    } catch (AssertionError e1) {
      ignoreExpectedException();
    }

    e.startTime = TimeHelper.getDateOffsetToCurrentTime(1);
    e.endTime = null;
    try {
      e.getInvalidityInfo();
      signalFailureToDetectException("null end time not detected");
    } catch (AssertionError e1) {
      ignoreExpectedException();
    }

    // SUCCESS : end == start
    e.endTime = TimeHelper.getDateOffsetToCurrentTime(1);
    e.startTime = e.endTime;
    assertTrue(e.isValid());

    // FAIL : end before start
    e.endTime = TimeHelper.getDateOffsetToCurrentTime(1);
    e.startTime = TimeHelper.getDateOffsetToCurrentTime(2);
    assertFalse(e.isValid());
    errorMessage =
        String.format(
            TIME_FRAME_ERROR_MESSAGE, END_TIME_FIELD_NAME, EVALUATION_NAME, START_TIME_FIELD_NAME);
    assertEquals(errorMessage, StringHelper.toString(e.getInvalidityInfo()));

    // FAIL : published before endtime: invalid
    e.published = true;
    e.startTime = TimeHelper.getDateOffsetToCurrentTime(0);
    e.endTime = TimeHelper.getMsOffsetToCurrentTime(5);
    assertFalse(e.isValid());
    assertEquals(
        FieldValidator.EVALUATION_END_TIME_ERROR_MESSAGE,
        StringHelper.toString(e.getInvalidityInfo()));

    // SUCCESS : just after endtime and published: valid
    e.startTime = TimeHelper.getDateOffsetToCurrentTime(-1);
    e.endTime = TimeHelper.getMsOffsetToCurrentTime(-5);
    e.published = true;
    assertTrue(e.isValid());

    // FAIL : activated before start time: invalid
    e.startTime = TimeHelper.getDateOffsetToCurrentTime(1);
    e.endTime = TimeHelper.getDateOffsetToCurrentTime(2);
    e.published = false;
    e.activated = true;
    assertFalse(e.isValid());
    assertEquals(
        FieldValidator.EVALUATION_START_TIME_ERROR_MESSAGE,
        StringHelper.toString(e.getInvalidityInfo()));
  }
 public String getPublicProfilePictureUrl() {
   return new Url(Const.ActionURIs.STUDENT_PROFILE_PICTURE)
       .withStudentEmail(StringHelper.encrypt(email))
       .withCourseId(StringHelper.encrypt(course))
       .toString();
 }
public class InstructorCourseJoinConfirmationPageUiTest extends BaseUiTestCase {
  private static Browser browser;
  private static DataBundle testData;
  private static InstructorCourseJoinConfirmationPage confirmationPage;
  String invalidEncryptedKey = StringHelper.encrypt("invalidKey");

  @BeforeClass
  public void classSetup() {
    printTestClassHeader();
    testData = loadDataBundle("/InstructorCourseJoinConfirmationPageUiTest.json");

    // use the instructor account injected for this test

    testData.instructors.get("ICJConfirmationUiT.instr.CS2104").googleId =
        TestProperties.TEST_INSTRUCTOR_ACCOUNT;
    testData.instructors.get("ICJConfirmationUiT.instr.CS2104").email =
        TestProperties.TEST_INSTRUCTOR_ACCOUNT + "@gmail.com";
    testData.instructors.get("ICJConfirmationUiT.instr.CS1101").email =
        TestProperties.TEST_INSTRUCTOR_ACCOUNT + "@gmail.com";

    removeAndRestoreDataBundle(testData);

    browser = BrowserPool.getBrowser(true);
    browser.driver.manage().deleteAllCookies();
  }

  @Test
  public void testAll() throws Exception {

    testContent();
    testJoinConfirmation();
  }

  private void testContent() {

    /*covered in testJoinConfirmation()
     *case: Click join link then confirm: success: valid key
     */
  }

  private void testJoinConfirmation() throws Exception {

    ______TS("Click join link then cancel");

    String joinLink =
        createUrl(Const.ActionURIs.INSTRUCTOR_COURSE_JOIN)
            .withRegistrationKey(invalidEncryptedKey)
            .toAbsoluteString();
    logout(browser);
    browser.driver.get(joinLink);
    confirmationPage =
        AppPage.createCorrectLoginPageType(browser)
            .loginAsJoiningInstructor(
                TestProperties.TEST_INSTRUCTOR_ACCOUNT, TestProperties.TEST_INSTRUCTOR_PASSWORD);

    confirmationPage.clickCancelButton();

    ______TS("Click join link then confirm: fail: invalid key");

    browser.driver.get(joinLink);
    confirmationPage =
        AppPage.createCorrectLoginPageType(browser)
            .loginAsJoiningInstructor(
                TestProperties.TEST_INSTRUCTOR_ACCOUNT, TestProperties.TEST_INSTRUCTOR_PASSWORD);

    InstructorHomePage instructorHome = confirmationPage.clickConfirmButton();
    instructorHome.verifyContains(
        "You have used an invalid join link: /page/instructorCourseJoin?key="
            + invalidEncryptedKey);

    ______TS("Click join link then confirm: success: valid key");

    String courseId = testData.courses.get("ICJConfirmationUiT.CS1101").getId();
    String instructorEmail = testData.instructors.get("ICJConfirmationUiT.instr.CS1101").email;

    String regkey = BackDoor.getEncryptedKeyForInstructor(courseId, instructorEmail);
    joinLink =
        createUrl(Const.ActionURIs.INSTRUCTOR_COURSE_JOIN)
            .withRegistrationKey(regkey)
            .toAbsoluteString();

    browser.driver.get(joinLink);
    confirmationPage =
        AppPage.getNewPageInstance(browser, InstructorCourseJoinConfirmationPage.class);

    // test content here to make test finish faster
    ______TS("test instructor confirmation page content");
    // this test uses accounts from test.properties

    // This is the full HTML verification for Instructor Course Join Confirmation Page,
    // the rest can all be verifyMainHtml
    confirmationPage.verifyHtml("/instructorCourseJoinConfirmationHTML.html");

    instructorHome = confirmationPage.clickConfirmButton();

    ______TS("Already joined, no confirmation page");

    browser.driver.get(joinLink);
    instructorHome = AppPage.getNewPageInstance(browser, InstructorHomePage.class);
    instructorHome.verifyStatus(
        TestProperties.TEST_INSTRUCTOR_ACCOUNT + " has already joined this course");
  }

  @AfterClass
  public static void classTearDown() {
    BrowserPool.release(browser);
  }
}
  @SuppressWarnings("deprecation")
  private void testCreateInstructorAction() throws Exception {

    InstructorAttributes instructor = new InstructorAttributes();

    String shortName = "Instrúctör";
    instructor.name = "AHPUiT Instrúctör";
    instructor.email = "*****@*****.**";
    String institute = "TEAMMATES Test Institute 1";
    String demoCourseId = "AHPUiT.instr1.gma-demo";

    ______TS(
        "action success : create instructor account and the account is created successfully after user's verification");

    BackDoor.deleteAccount(TestProperties.inst().TEST_INSTRUCTOR_ACCOUNT);
    BackDoor.deleteCourse(demoCourseId);
    BackDoor.deleteInstructor(demoCourseId, instructor.email);

    homePage.createInstructor(shortName, instructor, institute);

    String expectedjoinUrl = Config.APP_URL + Const.ActionURIs.INSTRUCTOR_COURSE_JOIN;

    expectedjoinUrl =
        Url.addParamToUrl(
            expectedjoinUrl,
            Const.ParamsNames.REGKEY,
            StringHelper.encrypt(BackDoor.getKeyForInstructor(demoCourseId, instructor.email)));

    expectedjoinUrl =
        Url.addParamToUrl(expectedjoinUrl, Const.ParamsNames.INSTRUCTOR_INSTITUTION, institute);

    homePage
        .getStatus()
        .contains(
            "Instructor AHPUiT Instrúctör has been successfully created with join link:\n"
                + expectedjoinUrl);
    homePage.logout();
    // verify the instructor and the demo course have been created
    assertNotNull(BackDoor.getCourse(demoCourseId));
    assertNotNull(BackDoor.getInstructorByEmail(instructor.email, demoCourseId));

    // get the joinURL which sent to the requester's email
    String joinActionUrl =
        TestProperties.inst().TEAMMATES_URL + Const.ActionURIs.INSTRUCTOR_COURSE_JOIN;

    String joinLink =
        Url.addParamToUrl(
            joinActionUrl,
            Const.ParamsNames.REGKEY,
            StringHelper.encrypt(BackDoor.getKeyForInstructor(demoCourseId, instructor.email)));

    joinLink = Url.addParamToUrl(joinLink, Const.ParamsNames.INSTRUCTOR_INSTITUTION, institute);

    // simulate the user's verification here because it is added by admin
    browser.driver.get(joinLink);
    confirmationPage =
        createCorrectLoginPageType(browser.driver.getPageSource())
            .loginAsJoiningInstructor(
                TestProperties.inst().TEST_INSTRUCTOR_ACCOUNT,
                TestProperties.inst().TEST_INSTRUCTOR_PASSWORD);
    confirmationPage.clickCancelButton();

    browser.driver.get(joinLink);
    confirmationPage =
        createCorrectLoginPageType(browser.driver.getPageSource())
            .loginAsJoiningInstructor(
                TestProperties.inst().TEST_INSTRUCTOR_ACCOUNT,
                TestProperties.inst().TEST_INSTRUCTOR_PASSWORD);
    confirmationPage.clickConfirmButton();

    // check a account has been created for the requester successfully
    assertNotNull(BackDoor.getAccount(TestProperties.inst().TEST_INSTRUCTOR_ACCOUNT));

    // verify sample course is accessible for newly joined instructor as an instructor

    ______TS("new instructor can see sample course in homepage");
    InstructorHomePage instructorHomePage =
        AppPage.getNewPageInstance(browser, InstructorHomePage.class);
    instructorHomePage.verifyHtmlMainContent("/newlyJoinedInstructorHomePage.html");

    ______TS("new instructor can access sample coure enroll page");
    InstructorCourseEnrollPage enrollPage = instructorHomePage.clickCourseErollLink(demoCourseId);
    enrollPage.verifyHtmlMainContent("/newlyJoinedInstructorCourseEnrollPage.html");

    ______TS("new instructor can access sample coure details page");
    instructorHomePage = enrollPage.goToPreviousPage(InstructorHomePage.class);
    InstructorCourseDetailsPage detailsPage = instructorHomePage.clickCourseViewLink(demoCourseId);
    detailsPage.verifyHtmlMainContent("/newlyJoinedInstructorCourseDetailsPage.html");

    ______TS("new instructor can access sample coure edit page");
    instructorHomePage = detailsPage.goToPreviousPage(InstructorHomePage.class);
    InstructorCourseEditPage editPage = instructorHomePage.clickCourseEditLink(demoCourseId);
    editPage.verifyHtmlMainContent("/newlyJoinedInstructorCourseEditPage.html");

    ______TS("new instructor can access sample coure feedback session adding page");
    instructorHomePage = editPage.goToPreviousPage(InstructorHomePage.class);
    InstructorFeedbacksPage feedbacksPage =
        instructorHomePage.clickCourseAddEvaluationLink(demoCourseId);
    feedbacksPage.verifyHtmlMainContent("/newlyJoinedInstructorFeedbacksPage.html");

    ______TS("new instructor can archive sample course");
    instructorHomePage = feedbacksPage.goToPreviousPage(InstructorHomePage.class);
    instructorHomePage.clickArchiveCourseLinkAndConfirm(demoCourseId);
    instructorHomePage.verifyHtmlMainContent(
        "/newlyJoinedInstructorHomePageSampleCourseArchived.html");

    ______TS("new instructor can unarchive sample course");
    String url =
        Url.addParamToUrl(
            TestProperties.inst().TEAMMATES_URL + Const.ActionURIs.INSTRUCTOR_COURSES_PAGE,
            Const.ParamsNames.USER_ID,
            TestProperties.inst().TEST_INSTRUCTOR_ACCOUNT);
    browser.driver.get(url);
    InstructorCoursesPage coursesPage =
        AppPage.getNewPageInstance(browser, InstructorCoursesPage.class);
    coursesPage.unarchiveCourse(demoCourseId);
    coursesPage.verifyHtmlMainContent(
        "/newlyJoinedInstructorCoursesPageSampleCourseUnarhived.html");

    ______TS("new instructor can access sample course students page");
    coursesPage
        .loadStudentsTab()
        .verifyHtmlMainContent("/newlyJoinedInstructorStudentListPage.html");
    ______TS("new instructor can access sample course comments page");
    coursesPage
        .loadInstructorCommentsTab()
        .verifyHtmlMainContent("/newlyJoinedInstructorCommentsPage.html");

    ______TS("new instructor can view feedbackSession result of sample course");
    coursesPage.loadInstructorHomeTab();
    instructorHomePage = AppPage.getNewPageInstance(browser, InstructorHomePage.class);
    instructorHomePage
        .clickFeedbackSessionViewResultsLink(
            "AHPUiT.instr1.gma-demo", "Second team feedback session")
        .verifyHtmlMainContent("/newlyJoinedInstructorFeedbackResultsPage.html");

    ______TS("new instructor can edit feedbackSession of sample course");
    instructorHomePage.loadInstructorHomeTab();
    InstructorFeedbackEditPage feedbackEditPage =
        instructorHomePage.clickFeedbackSessionEditLink(
            "AHPUiT.instr1.gma-demo", "Second team feedback session");

    feedbackEditPage.clickEditSessionButton();

    FeedbackSessionAttributes feedbackSession =
        BackDoor.getFeedbackSession("AHPUiT.instr1.gma-demo", "Second team feedback session");
    feedbackEditPage.editFeedbackSession(
        feedbackSession.startTime,
        feedbackSession.endTime,
        new Text("updated instructions"),
        feedbackSession.gracePeriod);
    instructorHomePage.verifyHtmlMainContent(
        "/newlyJoinedInstructorFeedbackSessionSuccessEdited.html");

    ______TS("new instructor can click submit button of sample feedbackSession");
    instructorHomePage.loadInstructorHomeTab();
    FeedbackSubmitPage fbsp =
        instructorHomePage.clickFeedbackSessionSubmitLink(
            "AHPUiT.instr1.gma-demo", "Second team feedback session");
    fbsp.verifyHtmlMainContent("/newlyJoinedInstructorFeedbackSubmissionEditPage.html");

    ______TS("new instructor can send reminder of sample course");
    instructorHomePage.loadInstructorHomeTab();
    feedbacksPage =
        instructorHomePage.clickFeedbackSessionRemindLink(
            "AHPUiT.instr1.gma-demo", "Second team feedback session");
    feedbacksPage.verifyHtmlMainContent("/newlyJoinedInstructorFeedbackSessionRemind.html");

    ______TS("new instructor can unpublish feedbackSession of sample course");
    instructorHomePage.loadInstructorHomeTab();
    feedbacksPage =
        instructorHomePage.clickFeedbackSessionUnpublishLink(
            "AHPUiT.instr1.gma-demo", "Second team feedback session");
    feedbacksPage.verifyHtmlMainContent("/newlyJoinedInstructorFeedbackSessionUnpublished.html");

    ______TS("new instructor can publish feedbackSession of sample course");
    instructorHomePage.loadInstructorHomeTab();
    feedbacksPage =
        instructorHomePage.clickFeedbackSessionPublishLink(
            "AHPUiT.instr1.gma-demo", "Second team feedback session");
    feedbacksPage.verifyHtmlMainContent("/newlyJoinedInstructorFeedbackSessionPublished.html");

    feedbacksPage.logout();

    ______TS("action failure : invalid parameter");

    Url homeUrl = createUrl(Const.ActionURIs.ADMIN_HOME_PAGE);
    homePage = loginAdminToPage(browser, homeUrl, AdminHomePage.class);

    instructor.email = "AHPUiT.email.tmt";
    homePage
        .createInstructor(shortName, instructor, institute)
        .verifyStatus(
            String.format(
                FieldValidator.EMAIL_ERROR_MESSAGE,
                instructor.email,
                FieldValidator.REASON_INCORRECT_FORMAT));

    ______TS("action success: course is accessible for newly joined instructor as student");
    // in staging server, the student account uses the hardcoded email above, so this can only be
    // test on dev server
    if (!TestProperties.inst().TEAMMATES_URL.contains("local")) {

      BackDoor.deleteCourse(demoCourseId);
      BackDoor.deleteAccount(TestProperties.inst().TEST_INSTRUCTOR_ACCOUNT);
      BackDoor.deleteInstructor(demoCourseId, instructor.email);
      return;
    }

    // verify sample course is accessible for newly joined instructor as an student

    StudentHomePage studentHomePage =
        HomePage.getNewInstance(browser)
            .clickStudentLogin()
            .loginAsStudent(
                TestProperties.inst().TEST_INSTRUCTOR_ACCOUNT,
                TestProperties.inst().TEST_INSTRUCTOR_PASSWORD);

    studentHomePage.verifyContains(demoCourseId);
    studentHomePage.clickViewTeam();

    StudentCourseDetailsPage courseDetailsPage =
        AppPage.getNewPageInstance(browser, StudentCourseDetailsPage.class);
    courseDetailsPage.verifyHtmlMainContent("/newlyJoinedInstructorStudentCourseDetailsPage.html");

    studentHomePage = courseDetailsPage.goToPreviousPage(StudentHomePage.class);
    studentHomePage.getViewFeedbackButton("First team feedback session").click();
    StudentFeedbackResultsPage sfrp =
        AppPage.getNewPageInstance(browser, StudentFeedbackResultsPage.class);
    sfrp.verifyHtmlMainContent("/newlyJoinedInstructorStudentFeedbackResultsPage.html");

    studentHomePage = sfrp.goToPreviousPage(StudentHomePage.class);
    studentHomePage.getEditFeedbackButton("First team feedback session").click();
    FeedbackSubmitPage fsp = AppPage.getNewPageInstance(browser, FeedbackSubmitPage.class);
    fsp.verifyHtmlMainContent("/newlyJoinedInstructorStudentFeedbackSubmissionEdit.html");

    studentHomePage = fsp.loadStudentHomeTab();
    StudentCommentsPage scp = studentHomePage.loadStudentCommentsTab();
    scp.verifyHtmlMainContent("/newlyJoinedInstructorStudentCommentsPage.html");

    studentHomePage = scp.loadStudentHomeTab();

    StudentProfilePage spp = studentHomePage.loadProfileTab();
    spp.verifyContains("Student Profile");
    spp.verifyContains("AHPUiT Instrúctör");

    studentHomePage.logout();

    // login in as instructor again to test sample course deletion
    instructorHomePage =
        HomePage.getNewInstance(browser)
            .clickInstructorLogin()
            .loginAsInstructor(
                TestProperties.inst().TEST_INSTRUCTOR_ACCOUNT,
                TestProperties.inst().TEST_INSTRUCTOR_PASSWORD);

    instructorHomePage.clickAndConfirm(instructorHomePage.getDeleteCourseLink(demoCourseId));
    assertTrue(
        instructorHomePage
            .getStatus()
            .contains("The course " + demoCourseId + " has been deleted."));

    instructorHomePage.logout();

    BackDoor.deleteAccount(TestProperties.inst().TEST_INSTRUCTOR_ACCOUNT);
    BackDoor.deleteCourse(demoCourseId);
    BackDoor.deleteInstructor(demoCourseId, instructor.email);
  }
  @Test
  public void testExecuteAndPostProcess() throws Exception {
    StudentsDb studentsDb = new StudentsDb();
    AccountsDb accountsDb = new AccountsDb();

    StudentAttributes student1InCourse1 = dataBundle.students.get("student1InCourse1");
    student1InCourse1 =
        studentsDb.getStudentForGoogleId(student1InCourse1.course, student1InCourse1.googleId);

    gaeSimulation.loginAsStudent(student1InCourse1.googleId);

    ______TS("not enough parameters");

    verifyAssumptionFailure();

    ______TS("invalid key");

    String invalidKey = StringHelper.encrypt("invalid key");
    String[] submissionParams =
        new String[] {
          Const.ParamsNames.REGKEY,
          invalidKey,
          Const.ParamsNames.NEXT_URL,
          Const.ActionURIs.STUDENT_HOME_PAGE
        };

    try {
      StudentCourseJoinAuthenticatedAction authenticatedAction = getAction(submissionParams);
      getRedirectResult(authenticatedAction);
    } catch (UnauthorizedAccessException uae) {
      assertEquals("No student with given registration key:" + invalidKey, uae.getMessage());
    }

    ______TS("already registered student");

    submissionParams =
        new String[] {
          Const.ParamsNames.REGKEY,
          StringHelper.encrypt(student1InCourse1.key),
          Const.ParamsNames.NEXT_URL,
          Const.ActionURIs.STUDENT_PROFILE_PAGE
        };

    StudentCourseJoinAuthenticatedAction authenticatedAction = getAction(submissionParams);
    RedirectResult redirectResult = getRedirectResult(authenticatedAction);

    assertEquals(
        Const.ActionURIs.STUDENT_HOME_PAGE + "?error=true&user="******"You (student1InCourse1) have already joined this course",
        redirectResult.getStatusMessage());

    /*______TS("student object belongs to another account");

            StudentAttributes student2InCourse1 = dataBundle.students
                    .get("student2InCourse1");
            student2InCourse1 = studentsDb.getStudentForGoogleId(
                    student2InCourse1.course, student2InCourse1.googleId);

            submissionParams = new String[] {
                    Const.ParamsNames.REGKEY,
                    StringHelper.encrypt(student2InCourse1.key),
                    Const.ParamsNames.NEXT_URL, Const.ActionURIs.STUDENT_HOME_PAGE
            };

            authenticatedAction = getAction(submissionParams);
            redirectResult = getRedirectResult(authenticatedAction);

            assertEquals(
                    Const.ActionURIs.STUDENT_HOME_PAGE
                            + "?persistencecourse=" + student1InCourse1.course
                            + "&error=true&user="******"The join link used belongs to a different user"
                            + " whose Google ID is stude..ourse1 "
                            + "(only part of the Google ID is shown to protect privacy)."
                            + " If that Google ID is owned by you, "
                            + "please logout and re-login using that Google account."
                            + " If it doesn’t belong to you, please "
                            + "<a href=\"mailto:" + Config.SUPPORT_EMAIL
                            + "?body=Your name:%0AYour course:%0AYour university:\">"
                            + "contact us</a> so that we can investigate.",
                    redirectResult.getStatusMessage());
    */
    ______TS("join course with no feedback sessions, profile is empty");
    AccountAttributes studentWithEmptyProfile = dataBundle.accounts.get("noFSStudent");
    studentWithEmptyProfile = accountsDb.getAccount(studentWithEmptyProfile.googleId, true);
    assertNotNull(studentWithEmptyProfile.studentProfile);
    assertEquals("", studentWithEmptyProfile.studentProfile.pictureKey);
    assertEquals("", studentWithEmptyProfile.studentProfile.shortName);
    assertEquals("", studentWithEmptyProfile.studentProfile.nationality);
    assertEquals("", studentWithEmptyProfile.studentProfile.moreInfo);
    assertEquals("", studentWithEmptyProfile.studentProfile.email);

    StudentAttributes studentWithEmptyProfileAttributes =
        dataBundle.students.get("noFSStudentWithNoProfile");
    studentWithEmptyProfileAttributes =
        studentsDb.getStudentForEmail(
            studentWithEmptyProfileAttributes.course, studentWithEmptyProfileAttributes.email);

    gaeSimulation.loginUser("idOfNoFSStudent");

    submissionParams =
        new String[] {
          Const.ParamsNames.REGKEY,
          StringHelper.encrypt(studentWithEmptyProfileAttributes.key),
          Const.ParamsNames.NEXT_URL,
          Const.ActionURIs.STUDENT_HOME_PAGE
        };

    authenticatedAction = getAction(submissionParams);
    redirectResult = getRedirectResult(authenticatedAction);

    assertEquals(
        Const.ActionURIs.STUDENT_HOME_PAGE
            + "?persistencecourse=idOfCourseNoEvals"
            + "&error=false&user=idOfNoFSStudent",
        redirectResult.getDestinationWithParams());
    assertFalse(redirectResult.isError);
    assertEquals(
        String.format(
                Const.StatusMessages.STUDENT_COURSE_JOIN_SUCCESSFUL,
                "[idOfCourseNoEvals] Typical Course 3 with 0 Evals")
            + "<br>"
            + String.format(
                Const.StatusMessages.HINT_FOR_NO_SESSIONS_STUDENT,
                "[idOfCourseNoEvals] Typical Course 3 with 0 Evals")
            + "<br>"
            + Const.StatusMessages.STUDENT_UPDATE_PROFILE,
        redirectResult.getStatusMessage());

    ______TS("join course with no feedback sessions, profile has only one missing field");
    AccountAttributes studentWithoutProfilePicture = dataBundle.accounts.get("noFSStudent2");
    studentWithoutProfilePicture =
        accountsDb.getAccount(studentWithoutProfilePicture.googleId, true);
    assertNotNull(studentWithoutProfilePicture.studentProfile);
    assertEquals("", studentWithoutProfilePicture.studentProfile.pictureKey);
    assertFalse(studentWithoutProfilePicture.studentProfile.nationality.isEmpty());
    assertFalse(studentWithoutProfilePicture.studentProfile.shortName.isEmpty());
    assertFalse(studentWithoutProfilePicture.studentProfile.moreInfo.isEmpty());
    assertFalse(studentWithoutProfilePicture.studentProfile.email.isEmpty());

    StudentAttributes studentWithoutProfilePictureAttributes =
        dataBundle.students.get("noFSStudentWithPartialProfile");

    studentWithoutProfilePictureAttributes =
        studentsDb.getStudentForEmail(
            studentWithoutProfilePictureAttributes.course,
            studentWithoutProfilePictureAttributes.email);

    gaeSimulation.loginUser("idOfNoFSStudent2");

    submissionParams =
        new String[] {
          Const.ParamsNames.REGKEY,
          StringHelper.encrypt(studentWithoutProfilePictureAttributes.key),
          Const.ParamsNames.NEXT_URL,
          Const.ActionURIs.STUDENT_HOME_PAGE
        };

    authenticatedAction = getAction(submissionParams);
    redirectResult = getRedirectResult(authenticatedAction);

    assertEquals(
        Const.ActionURIs.STUDENT_HOME_PAGE
            + "?persistencecourse=idOfCourseNoEvals"
            + "&error=false&user=idOfNoFSStudent2",
        redirectResult.getDestinationWithParams());
    assertFalse(redirectResult.isError);
    assertEquals(
        String.format(
                Const.StatusMessages.STUDENT_COURSE_JOIN_SUCCESSFUL,
                "[idOfCourseNoEvals] Typical Course 3 with 0 Evals")
            + "<br>"
            + String.format(
                Const.StatusMessages.HINT_FOR_NO_SESSIONS_STUDENT,
                "[idOfCourseNoEvals] Typical Course 3 with 0 Evals")
            + "<br>"
            + Const.StatusMessages.STUDENT_UPDATE_PROFILE_PICTURE,
        redirectResult.getStatusMessage());

    ______TS("join course with no feedback sessions, profile has no missing field");
    AccountAttributes studentWithFullProfile = dataBundle.accounts.get("noFSStudent3");

    studentWithFullProfile = accountsDb.getAccount(studentWithFullProfile.googleId, true);
    assertNotNull(studentWithFullProfile.studentProfile);
    assertFalse(studentWithFullProfile.studentProfile.pictureKey.isEmpty());
    assertFalse(studentWithoutProfilePicture.studentProfile.nationality.isEmpty());
    assertFalse(studentWithoutProfilePicture.studentProfile.shortName.isEmpty());
    assertFalse(studentWithoutProfilePicture.studentProfile.moreInfo.isEmpty());
    assertFalse(studentWithoutProfilePicture.studentProfile.email.isEmpty());

    StudentAttributes studentWithFullProfileAttributes =
        dataBundle.students.get("noFSStudentWithFullProfile");
    studentWithFullProfileAttributes =
        studentsDb.getStudentForEmail(
            studentWithFullProfileAttributes.course, studentWithFullProfileAttributes.email);

    gaeSimulation.loginUser("idOfNoFSStudent3");

    submissionParams =
        new String[] {
          Const.ParamsNames.REGKEY,
          StringHelper.encrypt(studentWithFullProfileAttributes.key),
          Const.ParamsNames.NEXT_URL,
          Const.ActionURIs.STUDENT_HOME_PAGE
        };

    authenticatedAction = getAction(submissionParams);
    redirectResult = getRedirectResult(authenticatedAction);

    assertEquals(
        Const.ActionURIs.STUDENT_HOME_PAGE
            + "?persistencecourse=idOfCourseNoEvals"
            + "&error=false&user=idOfNoFSStudent3",
        redirectResult.getDestinationWithParams());
    assertFalse(redirectResult.isError);
    assertEquals(
        String.format(
                Const.StatusMessages.STUDENT_COURSE_JOIN_SUCCESSFUL,
                "[idOfCourseNoEvals] Typical Course 3 with 0 Evals")
            + "<br>"
            + String.format(
                Const.StatusMessages.HINT_FOR_NO_SESSIONS_STUDENT,
                "[idOfCourseNoEvals] Typical Course 3 with 0 Evals"),
        redirectResult.getStatusMessage());

    ______TS("typical case");

    AccountAttributes newStudentAccount =
        new AccountAttributes(
            "idOfNewStudent",
            "nameOfNewStudent",
            false,
            "*****@*****.**",
            "TEAMMATES Test Institute 5");
    accountsDb.createAccount(newStudentAccount);

    StudentAttributes newStudentAttributes =
        new StudentAttributes(
            student1InCourse1.section,
            student1InCourse1.team,
            "nameOfNewStudent",
            "*****@*****.**",
            "This is a new student",
            student1InCourse1.course);

    studentsDb.createEntity(newStudentAttributes);
    newStudentAttributes =
        studentsDb.getStudentForEmail(newStudentAttributes.course, newStudentAttributes.email);

    gaeSimulation.loginUser("idOfNewStudent");

    submissionParams =
        new String[] {
          Const.ParamsNames.REGKEY,
          StringHelper.encrypt(newStudentAttributes.key),
          Const.ParamsNames.NEXT_URL,
          Const.ActionURIs.STUDENT_PROFILE_PAGE
        };

    authenticatedAction = getAction(submissionParams);
    redirectResult = getRedirectResult(authenticatedAction);

    assertEquals(
        Const.ActionURIs.STUDENT_PROFILE_PAGE
            + "?persistencecourse=idOfTypicalCourse1"
            + "&error=false&user=idOfNewStudent",
        redirectResult.getDestinationWithParams());
    assertFalse(redirectResult.isError);
    assertEquals(
        String.format(
            Const.StatusMessages.STUDENT_COURSE_JOIN_SUCCESSFUL,
            "[idOfTypicalCourse1] Typical Course 1 with 2 Evals"),
        redirectResult.getStatusMessage());
  }
 public static String generateStringOfLength(int length) {
   return StringHelper.generateStringOfLength(length, 'a');
 }