/*==========================================================================*\ | $Id: GraderHomeStatus.java,v 1.11 2011/10/25 15:30:34 stedwar2 Exp $ |*-------------------------------------------------------------------------*| | Copyright (C) 2006-2010 Virginia Tech | | This file is part of Web-CAT. | | Web-CAT is free software; you can redistribute it and/or modify | it under the terms of the GNU Affero General Public License as published | by the Free Software Foundation; either version 3 of the License, or | (at your option) any later version. | | Web-CAT is distributed in the hope that it will be useful, | but WITHOUT ANY WARRANTY; without even the implied warranty of | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | GNU General Public License for more details. | | You should have received a copy of the GNU Affero General Public License | along with Web-CAT; if not, see <http://www.gnu.org/licenses/>. \*==========================================================================*/ package org.webcat.grader; import com.webobjects.appserver.*; import com.webobjects.eocontrol.*; import com.webobjects.foundation.*; import er.extensions.appserver.ERXDisplayGroup; import er.extensions.eof.ERXQ; import er.extensions.foundation.ERXArrayUtilities; import org.apache.log4j.Logger; import org.webcat.core.Course; import org.webcat.core.CourseOffering; import org.webcat.core.Semester; // ------------------------------------------------------------------------- /** * Generates the grader subsystem's page sections for the home->status page. * * @author Stephen Edwards * @author Last changed by $Author: stedwar2 $ * @version $Revision: 1.11 $, $Date: 2011/10/25 15:30:34 $ */ public class GraderHomeStatus extends GraderComponent { //~ Constructors .......................................................... // ---------------------------------------------------------- /** * Creates a new GraderSystemStatusRows object. * * @param context The page's context */ public GraderHomeStatus(WOContext context) { super(context); } //~ KVC Attributes (must be public) ....................................... public ERXDisplayGroup<EnqueuedJob> enqueuedJobGroup; public EnqueuedJob job; public ERXDisplayGroup<AssignmentOffering> oldAssignmentGroup; public ERXDisplayGroup<AssignmentOffering> upcomingAssignmentsGroup; public int index; public ERXDisplayGroup<Course> courses; public ERXDisplayGroup<Assignment> assignments; public ERXDisplayGroup<AssignmentOffering> offerings; public AssignmentOffering assignmentOffering; public ERXDisplayGroup<Course> coursesForOld; //~ Methods ............................................................... // ---------------------------------------------------------- /** * Adds to the response of the page * * @param response The response being built * @param context The context of the request */ protected void beforeAppendToResponse( WOResponse response, WOContext context) { if (log.isDebugEnabled()) { log.debug( "starting beforeAppendToResponse()" ); // Application.enableSQLLogging(); } enqueuedJobGroup.queryBindings().setObjectForKey( user(), "user" ); enqueuedJobGroup.fetch(); currentTime = new NSTimestamp(); // First, grab all this student can see @SuppressWarnings("unchecked") NSMutableArray<AssignmentOffering> interesting = new NSMutableArray<AssignmentOffering>( ERXArrayUtilities.filteredArrayWithQualifierEvaluation( AssignmentOffering.objectsMatchingQualifier(localContext(), AssignmentOffering.publish.isTrue().and( AssignmentOffering.courseOffering .dot(CourseOffering.students).is(user()))), AssignmentOffering.availableFrom.lessThan(currentTime))); // Now, add any user has instructor access to: ERXArrayUtilities.addObjectsFromArrayWithoutDuplicates(interesting, AssignmentOffering.objectsMatchingQualifier(localContext(), AssignmentOffering.courseOffering .dot(CourseOffering.instructors).is(user()))); // Now, add any user has grader access to: ERXArrayUtilities.addObjectsFromArrayWithoutDuplicates(interesting, AssignmentOffering.objectsMatchingQualifier(localContext(), AssignmentOffering.courseOffering .dot(CourseOffering.graders).is(user()))); @SuppressWarnings("unchecked") NSArray<AssignmentOffering> open = ERXArrayUtilities .filteredArrayWithQualifierEvaluation(interesting, AssignmentOffering.lateDeadline.greaterThan(currentTime)); currentAssignments = organizeAssignments(open); courses.setObjectArray( new NSArray<Course>(currentAssignments.keySet())); if (log.isDebugEnabled()) { log.debug("organized = " + currentAssignments); } Semester currentSemester = null; NSArray<Semester> semesters = Semester.allObjectsOrderedByStartDate(localContext()); if (semesters.count() > 0) { currentSemester = semesters.get(0); } @SuppressWarnings("unchecked") NSArray<AssignmentOffering> old = ERXArrayUtilities .filteredArrayWithQualifierEvaluation(interesting, currentSemester == null ? ERXQ.not(AssignmentOffering.lateDeadline .greaterThan(currentTime)) : ERXQ.and( ERXQ.not(AssignmentOffering.lateDeadline .greaterThan(currentTime)), AssignmentOffering.courseOffering.dot( CourseOffering.semester).is(currentSemester))); oldAssignments = organizeAssignments(old); coursesForOld.setObjectArray( new NSArray<Course>(oldAssignments.keySet())); // FIXME: remove oldAssignmentGroup.setObjectArray(old); if (log.isDebugEnabled()) { // Application.disableSQLLogging(); log.debug("ending beforeAppendToResponse()"); } super.beforeAppendToResponse( response, context ); } // ---------------------------------------------------------- /** * View results for the most recent submission to the selected assignments. * * @return the most recent results page */ public Number mostRecentScore() { SubmissionResult subResult = assignmentOffering.mostRecentSubmissionResultFor(user()); return (subResult == null) ? null : new Double(subResult.automatedScore()); } // ---------------------------------------------------------- /** * Check whether the user can edit the selected assignment. * * @return true if the user can edit the assignment */ public boolean canEditAssignment() { if (offerings.displayedObjects() == null || offerings.displayedObjects().count() == 0) { return false; } AssignmentOffering ao = offerings.displayedObjects().get(0); return ao.courseOffering().isInstructor(user()); } // ---------------------------------------------------------- /** * Check whether the user can edit the selected assignment. * * @return true if the user can edit the assignment */ public boolean canGradeAssignmentOffering() { boolean result = assignmentOffering.courseOffering().isInstructor(user()) || assignmentOffering.courseOffering().isGrader(user()); log.debug("can grade = " + result); return result; } // ---------------------------------------------------------- /** * Check whether the user can edit the selected assignment. * * @return true if the user can edit the assignment */ public boolean canGradeAssignment() { if (offerings.displayedObjects() == null || offerings.displayedObjects().count() == 0) { return false; } AssignmentOffering ao = offerings.displayedObjects().get(0); boolean result = ao.courseOffering().isInstructor(user()) || ao.courseOffering().isGrader(user()); log.debug("can grade = " + result); return result; } // ---------------------------------------------------------- /** * An action to go to the submission page for a given assignment. * * @return the submission page for the selected assignment */ public WOComponent submitAssignment() { selectAssignment(assignmentOffering); return pageWithName( wcSession().tabs.selectById("UploadSubmission").pageName()); } // ---------------------------------------------------------- /** * View results for the most recent submission to the selected assignments. * * @return the most recent results page */ public WOComponent viewResults() { selectSubmission(assignmentOffering); return pageWithName( wcSession().tabs.selectById("MostRecent").pageName()); } // ---------------------------------------------------------- /** * An action to go to the graphing page for a given assignment. * * @return the graphing page for the selected assignment */ public WOComponent graphResults() { selectSubmission(assignmentOffering); return pageWithName( wcSession().tabs.selectById("GraphResults").pageName()); } // ---------------------------------------------------------- /** * An action to go to edit page for a given assignment. * * @return the properties page for the selected assignment */ public WOComponent editAssignment() { assignmentOffering = currentAssignments.get(course()).get(anAssignment()).get(0); selectAssignment(assignmentOffering); return pageWithName( wcSession().tabs.selectById("AssignmentProperties").pageName()); } // ---------------------------------------------------------- /** * An action to go to edit page for a given assignment. * * @return the properties page for the selected assignment */ public WOComponent editOldAssignment() { assignmentOffering = oldAssignments.get(courseForOld()).get(anOldAssignment()).get(0); selectAssignment(assignmentOffering); return pageWithName( wcSession().tabs.selectById("AssignmentProperties").pageName()); } // ---------------------------------------------------------- /** * An action to go to edit page for a given assignment. * * @return the properties page for the selected assignment */ public WOComponent viewOrGrade() { assignmentOffering = currentAssignments.get(course()).get(anAssignment()).get(0); selectAssignment(assignmentOffering); return pageWithName( wcSession().tabs.selectById("EnterGrades").pageName()); } // ---------------------------------------------------------- /** * An action to go to edit page for a given assignment. * * @return the properties page for the selected assignment */ public WOComponent viewOrGradeOld() { assignmentOffering = oldAssignments.get(courseForOld()).get(anOldAssignment()).get(0); selectAssignment(assignmentOffering); return pageWithName( wcSession().tabs.selectById("EnterGrades").pageName()); } // ---------------------------------------------------------- private void selectAssignment(AssignmentOffering offering) { coreSelections().setSemester(offering.courseOffering().semester()); coreSelections().setCourseOfferingRelationship( offering.courseOffering()); coreSelections().setCourseRelationship( offering.courseOffering().course()); prefs().setAssignmentRelationship(offering.assignment()); prefs().setAssignmentOfferingRelationship(offering); if (!offering.courseOffering().isStaff(user()) && user().hasAdminPrivileges()) { coreSelections().setIncludeAdminAccess(true); } if (!offering.publish()) { prefs().setShowUnpublishedAssignments(true); } if (offering.lateDeadline().before(new NSTimestamp())) { prefs().setShowClosedAssignments(true); } } // ---------------------------------------------------------- private void selectSubmission(AssignmentOffering offering) { selectAssignment(offering); SubmissionResult subResult = offering.mostRecentSubmissionResultFor(user()); Submission sub = null; if (subResult != null) { sub = subResult.submissionFor(user()); } prefs().setSubmissionRelationship(sub); } // ---------------------------------------------------------- /** * Determine if the current assignment has suspended submissions (that * this user can see). * * @return true if the user can see this assignment's status and this * assignment has suspended submissions */ public boolean assignmentOfferingHasSuspendedSubs() { return ( user().hasAdminPrivileges() || assignmentOffering.courseOffering().instructors() .containsObject( user() ) ) && assignmentOffering.suspendedSubmissionsInQueue().count() > 0; } // ---------------------------------------------------------- /** * Determine if the current assignment is available to students. * * @return true if the "available from" time for the offering is after * now. */ public boolean assignmentOfferingIsUnavailable() { return assignmentOffering.availableFrom() != null && assignmentOffering.availableFrom().after(currentTime); } // ---------------------------------------------------------- public boolean hasUpcomingAssignments() { // set up the upcoming assignments list if (upcomingAssignmentsGroup.displayedObjects() == null || upcomingAssignmentsGroup.displayedObjects().count() == 0) { EOQualifier baseQualifier = AssignmentOffering.availableFrom.lessThan(currentTime).and( AssignmentOffering.publish.isTrue()).and( new EOKeyValueQualifier( AssignmentOffering.COURSE_OFFERING_STUDENTS_KEY, EOQualifier.QualifierOperatorContains, user())); baseQualifier = ERXQ.or(baseQualifier, new EOKeyValueQualifier( AssignmentOffering.COURSE_OFFERING_INSTRUCTORS_KEY, EOQualifier.QualifierOperatorContains, user()), new EOKeyValueQualifier( AssignmentOffering.COURSE_OFFERING_GRADERS_KEY, EOQualifier.QualifierOperatorContains, user())); upcomingAssignmentsGroup.setQualifier(ERXQ.and( // Not in either of the upper lists ERXQ.not(baseQualifier), // Also, more recent than two weeks ago AssignmentOffering.dueDate.greaterThan( currentTime.timestampByAddingGregorianUnits( 0, 0, -14, 0, 0, 0) ), // Also, some time within the next 4 weeks AssignmentOffering.dueDate.lessThan( currentTime.timestampByAddingGregorianUnits( 0, 0, 28, 0, 0, 0)) )); upcomingAssignmentsGroup.fetch(); } return upcomingAssignmentsGroup.displayedObjects().count() > 0; } // ---------------------------------------------------------- public Course course() { return course; } // ---------------------------------------------------------- public void setCourse(Course newCourse) { if (newCourse == null) { assignments.setObjectArray(NSArray.EmptyArray); } else { NSMutableDictionary<Assignment, NSMutableArray<AssignmentOffering>> newAssignments = currentAssignments.get(newCourse); if (newAssignments == null || newAssignments.isEmpty()) { assignments.setObjectArray(NSArray.EmptyArray); } else { assignments.setObjectArray( new NSArray<Assignment>(newAssignments.keySet())); } } course = newCourse; } // ---------------------------------------------------------- public Assignment anAssignment() { return anAssignment; } // ---------------------------------------------------------- public void setAnAssignment(Assignment newAssignment) { if (newAssignment == null) { offerings.setObjectArray(NSArray.EmptyArray); } else { NSMutableArray<AssignmentOffering> newOfferings = currentAssignments.get(course()).get(newAssignment); if (newOfferings == null || newOfferings.isEmpty()) { offerings.setObjectArray(NSArray.EmptyArray); } else { offerings.setObjectArray(newOfferings); } } anAssignment = newAssignment; } // ---------------------------------------------------------- public Course courseForOld() { return courseForOld; } // ---------------------------------------------------------- public void setCourseForOld(Course aCourse) { if (aCourse == null) { assignments.setObjectArray(NSArray.EmptyArray); } else { NSMutableDictionary<Assignment, NSMutableArray<AssignmentOffering>> newAssignments = oldAssignments.get(aCourse); if (newAssignments == null || newAssignments.isEmpty()) { assignments.setObjectArray(NSArray.EmptyArray); } else { assignments.setObjectArray( new NSArray<Assignment>(newAssignments.keySet())); } } courseForOld = aCourse; } // ---------------------------------------------------------- public Assignment anOldAssignment() { return anOldAssignment; } // ---------------------------------------------------------- public void setAnOldAssignment(Assignment oldAssignment) { if (oldAssignment == null) { offerings.setObjectArray(NSArray.EmptyArray); } else { NSMutableArray<AssignmentOffering> newOfferings = oldAssignments.get(courseForOld()).get(oldAssignment); if (newOfferings == null || newOfferings.isEmpty()) { offerings.setObjectArray(NSArray.EmptyArray); } else { offerings.setObjectArray(newOfferings); } } anOldAssignment = oldAssignment; } // ---------------------------------------------------------- private NSMutableDictionary<Course, NSMutableDictionary<Assignment, NSMutableArray<AssignmentOffering>>> organizeAssignments(NSArray<AssignmentOffering> offeringList) { NSMutableDictionary<Course, NSMutableDictionary<Assignment, NSMutableArray<AssignmentOffering>>> result = new NSMutableDictionary<Course, NSMutableDictionary<Assignment, NSMutableArray<AssignmentOffering>>>(); for (AssignmentOffering ao : offeringList) { Course c = ao.courseOffering().course(); // Look up the course in the result, creating it if necessary NSMutableDictionary<Assignment, NSMutableArray<AssignmentOffering>> courseAssignments = result.get(c); if (courseAssignments == null) { courseAssignments = new NSMutableDictionary<Assignment, NSMutableArray<AssignmentOffering>>(); result.put(c, courseAssignments); } // Look up the assignment, creating its array if necessary Assignment a = ao.assignment(); NSMutableArray<AssignmentOffering> cOfferings = courseAssignments.get(a); if (cOfferings == null) { cOfferings = new NSMutableArray<AssignmentOffering>(); courseAssignments.put(a, cOfferings); } cOfferings.add(ao); } return result; } //~ Instance/static variables ............................................. private NSTimestamp currentTime; private NSMutableDictionary<Course, NSMutableDictionary<Assignment, NSMutableArray<AssignmentOffering>>> currentAssignments; private NSMutableDictionary<Course, NSMutableDictionary<Assignment, NSMutableArray<AssignmentOffering>>> oldAssignments; private Course course; private Assignment anAssignment; private Course courseForOld; private Assignment anOldAssignment; static Logger log = Logger.getLogger( GraderHomeStatus.class ); }