Search in sources :

Example 11 with FeedbackQuestionDetails

use of teammates.common.datatransfer.questions.FeedbackQuestionDetails in project teammates by TEAMMATES.

the class FeedbackQuestionsLogicTest method testCopyQuestion.

private void testCopyQuestion() throws Exception {
    InstructorAttributes instructor2OfCourse1 = dataBundle.instructors.get("instructor2OfCourse1");
    ______TS("Typical case: copy question successfully");
    FeedbackQuestionAttributes question1 = dataBundle.feedbackQuestions.get("qn1InSession1InCourse1");
    question1 = fqLogic.getFeedbackQuestion(question1.feedbackSessionName, question1.courseId, question1.questionNumber);
    FeedbackQuestionAttributes copiedQuestion = fqLogic.copyFeedbackQuestion(question1.getId(), question1.feedbackSessionName, question1.courseId, instructor2OfCourse1.email);
    FeedbackQuestionDetails question1Details = question1.getQuestionDetails();
    FeedbackQuestionDetails copiedQuestionDetails = copiedQuestion.getQuestionDetails();
    assertEquals(question1.numberOfEntitiesToGiveFeedbackTo, copiedQuestion.numberOfEntitiesToGiveFeedbackTo);
    assertEquals(question1.questionType, copiedQuestion.questionType);
    assertEquals(question1.giverType, copiedQuestion.giverType);
    assertEquals(question1.recipientType, copiedQuestion.recipientType);
    assertEquals(question1Details.getQuestionText(), copiedQuestionDetails.getQuestionText());
}
Also used : FeedbackQuestionDetails(teammates.common.datatransfer.questions.FeedbackQuestionDetails) FeedbackQuestionAttributes(teammates.common.datatransfer.attributes.FeedbackQuestionAttributes) InstructorAttributes(teammates.common.datatransfer.attributes.InstructorAttributes)

Example 12 with FeedbackQuestionDetails

use of teammates.common.datatransfer.questions.FeedbackQuestionDetails in project teammates by TEAMMATES.

the class FeedbackQuestionsDbTest method testUpdateFeedbackQuestion.

@Test
public void testUpdateFeedbackQuestion() throws Exception {
    ______TS("null params");
    try {
        fqDb.updateFeedbackQuestion(null);
        signalFailureToDetectException();
    } catch (AssertionError e) {
        AssertHelper.assertContains(Const.StatusCodes.DBLEVEL_NULL_INPUT, e.getLocalizedMessage());
    }
    ______TS("invalid feedback question attributes");
    FeedbackQuestionAttributes invalidFqa = getNewFeedbackQuestionAttributes();
    fqDb.deleteEntity(invalidFqa);
    fqDb.createEntity(invalidFqa);
    invalidFqa.setId(fqDb.getFeedbackQuestion(invalidFqa.feedbackSessionName, invalidFqa.courseId, invalidFqa.questionNumber).getId());
    invalidFqa.creatorEmail = "haha";
    try {
        fqDb.updateFeedbackQuestion(invalidFqa);
        signalFailureToDetectException();
    } catch (InvalidParametersException e) {
        AssertHelper.assertContains("Invalid creator's email", e.getLocalizedMessage());
    }
    ______TS("feedback session does not exist");
    FeedbackQuestionAttributes nonexistantFq = getNewFeedbackQuestionAttributes();
    nonexistantFq.setId("non-existent fq id");
    try {
        fqDb.updateFeedbackQuestion(nonexistantFq);
        signalFailureToDetectException();
    } catch (EntityDoesNotExistException e) {
        AssertHelper.assertContains(FeedbackQuestionsDb.ERROR_UPDATE_NON_EXISTENT, e.getLocalizedMessage());
    }
    ______TS("standard success case");
    FeedbackQuestionAttributes modifiedQuestion = getNewFeedbackQuestionAttributes();
    fqDb.deleteEntity(modifiedQuestion);
    fqDb.createEntity(modifiedQuestion);
    verifyPresentInDatastore(modifiedQuestion);
    modifiedQuestion = fqDb.getFeedbackQuestion(modifiedQuestion.feedbackSessionName, modifiedQuestion.courseId, modifiedQuestion.questionNumber);
    FeedbackQuestionDetails fqd = modifiedQuestion.getQuestionDetails();
    fqd.setQuestionText("New question text!");
    modifiedQuestion.setQuestionDetails(fqd);
    fqDb.updateFeedbackQuestion(modifiedQuestion);
    verifyPresentInDatastore(modifiedQuestion);
    modifiedQuestion = fqDb.getFeedbackQuestion(modifiedQuestion.feedbackSessionName, modifiedQuestion.courseId, modifiedQuestion.questionNumber);
    assertEquals("New question text!", modifiedQuestion.getQuestionDetails().getQuestionText());
    fqDb.deleteEntity(modifiedQuestion);
}
Also used : FeedbackQuestionDetails(teammates.common.datatransfer.questions.FeedbackQuestionDetails) FeedbackQuestionAttributes(teammates.common.datatransfer.attributes.FeedbackQuestionAttributes) InvalidParametersException(teammates.common.exception.InvalidParametersException) EntityDoesNotExistException(teammates.common.exception.EntityDoesNotExistException) Test(org.testng.annotations.Test)

