/** * This class is the parent class for all *WorkerServlets. This class provides logging of exceptions * that are uncaught by child *WorkerServlet classes. Child classes should also perform their own * logging of exceptions that could occur during the execution of the servlet. */ @SuppressWarnings("serial") public abstract class WorkerServlet extends HttpServlet { protected static Logger log = Utils.getLogger(); protected String servletName = "unspecified"; protected String action = "unspecified"; public void doPost(HttpServletRequest req, HttpServletResponse resp) { try { doGet(req, resp); } catch (Exception e) { log.severe("Exception occured while performing " + servletName + e.getMessage()); } } public abstract void doGet(HttpServletRequest req, HttpServletResponse resp); protected void logMessage(HttpServletRequest request, String message) { String url = HttpRequestHelper.getRequestedURL(request); ActivityLogEntry activityLogEntry = new ActivityLogEntry(servletName, action, null, message, url); log.log(Level.INFO, activityLogEntry.generateLogMessage()); } }
public class FeedbackSessionsDb extends EntitiesDb { public static final String ERROR_UPDATE_NON_EXISTENT = "Trying to update non-existent Feedback Session : "; private static final Logger log = Utils.getLogger(); public void createFeedbackSessions(Collection<FeedbackSessionAttributes> feedbackSessionsToAdd) throws InvalidParametersException { List<EntityAttributes> feedbackSessionsToUpdate = createEntities(feedbackSessionsToAdd); for (EntityAttributes entity : feedbackSessionsToUpdate) { FeedbackSessionAttributes session = (FeedbackSessionAttributes) entity; try { updateFeedbackSession(session); } catch (EntityDoesNotExistException e) { // This situation is not tested as replicating such a situation is // difficult during testing Assumption.fail("Entity found be already existing and not existing simultaneously"); } } } public List<FeedbackSessionAttributes> getAllOpenFeedbackSessions( Date start, Date end, double zone) { List<FeedbackSessionAttributes> list = new LinkedList<FeedbackSessionAttributes>(); final Query endTimequery = getPM() .newQuery( "SELECT FROM teammates.storage.entity.FeedbackSession " + "WHERE this.endTime>rangeStart && this.endTime<=rangeEnd " + " PARAMETERS java.util.Date rangeStart, " + "java.util.Date rangeEnd"); final Query startTimequery = getPM() .newQuery( "SELECT FROM teammates.storage.entity.FeedbackSession " + "WHERE this.startTime>=rangeStart && this.startTime<rangeEnd " + "PARAMETERS java.util.Date rangeStart, " + "java.util.Date rangeEnd"); Calendar startCal = Calendar.getInstance(); startCal.setTime(start); Calendar endCal = Calendar.getInstance(); endCal.setTime(end); Date curStart = TimeHelper.convertToUserTimeZone(startCal, -25).getTime(); Date curEnd = TimeHelper.convertToUserTimeZone(endCal, 25).getTime(); @SuppressWarnings("unchecked") List<FeedbackSession> endEntities = (List<FeedbackSession>) endTimequery.execute(curStart, curEnd); @SuppressWarnings("unchecked") List<FeedbackSession> startEntities = (List<FeedbackSession>) startTimequery.execute(curStart, curEnd); List<FeedbackSession> endTimeEntities = new ArrayList<FeedbackSession>(endEntities); List<FeedbackSession> startTimeEntities = new ArrayList<FeedbackSession>(startEntities); endTimeEntities.removeAll(startTimeEntities); startTimeEntities.removeAll(endTimeEntities); endTimeEntities.addAll(startTimeEntities); Iterator<FeedbackSession> it = endTimeEntities.iterator(); while (it.hasNext()) { startCal.setTime(start); endCal.setTime(end); FeedbackSessionAttributes fs = new FeedbackSessionAttributes(it.next()); Date standardStart = TimeHelper.convertToUserTimeZone(startCal, fs.timeZone - zone).getTime(); Date standardEnd = TimeHelper.convertToUserTimeZone(endCal, fs.timeZone - zone).getTime(); if ((fs.startTime.getTime() >= standardStart.getTime() && fs.startTime.getTime() < standardEnd.getTime()) || (fs.endTime.getTime() > standardStart.getTime() && fs.endTime.getTime() <= standardEnd.getTime())) list.add(fs); } return list; } /** * Preconditions: <br> * * All parameters are non-null. * * @return Null if not found. */ public FeedbackSessionAttributes getFeedbackSession(String courseId, String feedbackSessionName) { Assumption.assertNotNull(Const.StatusCodes.DBLEVEL_NULL_INPUT, feedbackSessionName); Assumption.assertNotNull(Const.StatusCodes.DBLEVEL_NULL_INPUT, courseId); FeedbackSession fs = getFeedbackSessionEntity(feedbackSessionName, courseId); if (fs == null) { log.info("Trying to get non-existent Session: " + feedbackSessionName + "/" + courseId); return null; } return new FeedbackSessionAttributes(fs); } /** * @return empty list if none found. * @deprecated Not scalable. Created for data migration purposes. */ @Deprecated public List<FeedbackSessionAttributes> getAllFeedbackSessions() { List<FeedbackSession> allFS = getAllFeedbackSessionEntities(); List<FeedbackSessionAttributes> fsaList = new ArrayList<FeedbackSessionAttributes>(); for (FeedbackSession fs : allFS) { fsaList.add(new FeedbackSessionAttributes(fs)); } return fsaList; } /** * Preconditions: <br> * * All parameters are non-null. * * @return An empty list if no non-private sessions are found. */ public List<FeedbackSessionAttributes> getNonPrivateFeedbackSessions() { List<FeedbackSession> fsList = getNonPrivateFeedbackSessionEntities(); List<FeedbackSessionAttributes> fsaList = new ArrayList<FeedbackSessionAttributes>(); for (FeedbackSession fs : fsList) { fsaList.add(new FeedbackSessionAttributes(fs)); } return fsaList; } /** * Preconditions: <br> * * All parameters are non-null. * * @return An empty list if no sessions are found for the given course. */ public List<FeedbackSessionAttributes> getFeedbackSessionsForCourse(String courseId) { Assumption.assertNotNull(Const.StatusCodes.DBLEVEL_NULL_INPUT, courseId); List<FeedbackSession> fsList = getFeedbackSessionEntitiesForCourse(courseId); List<FeedbackSessionAttributes> fsaList = new ArrayList<FeedbackSessionAttributes>(); for (FeedbackSession fs : fsList) { fsaList.add(new FeedbackSessionAttributes(fs)); } return fsaList; } /** * Preconditions: <br> * * All parameters are non-null. * * @return An empty list if no sessions are found that have unsent open emails. */ public List<FeedbackSessionAttributes> getFeedbackSessionsWithUnsentOpenEmail() { List<FeedbackSession> fsList = getFeedbackSessionEntitiesWithUnsentOpenEmail(); List<FeedbackSessionAttributes> fsaList = new ArrayList<FeedbackSessionAttributes>(); for (FeedbackSession fs : fsList) { fsaList.add(new FeedbackSessionAttributes(fs)); } return fsaList; } /** * Preconditions: <br> * * All parameters are non-null. * * @return An empty list if no sessions are found that have unsent published emails. */ public List<FeedbackSessionAttributes> getFeedbackSessionsWithUnsentPublishedEmail() { List<FeedbackSession> fsList = getFeedbackSessionEntitiesWithUnsentPublishedEmail(); List<FeedbackSessionAttributes> fsaList = new ArrayList<FeedbackSessionAttributes>(); for (FeedbackSession fs : fsList) { fsaList.add(new FeedbackSessionAttributes(fs)); } return fsaList; } /** * Updates the feedback session identified by {@code newAttributes.feedbackSesionName} and {@code * newAttributes.courseId}. For the remaining parameters, the existing value is preserved if the * parameter is null (due to 'keep existing' policy).<br> * Preconditions: <br> * * {@code newAttributes.feedbackSesionName} and {@code newAttributes.courseId} are non-null and * correspond to an existing feedback session. <br> */ public void updateFeedbackSession(FeedbackSessionAttributes newAttributes) throws InvalidParametersException, EntityDoesNotExistException { Assumption.assertNotNull(Const.StatusCodes.DBLEVEL_NULL_INPUT, newAttributes); newAttributes.sanitizeForSaving(); if (!newAttributes.isValid()) { throw new InvalidParametersException(newAttributes.getInvalidityInfo()); } FeedbackSession fs = (FeedbackSession) getEntity(newAttributes); if (fs == null) { throw new EntityDoesNotExistException(ERROR_UPDATE_NON_EXISTENT + newAttributes.toString()); } fs.setInstructions(newAttributes.instructions); fs.setStartTime(newAttributes.startTime); fs.setEndTime(newAttributes.endTime); fs.setSessionVisibleFromTime(newAttributes.sessionVisibleFromTime); fs.setResultsVisibleFromTime(newAttributes.resultsVisibleFromTime); fs.setTimeZone(newAttributes.timeZone); fs.setGracePeriod(newAttributes.gracePeriod); fs.setFeedbackSessionType(newAttributes.feedbackSessionType); fs.setSentOpenEmail(newAttributes.sentOpenEmail); fs.setSentPublishedEmail(newAttributes.sentPublishedEmail); fs.setIsOpeningEmailEnabled(newAttributes.isOpeningEmailEnabled); fs.setSendClosingEmail(newAttributes.isClosingEmailEnabled); fs.setSendPublishedEmail(newAttributes.isPublishedEmailEnabled); getPM().close(); } public void deleteFeedbackSessionsForCourses(List<String> courseIds) { Assumption.assertNotNull(Const.StatusCodes.DBLEVEL_NULL_INPUT, courseIds); List<FeedbackSession> feedbackSessionList = getFeedbackSessionEntitiesForCourses(courseIds); getPM().deletePersistentAll(feedbackSessionList); getPM().flush(); } private List<FeedbackSession> getFeedbackSessionEntitiesForCourses(List<String> courseIds) { Query q = getPM().newQuery(FeedbackSession.class); q.setFilter(":p.contains(courseId)"); @SuppressWarnings("unchecked") List<FeedbackSession> feedbackSessionList = (List<FeedbackSession>) q.execute(courseIds); return feedbackSessionList; } private List<FeedbackSession> getAllFeedbackSessionEntities() { Query q = getPM().newQuery(FeedbackSession.class); @SuppressWarnings("unchecked") List<FeedbackSession> fsList = (List<FeedbackSession>) q.execute(); return fsList; } private List<FeedbackSession> getNonPrivateFeedbackSessionEntities() { Query q = getPM().newQuery(FeedbackSession.class); q.declareParameters("Enum private"); q.setFilter("feedbackSessionType != private"); @SuppressWarnings("unchecked") List<FeedbackSession> fsList = (List<FeedbackSession>) q.execute(FeedbackSessionType.PRIVATE); return fsList; } private List<FeedbackSession> getFeedbackSessionEntitiesForCourse(String courseId) { Query q = getPM().newQuery(FeedbackSession.class); q.declareParameters("String courseIdParam"); q.setFilter("courseId == courseIdParam"); @SuppressWarnings("unchecked") List<FeedbackSession> fsList = (List<FeedbackSession>) q.execute(courseId); return fsList; } private List<FeedbackSession> getFeedbackSessionEntitiesWithUnsentOpenEmail() { Query q = getPM().newQuery(FeedbackSession.class); q.declareParameters("boolean sentParam, Enum notTypeParam"); q.setFilter("sentOpenEmail == sentParam && feedbackSessionType != notTypeParam"); @SuppressWarnings("unchecked") List<FeedbackSession> fsList = (List<FeedbackSession>) q.execute(false, FeedbackSessionType.PRIVATE); return fsList; } private List<FeedbackSession> getFeedbackSessionEntitiesWithUnsentPublishedEmail() { Query q = getPM().newQuery(FeedbackSession.class); q.declareParameters("boolean sentParam, Enum notTypeParam"); q.setFilter("sentPublishedEmail == sentParam && feedbackSessionType != notTypeParam"); @SuppressWarnings("unchecked") List<FeedbackSession> fsList = (List<FeedbackSession>) q.execute(false, FeedbackSessionType.PRIVATE); return fsList; } private FeedbackSession getFeedbackSessionEntity(String feedbackSessionName, String courseId) { Query q = getPM().newQuery(FeedbackSession.class); q.declareParameters("String feedbackSessionNameParam, String courseIdParam"); q.setFilter("feedbackSessionName == feedbackSessionNameParam && courseId == courseIdParam"); @SuppressWarnings("unchecked") List<FeedbackSession> feedbackSessionList = (List<FeedbackSession>) q.execute(feedbackSessionName, courseId); if (feedbackSessionList.isEmpty() || JDOHelper.isDeleted(feedbackSessionList.get(0))) { return null; } return feedbackSessionList.get(0); } @Override protected Object getEntity(EntityAttributes attributes) { FeedbackSessionAttributes feedbackSessionToGet = (FeedbackSessionAttributes) attributes; return getFeedbackSessionEntity( feedbackSessionToGet.feedbackSessionName, feedbackSessionToGet.courseId); } }
public class FeedbackRubricResponseDetails extends FeedbackResponseDetails { private static final Logger log = Utils.getLogger(); /** * List of integers, the size of the list corresponds to the number of sub-questions Each integer * at index i, represents the choice chosen for sub-question i */ public List<Integer> answer; public FeedbackRubricResponseDetails() { super(FeedbackQuestionType.RUBRIC); } @Override public void extractResponseDetails( FeedbackQuestionType questionType, FeedbackQuestionDetails questionDetails, String[] answer) { /** * Example: a response in the form: "0-1,1-0" means that for sub-question 0, choice 1 is chosen, * and for sub-question 1, choice 0 is chosen. */ String rawResponses = answer[0]; FeedbackRubricQuestionDetails fqd = (FeedbackRubricQuestionDetails) questionDetails; initializeEmptyAnswerList(fqd.getNumOfRubricSubQuestions()); // Parse and extract answers String[] subQuestionResponses = rawResponses.split(Pattern.quote(",")); for (String subQuestionResponse : subQuestionResponses) { String[] subQuestionIndexAndChoice = subQuestionResponse.split(Pattern.quote("-")); if (subQuestionIndexAndChoice.length != 2) { // Expected length is 2. // Failed to parse, ignore response. continue; } try { int subQuestionIndex = Integer.parseInt(subQuestionIndexAndChoice[0]); int subQuestionChoice = Integer.parseInt(subQuestionIndexAndChoice[1]); if (subQuestionIndex >= 0 && subQuestionIndex < fqd.getNumOfRubricSubQuestions() && subQuestionChoice >= 0 && subQuestionChoice < fqd.getNumOfRubricChoices()) { setAnswer(subQuestionIndex, subQuestionChoice); } // else the indexes are invalid. } catch (NumberFormatException e) { // Failed to parse, ignore response. log.warning(TeammatesException.toStringWithStackTrace(e)); } } } /** * Initializes the answer list to have empty responses -1 indicates no choice chosen * * @param numSubQuestions */ private void initializeEmptyAnswerList(int numSubQuestions) { answer = new ArrayList<Integer>(); for (int i = 0; i < numSubQuestions; i++) { answer.add(-1); } } @Override public String getAnswerString() { return this.answer.toString(); } @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(); } @Override public String getAnswerCsv(FeedbackQuestionDetails questionDetails) { return answer.toString(); } public int getAnswer(int subQuestionIndex) { return answer.get(subQuestionIndex); } public void setAnswer(int subQuestionIndex, int choice) { this.answer.set(subQuestionIndex, choice); } }
/** Handles the logic related to {@link CommentAttributes}. */ public class CommentsLogic { private static CommentsLogic instance; @SuppressWarnings("unused") // used by test private static final Logger log = Utils.getLogger(); private static final CommentsDb commentsDb = new CommentsDb(); private static final CoursesLogic coursesLogic = CoursesLogic.inst(); private static final InstructorsLogic instructorsLogic = InstructorsLogic.inst(); private static final StudentsLogic studentsLogic = StudentsLogic.inst(); private static final FeedbackQuestionsLogic fqLogic = FeedbackQuestionsLogic.inst(); private static final FeedbackResponsesLogic frLogic = FeedbackResponsesLogic.inst(); private static final FeedbackResponseCommentsLogic frcLogic = FeedbackResponseCommentsLogic.inst(); public static CommentsLogic inst() { if (instance == null) { instance = new CommentsLogic(); } return instance; } /** ********** CRUD *********** */ public CommentAttributes createComment(CommentAttributes comment) throws InvalidParametersException, EntityAlreadyExistsException, EntityDoesNotExistException { verifyIsCoursePresent(comment.courseId, "create"); verifyIsInstructorOfCourse(comment.courseId, comment.giverEmail); return commentsDb.createEntity(comment); } public CommentAttributes getComment(Long commentId) { return commentsDb.getComment(commentId); } public List<CommentAttributes> getCommentsForGiver(String courseId, String giverEmail) throws EntityDoesNotExistException { verifyIsCoursePresent(courseId, "get"); return commentsDb.getCommentsForGiver(courseId, giverEmail); } public List<CommentAttributes> getCommentsForReceiver( String courseId, String giverEmail, CommentParticipantType recipientType, String receiverEmail) throws EntityDoesNotExistException { verifyIsCoursePresent(courseId, "get"); List<CommentAttributes> comments = commentsDb.getCommentsForReceiver(courseId, recipientType, receiverEmail); Iterator<CommentAttributes> iterator = comments.iterator(); while (iterator.hasNext()) { CommentAttributes c = iterator.next(); if (!c.giverEmail.equals(giverEmail)) { iterator.remove(); } } return comments; } public List<CommentAttributes> getCommentsForReceiver( String courseId, CommentParticipantType recipientType, String receiverEmail) throws EntityDoesNotExistException { verifyIsCoursePresent(courseId, "get"); return commentsDb.getCommentsForReceiver(courseId, recipientType, receiverEmail); } public List<CommentAttributes> getCommentsForSendingState( String courseId, CommentSendingState sendingState) throws EntityDoesNotExistException { verifyIsCoursePresent(courseId, "get"); return commentsDb.getCommentsForSendingState(courseId, sendingState); } public void updateCommentsSendingState( String courseId, CommentSendingState oldState, CommentSendingState newState) throws EntityDoesNotExistException { verifyIsCoursePresent(courseId, "clear pending"); commentsDb.updateComments(courseId, oldState, newState); } public CommentAttributes updateComment(CommentAttributes comment) throws InvalidParametersException, EntityDoesNotExistException { verifyIsCoursePresent(comment.courseId, "update"); return commentsDb.updateComment(comment); } /** * update comment's giver email (assume to be an instructor) * * @param courseId * @param oldInstrEmail * @param updatedInstrEmail */ public void updateInstructorEmail( String courseId, String oldInstrEmail, String updatedInstrEmail) { commentsDb.updateInstructorEmail(courseId, oldInstrEmail, updatedInstrEmail); } /** * update comment's recipient email (assume to be a student) * * @param courseId * @param oldStudentEmail * @param updatedStudentEmail */ public void updateStudentEmail( String courseId, String oldStudentEmail, String updatedStudentEmail) { commentsDb.updateStudentEmail(courseId, oldStudentEmail, updatedStudentEmail); } public void deleteCommentsForInstructor(String courseId, String instructorEmail) { commentsDb.deleteCommentsByInstructorEmail(courseId, instructorEmail); } public void deleteCommentsForStudent(String courseId, String studentEmail) { commentsDb.deleteCommentsByStudentEmail(courseId, studentEmail); } public void deleteCommentsForTeam(String courseId, String teamName) { commentsDb.deleteCommentsForTeam(courseId, teamName); } public void deleteCommentsForSection(String courseId, String sectionName) { commentsDb.deleteCommentsForSection(courseId, sectionName); } public void deleteCommentsForCourse(String courseId) { commentsDb.deleteCommentsForCourse(courseId); } public void deleteCommentAndDocument(CommentAttributes comment) { this.deleteComment(comment); this.deleteDocument(comment); } public void deleteComment(CommentAttributes comment) { commentsDb.deleteEntity(comment); } public void deleteDocument(CommentAttributes comment) { commentsDb.deleteDocument(comment); } public List<CommentAttributes> getCommentDrafts(String giverEmail) { return commentsDb.getCommentDrafts(giverEmail); } /** * Create or update document for comment * * @param comment */ public void putDocument(CommentAttributes comment) { commentsDb.putDocument(comment); } public CommentSearchResultBundle searchComment( String queryString, List<InstructorAttributes> instructors, String cursorString) { return commentsDb.search(queryString, instructors, cursorString); } private void verifyIsCoursePresent(String courseId, String action) throws EntityDoesNotExistException { if (!coursesLogic.isCoursePresent(courseId)) { throw new EntityDoesNotExistException( "Trying to " + action + " comments for a course that does not exist."); } } private void verifyIsInstructorOfCourse(String courseId, String email) throws EntityDoesNotExistException { InstructorAttributes instructor = instructorsLogic.getInstructorForEmail(courseId, email); if (instructor == null) { throw new EntityDoesNotExistException( "User " + email + " is not a registered instructor for course " + courseId + "."); } } /** ********** Get Comments For an Instructor *********** */ /** * Get comments visible for the given instructor * * @param instructor * @return list of {@link CommentAttributes} * @throws EntityDoesNotExistException when the course doesn't exist */ public List<CommentAttributes> getCommentsForInstructor(InstructorAttributes instructor) throws EntityDoesNotExistException { verifyIsCoursePresent(instructor.courseId, "get"); verifyIsInstructorOfCourse(instructor.courseId, instructor.email); HashSet<String> commentsVisitedSet = new HashSet<String>(); // When the given instructor is the comment giver, List<CommentAttributes> comments = getCommentsForGiverAndStatus(instructor.courseId, instructor.email, CommentStatus.FINAL); for (CommentAttributes c : comments) { preventAppendingThisCommentAgain(commentsVisitedSet, c); } // When other giver's comments are visible to the given instructor List<CommentAttributes> commentsForOtherInstructor = getCommentsForCommentViewer(instructor.courseId, CommentParticipantType.INSTRUCTOR); removeNonVisibleCommentsForInstructor(commentsForOtherInstructor, commentsVisitedSet, comments); java.util.Collections.sort(comments); return comments; } private void removeNonVisibleCommentsForInstructor( List<CommentAttributes> commentsForInstructor, HashSet<String> commentsVisitedSet, List<CommentAttributes> comments) { for (CommentAttributes c : commentsForInstructor) { removeGiverAndRecipientNameByVisibilityOptions(c, CommentParticipantType.INSTRUCTOR); appendComments(c, comments, commentsVisitedSet); } } private List<CommentAttributes> getCommentsForCommentViewer( String courseId, CommentParticipantType commentViewerType) throws EntityDoesNotExistException { verifyIsCoursePresent(courseId, "get"); return commentsDb.getCommentsForCommentViewer(courseId, commentViewerType); } private List<CommentAttributes> getCommentsForGiverAndStatus( String courseId, String giverEmail, CommentStatus status) throws EntityDoesNotExistException { verifyIsCoursePresent(courseId, "get"); return commentsDb.getCommentsForGiverAndStatus(courseId, giverEmail, status); } /** ********** Get Comments For a Student *********** */ /** * Get comments visible to the given student * * @param student * @return list of {@link CommentAttributes} * @throws EntityDoesNotExistException when the course doesn't exist */ public List<CommentAttributes> getCommentsForStudent(StudentAttributes student) throws EntityDoesNotExistException { verifyIsCoursePresent(student.course, "get"); List<StudentAttributes> teammates = studentsLogic.getStudentsForTeam(student.team, student.course); List<StudentAttributes> studentsInTheSameSection = studentsLogic.getStudentsForSection(student.section, student.course); List<String> teammatesEmails = getTeammatesEmails(teammates); List<String> sectionStudentsEmails = getSectionStudentsEmails(studentsInTheSameSection); List<String> teamsInThisSection = getTeamsForSection(studentsInTheSameSection); List<CommentAttributes> comments = new ArrayList<CommentAttributes>(); HashSet<String> commentsVisitedSet = new HashSet<String>(); // Get comments sent to the given student List<CommentAttributes> commentsForStudent = getCommentsForReceiver(student.course, CommentParticipantType.PERSON, student.email); removeNonVisibleCommentsForStudent(commentsForStudent, commentsVisitedSet, comments); // Get comments visible to the given student's teammates List<CommentAttributes> commentsForTeam = getCommentsForCommentViewer(student.course, CommentParticipantType.TEAM); removeNonVisibleCommentsForTeam( commentsForTeam, student, teammatesEmails, commentsVisitedSet, comments); // Get comments visible to the given student's section List<CommentAttributes> commentsForSection = getCommentsForCommentViewer(student.course, CommentParticipantType.SECTION); removeNonVisibleCommentsForSection( commentsForSection, student, teammatesEmails, sectionStudentsEmails, teamsInThisSection, commentsVisitedSet, comments); // Get comments visible to the whole course List<CommentAttributes> commentsForCourse = getCommentsForCommentViewer(student.course, CommentParticipantType.COURSE); removeNonVisibleCommentsForCourse( commentsForCourse, student, teammatesEmails, sectionStudentsEmails, teamsInThisSection, commentsVisitedSet, comments); java.util.Collections.sort(comments); return comments; } private List<String> getTeamsForSection(List<StudentAttributes> studentsInTheSameSection) { List<String> teams = new ArrayList<String>(); for (StudentAttributes stu : studentsInTheSameSection) { teams.add(stu.team); } return teams; } private List<String> getSectionStudentsEmails(List<StudentAttributes> studentsInTheSameSection) { List<String> sectionStudentsEmails = new ArrayList<String>(); for (StudentAttributes stu : studentsInTheSameSection) { sectionStudentsEmails.add(stu.email); } return sectionStudentsEmails; } private List<String> getTeammatesEmails(List<StudentAttributes> teammates) { List<String> teammatesEmails = new ArrayList<String>(); for (StudentAttributes teammate : teammates) { teammatesEmails.add(teammate.email); } return teammatesEmails; } private void removeNonVisibleCommentsForCourse( List<CommentAttributes> commentsForCourse, StudentAttributes student, List<String> teammates, List<String> sectionStudentsEmails, List<String> teamsInThisSection, HashSet<String> commentsVisitedSet, List<CommentAttributes> comments) { removeNonVisibleCommentsForSection( commentsForCourse, student, teammates, sectionStudentsEmails, teamsInThisSection, commentsVisitedSet, comments); for (CommentAttributes c : commentsForCourse) { if (c.courseId.equals(student.course)) { if (c.recipientType == CommentParticipantType.COURSE) { removeGiverNameByVisibilityOptions(c, CommentParticipantType.COURSE); } else { removeGiverAndRecipientNameByVisibilityOptions(c, CommentParticipantType.COURSE); } appendComments(c, comments, commentsVisitedSet); } } } private void removeNonVisibleCommentsForSection( List<CommentAttributes> commentsForSection, StudentAttributes student, List<String> teammatesEmails, List<String> sectionStudentsEmails, List<String> teamsInThisSection, HashSet<String> commentsVisitedSet, List<CommentAttributes> comments) { removeNonVisibleCommentsForTeam( commentsForSection, student, teammatesEmails, commentsVisitedSet, comments); for (CommentAttributes c : commentsForSection) { // for teammates if (c.recipientType == CommentParticipantType.PERSON && isCommentRecipientsWithinGroup(sectionStudentsEmails, c)) { if (c.showCommentTo.contains(CommentParticipantType.SECTION)) { removeGiverAndRecipientNameByVisibilityOptions(c, CommentParticipantType.SECTION); appendComments(c, comments, commentsVisitedSet); } else { preventAppendingThisCommentAgain(commentsVisitedSet, c); } // for team } else if (c.recipientType == CommentParticipantType.TEAM && isCommentRecipientsWithinGroup(teamsInThisSection, c)) { if (c.showCommentTo.contains(CommentParticipantType.SECTION)) { removeGiverNameByVisibilityOptions(c, CommentParticipantType.SECTION); appendComments(c, comments, commentsVisitedSet); } else { preventAppendingThisCommentAgain(commentsVisitedSet, c); } // for section } else if (c.recipientType == CommentParticipantType.SECTION && c.recipients.contains(student.section)) { if (c.showCommentTo.contains(CommentParticipantType.SECTION)) { removeGiverNameByVisibilityOptions(c, CommentParticipantType.SECTION); appendComments(c, comments, commentsVisitedSet); } else { preventAppendingThisCommentAgain(commentsVisitedSet, c); } } } } private void removeNonVisibleCommentsForTeam( List<CommentAttributes> commentsForTeam, StudentAttributes student, List<String> teammates, HashSet<String> commentsVisitedSet, List<CommentAttributes> comments) { for (CommentAttributes c : commentsForTeam) { // for teammates if (c.recipientType == CommentParticipantType.PERSON && isCommentRecipientsWithinGroup(teammates, c)) { if (c.showCommentTo.contains(CommentParticipantType.TEAM)) { removeGiverAndRecipientNameByVisibilityOptions(c, CommentParticipantType.TEAM); appendComments(c, comments, commentsVisitedSet); } else { preventAppendingThisCommentAgain(commentsVisitedSet, c); } // for team } else if (c.recipientType == CommentParticipantType.TEAM && c.recipients.contains(Sanitizer.sanitizeForHtml(student.team))) { if (c.showCommentTo.contains(CommentParticipantType.TEAM)) { removeGiverNameByVisibilityOptions(c, CommentParticipantType.TEAM); appendComments(c, comments, commentsVisitedSet); } else { preventAppendingThisCommentAgain(commentsVisitedSet, c); } } } } private void removeNonVisibleCommentsForStudent( List<CommentAttributes> commentsForStudent, HashSet<String> commentsVisitedSet, List<CommentAttributes> comments) { for (CommentAttributes c : commentsForStudent) { if (c.showCommentTo.contains(CommentParticipantType.PERSON)) { removeGiverNameByVisibilityOptions(c, CommentParticipantType.PERSON); appendComments(c, comments, commentsVisitedSet); } else { preventAppendingThisCommentAgain(commentsVisitedSet, c); } } } private void removeGiverNameByVisibilityOptions( CommentAttributes c, CommentParticipantType viewerType) { if (!c.showGiverNameTo.contains(viewerType)) { c.giverEmail = "Anonymous"; } } private void removeGiverAndRecipientNameByVisibilityOptions( CommentAttributes c, CommentParticipantType viewerType) { removeGiverNameByVisibilityOptions(c, viewerType); if (!c.showRecipientNameTo.contains(viewerType)) { c.recipients = new HashSet<String>(); c.recipients.add("Anonymous"); } } private void appendComments( CommentAttributes c, List<CommentAttributes> toThisCommentList, HashSet<String> commentsVisitedSet) { if (!commentsVisitedSet.contains(c.getCommentId().toString())) { toThisCommentList.add(c); preventAppendingThisCommentAgain(commentsVisitedSet, c); } } private void preventAppendingThisCommentAgain( HashSet<String> commentsVisitedSet, CommentAttributes c) { commentsVisitedSet.add(c.getCommentId().toString()); } private boolean isCommentRecipientsWithinGroup(List<String> group, CommentAttributes c) { for (String recipient : c.recipients) { if (group.contains(recipient)) { return true; } } return false; } /** ********** Send Email For Pending Comments *********** */ /** * Get recipient emails for comments with sending state. When pending comments are cleared, * they'll become sending comments. * * @param courseId * @return set of emails for recipients who can see the sending comments * @throws EntityDoesNotExistException when the course doesn't exist */ public Set<String> getRecipientEmailsForSendingComments(String courseId) throws EntityDoesNotExistException { List<StudentAttributes> allStudents = new StudentsDb().getStudentsForCourse(courseId); CourseRoster roster = new CourseRoster(allStudents, new InstructorsDb().getInstructorsForCourse(courseId)); Map<String, List<StudentAttributes>> teamStudentTable = new HashMap<String, List<StudentAttributes>>(); Map<String, List<StudentAttributes>> sectionStudentTable = new HashMap<String, List<StudentAttributes>>(); populateTeamSectionStudentTables(allStudents, teamStudentTable, sectionStudentTable); Set<String> recipientEmailsList = populateRecipientEmails( courseId, allStudents, roster, teamStudentTable, sectionStudentTable); return recipientEmailsList; } private Set<String> populateRecipientEmails( String courseId, List<StudentAttributes> allStudents, CourseRoster roster, Map<String, List<StudentAttributes>> teamStudentTable, Map<String, List<StudentAttributes>> sectionStudentTable) throws EntityDoesNotExistException { Set<String> recipientEmailsList = new HashSet<String>(); List<CommentAttributes> sendingCommentsList = commentsDb.getCommentsForSendingState(courseId, CommentSendingState.SENDING); populateRecipientEmailsFromPendingComments( sendingCommentsList, allStudents, roster, teamStudentTable, sectionStudentTable, recipientEmailsList); List<FeedbackResponseCommentAttributes> sendingResponseCommentsList = frcLogic.getFeedbackResponseCommentsForSendingState(courseId, CommentSendingState.SENDING); populateRecipientEmailsFromPendingResponseComments( sendingResponseCommentsList, allStudents, roster, teamStudentTable, recipientEmailsList); return recipientEmailsList; } private void populateTeamSectionStudentTables( List<StudentAttributes> allStudents, Map<String, List<StudentAttributes>> teamStudentTable, Map<String, List<StudentAttributes>> sectionStudentTable) { for (StudentAttributes student : allStudents) { List<StudentAttributes> teammates = teamStudentTable.get(student.team); if (teammates == null) { teammates = new ArrayList<StudentAttributes>(); teamStudentTable.put(student.team, teammates); } teammates.add(student); List<StudentAttributes> studentsInTheSameSection = sectionStudentTable.get(student.section); if (studentsInTheSameSection == null) { studentsInTheSameSection = new ArrayList<StudentAttributes>(); sectionStudentTable.put(student.section, studentsInTheSameSection); } studentsInTheSameSection.add(student); } } /** * ********** Send Email For Pending Comments : populate recipients emails from Feedback Response * Comments *********** */ private void populateRecipientEmailsFromPendingResponseComments( List<FeedbackResponseCommentAttributes> sendingResponseCommentsList, List<StudentAttributes> allStudents, CourseRoster roster, Map<String, List<StudentAttributes>> teamStudentTable, Set<String> recipientEmailsList) { Map<String, FeedbackQuestionAttributes> feedbackQuestionsTable = new HashMap<String, FeedbackQuestionAttributes>(); Map<String, FeedbackResponseAttributes> feedbackResponsesTable = new HashMap<String, FeedbackResponseAttributes>(); Map<String, Set<String>> responseCommentsAddedTable = new HashMap<String, Set<String>>(); for (FeedbackResponseCommentAttributes frc : sendingResponseCommentsList) { FeedbackQuestionAttributes relatedQuestion = getRelatedQuestion(feedbackQuestionsTable, frc); FeedbackResponseAttributes relatedResponse = getRelatedResponse(feedbackResponsesTable, frc); if (relatedQuestion != null && relatedResponse != null) { populateRecipientEmailsForGiver( roster, teamStudentTable, recipientEmailsList, responseCommentsAddedTable, frc, relatedQuestion, relatedResponse); populateRecipientEmailsForReceiver( roster, teamStudentTable, recipientEmailsList, responseCommentsAddedTable, frc, relatedResponse); populateRecipientEmailsForTeamMember( roster, teamStudentTable, recipientEmailsList, responseCommentsAddedTable, frc, relatedResponse); populateRecipientEmailsForAllStudents( allStudents, recipientEmailsList, responseCommentsAddedTable, frc); } } } private void populateRecipientEmailsForAllStudents( List<StudentAttributes> allStudents, Set<String> recipientEmailsList, Map<String, Set<String>> responseCommentsAddedTable, FeedbackResponseCommentAttributes frc) { if (frc.isVisibleTo(FeedbackParticipantType.STUDENTS)) { for (StudentAttributes student : allStudents) { addRecipientEmailsToList( responseCommentsAddedTable, recipientEmailsList, frc.getId().toString(), student.email); } } } private void populateRecipientEmailsForTeamMember( CourseRoster roster, Map<String, List<StudentAttributes>> teamStudentTable, Set<String> recipientEmailsList, Map<String, Set<String>> responseCommentsAddedTable, FeedbackResponseCommentAttributes frc, FeedbackResponseAttributes relatedResponse) { if (frc.isVisibleTo(FeedbackParticipantType.RECEIVER_TEAM_MEMBERS)) { StudentAttributes studentOfThisEmail = roster.getStudentForEmail(relatedResponse.recipient); if (studentOfThisEmail == null) { addRecipientEmailsForTeam( teamStudentTable, recipientEmailsList, responseCommentsAddedTable, frc.getId().toString(), relatedResponse.recipient); } else { addRecipientEmailsForTeam( teamStudentTable, recipientEmailsList, responseCommentsAddedTable, frc.getId().toString(), studentOfThisEmail.team); } } } private void populateRecipientEmailsForReceiver( CourseRoster roster, Map<String, List<StudentAttributes>> teamStudentTable, Set<String> recipientEmailsList, Map<String, Set<String>> responseCommentsAddedTable, FeedbackResponseCommentAttributes frc, FeedbackResponseAttributes relatedResponse) { if (frc.isVisibleTo(FeedbackParticipantType.RECEIVER)) { // recipientEmail is email if (roster.getStudentForEmail(relatedResponse.recipient) == null) { addRecipientEmailsForTeam( teamStudentTable, recipientEmailsList, responseCommentsAddedTable, frc.getId().toString(), relatedResponse.recipient); } else { addRecipientEmailsToList( responseCommentsAddedTable, recipientEmailsList, frc.getId().toString(), relatedResponse.recipient); } } } private void populateRecipientEmailsForGiver( CourseRoster roster, Map<String, List<StudentAttributes>> teamStudentTable, Set<String> recipientEmailsList, Map<String, Set<String>> responseCommentsAddedTable, FeedbackResponseCommentAttributes frc, FeedbackQuestionAttributes relatedQuestion, FeedbackResponseAttributes relatedResponse) { StudentAttributes giver = roster.getStudentForEmail(relatedResponse.giver); if (giver == null) { return; } if (frc.isVisibleTo(FeedbackParticipantType.GIVER)) { addRecipientEmailsToList( responseCommentsAddedTable, recipientEmailsList, frc.getId().toString(), relatedResponse.giver); } if (relatedQuestion.giverType == FeedbackParticipantType.TEAMS || frc.isVisibleTo(FeedbackParticipantType.OWN_TEAM_MEMBERS)) { addRecipientEmailsForTeam( teamStudentTable, recipientEmailsList, responseCommentsAddedTable, frc.getId().toString(), giver.team); } } private FeedbackResponseAttributes getRelatedResponse( Map<String, FeedbackResponseAttributes> feedbackResponsesTable, FeedbackResponseCommentAttributes frc) { FeedbackResponseAttributes relatedResponse = feedbackResponsesTable.get(frc.feedbackResponseId); if (relatedResponse == null) { relatedResponse = frLogic.getFeedbackResponse(frc.feedbackResponseId); feedbackResponsesTable.put(frc.feedbackResponseId, relatedResponse); } return relatedResponse; } private FeedbackQuestionAttributes getRelatedQuestion( Map<String, FeedbackQuestionAttributes> feedbackQuestionsTable, FeedbackResponseCommentAttributes frc) { FeedbackQuestionAttributes relatedQuestion = feedbackQuestionsTable.get(frc.feedbackQuestionId); if (relatedQuestion == null) { relatedQuestion = fqLogic.getFeedbackQuestion(frc.feedbackQuestionId); feedbackQuestionsTable.put(frc.feedbackQuestionId, relatedQuestion); } return relatedQuestion; } /** * ********** Send Email For Pending Comments : populate recipients emails from Student Comments * *********** */ private void populateRecipientEmailsFromPendingComments( List<CommentAttributes> sendingCommentsList, List<StudentAttributes> allStudents, CourseRoster roster, Map<String, List<StudentAttributes>> teamStudentTable, Map<String, List<StudentAttributes>> sectionStudentTable, Set<String> recipientEmailList) { Map<String, Set<String>> studentCommentsAddedTable = new HashMap<String, Set<String>>(); for (CommentAttributes pendingComment : sendingCommentsList) { populateRecipientEmailsForPerson( recipientEmailList, studentCommentsAddedTable, pendingComment); populateRecipientEmailsForTeam( recipientEmailList, roster, teamStudentTable, studentCommentsAddedTable, pendingComment); populateRecipientEmailsForSection( recipientEmailList, roster, teamStudentTable, sectionStudentTable, studentCommentsAddedTable, pendingComment); populateRecipientEmailsForCourse( recipientEmailList, allStudents, studentCommentsAddedTable, pendingComment); } } private void populateRecipientEmailsForCourse( Set<String> recipientEmailList, List<StudentAttributes> allStudents, Map<String, Set<String>> studentCommentsAddedTable, CommentAttributes pendingComment) { if (pendingComment.isVisibleTo(CommentParticipantType.COURSE)) { for (StudentAttributes student : allStudents) { addRecipientEmailsToList( studentCommentsAddedTable, recipientEmailList, pendingComment.getCommentId().toString(), student.email); } } } private void populateRecipientEmailsForSection( Set<String> recipientEmailList, CourseRoster roster, Map<String, List<StudentAttributes>> teamStudentTable, Map<String, List<StudentAttributes>> sectionStudentTable, Map<String, Set<String>> studentCommentsAddedTable, CommentAttributes pendingComment) { String commentId = pendingComment.getCommentId().toString(); if (pendingComment.isVisibleTo(CommentParticipantType.SECTION)) { if (pendingComment.recipientType == CommentParticipantType.PERSON) { for (String recipientEmail : pendingComment.recipients) { StudentAttributes student = roster.getStudentForEmail(recipientEmail); if (student == null) { continue; } addRecipientEmailsForSection( sectionStudentTable, recipientEmailList, studentCommentsAddedTable, commentId, student.section); } } else if (pendingComment.recipientType == CommentParticipantType.TEAM) { for (String team : pendingComment.recipients) { List<StudentAttributes> students = teamStudentTable.get(team); if (students == null) { continue; } for (StudentAttributes stu : students) { addRecipientEmailsForSection( sectionStudentTable, recipientEmailList, studentCommentsAddedTable, commentId, stu.section); } } } else if (pendingComment.recipientType == CommentParticipantType.SECTION) { for (String section : pendingComment.recipients) { addRecipientEmailsForSection( sectionStudentTable, recipientEmailList, studentCommentsAddedTable, commentId, section); } } } else { // not visible to SECTION if (pendingComment.recipientType == CommentParticipantType.PERSON) { for (String recipientEmail : pendingComment.recipients) { StudentAttributes student = roster.getStudentForEmail(recipientEmail); if (student == null) { continue; } preventAddRecipientEmailsForSection( teamStudentTable, studentCommentsAddedTable, commentId, student.section); } } else if (pendingComment.recipientType == CommentParticipantType.TEAM) { for (String team : pendingComment.recipients) { List<StudentAttributes> students = teamStudentTable.get(team); if (students == null) { continue; } for (StudentAttributes stu : students) { preventAddRecipientEmailsForSection( teamStudentTable, studentCommentsAddedTable, commentId, stu.section); } } } else if (pendingComment.recipientType == CommentParticipantType.SECTION) { for (String section : pendingComment.recipients) { preventAddRecipientEmailsForSection( teamStudentTable, studentCommentsAddedTable, commentId, section); } } } } private void populateRecipientEmailsForTeam( Set<String> recipientEmailList, CourseRoster roster, Map<String, List<StudentAttributes>> teamStudentTable, Map<String, Set<String>> studentCommentsAddedTable, CommentAttributes pendingComment) { String commentId = pendingComment.getCommentId().toString(); if (pendingComment.isVisibleTo(CommentParticipantType.TEAM)) { if (pendingComment.recipientType == CommentParticipantType.PERSON) { for (String recipientEmail : pendingComment.recipients) { StudentAttributes student = roster.getStudentForEmail(recipientEmail); if (student == null) { continue; } addRecipientEmailsForTeam( teamStudentTable, recipientEmailList, studentCommentsAddedTable, commentId, student.team); } } else if (pendingComment.recipientType == CommentParticipantType.TEAM) { for (String team : pendingComment.recipients) { addRecipientEmailsForTeam( teamStudentTable, recipientEmailList, studentCommentsAddedTable, commentId, team); } } } else { // not visible to TEAM if (pendingComment.recipientType == CommentParticipantType.PERSON) { for (String recipientEmail : pendingComment.recipients) { StudentAttributes student = roster.getStudentForEmail(recipientEmail); if (student == null) { continue; } preventAddRecipientEmailsForTeam( teamStudentTable, studentCommentsAddedTable, commentId, student.team); } } else if (pendingComment.recipientType == CommentParticipantType.TEAM) { for (String team : pendingComment.recipients) { preventAddRecipientEmailsForTeam( teamStudentTable, studentCommentsAddedTable, commentId, team); } } } } private void populateRecipientEmailsForPerson( Set<String> recipientEmailList, Map<String, Set<String>> studentCommentsAddedTable, CommentAttributes pendingComment) { String commentId = pendingComment.getCommentId().toString(); if (pendingComment.isVisibleTo(CommentParticipantType.PERSON)) { for (String recipientEmail : pendingComment.recipients) { addRecipientEmailsToList( studentCommentsAddedTable, recipientEmailList, commentId, recipientEmail); } } else { // not visible to PERSON for (String recipientEmail : pendingComment.recipients) { preventAddRecipientEmailsToList(studentCommentsAddedTable, commentId, recipientEmail); } } } private void addRecipientEmailsToList( Map<String, Set<String>> isAddedTable, Set<String> targetTable, String subKey, String key) { // prevent re-entry Set<String> commentIdsSet = isAddedTable.get(key); if (commentIdsSet == null) { commentIdsSet = new HashSet<String>(); isAddedTable.put(key, commentIdsSet); } if (!commentIdsSet.contains(subKey)) { commentIdsSet.add(subKey); targetTable.add(key); } } private void addRecipientEmailsForSection( Map<String, List<StudentAttributes>> sectionStudentTable, Set<String> recipientEmailsList, Map<String, Set<String>> responseCommentsAddedTable, String commentId, String sectionName) { List<StudentAttributes> students = sectionStudentTable.get(sectionName); if (students == null) { return; } for (StudentAttributes stu : students) { addRecipientEmailsToList( responseCommentsAddedTable, recipientEmailsList, commentId, stu.email); } } private void addRecipientEmailsForTeam( Map<String, List<StudentAttributes>> teamStudentTable, Set<String> recipientEmailsList, Map<String, Set<String>> responseCommentsAddedTable, String commentId, String teamName) { List<StudentAttributes> students = teamStudentTable.get(teamName); if (students == null) { return; } for (StudentAttributes stu : students) { addRecipientEmailsToList( responseCommentsAddedTable, recipientEmailsList, commentId, stu.email); } } private void preventAddRecipientEmailsToList( Map<String, Set<String>> isAddedTable, String subKey, String key) { Set<String> commentIdsSet = isAddedTable.get(key); if (commentIdsSet == null) { commentIdsSet = new HashSet<String>(); isAddedTable.put(key, commentIdsSet); } commentIdsSet.add(subKey); } private void preventAddRecipientEmailsForSection( Map<String, List<StudentAttributes>> sectionStudentTable, Map<String, Set<String>> isAddedTable, String commentId, String section) { List<StudentAttributes> students = sectionStudentTable.get(section); if (students == null) { return; } for (StudentAttributes stu : students) { preventAddRecipientEmailsToList(isAddedTable, commentId, stu.email); } } private void preventAddRecipientEmailsForTeam( Map<String, List<StudentAttributes>> teamStudentTable, Map<String, Set<String>> isAddedTable, String commentId, String team) { List<StudentAttributes> teammates = teamStudentTable.get(team); if (teammates == null) { return; } for (StudentAttributes teamMember : teammates) { preventAddRecipientEmailsToList(isAddedTable, commentId, teamMember.email); } } @SuppressWarnings("deprecation") public List<CommentAttributes> getAllComments() { return commentsDb.getAllComments(); } /** * Sends notifications to students in course {@code courseId} who have received comments and not * yet been notified. */ public void sendCommentNotification(String courseId) { Map<String, String> paramMap = new HashMap<String, String>(); paramMap.put(Const.ParamsNames.EMAIL_COURSE, courseId); paramMap.put(Const.ParamsNames.EMAIL_TYPE, EmailType.PENDING_COMMENT_CLEARED.toString()); TaskQueuesLogic taskQueueLogic = TaskQueuesLogic.inst(); taskQueueLogic.createAndAddTask( Const.SystemParams.EMAIL_TASK_QUEUE, Const.ActionURIs.EMAIL_WORKER, paramMap); } }
public class FeedbackResponsesLogic { private static final Logger log = Utils.getLogger(); private static FeedbackResponsesLogic instance = null; private static final StudentsLogic studentsLogic = StudentsLogic.inst(); private static final FeedbackQuestionsLogic fqLogic = FeedbackQuestionsLogic.inst(); private static final FeedbackResponseCommentsLogic frcLogic = FeedbackResponseCommentsLogic.inst(); private static final FeedbackResponsesDb frDb = new FeedbackResponsesDb(); public static FeedbackResponsesLogic inst() { if (instance == null) instance = new FeedbackResponsesLogic(); return instance; } public void createFeedbackResponse(FeedbackResponseAttributes fra) throws InvalidParametersException { try { frDb.createEntity(fra); } catch (Exception EntityAlreadyExistsException) { try { FeedbackResponseAttributes existingFeedback = new FeedbackResponseAttributes(); existingFeedback = frDb.getFeedbackResponse(fra.feedbackQuestionId, fra.giverEmail, fra.recipientEmail); fra.setId(existingFeedback.getId()); frDb.updateFeedbackResponse(fra); } catch (Exception EntityDoesNotExistException) { Assumption.fail(); } } } public FeedbackResponseAttributes getFeedbackResponse(String feedbackResponseId) { return frDb.getFeedbackResponse(feedbackResponseId); } public FeedbackResponseAttributes getFeedbackResponse( String feedbackQuestionId, String giverEmail, String recipient) { // TODO: check what is this line doing here!!! log.warning(feedbackQuestionId); return frDb.getFeedbackResponse(feedbackQuestionId, giverEmail, recipient); } public List<FeedbackResponseAttributes> getFeedbackResponsesForSession( String feedbackSessionName, String courseId) { return frDb.getFeedbackResponsesForSession(feedbackSessionName, courseId); } public List<FeedbackResponseAttributes> getFeedbackResponsesForSessionInSection( String feedbackSessionName, String courseId, String section) { if (section == null) { return getFeedbackResponsesForSession(feedbackSessionName, courseId); } else { return frDb.getFeedbackResponsesForSessionInSection(feedbackSessionName, courseId, section); } } public List<FeedbackResponseAttributes> getFeedbackResponsesForSessionFromSection( String feedbackSessionName, String courseId, String section) { if (section == null) { return getFeedbackResponsesForSession(feedbackSessionName, courseId); } else { return frDb.getFeedbackResponsesForSessionFromSection(feedbackSessionName, courseId, section); } } public List<FeedbackResponseAttributes> getFeedbackResponsesForSessionToSection( String feedbackSessionName, String courseId, String section) { if (section == null) { return getFeedbackResponsesForSession(feedbackSessionName, courseId); } else { return frDb.getFeedbackResponsesForSessionToSection(feedbackSessionName, courseId, section); } } public List<FeedbackResponseAttributes> getFeedbackResponsesForSessionWithinRange( String feedbackSessionName, String courseId, long range) { return frDb.getFeedbackResponsesForSessionWithinRange(feedbackSessionName, courseId, range); } public List<FeedbackResponseAttributes> getFeedbackResponsesForSessionInSectionWithinRange( String feedbackSessionName, String courseId, String section, long range) { if (section == null) { return getFeedbackResponsesForSessionWithinRange(feedbackSessionName, courseId, range); } else { return frDb.getFeedbackResponsesForSessionInSectionWithinRange( feedbackSessionName, courseId, section, range); } } public List<FeedbackResponseAttributes> getFeedbackResponsesForSessionFromSectionWithinRange( String feedbackSessionName, String courseId, String section, long range) { if (section == null) { return getFeedbackResponsesForSessionWithinRange(feedbackSessionName, courseId, range); } else { return frDb.getFeedbackResponsesForSessionFromSectionWithinRange( feedbackSessionName, courseId, section, range); } } public List<FeedbackResponseAttributes> getFeedbackResponsesForSessionToSectionWithinRange( String feedbackSessionName, String courseId, String section, long range) { if (section == null) { return getFeedbackResponsesForSessionWithinRange(feedbackSessionName, courseId, range); } else { return frDb.getFeedbackResponsesForSessionToSectionWithinRange( feedbackSessionName, courseId, section, range); } } public List<FeedbackResponseAttributes> getFeedbackResponsesForQuestion( String feedbackQuestionId) { return frDb.getFeedbackResponsesForQuestion(feedbackQuestionId); } public List<FeedbackResponseAttributes> getFeedbackResponsesForQuestionWithinRange( String feedbackQuestionId, long range) { return frDb.getFeedbackResponsesForQuestionWithinRange(feedbackQuestionId, range); } public List<FeedbackResponseAttributes> getFeedbackResponsesForQuestionInSection( String feedbackQuestionId, String section) { if (section == null) { return getFeedbackResponsesForQuestion(feedbackQuestionId); } return frDb.getFeedbackResponsesForQuestionInSection(feedbackQuestionId, section); } public List<FeedbackResponseAttributes> getFeedbackResponsesForReceiverForQuestion( String feedbackQuestionId, String userEmail) { return frDb.getFeedbackResponsesForReceiverForQuestion(feedbackQuestionId, userEmail); } public List<FeedbackResponseAttributes> getFeedbackResponsesForReceiverForQuestionInSection( String feedbackQuestionId, String userEmail, String section) { if (section == null) { return getFeedbackResponsesForReceiverForQuestion(feedbackQuestionId, userEmail); } return frDb.getFeedbackResponsesForReceiverForQuestionInSection( feedbackQuestionId, userEmail, section); } public List<FeedbackResponseAttributes> getFeedbackResponsesFromGiverForQuestion( String feedbackQuestionId, String userEmail) { return frDb.getFeedbackResponsesFromGiverForQuestion(feedbackQuestionId, userEmail); } public List<FeedbackResponseAttributes> getFeedbackResponsesFromGiverForQuestionInSection( String feedbackQuestionId, String userEmail, String section) { if (section == null) { return getFeedbackResponsesFromGiverForQuestion(feedbackQuestionId, userEmail); } return frDb.getFeedbackResponsesFromGiverForQuestionInSection( feedbackQuestionId, userEmail, section); } public List<FeedbackResponseAttributes> getFeedbackResponsesForReceiverForCourse( String courseId, String userEmail) { return frDb.getFeedbackResponsesForReceiverForCourse(courseId, userEmail); } public List<FeedbackResponseAttributes> getFeedbackResponsesFromGiverForCourse( String courseId, String userEmail) { return frDb.getFeedbackResponsesFromGiverForCourse(courseId, userEmail); } /** Get existing feedback responses from student or his team for the given question. */ public List<FeedbackResponseAttributes> getFeedbackResponsesFromStudentOrTeamForQuestion( FeedbackQuestionAttributes question, StudentAttributes student) { if (question.giverType == FeedbackParticipantType.TEAMS) { return getFeedbackResponsesFromTeamForQuestion( question.getId(), question.courseId, student.team); } else { return frDb.getFeedbackResponsesFromGiverForQuestion(question.getId(), student.email); } } public List<FeedbackResponseAttributes> getViewableFeedbackResponsesForQuestionInSection( FeedbackQuestionAttributes question, String userEmail, UserType.Role role, String section) throws EntityDoesNotExistException { List<FeedbackResponseAttributes> viewableResponses = new ArrayList<FeedbackResponseAttributes>(); // Add responses that the user submitted himself addNewResponses( viewableResponses, getFeedbackResponsesFromGiverForQuestionInSection(question.getId(), userEmail, section)); // Add responses that user is a receiver of when question is visible to // receiver. if (question.isResponseVisibleTo(FeedbackParticipantType.RECEIVER)) { addNewResponses( viewableResponses, getFeedbackResponsesForReceiverForQuestionInSection( question.getId(), userEmail, section)); } switch (role) { case STUDENT: addNewResponses( viewableResponses, // many queries getViewableFeedbackResponsesForStudentForQuestion(question, userEmail)); break; case INSTRUCTOR: if (question.isResponseVisibleTo(FeedbackParticipantType.INSTRUCTORS)) { addNewResponses( viewableResponses, getFeedbackResponsesForQuestionInSection(question.getId(), section)); } break; default: Assumption.fail("The role of the requesting use has to be Student or Instructor"); } return viewableResponses; } public boolean isNameVisibleTo( FeedbackQuestionAttributes question, FeedbackResponseAttributes response, String userEmail, UserType.Role role, boolean isGiverName, CourseRoster roster) { if (question == null) { return false; } List<FeedbackParticipantType> showNameTo = isGiverName ? question.showGiverNameTo : question.showRecipientNameTo; // Giver can always see giver and recipient.(because he answered.) if (response.giverEmail.equals(userEmail)) { return true; } for (FeedbackParticipantType type : showNameTo) { switch (type) { case INSTRUCTORS: if (roster.getInstructorForEmail(userEmail) != null && role == UserType.Role.INSTRUCTOR) { return true; } else { break; } case OWN_TEAM_MEMBERS: case OWN_TEAM_MEMBERS_INCLUDING_SELF: // Refers to Giver's Team Members if (roster.isStudentsInSameTeam(response.giverEmail, userEmail)) { return true; } else { break; } case RECEIVER: // Response to team if (question.recipientType == FeedbackParticipantType.TEAMS) { if (roster.isStudentInTeam( userEmail, /* this is a team name */ response.recipientEmail)) { return true; } // Response to individual } else if (response.recipientEmail.equals(userEmail)) { return true; } else { break; } case RECEIVER_TEAM_MEMBERS: // Response to team; recipient = teamName if (question.recipientType == FeedbackParticipantType.TEAMS) { if (roster.isStudentInTeam( userEmail, /* this is a team name */ response.recipientEmail)) { return true; } // Response to individual } else if (roster.isStudentsInSameTeam(response.recipientEmail, userEmail)) { return true; } else { break; } case STUDENTS: if (roster.isStudentInCourse(userEmail)) { return true; } else { break; } default: Assumption.fail( "Invalid FeedbackPariticipantType for showNameTo in " + "FeedbackResponseLogic.isNameVisible()"); break; } } return false; } /** * Updates a {@link FeedbackResponse} based on it's {@code id}.<br> * If the giver/recipient field is changed, the {@link FeedbackResponse} is updated by recreating * the response<br> * in order to prevent an id clash if the previous email is reused later on. */ public void updateFeedbackResponse(FeedbackResponseAttributes responseToUpdate) throws InvalidParametersException, EntityDoesNotExistException, EntityAlreadyExistsException { // Create a copy. FeedbackResponseAttributes newResponse = new FeedbackResponseAttributes(responseToUpdate); FeedbackResponseAttributes oldResponse = null; if (newResponse.getId() == null) { oldResponse = frDb.getFeedbackResponse( newResponse.feedbackQuestionId, newResponse.giverEmail, newResponse.recipientEmail); } else { oldResponse = frDb.getFeedbackResponse(newResponse.getId()); } if (oldResponse == null) { throw new EntityDoesNotExistException( "Trying to update a feedback response that does not exist."); } // Copy values that cannot be changed to defensively avoid invalid // parameters. newResponse.courseId = oldResponse.courseId; newResponse.feedbackSessionName = oldResponse.feedbackSessionName; newResponse.feedbackQuestionId = oldResponse.feedbackQuestionId; newResponse.feedbackQuestionType = oldResponse.feedbackQuestionType; if (newResponse.responseMetaData == null) { newResponse.responseMetaData = oldResponse.responseMetaData; } if (newResponse.giverEmail == null) { newResponse.giverEmail = oldResponse.giverEmail; } if (newResponse.recipientEmail == null) { newResponse.recipientEmail = oldResponse.recipientEmail; } if (newResponse.giverSection == null) { newResponse.giverSection = oldResponse.giverSection; } if (newResponse.recipientSection == null) { newResponse.recipientSection = oldResponse.recipientSection; } if (!newResponse.recipientEmail.equals(oldResponse.recipientEmail) || !newResponse.giverEmail.equals(oldResponse.giverEmail)) { // Recreate response to prevent possible future id conflict. try { newResponse.setId(null); frDb.createEntity(newResponse); frDb.deleteEntity(oldResponse); } catch (EntityAlreadyExistsException e) { log.warning("Trying to update an existing response to one that already exists."); throw new EntityAlreadyExistsException( e.getMessage() + Const.EOL + "Trying to update recipient for response to one that already exists for this giver."); } } else { frDb.updateFeedbackResponse(newResponse); } } /** * Updates responses for a student when his team changes. This is done by deleting responses that * are no longer relevant to him in his new team. */ public void updateFeedbackResponsesForChangingTeam( String courseId, String userEmail, String oldTeam, String newTeam) throws EntityDoesNotExistException { FeedbackQuestionAttributes question; List<FeedbackResponseAttributes> responsesFromUser = getFeedbackResponsesFromGiverForCourse(courseId, userEmail); for (FeedbackResponseAttributes response : responsesFromUser) { question = fqLogic.getFeedbackQuestion(response.feedbackQuestionId); if (question.giverType == FeedbackParticipantType.TEAMS || question.recipientType == FeedbackParticipantType.OWN_TEAM_MEMBERS || question.recipientType == FeedbackParticipantType.OWN_TEAM_MEMBERS_INCLUDING_SELF) { frDb.deleteEntity(response); } } List<FeedbackResponseAttributes> responsesToUser = getFeedbackResponsesForReceiverForCourse(courseId, userEmail); for (FeedbackResponseAttributes response : responsesToUser) { question = fqLogic.getFeedbackQuestion(response.feedbackQuestionId); if (question.recipientType == FeedbackParticipantType.OWN_TEAM_MEMBERS || question.recipientType == FeedbackParticipantType.OWN_TEAM_MEMBERS_INCLUDING_SELF) { frDb.deleteEntity(response); } } if (studentsLogic.getStudentsForTeam(oldTeam, courseId).isEmpty()) { List<FeedbackResponseAttributes> responsesToTeam = getFeedbackResponsesForReceiverForCourse(courseId, oldTeam); for (FeedbackResponseAttributes response : responsesToTeam) { frDb.deleteEntity(response); } } } public void updateFeedbackResponsesForChangingSection( String courseId, String userEmail, String oldSection, String newSection) throws EntityDoesNotExistException, InvalidParametersException { List<FeedbackResponseAttributes> responsesFromUser = getFeedbackResponsesFromGiverForCourse(courseId, userEmail); for (FeedbackResponseAttributes response : responsesFromUser) { response.giverSection = newSection; frDb.updateFeedbackResponse(response); frcLogic.updateFeedbackResponseCommentsForResponse(response.getId()); } List<FeedbackResponseAttributes> responsesToUser = getFeedbackResponsesForReceiverForCourse(courseId, userEmail); for (FeedbackResponseAttributes response : responsesToUser) { response.recipientSection = newSection; frDb.updateFeedbackResponse(response); frcLogic.updateFeedbackResponseCommentsForResponse(response.getId()); } } public boolean updateFeedbackResponseForChangingTeam( StudentEnrollDetails enrollment, FeedbackResponseAttributes response) { FeedbackQuestionAttributes question = fqLogic.getFeedbackQuestion(response.feedbackQuestionId); boolean isGiverSameForResponseAndEnrollment = response.giverEmail.equals(enrollment.email); boolean isReceiverSameForResponseAndEnrollment = response.recipientEmail.equals(enrollment.email); boolean shouldDeleteByChangeOfGiver = (isGiverSameForResponseAndEnrollment && (question.giverType == FeedbackParticipantType.TEAMS || question.recipientType == FeedbackParticipantType.OWN_TEAM_MEMBERS)); boolean shouldDeleteByChangeOfRecipient = (isReceiverSameForResponseAndEnrollment && question.recipientType == FeedbackParticipantType.OWN_TEAM_MEMBERS); boolean shouldDeleteResponse = shouldDeleteByChangeOfGiver || shouldDeleteByChangeOfRecipient; if (shouldDeleteResponse) { frDb.deleteEntity(response); } return shouldDeleteResponse; } public void updateFeedbackResponseForChangingSection( StudentEnrollDetails enrollment, FeedbackResponseAttributes response) throws InvalidParametersException, EntityDoesNotExistException { FeedbackResponse feedbackResponse = frDb.getFeedbackResponseEntityOptimized(response); boolean isGiverSameForResponseAndEnrollment = feedbackResponse.getGiverEmail().equals(enrollment.email); boolean isReceiverSameForResponseAndEnrollment = feedbackResponse.getRecipientEmail().equals(enrollment.email); if (isGiverSameForResponseAndEnrollment) { feedbackResponse.setGiverSection(enrollment.newSection); } if (isReceiverSameForResponseAndEnrollment) { feedbackResponse.setRecipientSection(enrollment.newSection); } frDb.commitOutstandingChanges(); if (isGiverSameForResponseAndEnrollment || isReceiverSameForResponseAndEnrollment) { frcLogic.updateFeedbackResponseCommentsForResponse(response.getId()); } } /** Updates responses for a student when his email changes. */ // TODO: cascade the update to response comments public void updateFeedbackResponsesForChangingEmail( String courseId, String oldEmail, String newEmail) throws InvalidParametersException, EntityDoesNotExistException { List<FeedbackResponseAttributes> responsesFromUser = getFeedbackResponsesFromGiverForCourse(courseId, oldEmail); for (FeedbackResponseAttributes response : responsesFromUser) { response.giverEmail = newEmail; try { updateFeedbackResponse(response); } catch (EntityAlreadyExistsException e) { Assumption.fail( "Feedback response failed to update successfully" + "as email was already in use."); } } List<FeedbackResponseAttributes> responsesToUser = getFeedbackResponsesForReceiverForCourse(courseId, oldEmail); for (FeedbackResponseAttributes response : responsesToUser) { response.recipientEmail = newEmail; try { updateFeedbackResponse(response); } catch (EntityAlreadyExistsException e) { Assumption.fail( "Feedback response failed to update successfully" + "as email was already in use."); } } } public void deleteFeedbackResponseAndCascade(FeedbackResponseAttributes responseToDelete) { frcLogic.deleteFeedbackResponseCommentsForResponse(responseToDelete.getId()); frDb.deleteEntity(responseToDelete); } public void deleteFeedbackResponsesForQuestionAndCascade(String feedbackQuestionId) { List<FeedbackResponseAttributes> responsesForQuestion = getFeedbackResponsesForQuestion(feedbackQuestionId); for (FeedbackResponseAttributes response : responsesForQuestion) { this.deleteFeedbackResponseAndCascade(response); } } public void deleteFeedbackResponsesForStudentAndCascade(String courseId, String studentEmail) { String studentTeam = ""; StudentAttributes student = studentsLogic.getStudentForEmail(courseId, studentEmail); if (student != null) { studentTeam = student.team; } List<FeedbackResponseAttributes> responses = getFeedbackResponsesFromGiverForCourse(courseId, studentEmail); responses.addAll(getFeedbackResponsesForReceiverForCourse(courseId, studentEmail)); // Delete responses to team as well if student is last person in team. if (studentsLogic.getStudentsForTeam(studentTeam, courseId).size() <= 1) { responses.addAll(getFeedbackResponsesForReceiverForCourse(courseId, studentTeam)); } for (FeedbackResponseAttributes response : responses) { this.deleteFeedbackResponseAndCascade(response); } } /** * Adds {@link FeedbackResponseAttributes} in {@code newResponses} that are not already in to * {@code existingResponses} to {@code existingResponses}. */ private void addNewResponses( List<FeedbackResponseAttributes> existingResponses, List<FeedbackResponseAttributes> newResponses) { Map<String, FeedbackResponseAttributes> responses = new HashMap<String, FeedbackResponseAttributes>(); for (FeedbackResponseAttributes existingResponse : existingResponses) { responses.put(existingResponse.getId(), existingResponse); } for (FeedbackResponseAttributes newResponse : newResponses) { if (!responses.containsKey(newResponse.getId())) { responses.put(newResponse.getId(), newResponse); existingResponses.add(newResponse); } } } private List<FeedbackResponseAttributes> getFeedbackResponsesFromTeamForQuestion( String feedbackQuestionId, String courseId, String teamName) { List<FeedbackResponseAttributes> responses = new ArrayList<FeedbackResponseAttributes>(); List<StudentAttributes> studentsInTeam = studentsLogic.getStudentsForTeam(teamName, courseId); for (StudentAttributes student : studentsInTeam) { responses.addAll( frDb.getFeedbackResponsesFromGiverForQuestion(feedbackQuestionId, student.email)); } return responses; } private List<FeedbackResponseAttributes> getFeedbackResponsesForTeamMembersOfStudent( String feedbackQuestionId, StudentAttributes student) { List<StudentAttributes> studentsInTeam = studentsLogic.getStudentsForTeam(student.team, student.course); List<FeedbackResponseAttributes> teamResponses = new ArrayList<FeedbackResponseAttributes>(); for (StudentAttributes studentInTeam : studentsInTeam) { if (studentInTeam.email.equals(student.email)) { continue; } List<FeedbackResponseAttributes> responses = frDb.getFeedbackResponsesForReceiverForQuestion(feedbackQuestionId, studentInTeam.email); teamResponses.addAll(responses); } return teamResponses; } private List<FeedbackResponseAttributes> getViewableFeedbackResponsesForStudentForQuestion( FeedbackQuestionAttributes question, String studentEmail) { List<FeedbackResponseAttributes> viewableResponses = new ArrayList<FeedbackResponseAttributes>(); StudentAttributes student = studentsLogic.getStudentForEmail(question.courseId, studentEmail); if (question.isResponseVisibleTo(FeedbackParticipantType.STUDENTS)) { addNewResponses(viewableResponses, getFeedbackResponsesForQuestion(question.getId())); // Early return as STUDENTS covers all other student types. return viewableResponses; } if (question.recipientType == FeedbackParticipantType.TEAMS && question.isResponseVisibleTo(FeedbackParticipantType.RECEIVER)) { addNewResponses( viewableResponses, getFeedbackResponsesForReceiverForQuestion(question.getId(), student.team)); } if (question.giverType == FeedbackParticipantType.TEAMS || question.isResponseVisibleTo(FeedbackParticipantType.OWN_TEAM_MEMBERS)) { addNewResponses( viewableResponses, getFeedbackResponsesFromTeamForQuestion( question.getId(), question.courseId, student.team)); } if (question.isResponseVisibleTo(FeedbackParticipantType.RECEIVER_TEAM_MEMBERS)) { addNewResponses( viewableResponses, getFeedbackResponsesForTeamMembersOfStudent(question.getId(), student)); } return viewableResponses; } }