Example 13 with FeedbackQuestionDetails

use of teammates.common.datatransfer.questions.FeedbackQuestionDetails in project teammates by TEAMMATES.

the class InstructorFeedbackQuestionEditAction method editQuestion.

private void editQuestion(FeedbackQuestionAttributes updatedQuestion) throws InvalidParametersException, EntityDoesNotExistException {
    String err = validateQuestionGiverRecipientVisibility(updatedQuestion);
    if (!err.isEmpty()) {
        statusToUser.add(new StatusMessage(err, StatusMessageColor.DANGER));
        isError = true;
    }
    FeedbackQuestionDetails updatedQuestionDetails = updatedQuestion.getQuestionDetails();
    List<String> questionDetailsErrors = updatedQuestionDetails.validateQuestionDetails();
    List<StatusMessage> questionDetailsErrorsMessages = new ArrayList<>();
    for (String error : questionDetailsErrors) {
        questionDetailsErrorsMessages.add(new StatusMessage(error, StatusMessageColor.DANGER));
    }
    if (questionDetailsErrors.isEmpty()) {
        logic.updateFeedbackQuestionNumber(updatedQuestion);
        statusToUser.add(new StatusMessage(Const.StatusMessages.FEEDBACK_QUESTION_EDITED, StatusMessageColor.SUCCESS));
        statusToAdmin = "Feedback Question " + updatedQuestion.questionNumber + " for session:<span class=\"bold\">(" + updatedQuestion.feedbackSessionName + ")</span> for Course <span class=\"bold\">[" + updatedQuestion.courseId + "]</span> edited.<br>" + "<span class=\"bold\">" + updatedQuestionDetails.getQuestionTypeDisplayName() + ":</span> " + SanitizationHelper.sanitizeForHtml(updatedQuestionDetails.getQuestionText());
    } else {
        statusToUser.addAll(questionDetailsErrorsMessages);
        isError = true;
    }
}
Also used : FeedbackQuestionDetails(teammates.common.datatransfer.questions.FeedbackQuestionDetails) ArrayList(java.util.ArrayList) StatusMessage(teammates.common.util.StatusMessage)

Example 14 with FeedbackQuestionDetails

use of teammates.common.datatransfer.questions.FeedbackQuestionDetails in project teammates by TEAMMATES.

the class InstructorFeedbackQuestionEditAction method validateQuestionGiverRecipientVisibility.

/**
 * Validates that the giver and recipient for the given FeedbackQuestionAttributes is valid for its question type.
 * Validates that the visibility for the given FeedbackQuestionAttributes is valid for its question type.
 *
 * @return error message detailing the error, or an empty string if valid.
 */
public static String validateQuestionGiverRecipientVisibility(FeedbackQuestionAttributes feedbackQuestionAttributes) {
    String errorMsg = "";
    FeedbackQuestionDetails questionDetails = null;
    Class<? extends FeedbackQuestionDetails> questionDetailsClass = feedbackQuestionAttributes.questionType.getQuestionDetailsClass();
    Constructor<? extends FeedbackQuestionDetails> questionDetailsClassConstructor;
    try {
        questionDetailsClassConstructor = questionDetailsClass.getConstructor();
        questionDetails = questionDetailsClassConstructor.newInstance();
        Method m = questionDetailsClass.getMethod("validateGiverRecipientVisibility", FeedbackQuestionAttributes.class);
        errorMsg = (String) m.invoke(questionDetails, feedbackQuestionAttributes);
    } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | InstantiationException e) {
        log.severe(TeammatesException.toStringWithStackTrace(e));
        // Assumption.fails are not tested
        Assumption.fail("Failed to instantiate Feedback*QuestionDetails instance for " + feedbackQuestionAttributes.questionType.toString() + " question type.");
    }
    return errorMsg;
}
Also used : FeedbackQuestionDetails(teammates.common.datatransfer.questions.FeedbackQuestionDetails) Method(java.lang.reflect.Method) InvocationTargetException(java.lang.reflect.InvocationTargetException)

Example 15 with FeedbackQuestionDetails

use of teammates.common.datatransfer.questions.FeedbackQuestionDetails in project teammates by TEAMMATES.

the class FeedbackSubmissionEditSaveAction method execute.

@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();
    verifyAccessibleForSpecificUser();
    String userEmailForCourse = getUserEmailForCourse();
    data = new FeedbackSubmissionEditPageData(account, student, sessionToken);
    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();
    }
    String userTeamForCourse = getUserTeamForCourse();
    String userSectionForCourse = getUserSectionForCourse();
    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) {
            // question has been skipped (not displayed).
            continue;
        }
        List<FeedbackResponseAttributes> responsesForQuestion = new ArrayList<>();
        String questionId = getRequestParamValue(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);
        Set<String> emailSet = data.bundle.getRecipientEmails(questionAttributes.getId());
        emailSet.add("");
        emailSet = SanitizationHelper.desanitizeFromHtml(emailSet);
        ArrayList<String> responsesRecipients = new ArrayList<>();
        List<String> errors = new ArrayList<>();
        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));
            }
            boolean isExistingResponse = response.getId() != null;
            // 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.recipient);
            // if the answer is not empty but the recipient is empty
            if (response.recipient.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
                addToPendingResponses(response);
            } else {
                response.giver = questionAttributes.giverType.isTeam() ? userTeamForCourse : userEmailForCourse;
                response.giverSection = userSectionForCourse;
                responsesForQuestion.add(response);
            }
        }
        List<String> questionSpecificErrors = questionDetails.validateResponseAttributes(responsesForQuestion, data.bundle.recipientList.get(questionId).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) {
                addToPendingResponses(response);
            }
        } else {
            List<StatusMessage> errorMessages = new ArrayList<>();
            for (String error : errors) {
                errorMessages.add(new StatusMessage(error, StatusMessageColor.DANGER));
            }
            statusToUser.addAll(errorMessages);
            isError = true;
        }
    }
    saveNewReponses(responsesToSave);
    deleteResponses(responsesToDelete);
    updateResponses(responsesToUpdate);
    if (!isError) {
        statusToUser.add(new StatusMessage(Const.StatusMessages.FEEDBACK_RESPONSES_SAVED, StatusMessageColor.SUCCESS));
    }
    if (isUserRespondentOfSession()) {
        appendRespondent();
    } else {
        removeRespondent();
    }
    boolean isSubmissionEmailRequested = "on".equals(getRequestParamValue(Const.ParamsNames.SEND_SUBMISSION_EMAIL));
    if (!isError && isSendSubmissionEmail && isSubmissionEmailRequested) {
        FeedbackSessionAttributes session = logic.getFeedbackSession(feedbackSessionName, courseId);
        Assumption.assertNotNull(session);
        String user = account == null ? null : account.googleId;
        String unregisteredStudentEmail = student == null ? null : student.email;
        String unregisteredStudentRegisterationKey = student == null ? null : student.key;
        StudentAttributes student = null;
        InstructorAttributes instructor = null;
        if (user != null) {
            student = logic.getStudentForGoogleId(courseId, user);
            instructor = logic.getInstructorForGoogleId(courseId, user);
        }
        if (student == null && unregisteredStudentEmail != null) {
            student = StudentAttributes.builder("", unregisteredStudentEmail, unregisteredStudentEmail).withKey(unregisteredStudentRegisterationKey).build();
        }
        Assumption.assertFalse(student == null && instructor == null);
        try {
            EmailWrapper email = instructor == null ? new EmailGenerator().generateFeedbackSubmissionConfirmationEmailForStudent(session, student, Instant.now()) : new EmailGenerator().generateFeedbackSubmissionConfirmationEmailForInstructor(session, instructor, Instant.now());
            emailSender.sendEmail(email);
        } catch (EmailSendingException e) {
            log.severe("Submission confirmation email failed to send: " + TeammatesException.toStringWithStackTrace(e));
        }
    }
    // TODO: Refactor to AjaxResult so status messages do not have to be passed by session
    return createSpecificRedirectResult();
}
Also used : EmailGenerator(teammates.logic.api.EmailGenerator) FeedbackQuestionDetails(teammates.common.datatransfer.questions.FeedbackQuestionDetails) ArrayList(java.util.ArrayList) FeedbackSubmissionEditPageData(teammates.ui.pagedata.FeedbackSubmissionEditPageData) EmailSendingException(teammates.common.exception.EmailSendingException) StudentAttributes(teammates.common.datatransfer.attributes.StudentAttributes) StatusMessage(teammates.common.util.StatusMessage) InstructorAttributes(teammates.common.datatransfer.attributes.InstructorAttributes) EmailWrapper(teammates.common.util.EmailWrapper) FeedbackSessionAttributes(teammates.common.datatransfer.attributes.FeedbackSessionAttributes) FeedbackResponseAttributes(teammates.common.datatransfer.attributes.FeedbackResponseAttributes) FeedbackQuestionAttributes(teammates.common.datatransfer.attributes.FeedbackQuestionAttributes)

Aggregations

FeedbackQuestionDetails (teammates.common.datatransfer.questions.FeedbackQuestionDetails)18 FeedbackQuestionAttributes (teammates.common.datatransfer.attributes.FeedbackQuestionAttributes)10 ArrayList (java.util.ArrayList)9 FeedbackResponseAttributes (teammates.common.datatransfer.attributes.FeedbackResponseAttributes)5 Text (com.google.appengine.api.datastore.Text)4 InstructorAttributes (teammates.common.datatransfer.attributes.InstructorAttributes)3 ElementTag (teammates.ui.template.ElementTag)3 InstructorFeedbackResultsResponseRow (teammates.ui.template.InstructorFeedbackResultsResponseRow)3 FeedbackSessionAttributes (teammates.common.datatransfer.attributes.FeedbackSessionAttributes)2 StudentAttributes (teammates.common.datatransfer.attributes.StudentAttributes)2 StatusMessage (teammates.common.util.StatusMessage)2 FeedbackResultsResponseTable (teammates.ui.template.FeedbackResultsResponseTable)2 InstructorFeedbackResultsModerationButton (teammates.ui.template.InstructorFeedbackResultsModerationButton)2 InvocationTargetException (java.lang.reflect.InvocationTargetException)1 Method (java.lang.reflect.Method)1 HashMap (java.util.HashMap)1 LinkedHashMap (java.util.LinkedHashMap)1 List (java.util.List)1 Map (java.util.Map)1 Test (org.testng.annotations.Test)1