/********************************************************************************** * * $Id: GradebookServiceHibernateImpl.java 130070 2013-09-30 23:54:12Z matthew@longsight.com $ * *********************************************************************************** * * Copyright (c) 2005, 2006, 2007, 2008, 2009 The Sakai Foundation, The MIT Corporation * * Licensed under the Educational Community License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.opensource.org/licenses/ECL-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * **********************************************************************************/ package org.sakaiproject.component.gradebook; import java.math.BigDecimal; import java.text.NumberFormat; import java.text.ParseException; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.HashSet; import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.hibernate.HibernateException; import org.hibernate.Query; import org.hibernate.Session; import org.hibernate.StaleObjectStateException; import org.sakaiproject.service.gradebook.shared.AssessmentNotFoundException; import org.sakaiproject.service.gradebook.shared.AssignmentHasIllegalPointsException; import org.sakaiproject.service.gradebook.shared.CategoryDefinition; import org.sakaiproject.service.gradebook.shared.CommentDefinition; import org.sakaiproject.service.gradebook.shared.GradeDefinition; import org.sakaiproject.service.gradebook.shared.ConflictingAssignmentNameException; import org.sakaiproject.service.gradebook.shared.ConflictingExternalIdException; import org.sakaiproject.service.gradebook.shared.GradebookExternalAssessmentService; import org.sakaiproject.service.gradebook.shared.GradebookFrameworkService; import org.sakaiproject.service.gradebook.shared.GradebookNotFoundException; import org.sakaiproject.service.gradebook.shared.GradebookService; import org.sakaiproject.service.gradebook.shared.GradebookPermissionService; import org.sakaiproject.service.gradebook.shared.InvalidGradeException; import org.sakaiproject.service.gradebook.shared.StaleObjectModificationException; import org.sakaiproject.tool.gradebook.Assignment; import org.sakaiproject.tool.gradebook.AssignmentGradeRecord; import org.sakaiproject.tool.gradebook.Comment; import org.sakaiproject.tool.gradebook.GradableObject; import org.sakaiproject.tool.gradebook.GradeMapping; import org.sakaiproject.tool.gradebook.Gradebook; import org.sakaiproject.tool.gradebook.GradingEvent; import org.sakaiproject.tool.gradebook.LetterGradePercentMapping; import org.sakaiproject.tool.gradebook.facades.Authz; import org.sakaiproject.tool.gradebook.CourseGradeRecord; import org.sakaiproject.tool.gradebook.CourseGrade; import org.sakaiproject.tool.gradebook.Category; import org.sakaiproject.util.ResourceLoader; import org.sakaiproject.section.api.coursemanagement.EnrollmentRecord; import org.sakaiproject.section.api.coursemanagement.CourseSection; import org.springframework.orm.hibernate3.HibernateCallback; import org.springframework.orm.hibernate3.HibernateOptimisticLockingFailureException; /** * A Hibernate implementation of GradebookService. */ public class GradebookServiceHibernateImpl extends BaseHibernateManager implements GradebookService { private static final Log log = LogFactory.getLog(GradebookServiceHibernateImpl.class); private GradebookFrameworkService frameworkService; private GradebookExternalAssessmentService externalAssessmentService; private Authz authz; private GradebookPermissionService gradebookPermissionService; public boolean isAssignmentDefined(final String gradebookUid, final String assignmentName) throws GradebookNotFoundException { if (!isUserAbleToViewAssignments(gradebookUid)) { log.warn("AUTHORIZATION FAILURE: User " + getUserUid() + " in gradebook " + gradebookUid + " attempted to check for assignment " + assignmentName); throw new SecurityException("You do not have permission to perform this operation"); } Assignment assignment = (Assignment)getHibernateTemplate().execute(new HibernateCallback() { public Object doInHibernate(Session session) throws HibernateException { return getAssignmentWithoutStats(gradebookUid, assignmentName, session); } }); return (assignment != null); } private boolean isUserAbleToViewAssignments(String gradebookUid) { Authz authz = getAuthz(); return (authz.isUserAbleToEditAssessments(gradebookUid) || authz.isUserAbleToGrade(gradebookUid)); } public boolean isUserAbleToGradeItemForStudent(String gradebookUid, Long itemId, String studentUid) { return getAuthz().isUserAbleToGradeItemForStudent(gradebookUid, itemId, studentUid); } public boolean isUserAbleToGradeItemForStudent(String gradebookUid, String itemName, String studentUid) { if (itemName == null || studentUid == null) { throw new IllegalArgumentException("Null parameter(s) in GradebookServiceHibernateImpl.isUserAbleToGradeItemForStudent"); } org.sakaiproject.service.gradebook.shared.Assignment assignment = getAssignment(gradebookUid, itemName); if (assignment != null) { return isUserAbleToGradeItemForStudent(gradebookUid, assignment.getId(), studentUid); } return false; } public boolean isUserAbleToViewItemForStudent(String gradebookUid, Long itemId, String studentUid) { return getAuthz().isUserAbleToViewItemForStudent(gradebookUid, itemId, studentUid); } public boolean isUserAbleToViewItemForStudent(String gradebookUid, String itemName, String studentUid) { if (itemName == null || studentUid == null) { throw new IllegalArgumentException("Null parameter(s) in GradebookServiceHibernateImpl.isUserAbleToGradeItemForStudent"); } org.sakaiproject.service.gradebook.shared.Assignment assignment = getAssignment(gradebookUid, itemName); if (assignment != null) { return isUserAbleToViewItemForStudent(gradebookUid, assignment.getId(), studentUid); } return false; } public String getGradeViewFunctionForUserForStudentForItem(String gradebookUid, Long itemId, String studentUid) { return getAuthz().getGradeViewFunctionForUserForStudentForItem(gradebookUid, itemId, studentUid); } public String getGradeViewFunctionForUserForStudentForItem(String gradebookUid, String itemName, String studentUid) { if (itemName == null || studentUid == null) { throw new IllegalArgumentException("Null parameter(s) in G.isUserAbleToGradeItemForStudent"); } org.sakaiproject.service.gradebook.shared.Assignment assignment = getAssignment(gradebookUid, itemName); if (assignment != null) { return getGradeViewFunctionForUserForStudentForItem(gradebookUid, assignment.getId(), studentUid); } return null; } public List<org.sakaiproject.service.gradebook.shared.Assignment> getAssignments(String gradebookUid) throws GradebookNotFoundException { if (!isUserAbleToViewAssignments(gradebookUid)) { log.warn("AUTHORIZATION FAILURE: User " + getUserUid() + " in gradebook " + gradebookUid + " attempted to get assignments list"); throw new SecurityException("You do not have permission to perform this operation"); } final Long gradebookId = getGradebook(gradebookUid).getId(); List internalAssignments = (List)getHibernateTemplate().execute(new HibernateCallback() { public Object doInHibernate(Session session) throws HibernateException { return getAssignments(gradebookId, session); } }); List<org.sakaiproject.service.gradebook.shared.Assignment> assignments = new ArrayList<org.sakaiproject.service.gradebook.shared.Assignment>(); for (Iterator iter = internalAssignments.iterator(); iter.hasNext(); ) { Assignment assignment = (Assignment)iter.next(); assignments.add(getAssignmentDefinition(assignment)); } return assignments; } public org.sakaiproject.service.gradebook.shared.Assignment getAssignment(final String gradebookUid, final String assignmentName) throws GradebookNotFoundException { if (!isUserAbleToViewAssignments(gradebookUid)) { log.warn("AUTHORIZATION FAILURE: User " + getUserUid() + " in gradebook " + gradebookUid + " attempted to get assignment " + assignmentName); throw new SecurityException("You do not have permission to perform this operation"); } Assignment assignment = (Assignment)getHibernateTemplate().execute(new HibernateCallback() { public Object doInHibernate(Session session) throws HibernateException { return getAssignmentWithoutStats(gradebookUid, assignmentName, session); } }); if (assignment != null) { return getAssignmentDefinition(assignment); } else { return null; } } public org.sakaiproject.service.gradebook.shared.Assignment getAssignment(final String gradebookUid, final Long gbItemId) throws AssessmentNotFoundException { if (gbItemId == null || gradebookUid == null) { throw new IllegalArgumentException("null gbItemId passed to getAssignment"); } if (!isUserAbleToViewAssignments(gradebookUid) && !currentUserHasViewOwnGradesPerm(gradebookUid)) { log.warn("AUTHORIZATION FAILURE: User " + getUserUid() + " in gradebook " + gradebookUid + " attempted to get gb item with id " + gbItemId); throw new SecurityException("You do not have permission to perform this operation"); } Assignment assignment = (Assignment)getHibernateTemplate().execute(new HibernateCallback() { public Object doInHibernate(Session session) throws HibernateException { return getAssignmentWithoutStats(gradebookUid, gbItemId, session); } }); if (assignment == null) { throw new AssessmentNotFoundException("No gradebook item exists with gradable object id = " + gbItemId); } org.sakaiproject.service.gradebook.shared.Assignment assnDef; if (assignment != null) { assnDef = getAssignmentDefinition(assignment); } else { assnDef = null; } return assnDef; } private org.sakaiproject.service.gradebook.shared.Assignment getAssignmentDefinition(Assignment internalAssignment) { org.sakaiproject.service.gradebook.shared.Assignment assignmentDefinition = new org.sakaiproject.service.gradebook.shared.Assignment(); assignmentDefinition.setName(internalAssignment.getName()); assignmentDefinition.setPoints(internalAssignment.getPointsPossible()); assignmentDefinition.setDueDate(internalAssignment.getDueDate()); assignmentDefinition.setCounted(internalAssignment.isCounted()); assignmentDefinition.setExternallyMaintained(internalAssignment.isExternallyMaintained()); assignmentDefinition.setExternalAppName(internalAssignment.getExternalAppName()); assignmentDefinition.setExternalId(internalAssignment.getExternalId()); assignmentDefinition.setReleased(internalAssignment.isReleased()); assignmentDefinition.setId(internalAssignment.getId()); assignmentDefinition.setExtraCredit(internalAssignment.isExtraCredit()); if(internalAssignment.getCategory() != null) { assignmentDefinition.setCategoryName(internalAssignment.getCategory().getName()); assignmentDefinition.setWeight(internalAssignment.getCategory().getWeight()); assignmentDefinition.setCategoryExtraCredit(internalAssignment.getCategory().isExtraCredit()); } assignmentDefinition.setUngraded(internalAssignment.getUngraded()); return assignmentDefinition; } public Double getAssignmentScore(final String gradebookUid, final String assignmentName, final String studentUid) throws GradebookNotFoundException, AssessmentNotFoundException { final boolean studentRequestingOwnScore = authn.getUserUid().equals(studentUid); Double assignmentScore = (Double)getHibernateTemplate().execute(new HibernateCallback() { public Object doInHibernate(Session session) throws HibernateException { Assignment assignment = getAssignmentWithoutStats(gradebookUid, assignmentName, session); if (assignment == null) { throw new AssessmentNotFoundException("There is no assignment named " + assignmentName + " in gradebook " + gradebookUid); } if (!studentRequestingOwnScore && !isUserAbleToViewItemForStudent(gradebookUid, assignment.getId(), studentUid)) { log.error("AUTHORIZATION FAILURE: User " + getUserUid() + " in gradebook " + gradebookUid + " attempted to retrieve grade for student " + studentUid + " for assignment " + assignmentName); throw new SecurityException("You do not have permission to perform this operation"); } // If this is the student, then the assignment needs to have // been released. if (studentRequestingOwnScore && !assignment.isReleased()) { log.error("AUTHORIZATION FAILURE: Student " + getUserUid() + " in gradebook " + gradebookUid + " attempted to retrieve score for unreleased assignment " + assignment.getName()); throw new SecurityException("You do not have permission to perform this operation"); } AssignmentGradeRecord gradeRecord = getAssignmentGradeRecord(assignment, studentUid, session); if (log.isDebugEnabled()) log.debug("gradeRecord=" + gradeRecord); if (gradeRecord == null) { return null; } else { return gradeRecord.getPointsEarned(); } } }); if (log.isDebugEnabled()) log.debug("returning " + assignmentScore); return assignmentScore; } public Double getAssignmentScore(final String gradebookUid, final Long gbItemId, final String studentUid) { if (gradebookUid == null || gbItemId == null || studentUid == null) { throw new IllegalArgumentException("null parameter passed to getAssignmentScore"); } Assignment assignment = (Assignment)getHibernateTemplate().execute(new HibernateCallback() { public Object doInHibernate(Session session) throws HibernateException { return getAssignmentWithoutStats(gradebookUid, gbItemId, session); } }); if (assignment == null) { throw new AssessmentNotFoundException("There is no assignment with the gbItemId " + gbItemId); } return getAssignmentScore(gradebookUid, assignment.getName(), studentUid); } public GradeDefinition getGradeDefinitionForStudentForItem(final String gradebookUid, final Long gbItemId, final String studentUid) { if (gradebookUid == null || gbItemId == null || studentUid == null) { throw new IllegalArgumentException("Null gradebookUid or gbItemId or studentUid" + " passed to getGradeDefinitionForStudentForItem"); } final boolean studentRequestingOwnScore = authn.getUserUid().equals(studentUid); GradeDefinition gradeDef = (GradeDefinition)getHibernateTemplate().execute(new HibernateCallback() { public Object doInHibernate(Session session) throws HibernateException { Assignment assignment = getAssignmentWithoutStats(gradebookUid, gbItemId, session); if (assignment == null) { throw new AssessmentNotFoundException("There is no assignment with the gbItemId " + gbItemId + " in gradebook " + gradebookUid); } if (!studentRequestingOwnScore && !isUserAbleToViewItemForStudent(gradebookUid, assignment.getId(), studentUid)) { log.error("AUTHORIZATION FAILURE: User " + getUserUid() + " in gradebook " + gradebookUid + " attempted to retrieve grade for student " + studentUid + " for assignment " + gbItemId); throw new SecurityException("You do not have permission to perform this operation"); } Gradebook gradebook = assignment.getGradebook(); GradeDefinition gradeDef = new GradeDefinition(); gradeDef.setStudentUid(studentUid); gradeDef.setGradeEntryType(gradebook.getGrade_type()); gradeDef.setGradeReleased(assignment.isReleased()); // If this is the student, then the assignment needs to have // been released. Return null score information if not released if (studentRequestingOwnScore && !assignment.isReleased()) { gradeDef.setDateRecorded(null); gradeDef.setGrade(null); gradeDef.setGraderUid(null); gradeDef.setGradeComment(null); log.debug("Student " + getUserUid() + " in gradebook " + gradebookUid + " retrieving score for unreleased assignment " + assignment.getName()); } else { AssignmentGradeRecord gradeRecord = getAssignmentGradeRecord(assignment, studentUid, session); CommentDefinition gradeComment = getAssignmentScoreComment(gradebookUid, gbItemId, studentUid); String commentText = gradeComment != null ? gradeComment.getCommentText() : null; if (log.isDebugEnabled()) log.debug("gradeRecord=" + gradeRecord); if (gradeRecord == null) { gradeDef.setDateRecorded(null); gradeDef.setGrade(null); gradeDef.setGraderUid(null); gradeDef.setGradeComment(commentText); } else { gradeDef.setDateRecorded(gradeRecord.getDateRecorded()); gradeDef.setGraderUid(gradeRecord.getGraderId()); gradeDef.setGradeComment(commentText); if (gradebook.getGrade_type() == GradebookService.GRADE_TYPE_LETTER) { List<AssignmentGradeRecord> gradeList = new ArrayList<AssignmentGradeRecord>(); gradeList.add(gradeRecord); convertPointsToLetterGrade(gradebook, gradeList); AssignmentGradeRecord gradeRec = (AssignmentGradeRecord)gradeList.get(0); if (gradeRec != null) { gradeDef.setGrade(gradeRec.getLetterEarned()); } } else if (gradebook.getGrade_type() == GradebookService.GRADE_TYPE_PERCENTAGE) { Double percent = calculateEquivalentPercent(assignment.getPointsPossible(), gradeRecord.getPointsEarned()); if (percent != null) { gradeDef.setGrade(percent.toString()); } } else { if (gradeRecord.getPointsEarned() != null) { gradeDef.setGrade(gradeRecord.getPointsEarned().toString()); } } } } return gradeDef; } }); if (log.isDebugEnabled()) log.debug("returning grade def for " + studentUid); return gradeDef; } public void setAssignmentScore(final String gradebookUid, final String assignmentName, final String studentUid, final Double score, final String clientServiceDescription) throws GradebookNotFoundException, AssessmentNotFoundException { getHibernateTemplate().execute(new HibernateCallback() { public Object doInHibernate(Session session) throws HibernateException { Assignment assignment = getAssignmentWithoutStats(gradebookUid, assignmentName, session); if (assignment == null) { throw new AssessmentNotFoundException("There is no assignment named " + assignmentName + " in gradebook " + gradebookUid); } if (assignment.isExternallyMaintained()) { log.error("AUTHORIZATION FAILURE: User " + getUserUid() + " in gradebook " + gradebookUid + " attempted to grade externally maintained assignment " + assignmentName + " from " + clientServiceDescription); throw new SecurityException("You do not have permission to perform this operation"); } if (!isUserAbleToGradeItemForStudent(gradebookUid, assignment.getId(), studentUid)) { log.error("AUTHORIZATION FAILURE: User " + getUserUid() + " in gradebook " + gradebookUid + " attempted to grade student " + studentUid + " from " + clientServiceDescription + " for item " + assignmentName); throw new SecurityException("You do not have permission to perform this operation"); } Date now = new Date(); String graderId = getAuthn().getUserUid(); AssignmentGradeRecord gradeRecord = getAssignmentGradeRecord(assignment, studentUid, session); if (gradeRecord == null) { // Creating a new grade record. gradeRecord = new AssignmentGradeRecord(assignment, studentUid, score); } else { gradeRecord.setPointsEarned(score); } gradeRecord.setGraderId(graderId); gradeRecord.setDateRecorded(now); session.saveOrUpdate(gradeRecord); session.save(new GradingEvent(assignment, graderId, studentUid, score)); // Sync database. session.flush(); session.clear(); return null; } }); if (log.isDebugEnabled()) log.debug("Score updated in gradebookUid=" + gradebookUid + ", assignmentName=" + assignmentName + " by userUid=" + getUserUid() + " from client=" + clientServiceDescription + ", new score=" + score); } public String getGradebookDefinitionXml(String gradebookUid) { Long gradebookId = getGradebook(gradebookUid).getId(); Gradebook gradebook = getGradebook(gradebookUid); GradebookDefinition gradebookDefinition = new GradebookDefinition(); GradeMapping selectedGradeMapping = gradebook.getSelectedGradeMapping(); gradebookDefinition.setSelectedGradingScaleUid(selectedGradeMapping.getGradingScale().getUid()); gradebookDefinition.setSelectedGradingScaleBottomPercents(new HashMap<String,Double>(selectedGradeMapping.getGradeMap())); gradebookDefinition.setAssignments(getAssignments(gradebookUid)); gradebookDefinition.setGradeType(gradebook.getGrade_type()); gradebookDefinition.setCategoryType(gradebook.getCategory_type()); gradebookDefinition.setCategory(getCategories(gradebookId)); return VersionedExternalizable.toXml(gradebookDefinition); } public void transferGradebookDefinitionXml(String fromGradebookUid, String toGradebookUid, String fromGradebookXml) { final Gradebook gradebook = getGradebook(toGradebookUid); final Gradebook fromGradebook = getGradebook(fromGradebookUid); GradebookDefinition gradebookDefinition = (GradebookDefinition)VersionedExternalizable.fromXml(fromGradebookXml); gradebook.setCategory_type(gradebookDefinition.getCategoryType()); gradebook.setGrade_type(gradebookDefinition.getGradeType()); updateGradebook(gradebook); List category = getCategories(fromGradebook.getId()); int assignmentsAddedCount = 0; Long catId = null; int undefined_nb = 0; List catList = gradebookDefinition.getCategory(); List<Category> catList_tempt = new ArrayList<Category>(); if(category.size() !=0) { //deal with category with assignments for(Iterator iter = category.iterator(); iter.hasNext();) { int categoryCount = 0; String catName = ((Category)iter.next()).getName(); for (org.sakaiproject.service.gradebook.shared.Assignment obj : gradebookDefinition.getAssignments()) { org.sakaiproject.service.gradebook.shared.Assignment assignmentDef = (org.sakaiproject.service.gradebook.shared.Assignment)obj; boolean newCategory = false; // Externally managed assessments should not be included. if (assignmentDef.isExternallyMaintained()) { continue; } if(catName.equals(assignmentDef.getCategoryName())) { newCategory = true; categoryCount++; } if (assignmentDef.getCategoryName() != null) { if(!newCategory) {} else if(newCategory && categoryCount == 1) { catId = createCategory(gradebook.getId(), assignmentDef.getCategoryName(), assignmentDef.getWeight(), 0, 0, 0, assignmentDef.isCategoryExtraCredit()); Category catTempt = getCategory(catId); catList_tempt.add(catTempt); createAssignmentForCategory(gradebook.getId(), catId, assignmentDef.getName(), assignmentDef.getPoints(), assignmentDef.getDueDate(), true, false, assignmentDef.isExtraCredit()); assignmentsAddedCount++; } else{ createAssignmentForCategory(gradebook.getId(), catId, assignmentDef.getName(), assignmentDef.getPoints(), assignmentDef.getDueDate(), true, false, assignmentDef.isExtraCredit()); assignmentsAddedCount++; } } //deal with assignments in undefined. else { if (undefined_nb == 0) { createAssignment(gradebook.getId(), assignmentDef.getName(), assignmentDef.getPoints(), assignmentDef.getDueDate(), true, false, assignmentDef.isExtraCredit()); assignmentsAddedCount++; } } } undefined_nb++; } //deal with Category without assignments inside Iterator it_tempt = catList_tempt.iterator(); Iterator it = catList.iterator(); Category cat_cat ; Category cat_tempt; while(it_tempt.hasNext()) { cat_tempt = (Category) it_tempt.next(); while(it.hasNext()) { cat_cat = (Category) it.next(); if(cat_tempt.getName().equals(cat_cat.getName())) { it.remove(); it = catList.iterator(); } } it = catList.iterator(); } Iterator itUpdate = catList.iterator(); while(itUpdate.hasNext()){ Category catObj = (Category)itUpdate.next(); createCategory(gradebook.getId(), catObj.getName(), catObj.getWeight(), catObj.getDrop_lowest(), catObj.getDropHighest(), catObj.getKeepHighest(), catObj.isExtraCredit()); } } //deal with no categories else { for (org.sakaiproject.service.gradebook.shared.Assignment obj : gradebookDefinition.getAssignments()) { org.sakaiproject.service.gradebook.shared.Assignment assignmentDef = (org.sakaiproject.service.gradebook.shared.Assignment)obj; // Externally managed assessments should not be included. if (assignmentDef.isExternallyMaintained()) { continue; } // All assignments should be unreleased even if they were released in the original. createAssignment(gradebook.getId(), assignmentDef.getName(), assignmentDef.getPoints(), assignmentDef.getDueDate(), true, false, assignmentDef.isExtraCredit()); assignmentsAddedCount++; } } if (log.isInfoEnabled()) log.info("Merge to gradebook " + toGradebookUid + " added " + assignmentsAddedCount + " assignments"); // Carry over the old gradebook's selected grading scheme if possible. String fromGradingScaleUid = gradebookDefinition.getSelectedGradingScaleUid(); MERGE_GRADE_MAPPING: if (!StringUtils.isEmpty(fromGradingScaleUid)) { for (GradeMapping gradeMapping : gradebook.getGradeMappings()) { if (gradeMapping.getGradingScale().getUid().equals(fromGradingScaleUid)) { // We have a match. Now make sure that the grades are as expected. Map<String, Double> inputGradePercents = gradebookDefinition.getSelectedGradingScaleBottomPercents(); Set<String> gradeCodes = (Set<String>)inputGradePercents.keySet(); if (gradeCodes.containsAll(gradeMapping.getGradeMap().keySet())) { // Modify the existing grade-to-percentage map. for (String gradeCode : gradeCodes) { gradeMapping.getGradeMap().put(gradeCode, inputGradePercents.get(gradeCode)); } gradebook.setSelectedGradeMapping(gradeMapping); updateGradebook(gradebook); if (log.isInfoEnabled()) log.info("Merge to gradebook " + toGradebookUid + " updated grade mapping"); } else { if (log.isInfoEnabled()) log.info("Merge to gradebook " + toGradebookUid + " skipped grade mapping change because the " + fromGradingScaleUid + " grade codes did not match"); } break MERGE_GRADE_MAPPING; } } // Did not find a matching grading scale. if (log.isInfoEnabled()) log.info("Merge to gradebook " + toGradebookUid + " skipped grade mapping change because grading scale " + fromGradingScaleUid + " is not defined"); } } public void mergeGradebookDefinitionXml(String toGradebookUid, String fromGradebookXml) { final Gradebook gradebook = getGradebook(toGradebookUid); GradebookDefinition gradebookDefinition = (GradebookDefinition)VersionedExternalizable.fromXml(fromGradebookXml); List<String> assignmentNames = (List<String>)getHibernateTemplate().execute(new HibernateCallback() { public Object doInHibernate(final Session session) throws HibernateException { return session.createQuery( "select asn.name from Assignment as asn where asn.gradebook.id=? and asn.removed=false"). setLong(0, gradebook.getId().longValue()). list(); } }); // Add any non-externally-managed assignments with non-duplicate names. int assignmentsAddedCount = 0; for (org.sakaiproject.service.gradebook.shared.Assignment obj : gradebookDefinition.getAssignments()) { org.sakaiproject.service.gradebook.shared.Assignment assignmentDef = (org.sakaiproject.service.gradebook.shared.Assignment)obj; // Externally managed assessments should not be included. if (assignmentDef.isExternallyMaintained()) { continue; } // Skip any input assignments with duplicate names. if (assignmentNames.contains(assignmentDef.getName())) { if (log.isInfoEnabled()) log.info("Merge to gradebook " + toGradebookUid + " skipped duplicate assignment named " + assignmentDef.getName()); continue; } // All assignments should be unreleased even if they were released in the original. createAssignment(gradebook.getId(), assignmentDef.getName(), assignmentDef.getPoints(), assignmentDef.getDueDate(), true, false, assignmentDef.isExtraCredit()); assignmentsAddedCount++; } if (log.isInfoEnabled()) log.info("Merge to gradebook " + toGradebookUid + " added " + assignmentsAddedCount + " assignments"); // Carry over the old gradebook's selected grading scheme if possible. String fromGradingScaleUid = gradebookDefinition.getSelectedGradingScaleUid(); MERGE_GRADE_MAPPING: if (!StringUtils.isEmpty(fromGradingScaleUid)) { for (GradeMapping gradeMapping : gradebook.getGradeMappings()) { if (gradeMapping.getGradingScale().getUid().equals(fromGradingScaleUid)) { // We have a match. Now make sure that the grades are as expected. Map<String, Double> inputGradePercents = gradebookDefinition.getSelectedGradingScaleBottomPercents(); Set<String> gradeCodes = (Set<String>)inputGradePercents.keySet(); if (gradeCodes.containsAll(gradeMapping.getGradeMap().keySet())) { // Modify the existing grade-to-percentage map. for (String gradeCode : gradeCodes) { gradeMapping.getGradeMap().put(gradeCode, inputGradePercents.get(gradeCode)); } gradebook.setSelectedGradeMapping(gradeMapping); updateGradebook(gradebook); if (log.isInfoEnabled()) log.info("Merge to gradebook " + toGradebookUid + " updated grade mapping"); } else { if (log.isInfoEnabled()) log.info("Merge to gradebook " + toGradebookUid + " skipped grade mapping change because the " + fromGradingScaleUid + " grade codes did not match"); } break MERGE_GRADE_MAPPING; } } // Did not find a matching grading scale. if (log.isInfoEnabled()) log.info("Merge to gradebook " + toGradebookUid + " skipped grade mapping change because grading scale " + fromGradingScaleUid + " is not defined"); } } public void removeAssignment(final Long assignmentId) throws StaleObjectModificationException { HibernateCallback hc = new HibernateCallback() { public Object doInHibernate(Session session) throws HibernateException { Assignment asn = (Assignment)session.load(Assignment.class, assignmentId); Gradebook gradebook = asn.getGradebook(); asn.setRemoved(true); session.update(asn); if(log.isInfoEnabled()) log.info("Assignment " + asn.getName() + " has been removed from " + gradebook); return null; } }; getHibernateTemplate().execute(hc); } public void addAssignment(String gradebookUid, org.sakaiproject.service.gradebook.shared.Assignment assignmentDefinition) { if (!getAuthz().isUserAbleToEditAssessments(gradebookUid)) { log.error("AUTHORIZATION FAILURE: User " + getUserUid() + " in gradebook " + gradebookUid + " attempted to add an assignment"); throw new SecurityException("You do not have permission to perform this operation"); } // Ensure that points is > zero. Double points = assignmentDefinition.getPoints(); if ((points == null) || (points.doubleValue() <= 0)) { throw new AssignmentHasIllegalPointsException("Points must be > 0"); } Gradebook gradebook = getGradebook(gradebookUid); createAssignment(gradebook.getId(), assignmentDefinition.getName(), points, assignmentDefinition.getDueDate(), !assignmentDefinition.isCounted(), assignmentDefinition.isReleased(), assignmentDefinition.isExtraCredit()); } public void updateAssignment(final String gradebookUid, final String assignmentName, final org.sakaiproject.service.gradebook.shared.Assignment assignmentDefinition) { if (!getAuthz().isUserAbleToEditAssessments(gradebookUid)) { log.error("AUTHORIZATION FAILURE: User " + getUserUid() + " in gradebook " + gradebookUid + " attempted to change the definition of assignment " + assignmentName); throw new SecurityException("You do not have permission to perform this operation"); } // This method is for Gradebook-managed assignments only. if (assignmentDefinition.isExternallyMaintained()) { log.error("User " + getUserUid() + " in gradebook " + gradebookUid + " attempted to set assignment " + assignmentName + " to be externally maintained"); throw new SecurityException("You do not have permission to perform this operation"); } getHibernateTemplate().execute(new HibernateCallback() { public Object doInHibernate(Session session) throws HibernateException { Assignment assignment = getAssignmentWithoutStats(gradebookUid, assignmentName, session); if (assignment == null) { throw new AssessmentNotFoundException("There is no assignment named " + assignmentName + " in gradebook " + gradebookUid); } if (assignment.isExternallyMaintained()) { log.error("AUTHORIZATION FAILURE: User " + getUserUid() + " in gradebook " + gradebookUid + " attempted to change the definition of externally maintained assignment " + assignmentName); throw new SecurityException("You do not have permission to perform this operation"); } assignment.setCounted(assignmentDefinition.isCounted()); assignment.setDueDate(assignmentDefinition.getDueDate()); assignment.setName(assignmentDefinition.getName().trim()); assignment.setPointsPossible(assignmentDefinition.getPoints()); assignment.setReleased(assignmentDefinition.isReleased()); updateAssignment(assignment, session); return null; } }); } public Authz getAuthz() { return authz; } public void setAuthz(Authz authz) { this.authz = authz; } public GradebookPermissionService getGradebookPermissionService() { return gradebookPermissionService; } public void setGradebookPermissionService(GradebookPermissionService gradebookPermissionService) { this.gradebookPermissionService = gradebookPermissionService; } // Deprecated calls to new framework-specific interface. public void addGradebook(String uid, String name) { frameworkService.addGradebook(uid, name); } public void setAvailableGradingScales(Collection gradingScaleDefinitions) { frameworkService.setAvailableGradingScales(gradingScaleDefinitions); } public void setDefaultGradingScale(String uid) { frameworkService.setDefaultGradingScale(uid); } public void deleteGradebook( String uid) throws GradebookNotFoundException { frameworkService.deleteGradebook(uid); } public boolean isGradebookDefined(String gradebookUid) { return frameworkService.isGradebookDefined(gradebookUid); } public GradebookFrameworkService getFrameworkService() { return frameworkService; } public void setFrameworkService(GradebookFrameworkService frameworkService) { this.frameworkService = frameworkService; } // Deprecated calls to new interface for external assessment engines. public void addExternalAssessment(String gradebookUid, String externalId, String externalUrl, String title, double points, Date dueDate, String externalServiceDescription) throws ConflictingAssignmentNameException, ConflictingExternalIdException, GradebookNotFoundException { externalAssessmentService.addExternalAssessment(gradebookUid, externalId, externalUrl, title, points, dueDate, externalServiceDescription); } public void addExternalAssessment(String gradebookUid, String externalId, String externalUrl, String title, Double points, Date dueDate, String externalServiceDescription, Boolean ungraded) throws ConflictingAssignmentNameException, ConflictingExternalIdException, GradebookNotFoundException { externalAssessmentService.addExternalAssessment(gradebookUid, externalId, externalUrl, title, points, dueDate, externalServiceDescription, ungraded); } public void updateExternalAssessment(String gradebookUid, String externalId, String externalUrl, String title, double points, Date dueDate) throws GradebookNotFoundException, AssessmentNotFoundException,AssignmentHasIllegalPointsException { externalAssessmentService.updateExternalAssessment(gradebookUid, externalId, externalUrl, title, Double.valueOf(points), dueDate, Boolean.valueOf(false)); } public void updateExternalAssessment(String gradebookUid, String externalId, String externalUrl, String title, Double points, Date dueDate) throws GradebookNotFoundException, AssessmentNotFoundException,AssignmentHasIllegalPointsException { externalAssessmentService.updateExternalAssessment(gradebookUid, externalId, externalUrl, title, points, dueDate, Boolean.valueOf(false)); } public void removeExternalAssessment(String gradebookUid, String externalId) throws GradebookNotFoundException, AssessmentNotFoundException { externalAssessmentService.removeExternalAssessment(gradebookUid, externalId); } public void updateExternalAssessmentScore(String gradebookUid, String externalId, String studentUid, Double points) throws GradebookNotFoundException, AssessmentNotFoundException { String strPoints = (points == null ? null : points.toString()); externalAssessmentService.updateExternalAssessmentScore(gradebookUid, externalId, studentUid, strPoints); } public void updateExternalAssessmentScores(String gradebookUid, String externalId, Map studentUidsToScores) throws GradebookNotFoundException, AssessmentNotFoundException { externalAssessmentService.updateExternalAssessmentScores(gradebookUid, externalId, studentUidsToScores); } public void updateExternalAssessmentComment(String gradebookUid, String externalId, String studentUid, String comment) throws GradebookNotFoundException, AssessmentNotFoundException { externalAssessmentService.updateExternalAssessmentComment(gradebookUid, externalId, studentUid, comment); } public void updateExternalAssessmentComments(String gradebookUid, String externalId, Map studentUidsToComments) throws GradebookNotFoundException, AssessmentNotFoundException { externalAssessmentService.updateExternalAssessmentComments(gradebookUid, externalId, studentUidsToComments); } public boolean isExternalAssignmentDefined(String gradebookUid, String externalId) throws GradebookNotFoundException { return externalAssessmentService.isExternalAssignmentDefined(gradebookUid, externalId); } public GradebookExternalAssessmentService getExternalAssessmentService() { return externalAssessmentService; } public void setExternalAssessmentService( GradebookExternalAssessmentService externalAssessmentService) { this.externalAssessmentService = externalAssessmentService; } /** * @param gradebookUid * @return A mapping from user display IDs to grades. If no grade is available for a user, default to zero. */ public Map getImportCourseGrade(String gradebookUid) { return getImportCourseGrade(gradebookUid, true); } /** * @param gradebookUid * @param useDefault If true, assume zero for missing grades. Otherwise, null. * @return A mapping from user display IDs to grades. */ public Map getImportCourseGrade(String gradebookUid, boolean useDefault) { HashMap returnMap = new HashMap(); try { Gradebook thisGradebook = getGradebook(gradebookUid); List assignList = getAssignmentsCounted(thisGradebook.getId()); boolean nonAssignment = false; if(assignList == null || assignList.size() < 1) { nonAssignment = true; } Long gradebookId = thisGradebook.getId(); CourseGrade courseGrade = getCourseGrade(gradebookId); Map viewableEnrollmentsMap = authz.findMatchingEnrollmentsForViewableCourseGrade(gradebookUid, thisGradebook.getCategory_type(), null, null); Map enrollmentMap = new HashMap(); Map enrollmentMapUid = new HashMap(); for (Iterator iter = viewableEnrollmentsMap.keySet().iterator(); iter.hasNext(); ) { EnrollmentRecord enr = (EnrollmentRecord)iter.next(); enrollmentMap.put(enr.getUser().getUserUid(), enr); enrollmentMapUid.put(enr.getUser().getUserUid(), enr); } List gradeRecords = getPointsEarnedCourseGradeRecords(courseGrade, enrollmentMap.keySet()); for (Iterator iter = gradeRecords.iterator(); iter.hasNext(); ) { CourseGradeRecord gradeRecord = (CourseGradeRecord)iter.next(); GradeMapping gradeMap= thisGradebook.getSelectedGradeMapping(); EnrollmentRecord enr = (EnrollmentRecord)enrollmentMapUid.get(gradeRecord.getStudentId()); if(enr != null) { if(gradeRecord.getEnteredGrade() != null && !gradeRecord.getEnteredGrade().equalsIgnoreCase("")) { returnMap.put(enr.getUser().getDisplayId(), gradeRecord.getEnteredGrade()); } else { if(!nonAssignment) { String grade = null; if(useDefault) { grade = (String)gradeMap.getGrade(gradeRecord.getNonNullAutoCalculatedGrade()); } else { grade = (String)gradeMap.getGrade(gradeRecord.getAutoCalculatedGrade()); } returnMap.put(enr.getUser().getDisplayId(), grade); } } } } } catch(Exception e) { e.printStackTrace(); } return returnMap; } public CourseGrade getCourseGrade(Long gradebookId) { return (CourseGrade)getHibernateTemplate().find( "from CourseGrade as cg where cg.gradebook.id=?", gradebookId).get(0); } public List getPointsEarnedCourseGradeRecords(final CourseGrade courseGrade, final Collection studentUids) { HibernateCallback hc = new HibernateCallback() { public Object doInHibernate(Session session) throws HibernateException { if(studentUids == null || studentUids.size() == 0) { if(log.isInfoEnabled()) log.info("Returning no grade records for an empty collection of student UIDs"); return new ArrayList(); } Query q = session.createQuery("from CourseGradeRecord as cgr where cgr.gradableObject.id=:gradableObjectId"); q.setLong("gradableObjectId", courseGrade.getId().longValue()); List records = filterAndPopulateCourseGradeRecordsByStudents(courseGrade, q.list(), studentUids); Long gradebookId = courseGrade.getGradebook().getId(); Gradebook gradebook = getGradebook(gradebookId); List cates = getCategories(gradebookId); // get all of the AssignmentGradeRecords here to avoid repeated db calls Map<String, List<AssignmentGradeRecord>> gradeRecMap = getGradeRecordMapForStudents(session, gradebookId, studentUids); // get all of the counted assignments List<Assignment> countedAssigns = getCountedAssignments(session, gradebookId); //double totalPointsPossible = getTotalPointsInternal(gradebookId, session); //if(log.isDebugEnabled()) log.debug("Total points = " + totalPointsPossible); for(Iterator iter = records.iterator(); iter.hasNext();) { CourseGradeRecord cgr = (CourseGradeRecord)iter.next(); //double totalPointsEarned = getTotalPointsEarnedInternal(gradebookId, cgr.getStudentId(), session); List<AssignmentGradeRecord> studentGradeRecs = gradeRecMap.get(cgr.getStudentId()); applyDropScores(studentGradeRecs); List totalEarned = getTotalPointsEarnedInternal(gradebookId, cgr.getStudentId(), session, gradebook, cates, studentGradeRecs); double totalPointsEarned = ((Double)totalEarned.get(0)).doubleValue(); double literalTotalPointsEarned = ((Double)totalEarned.get(1)).doubleValue(); double totalPointsPossible = getTotalPointsInternal(gradebookId, session, gradebook, cates, cgr.getStudentId(), studentGradeRecs, countedAssigns); cgr.initNonpersistentFields(totalPointsPossible, totalPointsEarned, literalTotalPointsEarned); if(log.isDebugEnabled()) log.debug("Points earned = " + cgr.getPointsEarned()); } return records; } }; return (List)getHibernateTemplate().execute(hc); } private List filterAndPopulateCourseGradeRecordsByStudents(CourseGrade courseGrade, Collection gradeRecords, Collection studentUids) { List filteredRecords = new ArrayList(); Set missingStudents = new HashSet(studentUids); for (Iterator iter = gradeRecords.iterator(); iter.hasNext(); ) { CourseGradeRecord cgr = (CourseGradeRecord)iter.next(); if (studentUids.contains(cgr.getStudentId())) { filteredRecords.add(cgr); missingStudents.remove(cgr.getStudentId()); } } for (Iterator iter = missingStudents.iterator(); iter.hasNext(); ) { String studentUid = (String)iter.next(); CourseGradeRecord cgr = new CourseGradeRecord(courseGrade, studentUid); filteredRecords.add(cgr); } return filteredRecords; } private double getTotalPointsInternal(final Long gradebookId, Session session, final Gradebook gradebook, final List categories, final String studentId, List<AssignmentGradeRecord> studentGradeRecs, List<Assignment> countedAssigns) // private double getTotalPointsInternal(final Gradebook gradebook, Session session, final List categories, final String studentId, List<AssignmentGradeRecord> studentGradeRecs, List<Assignment> countedAssigns) { double totalPointsPossible = 0; List assgnsList = session.createQuery( "select asn from Assignment asn where asn.gradebook.id=:gbid and asn.removed=false and asn.notCounted=false and asn.ungraded=false and asn.pointsPossible > 0"). setParameter("gbid", gradebookId). list(); Iterator scoresIter = session.createQuery( "select agr.pointsEarned, asn from AssignmentGradeRecord agr, Assignment asn where agr.gradableObject=asn and agr.studentId=:student and asn.gradebook.id=:gbid and asn.removed=false and asn.notCounted=false and asn.ungraded=false and asn.pointsPossible > 0"). setParameter("student", studentId). setParameter("gbid", gradebookId). list().iterator(); Set assignmentsTaken = new HashSet(); Set categoryTaken = new HashSet(); while (scoresIter.hasNext()) { Object[] returned = (Object[])scoresIter.next(); Double pointsEarned = (Double)returned[0]; Assignment go = (Assignment) returned[1]; //don't count extra credit assignments boolean extraCredit = false; if (go.isExtraCredit()!=null) extraCredit = go.isExtraCredit(); if(extraCredit){ continue; } if (pointsEarned != null) { //check if assignment is dropped from grade boolean skip = false; for(AssignmentGradeRecord gr : studentGradeRecs){ if(gr.getAssignment().getId().equals(go.getId())){ if(gr.getDroppedFromGrade()){ skip = true; } break; } } if(skip){ continue; } if(gradebook.getCategory_type() == GradebookService.CATEGORY_TYPE_NO_CATEGORY) { assignmentsTaken.add(go.getId()); } else if(gradebook.getCategory_type() == GradebookService.CATEGORY_TYPE_ONLY_CATEGORY && go != null) { for(int i=0; i<categories.size(); i++) { Category cate = (Category) categories.get(i); if(cate != null && !cate.isRemoved() && go.getCategory() != null && cate.getId().equals(go.getCategory().getId()) && ((cate.isExtraCredit()!=null && !cate.isExtraCredit()) || cate.isExtraCredit()==null)) { assignmentsTaken.add(go.getId()); } } } else if(gradebook.getCategory_type() == GradebookService.CATEGORY_TYPE_WEIGHTED_CATEGORY && go != null && categories != null) { for(int i=0; i<categories.size(); i++) { Category cate = (Category) categories.get(i); if(cate != null && !cate.isRemoved() && go.getCategory() != null && cate.getId().equals(go.getCategory().getId()) && ((cate.isExtraCredit()!=null && !cate.isExtraCredit()) || cate.isExtraCredit()==null)) { assignmentsTaken.add(go.getId()); categoryTaken.add(cate.getId()); break; } } } } } if(!assignmentsTaken.isEmpty()) { if(gradebook.getCategory_type() == GradebookService.CATEGORY_TYPE_WEIGHTED_CATEGORY) { for(int i=0; i<categories.size(); i++) { Category cate = (Category) categories.get(i); if(cate != null && !cate.isRemoved() && categoryTaken.contains(cate.getId()) ) { totalPointsPossible += cate.getWeight().doubleValue(); } } return totalPointsPossible; } Iterator assignmentIter = assgnsList.iterator(); while (assignmentIter.hasNext()) { Assignment asn = (Assignment) assignmentIter.next(); if(asn != null) { Double pointsPossible = asn.getPointsPossible(); if(gradebook.getCategory_type() == GradebookService.CATEGORY_TYPE_NO_CATEGORY && assignmentsTaken.contains(asn.getId())) { totalPointsPossible += pointsPossible.doubleValue(); } else if(gradebook.getCategory_type() == GradebookService.CATEGORY_TYPE_ONLY_CATEGORY && assignmentsTaken.contains(asn.getId())) { totalPointsPossible += pointsPossible.doubleValue(); } } } } else totalPointsPossible = -1; return totalPointsPossible; } private List getTotalPointsEarnedInternal(final Long gradebookId, final String studentId, final Session session, final Gradebook gradebook, final List categories, List<AssignmentGradeRecord> studentGradeRecs) { double totalPointsEarned = 0; double literalTotalPointsEarned = 0; Iterator scoresIter = session.createQuery( "select agr.pointsEarned, asn from AssignmentGradeRecord agr, Assignment asn where agr.gradableObject=asn and agr.studentId=:student and asn.gradebook.id=:gbid and asn.removed=false and asn.pointsPossible > 0"). setParameter("student", studentId). setParameter("gbid", gradebookId). list().iterator(); List assgnsList = session.createQuery( "from Assignment as asn where asn.gradebook.id=:gbid and asn.removed=false and asn.notCounted=false and asn.ungraded=false and asn.pointsPossible > 0"). setParameter("gbid", gradebookId). list(); Map cateScoreMap = new HashMap(); Map cateTotalScoreMap = new HashMap(); Set assignmentsTaken = new HashSet(); while (scoresIter.hasNext()) { Object[] returned = (Object[])scoresIter.next(); Double pointsEarned = (Double)returned[0]; Assignment go = (Assignment) returned[1]; if (go != null && go.isCounted() && pointsEarned != null) { boolean skip = false; for(AssignmentGradeRecord gr : studentGradeRecs){ if(gr.getAssignment().getId().equals(go.getId())){ if(gr.getDroppedFromGrade()){ skip = true; } break; } } if(skip){ continue; } if(gradebook.getCategory_type() == GradebookService.CATEGORY_TYPE_NO_CATEGORY) { totalPointsEarned += pointsEarned.doubleValue(); literalTotalPointsEarned += pointsEarned.doubleValue(); assignmentsTaken.add(go.getId()); } else if(gradebook.getCategory_type() == GradebookService.CATEGORY_TYPE_ONLY_CATEGORY && go != null) { totalPointsEarned += pointsEarned.doubleValue(); literalTotalPointsEarned += pointsEarned.doubleValue(); assignmentsTaken.add(go.getId()); } else if(gradebook.getCategory_type() == GradebookService.CATEGORY_TYPE_WEIGHTED_CATEGORY && go != null && categories != null) { for(int i=0; i<categories.size(); i++) { Category cate = (Category) categories.get(i); if(cate != null && !cate.isRemoved() && go.getCategory() != null && cate.getId().equals(go.getCategory().getId())) { assignmentsTaken.add(go.getId()); literalTotalPointsEarned += pointsEarned.doubleValue(); if(cateScoreMap.get(cate.getId()) != null) { cateScoreMap.put(cate.getId(), Double.valueOf(((Double)cateScoreMap.get(cate.getId())).doubleValue() + pointsEarned.doubleValue())); } else { cateScoreMap.put(cate.getId(), Double.valueOf(pointsEarned)); } break; } } } } } if(gradebook.getCategory_type() == GradebookService.CATEGORY_TYPE_WEIGHTED_CATEGORY && categories != null) { Iterator assgnsIter = assgnsList.iterator(); while (assgnsIter.hasNext()) { Assignment asgn = (Assignment)assgnsIter.next(); if(assignmentsTaken.contains(asgn.getId())) { for(int i=0; i<categories.size(); i++) { Category cate = (Category) categories.get(i); if(cate != null && !cate.isRemoved() && asgn.getCategory() != null && cate.getId().equals(asgn.getCategory().getId())) { if(cateTotalScoreMap.get(cate.getId()) == null) { cateTotalScoreMap.put(cate.getId(), asgn.getPointsPossible()); } else { cateTotalScoreMap.put(cate.getId(), Double.valueOf(((Double)cateTotalScoreMap.get(cate.getId())).doubleValue() + asgn.getPointsPossible().doubleValue())); } } } } } } if(assignmentsTaken.isEmpty()) totalPointsEarned = -1; if(gradebook.getCategory_type() == GradebookService.CATEGORY_TYPE_WEIGHTED_CATEGORY) { for(int i=0; i<categories.size(); i++) { Category cate = (Category) categories.get(i); if(cate != null && !cate.isRemoved() && cateScoreMap.get(cate.getId()) != null && cateTotalScoreMap.get(cate.getId()) != null) { totalPointsEarned += ((Double)cateScoreMap.get(cate.getId())).doubleValue() * cate.getWeight().doubleValue() / ((Double)cateTotalScoreMap.get(cate.getId())).doubleValue(); } } } if (log.isDebugEnabled()) log.debug("getTotalPointsEarnedInternal for studentId=" + studentId + " returning " + totalPointsEarned); List returnList = new ArrayList(); returnList.add(Double.valueOf(totalPointsEarned)); returnList.add(Double.valueOf(literalTotalPointsEarned)); return returnList; } public Gradebook getGradebook(Long id) { return (Gradebook)getHibernateTemplate().load(Gradebook.class, id); } protected List getAssignmentsCounted(final Long gradebookId) throws HibernateException { HibernateCallback hc = new HibernateCallback() { public Object doInHibernate(Session session) throws HibernateException { List assignments = session.createQuery( "from Assignment as asn where asn.gradebook.id=? and asn.removed=false and asn.notCounted=false"). setLong(0, gradebookId.longValue()). list(); return assignments; } }; return (List)getHibernateTemplate().execute(hc); } public boolean checkStudentsNotSubmitted(String gradebookUid) { Gradebook gradebook = getGradebook(gradebookUid); Set studentUids = getAllStudentUids(getGradebookUid(gradebook.getId())); if(gradebook.getCategory_type() == GradebookService.CATEGORY_TYPE_NO_CATEGORY || gradebook.getCategory_type() == GradebookService.CATEGORY_TYPE_ONLY_CATEGORY) { List records = getAllAssignmentGradeRecords(gradebook.getId(), studentUids); List assigns = getAssignments(gradebook.getId(), Assignment.DEFAULT_SORT, true); List filteredAssigns = new ArrayList(); for(Iterator iter = assigns.iterator(); iter.hasNext();) { Assignment assignment = (Assignment)iter.next(); if(assignment.isCounted() && !assignment.getUngraded()) filteredAssigns.add(assignment); } List filteredRecords = new ArrayList(); for(Iterator iter = records.iterator(); iter.hasNext();) { AssignmentGradeRecord agr = (AssignmentGradeRecord)iter.next(); if(!agr.isCourseGradeRecord() && agr.getAssignment().isCounted() && !agr.getAssignment().getUngraded()) { if(agr.getPointsEarned() == null) return true; filteredRecords.add(agr); } } if(filteredRecords.size() < (filteredAssigns.size() * studentUids.size())) return true; return false; } else { List assigns = getAssignments(gradebook.getId(), Assignment.DEFAULT_SORT, true); List records = getAllAssignmentGradeRecords(gradebook.getId(), studentUids); Set filteredAssigns = new HashSet(); for (Iterator iter = assigns.iterator(); iter.hasNext(); ) { Assignment assign = (Assignment) iter.next(); if(assign != null && assign.isCounted() && !assign.getUngraded()) { if(assign.getCategory() != null && !assign.getCategory().isRemoved()) { filteredAssigns.add(assign.getId()); } } } List filteredRecords = new ArrayList(); for(Iterator iter = records.iterator(); iter.hasNext();) { AssignmentGradeRecord agr = (AssignmentGradeRecord)iter.next(); if(filteredAssigns.contains(agr.getAssignment().getId()) && !agr.isCourseGradeRecord()) { if(agr.getPointsEarned() == null) return true; filteredRecords.add(agr); } } if(filteredRecords.size() < filteredAssigns.size() * studentUids.size()) return true; return false; } } public List getAllAssignmentGradeRecords(final Long gradebookId, final Collection studentUids) { HibernateCallback hc = new HibernateCallback() { public Object doInHibernate(Session session) throws HibernateException { if(studentUids.size() == 0) { // If there are no enrollments, no need to execute the query. if(log.isInfoEnabled()) log.info("No enrollments were specified. Returning an empty List of grade records"); return new ArrayList(); } else { Query q = session.createQuery("from AssignmentGradeRecord as agr where agr.gradableObject.removed=false and " + "agr.gradableObject.gradebook.id=:gradebookId order by agr.pointsEarned"); q.setLong("gradebookId", gradebookId.longValue()); return filterGradeRecordsByStudents(q.list(), studentUids); } } }; return (List)getHibernateTemplate().execute(hc); } private List getAllAssignmentGradeRecordsForGbItem(final Long gradableObjectId, final Collection studentUids) { HibernateCallback hc = new HibernateCallback() { public Object doInHibernate(Session session) throws HibernateException { if(studentUids.size() == 0) { // If there are no enrollments, no need to execute the query. if(log.isInfoEnabled()) log.info("No enrollments were specified. Returning an empty List of grade records"); return new ArrayList(); } else { Query q = session.createQuery("from AssignmentGradeRecord as agr where agr.gradableObject.removed=false and " + "agr.gradableObject.id=:gradableObjectId order by agr.pointsEarned"); q.setLong("gradableObjectId", gradableObjectId.longValue()); return filterGradeRecordsByStudents(q.list(), studentUids); } } }; return (List)getHibernateTemplate().execute(hc); } public List getAssignments(final Long gradebookId, final String sortBy, final boolean ascending) { return (List)getHibernateTemplate().execute(new HibernateCallback() { public Object doInHibernate(Session session) throws HibernateException { List assignments = getAssignments(gradebookId, session); sortAssignments(assignments, sortBy, ascending); return assignments; } }); } private void sortAssignments(List assignments, String sortBy, boolean ascending) { // WARNING: AZ - this method is duplicated in GradebookManagerHibernateImpl Comparator comp; if (Assignment.SORT_BY_NAME.equals(sortBy)) { comp = GradableObject.nameComparator; } else if(Assignment.SORT_BY_DATE.equals(sortBy)){ comp = GradableObject.dateComparator; } else if(Assignment.SORT_BY_MEAN.equals(sortBy)) { comp = GradableObject.meanComparator; } else if(Assignment.SORT_BY_POINTS.equals(sortBy)) { comp = Assignment.pointsComparator; } else if(Assignment.SORT_BY_RELEASED.equals(sortBy)){ comp = Assignment.releasedComparator; } else if(Assignment.SORT_BY_COUNTED.equals(sortBy)){ comp = Assignment.countedComparator; } else if(Assignment.SORT_BY_EDITOR.equals(sortBy)){ comp = Assignment.gradeEditorComparator; } else if (Assignment.SORT_BY_SORTING.equals(sortBy)) { comp = GradableObject.sortingComparator; } else { comp = GradableObject.defaultComparator; } Collections.sort(assignments, comp); if(!ascending) { Collections.reverse(assignments); } if (log.isDebugEnabled()) { log.debug("sortAssignments: ordering by "+sortBy+" ("+comp+"), ascending="+ascending); } } /* * (non-Javadoc) * @see org.sakaiproject.service.gradebook.shared.GradebookService#getViewableAssignmentsForCurrentUser(java.lang.String) */ public List<org.sakaiproject.service.gradebook.shared.Assignment> getViewableAssignmentsForCurrentUser(String gradebookUid) throws GradebookNotFoundException { List<Assignment> viewableAssignments = new ArrayList(); List<org.sakaiproject.service.gradebook.shared.Assignment> assignmentsToReturn = new ArrayList(); Gradebook gradebook = getGradebook(gradebookUid); // will send back all assignments if user can grade all if (getAuthz().isUserAbleToGradeAll(gradebookUid)) { viewableAssignments = getAssignments(gradebook.getId(), null, true); } else if (getAuthz().isUserAbleToGrade(gradebookUid)) { // if user can grade and doesn't have grader perm restrictions, they // may view all assigns if (!getAuthz().isUserHasGraderPermissions(gradebookUid)) { viewableAssignments = getAssignments(gradebook.getId(), null, true); } else { // this user has grader perms, so we need to filter the items returned // if this gradebook has categories enabled, we need to check for category-specific restrictions if (gradebook.getCategory_type() == GradebookService.CATEGORY_TYPE_NO_CATEGORY) { assignmentsToReturn = getAssignments(gradebookUid); } else { String userUid = getUserUid(); if (getGradebookPermissionService().getPermissionForUserForAllAssignment(gradebook.getId(), userUid)) { assignmentsToReturn = getAssignments(gradebookUid); } // categories are enabled, so we need to check the category restrictions List allCategories = getCategoriesWithAssignments(gradebook.getId()); if (allCategories != null && !allCategories.isEmpty()) { List<Long> catIds = new ArrayList<Long>(); for (Category category : (List<Category>) allCategories) { catIds.add(category.getId()); } List<Long> viewableCategorieIds = getGradebookPermissionService().getCategoriesForUser(gradebook.getId(), userUid, catIds, gradebook.getCategory_type()); List<Category> viewableCategories = new ArrayList<Category>(); for (Category category : (List<Category>) allCategories) { if(viewableCategorieIds.contains(category.getId())){ viewableCategories.add(category); } } for (Iterator catIter = viewableCategories.iterator(); catIter.hasNext();) { Category cat = (Category) catIter.next(); if (cat != null) { List assignments = cat.getAssignmentList(); if (assignments != null && !assignments.isEmpty()) { viewableAssignments.addAll(assignments); } } } } } } } else if (getAuthz().isUserAbleToViewOwnGrades(gradebookUid)) { // if user is just a student, we need to filter out unreleased items List allAssigns = getAssignments(gradebook.getId(), null, true); if (allAssigns != null) { for (Iterator aIter = allAssigns.iterator(); aIter.hasNext();) { Assignment assign = (Assignment) aIter.next(); if (assign != null && assign.isReleased()) { viewableAssignments.add(assign); } } } } // Now we need to convert these to the assignment template objects if (viewableAssignments != null && !viewableAssignments.isEmpty()) { for (Iterator assignIter = viewableAssignments.iterator(); assignIter.hasNext();) { Assignment assignment = (Assignment) assignIter.next(); assignmentsToReturn.add(getAssignmentDefinition(assignment)); } } return assignmentsToReturn; } public Map<String, String> getViewableStudentsForItemForCurrentUser(final String gradebookUid, final Long gradableObjectId) { String userUid = authn.getUserUid(); return getViewableStudentsForItemForUser(userUid, gradebookUid, gradableObjectId); } public Map<String, String> getViewableStudentsForItemForUser(final String userUid, final String gradebookUid, final Long gradableObjectId) { if (gradebookUid == null || gradableObjectId == null || userUid == null) { throw new IllegalArgumentException("null gradebookUid or gradableObjectId or " + "userId passed to getViewableStudentsForUserForItem." + " gradebookUid: " + gradebookUid + " gradableObjectId:" + gradableObjectId + " userId: " + userUid); } if (!authz.isUserAbleToGrade(gradebookUid, userUid)) { return new HashMap(); } Assignment gradebookItem = (Assignment)getHibernateTemplate().execute(new HibernateCallback() { public Object doInHibernate(Session session) throws HibernateException { return getAssignmentWithoutStats(gradebookUid, gradableObjectId, session); } }); if (gradebookItem == null) { log.debug("The gradebook item does not exist, so returning empty set"); return new HashMap(); } Long categoryId = gradebookItem.getCategory() == null ? null : gradebookItem.getCategory().getId(); Map<EnrollmentRecord, String> enrRecFunctionMap = authz.findMatchingEnrollmentsForItemForUser(userUid, gradebookUid, categoryId, getGradebook(gradebookUid).getCategory_type(), null, null); if (enrRecFunctionMap == null) { return new HashMap(); } Map<String, String> studentIdFunctionMap = new HashMap(); for (Iterator<Entry<EnrollmentRecord, String>> enrIter = enrRecFunctionMap.entrySet().iterator(); enrIter.hasNext();) { Entry<EnrollmentRecord, String> entry = enrIter.next(); EnrollmentRecord enr = entry.getKey(); if (enr != null && enrRecFunctionMap.get(enr) != null) { studentIdFunctionMap.put(enr.getUser().getUserUid(), entry.getValue()); } } return studentIdFunctionMap; } public boolean isGradableObjectDefined(Long gradableObjectId) { if (gradableObjectId == null) { throw new IllegalArgumentException("null gradableObjectId passed to isGradableObjectDefined"); } return isAssignmentDefined(gradableObjectId); } public Map getViewableSectionUuidToNameMap(String gradebookUid) { if (gradebookUid == null) { throw new IllegalArgumentException("Null gradebookUid passed to getViewableSectionIdToNameMap"); } Map<String, String> sectionIdNameMap = new HashMap(); List viewableCourseSections = getAuthz().getViewableSections(gradebookUid); if (viewableCourseSections == null || viewableCourseSections.isEmpty()) { return sectionIdNameMap; } for (Iterator sectionIter = viewableCourseSections.iterator(); sectionIter.hasNext();) { CourseSection section = (CourseSection) sectionIter.next(); if (section != null) { sectionIdNameMap.put(section.getUuid(), section.getTitle()); } } return sectionIdNameMap; } public boolean currentUserHasGradeAllPerm(String gradebookUid) { return authz.isUserAbleToGradeAll(gradebookUid); } public boolean isUserAllowedToGradeAll(String gradebookUid, String userUid) { return authz.isUserAbleToGradeAll(gradebookUid, userUid); } public boolean currentUserHasGradingPerm(String gradebookUid) { return authz.isUserAbleToGrade(gradebookUid); } public boolean isUserAllowedToGrade(String gradebookUid, String userUid) { return authz.isUserAbleToGrade(gradebookUid, userUid); } public boolean currentUserHasEditPerm(String gradebookUid) { return authz.isUserAbleToEditAssessments(gradebookUid); } public boolean currentUserHasViewOwnGradesPerm(String gradebookUid) { return authz.isUserAbleToViewOwnGrades(gradebookUid); } public List<GradeDefinition> getGradesForStudentsForItem(final String gradebookUid, final Long gradableObjectId, List<String> studentIds) { if (gradableObjectId == null) { throw new IllegalArgumentException("null gradableObjectId passed to getGradesForStudentsForItem"); } List<org.sakaiproject.service.gradebook.shared.GradeDefinition> studentGrades = new ArrayList(); if (studentIds != null && !studentIds.isEmpty()) { // first, we need to make sure the current user is authorized to view the // grades for all of the requested students Assignment gbItem = (Assignment)getHibernateTemplate().execute(new HibernateCallback() { public Object doInHibernate(Session session) throws HibernateException { return getAssignmentWithoutStats(gradebookUid, gradableObjectId, session); } }); if (gbItem != null) { Gradebook gradebook = gbItem.getGradebook(); if (!authz.isUserAbleToGrade(gradebook.getUid())) { throw new SecurityException("User " + authn.getUserUid() + " attempted to access grade information without permission in gb " + gradebook.getUid() + " using gradebookService.getGradesForStudentsForItem"); } Long categoryId = gbItem.getCategory() != null ? gbItem.getCategory().getId() : null; Map enrRecFunctionMap = authz.findMatchingEnrollmentsForItem(gradebook.getUid(), categoryId, gradebook.getCategory_type(), null, null); Set enrRecs = enrRecFunctionMap.keySet(); Map studentIdEnrRecMap = new HashMap(); if (enrRecs != null) { for (Iterator enrIter = enrRecs.iterator(); enrIter.hasNext();) { EnrollmentRecord enr = (EnrollmentRecord) enrIter.next(); if (enr != null) { studentIdEnrRecMap.put(enr.getUser().getUserUid(), enr); } } } for (Iterator stIter = studentIds.iterator(); stIter.hasNext();) { String studentId = (String) stIter.next(); if (studentId != null) { if (!studentIdEnrRecMap.containsKey(studentId)) { throw new SecurityException("User " + authn.getUserUid() + " attempted to access grade information for student " + studentId + " without permission in gb " + gradebook.getUid() + " using gradebookService.getGradesForStudentsForItem"); } } } // retrieve the grading comments for all of the students List<Comment> commentRecs = getComments(gbItem, studentIds); Map<String, String> studentIdCommentTextMap = new HashMap(); if (commentRecs != null) { for (Iterator<Comment> cIter = commentRecs.iterator(); cIter.hasNext();) { Comment comment = cIter.next(); if (comment != null) { studentIdCommentTextMap.put(comment.getStudentId(), comment.getCommentText()); } } } // now, we can populate the grade information List<AssignmentGradeRecord> gradeRecs = getAllAssignmentGradeRecordsForGbItem(gradableObjectId, studentIds); if (gradeRecs != null) { if (gradebook.getGrade_type() == GradebookService.GRADE_TYPE_LETTER) { convertPointsToLetterGrade(gradebook, gradeRecs); } else if (gradebook.getGrade_type() == GradebookService.GRADE_TYPE_PERCENTAGE) { convertPointsToPercentage(gradebook, gradeRecs); } boolean gradeReleased = gradebook.isAssignmentsDisplayed() && gbItem.isReleased(); for (Iterator gradeIter = gradeRecs.iterator(); gradeIter.hasNext();) { AssignmentGradeRecord agr = (AssignmentGradeRecord) gradeIter.next(); if (agr != null) { GradeDefinition gradeDef = new GradeDefinition(); gradeDef.setStudentUid(agr.getStudentId()); gradeDef.setGradeEntryType(gradebook.getGrade_type()); gradeDef.setGradeReleased(gradeReleased); gradeDef.setGraderUid(agr.getGraderId()); gradeDef.setDateRecorded(agr.getDateRecorded()); String commentText = studentIdCommentTextMap.get(agr.getStudentId()); if (commentText != null) { gradeDef.setGradeComment(commentText); } if (gradebook.getGrade_type() == GradebookService.GRADE_TYPE_LETTER) { gradeDef.setGrade(agr.getLetterEarned()); } else if (gradebook.getGrade_type() == GradebookService.GRADE_TYPE_PERCENTAGE) { String grade = agr.getPercentEarned() != null ? agr.getPercentEarned().toString() : null; gradeDef.setGrade(grade); } else { String grade = agr.getPointsEarned() != null ? agr.getPointsEarned().toString() : null; gradeDef.setGrade(grade); } studentGrades.add(gradeDef); } } } } } return studentGrades; } public boolean isGradeValid(String gradebookUuid, String grade) { if (gradebookUuid == null) { throw new IllegalArgumentException("Null gradebookUuid passed to isGradeValid"); } Gradebook gradebook; try { gradebook = getGradebook(gradebookUuid); } catch (GradebookNotFoundException gnfe) { throw new GradebookNotFoundException("No gradebook exists with the given gradebookUid: " + gradebookUuid + "Error: " + gnfe.getMessage()); } int gradeEntryType = gradebook.getGrade_type(); LetterGradePercentMapping mapping = null; if (gradeEntryType == GradebookService.GRADE_TYPE_LETTER) { mapping = getLetterGradePercentMapping(gradebook); } return isGradeValid(grade, gradeEntryType, mapping); } private boolean isGradeValid(String grade, int gradeEntryType, LetterGradePercentMapping gradeMapping) { boolean gradeIsValid = false; if (grade == null || "".equals(grade)) { gradeIsValid = true; } else { if (gradeEntryType == GradebookService.GRADE_TYPE_POINTS || gradeEntryType == GradebookService.GRADE_TYPE_PERCENTAGE) { try { Double gradeAsDouble = Double.parseDouble(grade); // grade must be greater than or equal to 0 if (gradeAsDouble.doubleValue() >= 0) { // check that there are no more than 2 decimal places String[] splitOnDecimal = grade.split("\\."); if (splitOnDecimal == null || splitOnDecimal.length < 2) { gradeIsValid = true; } else if (splitOnDecimal.length == 2) { String decimal = splitOnDecimal[1]; if (decimal.length() <= 2) { gradeIsValid = true; } } } } catch (NumberFormatException nfe) { if (log.isDebugEnabled()) log.debug("Passed grade is not a numeric value"); } } else if (gradeEntryType == GradebookService.GRADE_TYPE_LETTER) { if (gradeMapping == null) { throw new IllegalArgumentException("Null mapping passed to isGradeValid for a letter grade-based gradeook"); } String standardizedGrade = gradeMapping.standardizeInputGrade(grade); if (standardizedGrade != null) { gradeIsValid = true; } } else { throw new IllegalArgumentException("Invalid gradeEntryType passed to isGradeValid"); } } return gradeIsValid; } public List<String> identifyStudentsWithInvalidGrades(String gradebookUid, Map<String, String> studentIdToGradeMap) { if (gradebookUid == null) { throw new IllegalArgumentException("null gradebookUid passed to identifyStudentsWithInvalidGrades"); } List<String> studentsWithInvalidGrade = new ArrayList<String>(); if (studentIdToGradeMap != null) { Gradebook gradebook; try { gradebook = getGradebook(gradebookUid); } catch (GradebookNotFoundException gnfe) { throw new GradebookNotFoundException("No gradebook exists with the given gradebookUid: " + gradebookUid + "Error: " + gnfe.getMessage()); } LetterGradePercentMapping gradeMapping = null; if (gradebook.getGrade_type() == GradebookService.GRADE_TYPE_LETTER) { gradeMapping = getLetterGradePercentMapping(gradebook); } for (String studentId : studentIdToGradeMap.keySet()) { String grade = studentIdToGradeMap.get(studentId); if (!isGradeValid(grade, gradebook.getGrade_type(), gradeMapping)) { studentsWithInvalidGrade.add(studentId); } } } return studentsWithInvalidGrade; } public void saveGradeAndCommentForStudent(String gradebookUid, Long gradableObjectId, String studentUid, String grade, String comment) { if (gradebookUid == null || gradableObjectId == null || studentUid == null) { throw new IllegalArgumentException("Null gradebookUid or gradableObjectId or studentUid passed to saveGradeAndCommentForStudent"); } GradeDefinition gradeDef = new GradeDefinition(); gradeDef.setStudentUid(studentUid); gradeDef.setGrade(grade); gradeDef.setGradeComment(comment); List<GradeDefinition> gradeDefList = new ArrayList<GradeDefinition>(); gradeDefList.add(gradeDef); saveGradesAndComments(gradebookUid, gradableObjectId, gradeDefList); } public void saveGradesAndComments(final String gradebookUid, final Long gradableObjectId, List<GradeDefinition> gradeDefList) { if (gradebookUid == null || gradableObjectId == null) { throw new IllegalArgumentException("Null gradebookUid or gradableObjectId passed to saveGradesAndComments"); } if (gradeDefList != null) { Gradebook gradebook; try { gradebook = getGradebook(gradebookUid); } catch (GradebookNotFoundException gnfe) { throw new GradebookNotFoundException("No gradebook exists with the given gradebookUid: " + gradebookUid + "Error: " + gnfe.getMessage()); } Assignment assignment = (Assignment)getHibernateTemplate().execute(new HibernateCallback() { public Object doInHibernate(Session session) throws HibernateException { return getAssignmentWithoutStats(gradebookUid, gradableObjectId, session); } }); if (assignment == null) { throw new AssessmentNotFoundException("No gradebook item exists with gradable object id = " + gradableObjectId); } if (!currentUserHasGradingPerm(gradebookUid)) { log.warn("User attempted to save grades and comments without authorization"); throw new SecurityException("Current user is not authorized to save grades or comments in gradebook " + gradebookUid); } // let's identify all of the students being updated first Map<String, GradeDefinition> studentIdGradeDefMap = new HashMap<String, GradeDefinition>(); Map<String, String> studentIdToGradeMap = new HashMap<String, String>(); for (GradeDefinition gradeDef: gradeDefList) { studentIdGradeDefMap.put(gradeDef.getStudentUid(), gradeDef); studentIdToGradeMap.put(gradeDef.getStudentUid(), gradeDef.getGrade()); } // check for invalid grades List invalidStudents = identifyStudentsWithInvalidGrades(gradebookUid, studentIdToGradeMap); if (invalidStudents != null && !invalidStudents.isEmpty()) { throw new InvalidGradeException ("At least one grade passed to be updated is " + "invalid. No grades or comments were updated."); } boolean userHasGradeAllPerm = currentUserHasGradeAllPerm(gradebookUid); // let's retrieve all of the existing grade recs for the given students // and assignments List<AssignmentGradeRecord> allGradeRecs = getAllAssignmentGradeRecordsForGbItem(gradableObjectId, studentIdGradeDefMap.keySet()); // put in map for easier accessibility Map<String, AssignmentGradeRecord> studentIdToAgrMap = new HashMap<String, AssignmentGradeRecord>(); if (allGradeRecs != null) { for (AssignmentGradeRecord rec : allGradeRecs) { studentIdToAgrMap.put(rec.getStudentId(), rec); } } // set up the grader and grade time String graderId = getAuthn().getUserUid(); Date now = new Date(); // get grade mapping, if nec, to convert grades to points LetterGradePercentMapping mapping = null; if (gradebook.getGrade_type() == GradebookService.GRADE_TYPE_LETTER) { mapping = getLetterGradePercentMapping(gradebook); } // get all of the comments, as well List<Comment> allComments = getComments(assignment, studentIdGradeDefMap.keySet()); // put in a map for easier accessibility Map<String, Comment> studentIdCommentMap = new HashMap<String, Comment>(); if (allComments != null) { for (Comment comment : allComments) { studentIdCommentMap.put(comment.getStudentId(), comment); } } // these are the records that will need to be updated. iterate through // everything and then we'll save it all at once Set<AssignmentGradeRecord> agrToUpdate = new HashSet<AssignmentGradeRecord>(); // do not use a HashSet b/c you may have multiple Comments with null id and the same comment at this point. // the Comment object defines objects as equal if they have the same id, comment text, and gb item. the // only difference may be the student ids List<Comment> commentsToUpdate = new ArrayList<Comment>(); Set<GradingEvent> eventsToAdd = new HashSet<GradingEvent>(); for (GradeDefinition gradeDef : gradeDefList) { String studentId = gradeDef.getStudentUid(); // check specific grading privileges if user does not have // grade all perm if (!userHasGradeAllPerm) { if (!isUserAbleToGradeItemForStudent(gradebookUid, gradableObjectId, studentId)) { log.warn("User " + graderId + " attempted to save a grade for " + studentId + " without authorization"); throw new SecurityException("User " + graderId + " attempted to save a grade for " + studentId + " without authorization"); } } Double convertedGrade = convertInputGradeToPoints(gradebook.getGrade_type(), mapping, assignment.getPointsPossible(), gradeDef.getGrade()); // let's see if this agr needs to be updated AssignmentGradeRecord gradeRec = studentIdToAgrMap.get(studentId); if (gradeRec != null) { if ((convertedGrade == null && gradeRec.getPointsEarned() != null) || (convertedGrade != null && gradeRec.getPointsEarned() == null) || (convertedGrade != null && gradeRec.getPointsEarned() != null && !convertedGrade.equals(gradeRec.getPointsEarned()))) { gradeRec.setPointsEarned(convertedGrade); gradeRec.setGraderId(graderId); gradeRec.setDateRecorded(now); agrToUpdate.add(gradeRec); // we also need to add a GradingEvent // the event stores the actual input grade, not the converted one GradingEvent event = new GradingEvent(assignment, graderId, studentId, gradeDef.getGrade()); eventsToAdd.add(event); } } else { // if the grade is something other than null, add a new AGR if (gradeDef.getGrade() != null && !gradeDef.getGrade().trim().equals("")) { gradeRec = new AssignmentGradeRecord(assignment, studentId, convertedGrade); gradeRec.setPointsEarned(convertedGrade); gradeRec.setGraderId(graderId); gradeRec.setDateRecorded(now); agrToUpdate.add(gradeRec); // we also need to add a GradingEvent // the event stores the actual input grade, not the converted one GradingEvent event = new GradingEvent(assignment, graderId, studentId, gradeDef.getGrade()); eventsToAdd.add(event); } } // let's see if the comment needs to be updated Comment comment = studentIdCommentMap.get(studentId); if (comment != null) { boolean oldCommentIsNull = comment.getCommentText() == null || comment.getCommentText().equals(""); boolean newCommentIsNull = gradeDef.getGradeComment() == null || gradeDef.getGradeComment().equals(""); if ((oldCommentIsNull && !newCommentIsNull) || (!oldCommentIsNull && newCommentIsNull) || (!oldCommentIsNull && !newCommentIsNull && !gradeDef.getGradeComment().equals(comment.getCommentText()))) { // update this comment comment.setCommentText(gradeDef.getGradeComment()); comment.setGraderId(graderId); comment.setDateRecorded(now); commentsToUpdate.add(comment); } } else { // if there is a comment, add it if (gradeDef.getGradeComment() != null && !gradeDef.getGradeComment().trim().equals("")) { comment = new Comment(studentId, gradeDef.getGradeComment(), assignment); comment.setGraderId(graderId); comment.setDateRecorded(now); commentsToUpdate.add(comment); } } } // now let's save them try { getHibernateTemplate().saveOrUpdateAll(agrToUpdate); getHibernateTemplate().saveOrUpdateAll(commentsToUpdate); getHibernateTemplate().saveOrUpdateAll(eventsToAdd); } catch (HibernateOptimisticLockingFailureException holfe) { if(log.isInfoEnabled()) log.info("An optimistic locking failure occurred while attempting to save scores and comments for gb Item " + gradableObjectId); throw new StaleObjectModificationException(holfe); } catch (StaleObjectStateException sose) { if(log.isInfoEnabled()) log.info("An optimistic locking failure occurred while attempting to save scores and comments for gb Item " + gradableObjectId); throw new StaleObjectModificationException(sose); } } } /** * * @param gradeEntryType * @param mapping * @param gbItemPointsPossible * @param grade * @return given a generic String grade, converts it to the equivalent Double * point value that will be stored in the db based upon the gradebook's grade entry type */ private Double convertInputGradeToPoints(int gradeEntryType, LetterGradePercentMapping mapping, Double gbItemPointsPossible, String grade) throws InvalidGradeException { Double convertedValue = null; if (grade != null && !"".equals(grade)) { if (gradeEntryType == GradebookService.GRADE_TYPE_POINTS) { try { Double pointValue = Double.parseDouble(grade); convertedValue = pointValue; } catch (NumberFormatException nfe) { throw new InvalidGradeException("Invalid grade passed to convertInputGradeToPoints"); } } else if (gradeEntryType == GradebookService.GRADE_TYPE_PERCENTAGE || gradeEntryType == GradebookService.GRADE_TYPE_LETTER) { // for letter or %-based grading, we need to calculate the equivalent point value if (gbItemPointsPossible == null) { throw new IllegalArgumentException("Null points possible passed" + " to convertInputGradeToPoints for letter or % based grading"); } Double percentage = null; if (gradeEntryType == GradebookService.GRADE_TYPE_LETTER) { if (mapping == null) { throw new IllegalArgumentException("No mapping passed to convertInputGradeToPoints for a letter-based gb"); } if(mapping.getGradeMap() != null) { // standardize the grade mapping String standardizedGrade = mapping.standardizeInputGrade(grade); percentage = mapping.getValue(standardizedGrade); if(percentage == null) { throw new IllegalArgumentException("Invalid grade passed to convertInputGradeToPoints"); } } } else { try { percentage = Double.parseDouble(grade); } catch (NumberFormatException nfe) { throw new IllegalArgumentException("Invalid % grade passed to convertInputGradeToPoints"); } } convertedValue = calculateEquivalentPointValueForPercent(gbItemPointsPossible, percentage); } else { throw new InvalidGradeException("invalid grade entry type passed to convertInputGradeToPoints"); } } return convertedValue; } private List getTotalPointsEarnedInternalFixing(final Long gradebookId, final String studentId, final Session session, final Gradebook gradebook, final List categories, List<AssignmentGradeRecord> studentGradeRecs) { double totalPointsEarned = 0; double literalTotalPointsEarned = 0; Iterator scoresIter = session.createQuery( "select agr.pointsEarned, asn from AssignmentGradeRecord agr, Assignment asn where agr.gradableObject=asn and agr.studentId=:student and asn.gradebook.id=:gbid and asn.removed=false and asn.pointsPossible > 0"). setParameter("student", studentId). setParameter("gbid", gradebookId). list().iterator(); List assgnsList = session.createQuery( "from Assignment as asn where asn.gradebook.id=:gbid and asn.removed=false and asn.notCounted=false and asn.ungraded=false and asn.pointsPossible > 0"). setParameter("gbid", gradebookId). list(); Map cateScoreMap = new HashMap(); Map cateTotalScoreMap = new HashMap(); Set assignmentsTaken = new HashSet(); while (scoresIter.hasNext()) { Object[] returned = (Object[])scoresIter.next(); Double pointsEarned = (Double)returned[0]; Assignment go = (Assignment) returned[1]; if (go != null && go.isCounted() && pointsEarned != null) { boolean skip = false; for(AssignmentGradeRecord gr : studentGradeRecs){ if(gr.getAssignment().getId().equals(go.getId())){ if(gr.getDroppedFromGrade()){ skip = true; } break; } } if(skip){ continue; } Double fixingPointsEarned = fixingPointsEarned(pointsEarned, go, gradebook); if(gradebook.getCategory_type() == GradebookService.CATEGORY_TYPE_NO_CATEGORY) { totalPointsEarned += fixingPointsEarned.doubleValue(); literalTotalPointsEarned += fixingPointsEarned.doubleValue(); assignmentsTaken.add(go.getId()); } else if(gradebook.getCategory_type() == GradebookService.CATEGORY_TYPE_ONLY_CATEGORY && go != null) { totalPointsEarned += fixingPointsEarned.doubleValue(); literalTotalPointsEarned += fixingPointsEarned.doubleValue(); assignmentsTaken.add(go.getId()); } else if(gradebook.getCategory_type() == GradebookService.CATEGORY_TYPE_WEIGHTED_CATEGORY && go != null && categories != null) { for(int i=0; i<categories.size(); i++) { Category cate = (Category) categories.get(i); if(cate != null && !cate.isRemoved() && go.getCategory() != null && cate.getId().equals(go.getCategory().getId())) { assignmentsTaken.add(go.getId()); literalTotalPointsEarned += fixingPointsEarned.doubleValue(); if(cateScoreMap.get(cate.getId()) != null) { cateScoreMap.put(cate.getId(), Double.valueOf(((Double)cateScoreMap.get(cate.getId())).doubleValue() + fixingPointsEarned.doubleValue())); } else { cateScoreMap.put(cate.getId(), Double.valueOf(fixingPointsEarned)); } break; } } } } } if(gradebook.getCategory_type() == GradebookService.CATEGORY_TYPE_WEIGHTED_CATEGORY && categories != null) { Iterator assgnsIter = assgnsList.iterator(); while (assgnsIter.hasNext()) { Assignment asgn = (Assignment)assgnsIter.next(); if(assignmentsTaken.contains(asgn.getId())) { for(int i=0; i<categories.size(); i++) { Category cate = (Category) categories.get(i); if(cate != null && !cate.isRemoved() && asgn.getCategory() != null && cate.getId().equals(asgn.getCategory().getId())) { if(cateTotalScoreMap.get(cate.getId()) == null) { cateTotalScoreMap.put(cate.getId(), asgn.getPointsPossible()); } else { cateTotalScoreMap.put(cate.getId(), Double.valueOf(((Double)cateTotalScoreMap.get(cate.getId())).doubleValue() + asgn.getPointsPossible().doubleValue())); } } } } } } if(assignmentsTaken.isEmpty()) totalPointsEarned = -1; if(gradebook.getCategory_type() == GradebookService.CATEGORY_TYPE_WEIGHTED_CATEGORY) { for(int i=0; i<categories.size(); i++) { Category cate = (Category) categories.get(i); if(cate != null && !cate.isRemoved() && cateScoreMap.get(cate.getId()) != null && cateTotalScoreMap.get(cate.getId()) != null) { totalPointsEarned += ((Double)cateScoreMap.get(cate.getId())).doubleValue() * cate.getWeight().doubleValue() / ((Double)cateTotalScoreMap.get(cate.getId())).doubleValue(); } } } if (log.isDebugEnabled()) log.debug("getTotalPointsEarnedInternal for studentId=" + studentId + " returning " + totalPointsEarned); List returnList = new ArrayList(); returnList.add(Double.valueOf(totalPointsEarned)); returnList.add(Double.valueOf(literalTotalPointsEarned)); return returnList; } private Double fixingPointsEarned(Double pointsEarned, Assignment assignment, Gradebook gradebook) { Double pointPossible = assignment.getPointsPossible(); String letterGrade; if(pointPossible != null && pointPossible.doubleValue() > 0) { LetterGradePercentMapping lgpm = getLetterGradePercentMapping(assignment.getGradebook()); letterGrade = lgpm.getGrade(calculateEquivalentPercent(pointPossible, pointsEarned)); GradeMapping gradeMap = gradebook.getSelectedGradeMapping(); if(gradeMap != null) { Double rightPercent = gradeMap.getValue(letterGrade); //there could be no value in the grademap -SAK-22709 if (rightPercent == null) { log.warn("no value found in grademap for: " + letterGrade); return null; } BigDecimal rightPercentBD = new BigDecimal(rightPercent); BigDecimal pointPossibleBD = new BigDecimal(pointPossible); return Double.valueOf(rightPercentBD.multiply(pointPossibleBD).divide(new BigDecimal(Double.valueOf("100.0"))).doubleValue()); } } return null; } public Map getFixedGrade(String gradebookUid) { HashMap returnMap = new HashMap(); try { Gradebook thisGradebook = getGradebook(gradebookUid); List assignList = getAssignmentsCounted(thisGradebook.getId()); boolean nonAssignment = false; if(assignList == null || assignList.size() < 1) { nonAssignment = true; } Long gradebookId = thisGradebook.getId(); CourseGrade courseGrade = getCourseGrade(gradebookId); Map enrollmentMap; Map viewableEnrollmentsMap = authz.findMatchingEnrollmentsForViewableCourseGrade(gradebookUid, thisGradebook.getCategory_type(), null, null); enrollmentMap = new HashMap(); Map enrollmentMapUid = new HashMap(); for (Iterator iter = viewableEnrollmentsMap.keySet().iterator(); iter.hasNext(); ) { EnrollmentRecord enr = (EnrollmentRecord)iter.next(); enrollmentMap.put(enr.getUser().getUserUid(), enr); enrollmentMapUid.put(enr.getUser().getUserUid(), enr); } List gradeRecords = getPointsEarnedCourseGradeRecordsFixing(courseGrade, enrollmentMap.keySet()); for (Iterator iter = gradeRecords.iterator(); iter.hasNext(); ) { CourseGradeRecord gradeRecord = (CourseGradeRecord)iter.next(); GradeMapping gradeMap= thisGradebook.getSelectedGradeMapping(); EnrollmentRecord enr = (EnrollmentRecord)enrollmentMapUid.get(gradeRecord.getStudentId()); if(enr != null) { if(!nonAssignment) returnMap.put(enr.getUser().getDisplayId(), (String)gradeMap.getGrade(gradeRecord.getNonNullAutoCalculatedGrade())); } } } catch(Exception e) { e.printStackTrace(); } return returnMap; } public List getPointsEarnedCourseGradeRecordsFixing(final CourseGrade courseGrade, final Collection studentUids) { HibernateCallback hc = new HibernateCallback() { public Object doInHibernate(Session session) throws HibernateException { if(studentUids == null || studentUids.size() == 0) { if(log.isInfoEnabled()) log.info("Returning no grade records for an empty collection of student UIDs"); return new ArrayList(); } Query q = session.createQuery("from CourseGradeRecord as cgr where cgr.gradableObject.id=:gradableObjectId"); q.setLong("gradableObjectId", courseGrade.getId().longValue()); List records = filterAndPopulateCourseGradeRecordsByStudents(courseGrade, q.list(), studentUids); Long gradebookId = courseGrade.getGradebook().getId(); Gradebook gradebook = getGradebook(gradebookId); List cates = getCategories(gradebookId); //double totalPointsPossible = getTotalPointsInternal(gradebookId, session); //if(log.isDebugEnabled()) log.debug("Total points = " + totalPointsPossible); // get all of the AssignmentGradeRecords here to avoid repeated db calls Map<String, List<AssignmentGradeRecord>> gradeRecMap = getGradeRecordMapForStudents(session, gradebookId, studentUids); // get all of the counted assignments List<Assignment> countedAssigns = getCountedAssignments(session, gradebookId); for(Iterator iter = records.iterator(); iter.hasNext();) { CourseGradeRecord cgr = (CourseGradeRecord)iter.next(); List<AssignmentGradeRecord> studentGradeRecs = gradeRecMap.get(cgr.getStudentId()); applyDropScores(studentGradeRecs); //double totalPointsEarned = getTotalPointsEarnedInternal(gradebookId, cgr.getStudentId(), session); List totalEarned = getTotalPointsEarnedInternalFixing(gradebookId, cgr.getStudentId(), session, gradebook, cates, studentGradeRecs); double totalPointsEarned = ((Double)totalEarned.get(0)).doubleValue(); double literalTotalPointsEarned = ((Double)totalEarned.get(1)).doubleValue(); double totalPointsPossible = getTotalPointsInternal(gradebookId, session, gradebook, cates, cgr.getStudentId(), studentGradeRecs, countedAssigns); cgr.initNonpersistentFields(totalPointsPossible, totalPointsEarned, literalTotalPointsEarned); if(log.isDebugEnabled()) log.debug("Points earned = " + cgr.getPointsEarned()); } return records; } }; return (List)getHibernateTemplate().execute(hc); } public Map getFixedPoint(String gradebookUid) { HashMap returnMap = new HashMap(); try { Gradebook thisGradebook = getGradebook(gradebookUid); List assignList = getAssignmentsCounted(thisGradebook.getId()); boolean nonAssignment = false; if(assignList == null || assignList.size() < 1) { nonAssignment = true; } Long gradebookId = thisGradebook.getId(); CourseGrade courseGrade = getCourseGrade(gradebookId); Map enrollmentMap; Map viewableEnrollmentsMap = authz.findMatchingEnrollmentsForViewableCourseGrade(gradebookUid, thisGradebook.getCategory_type(), null, null); enrollmentMap = new HashMap(); Map enrollmentMapUid = new HashMap(); for (Iterator iter = viewableEnrollmentsMap.keySet().iterator(); iter.hasNext(); ) { EnrollmentRecord enr = (EnrollmentRecord)iter.next(); enrollmentMap.put(enr.getUser().getUserUid(), enr); enrollmentMapUid.put(enr.getUser().getUserUid(), enr); } List gradeRecords = getPointsEarnedCourseGradeRecordsFixing(courseGrade, enrollmentMap.keySet()); for (Iterator iter = gradeRecords.iterator(); iter.hasNext(); ) { CourseGradeRecord gradeRecord = (CourseGradeRecord)iter.next(); EnrollmentRecord enr = (EnrollmentRecord)enrollmentMapUid.get(gradeRecord.getStudentId()); if(enr != null) { if(!nonAssignment) returnMap.put(enr.getUser().getDisplayId(), gradeRecord.getNonNullAutoCalculatedGrade().toString()); } } } catch(Exception e) { e.printStackTrace(); } return returnMap; } public Map getOldPoint(String gradebookUid) { HashMap returnMap = new HashMap(); try { Gradebook thisGradebook = getGradebook(gradebookUid); List assignList = getAssignmentsCounted(thisGradebook.getId()); boolean nonAssignment = false; if(assignList == null || assignList.size() < 1) { nonAssignment = true; } Long gradebookId = thisGradebook.getId(); CourseGrade courseGrade = getCourseGrade(gradebookId); Map enrollmentMap; Map viewableEnrollmentsMap = authz.findMatchingEnrollmentsForViewableCourseGrade(gradebookUid, thisGradebook.getCategory_type(), null, null); enrollmentMap = new HashMap(); Map enrollmentMapUid = new HashMap(); for (Iterator iter = viewableEnrollmentsMap.keySet().iterator(); iter.hasNext(); ) { EnrollmentRecord enr = (EnrollmentRecord)iter.next(); enrollmentMap.put(enr.getUser().getUserUid(), enr); enrollmentMapUid.put(enr.getUser().getUserUid(), enr); } List gradeRecords = getPointsEarnedCourseGradeRecords(courseGrade, enrollmentMap.keySet()); for (Iterator iter = gradeRecords.iterator(); iter.hasNext(); ) { CourseGradeRecord gradeRecord = (CourseGradeRecord)iter.next(); GradeMapping gradeMap= thisGradebook.getSelectedGradeMapping(); EnrollmentRecord enr = (EnrollmentRecord)enrollmentMapUid.get(gradeRecord.getStudentId()); if(enr != null) { if(!nonAssignment) returnMap.put(enr.getUser().getDisplayId(), gradeRecord.getNonNullAutoCalculatedGrade().toString()); } } } catch(Exception e) { e.printStackTrace(); } return returnMap; } public int getGradeEntryType(String gradebookUid) { if (gradebookUid == null) { throw new IllegalArgumentException("null gradebookUid passed to getGradeEntryType"); } try { Gradebook gradebook = getGradebook(gradebookUid); return gradebook.getGrade_type(); } catch (GradebookNotFoundException gnfe) { throw new GradebookNotFoundException("No gradebook exists with the given gradebookUid: " + gradebookUid); } } public Map getEnteredCourseGrade(final String gradebookUid) { HibernateCallback hc = new HibernateCallback() { public Object doInHibernate(Session session) throws HibernateException { Gradebook thisGradebook = getGradebook(gradebookUid); Long gradebookId = thisGradebook.getId(); CourseGrade courseGrade = getCourseGrade(gradebookId); Map enrollmentMap; Map viewableEnrollmentsMap = authz.findMatchingEnrollmentsForViewableCourseGrade(gradebookUid, thisGradebook.getCategory_type(), null, null); enrollmentMap = new HashMap(); Map enrollmentMapUid = new HashMap(); for (Iterator iter = viewableEnrollmentsMap.keySet().iterator(); iter.hasNext(); ) { EnrollmentRecord enr = (EnrollmentRecord)iter.next(); enrollmentMap.put(enr.getUser().getUserUid(), enr); enrollmentMapUid.put(enr.getUser().getUserUid(), enr); } Query q = session.createQuery("from CourseGradeRecord as cgr where cgr.gradableObject.id=:gradableObjectId"); q.setLong("gradableObjectId", courseGrade.getId().longValue()); List records = filterAndPopulateCourseGradeRecordsByStudents(courseGrade, q.list(), enrollmentMap.keySet()); Map returnMap = new HashMap(); for(int i=0; i<records.size(); i++) { CourseGradeRecord cgr = (CourseGradeRecord) records.get(i); if(cgr.getEnteredGrade() != null && !cgr.getEnteredGrade().equalsIgnoreCase("")) { EnrollmentRecord enr = (EnrollmentRecord)enrollmentMapUid.get(cgr.getStudentId()); if(enr != null) { returnMap.put(enr.getUser().getDisplayId(), cgr.getEnteredGrade()); } } } return returnMap; } }; return (Map)getHibernateTemplate().execute(hc); } public Map getCalculatedCourseGrade(String gradebookUid) { return getCalculatedCourseGrade (gradebookUid, true); } public Map getCalculatedCourseGrade(String gradebookUid, boolean mapTheGrades) { HashMap returnMap = new HashMap(); try { Gradebook thisGradebook = getGradebook(gradebookUid); List assignList = getAssignmentsCounted(thisGradebook.getId()); boolean nonAssignment = false; if(assignList == null || assignList.size() < 1) { nonAssignment = true; } Long gradebookId = thisGradebook.getId(); CourseGrade courseGrade = getCourseGrade(gradebookId); Map enrollmentMap; Map viewableEnrollmentsMap = authz.findMatchingEnrollmentsForViewableCourseGrade(gradebookUid, thisGradebook.getCategory_type(), null, null); enrollmentMap = new HashMap(); Map enrollmentMapUid = new HashMap(); for (Iterator iter = viewableEnrollmentsMap.keySet().iterator(); iter.hasNext(); ) { EnrollmentRecord enr = (EnrollmentRecord)iter.next(); enrollmentMap.put(enr.getUser().getUserUid(), enr); enrollmentMapUid.put(enr.getUser().getUserUid(), enr); } List gradeRecords = getPointsEarnedCourseGradeRecords(courseGrade, enrollmentMap.keySet()); for (Iterator iter = gradeRecords.iterator(); iter.hasNext(); ) { CourseGradeRecord gradeRecord = (CourseGradeRecord)iter.next(); GradeMapping gradeMap= thisGradebook.getSelectedGradeMapping(); EnrollmentRecord enr = (EnrollmentRecord)enrollmentMapUid.get(gradeRecord.getStudentId()); if(enr != null) { if(!nonAssignment) { if (mapTheGrades) { returnMap.put(enr.getUser().getDisplayId(), (String)gradeMap.getGrade(gradeRecord.getNonNullAutoCalculatedGrade())); } else { returnMap.put(enr.getUser().getDisplayId(), gradeRecord.getNonNullAutoCalculatedGrade().toString()); } } } } } catch(Exception e) { e.printStackTrace(); } return returnMap; } public String getAssignmentScoreString(final String gradebookUid, final String assignmentName, final String studentUid) throws GradebookNotFoundException, AssessmentNotFoundException { final boolean studentRequestingOwnScore = authn.getUserUid().equals(studentUid); Double assignmentScore = (Double)getHibernateTemplate().execute(new HibernateCallback() { public Object doInHibernate(Session session) throws HibernateException { Assignment assignment = getAssignmentWithoutStats(gradebookUid, assignmentName, session); if (assignment == null) { throw new AssessmentNotFoundException("There is no assignment named " + assignmentName + " in gradebook " + gradebookUid); } if (!studentRequestingOwnScore && !isUserAbleToViewItemForStudent(gradebookUid, assignment.getId(), studentUid)) { log.error("AUTHORIZATION FAILURE: User " + getUserUid() + " in gradebook " + gradebookUid + " attempted to retrieve grade for student " + studentUid + " for assignment " + assignmentName); throw new SecurityException("You do not have permission to perform this operation"); } // If this is the student, then the assignment needs to have // been released. if (studentRequestingOwnScore && !assignment.isReleased()) { log.error("AUTHORIZATION FAILURE: Student " + getUserUid() + " in gradebook " + gradebookUid + " attempted to retrieve score for unreleased assignment " + assignment.getName()); throw new SecurityException("You do not have permission to perform this operation"); } AssignmentGradeRecord gradeRecord = getAssignmentGradeRecord(assignment, studentUid, session); if (log.isDebugEnabled()) log.debug("gradeRecord=" + gradeRecord); if (gradeRecord == null) { return null; } else { return gradeRecord.getPointsEarned(); } } }); if (log.isDebugEnabled()) log.debug("returning " + assignmentScore); //TODO: when ungraded items is considered, change column to ungraded-grade //its possible that the assignment score is null if (assignmentScore == null) return null; return Double.valueOf(assignmentScore).toString(); } public String getAssignmentScoreString(final String gradebookUid, final Long gbItemId, String studentUid) throws GradebookNotFoundException, AssessmentNotFoundException { if (gradebookUid == null || gbItemId == null || studentUid == null) { throw new IllegalArgumentException("null parameter passed to getAssignmentScore"); } Assignment assignment = (Assignment)getHibernateTemplate().execute(new HibernateCallback() { public Object doInHibernate(Session session) throws HibernateException { return getAssignmentWithoutStats(gradebookUid, gbItemId, session); } }); if (assignment == null) { throw new AssessmentNotFoundException("There is no assignment with the gbItemId " + gbItemId); } return getAssignmentScoreString(gradebookUid, assignment.getName(), studentUid); } public void setAssignmentScoreString(final String gradebookUid, final String assignmentName, final String studentUid, final String score, final String clientServiceDescription) throws GradebookNotFoundException, AssessmentNotFoundException { getHibernateTemplate().execute(new HibernateCallback() { public Object doInHibernate(Session session) throws HibernateException { Assignment assignment = getAssignmentWithoutStats(gradebookUid, assignmentName, session); if (assignment == null) { throw new AssessmentNotFoundException("There is no assignment named " + assignmentName + " in gradebook " + gradebookUid); } if (assignment.isExternallyMaintained()) { log.error("AUTHORIZATION FAILURE: User " + getUserUid() + " in gradebook " + gradebookUid + " attempted to grade externally maintained assignment " + assignmentName + " from " + clientServiceDescription); throw new SecurityException("You do not have permission to perform this operation"); } if (!isUserAbleToGradeItemForStudent(gradebookUid, assignment.getId(), studentUid)) { log.error("AUTHORIZATION FAILURE: User " + getUserUid() + " in gradebook " + gradebookUid + " attempted to grade student " + studentUid + " from " + clientServiceDescription + " for item " + assignmentName); throw new SecurityException("You do not have permission to perform this operation"); } Date now = new Date(); String graderId = getAuthn().getUserUid(); AssignmentGradeRecord gradeRecord = getAssignmentGradeRecord(assignment, studentUid, session); if (gradeRecord == null) { // Creating a new grade record. gradeRecord = new AssignmentGradeRecord(assignment, studentUid, convertStringToDouble(score)); //TODO: test if it's ungraded item or not. if yes, set ungraded grade for this record. if not, need validation?? } else { //TODO: test if it's ungraded item or not. if yes, set ungraded grade for this record. if not, need validation?? gradeRecord.setPointsEarned(convertStringToDouble(score)); } gradeRecord.setGraderId(graderId); gradeRecord.setDateRecorded(now); session.saveOrUpdate(gradeRecord); session.save(new GradingEvent(assignment, graderId, studentUid, score)); // Sync database. session.flush(); session.clear(); return null; } }); if (log.isInfoEnabled()) log.info("Score updated in gradebookUid=" + gradebookUid + ", assignmentName=" + assignmentName + " by userUid=" + getUserUid() + " from client=" + clientServiceDescription + ", new score=" + score); } public void finalizeGrades(String gradebookUid) throws GradebookNotFoundException { if (!getAuthz().isUserAbleToGradeAll(gradebookUid)) { log.error("AUTHORIZATION FAILURE: User " + getUserUid() + " in gradebook " + gradebookUid + " attempted to finalize grades"); throw new SecurityException("You do not have permission to perform this operation"); } finalizeNullGradeRecords(getGradebook(gradebookUid)); } public String getLowestPossibleGradeForGbItem(final String gradebookUid, final Long gradebookItemId) { if (gradebookUid == null || gradebookItemId == null) { throw new IllegalArgumentException("Null gradebookUid and/or gradebookItemId " + "passed to getLowestPossibleGradeForGbItem. gradebookUid:" + gradebookUid + " gradebookItemId:" + gradebookItemId); } Assignment gbItem = (Assignment)getHibernateTemplate().execute(new HibernateCallback() { public Object doInHibernate(Session session) throws HibernateException { return getAssignmentWithoutStats(gradebookUid, gradebookItemId, session); } }); if (gbItem == null) { throw new AssessmentNotFoundException("No gradebook item found with id " + gradebookItemId); } Gradebook gradebook = gbItem.getGradebook(); // double check that user has some permission to access gb items in this site if (!isUserAbleToViewAssignments(gradebookUid) && !currentUserHasViewOwnGradesPerm(gradebookUid)) { throw new SecurityException("User attempted to access gradebookItem: " + gradebookItemId + " in gradebook:" + gradebookUid + " without permission!"); } String lowestPossibleGrade = null; if (gbItem.getUngraded()) { lowestPossibleGrade = null; } else if (gradebook.getGrade_type() == GradebookService.GRADE_TYPE_PERCENTAGE || gradebook.getGrade_type() == GradebookService.GRADE_TYPE_POINTS) { lowestPossibleGrade = "0"; } else if (gbItem.getGradebook().getGrade_type() == GradebookService.GRADE_TYPE_LETTER) { LetterGradePercentMapping mapping = getLetterGradePercentMapping(gradebook); lowestPossibleGrade = mapping.getGrade(0d); } return lowestPossibleGrade; } public List<CategoryDefinition> getCategoryDefinitions(String gradebookUid) { if (gradebookUid == null) { throw new IllegalArgumentException("Null gradebookUid passed to getCategoryDefinitions"); } if (!isUserAbleToViewAssignments(gradebookUid)) { log.warn("AUTHORIZATION FAILURE: User " + getUserUid() + " in gradebook " + gradebookUid + " attempted to retrieve all categories without permission"); throw new SecurityException("You do not have permission to perform this operation"); } List<CategoryDefinition> categoryDefList = new ArrayList<CategoryDefinition>(); List<Category> gbCategories = getCategories(getGradebook(gradebookUid).getId()); if (gbCategories != null) { for (Category category : gbCategories) { categoryDefList.add(getCategoryDefinition(category)); } } return categoryDefList; } private CategoryDefinition getCategoryDefinition(Category category) { CategoryDefinition categoryDef = new CategoryDefinition(); if (category != null) { categoryDef.setId(category.getId()); categoryDef.setName(category.getName()); categoryDef.setWeight(category.getWeight()); categoryDef.setAssignmentList(getAssignments(category.getGradebook().getUid(), category.getName())); } return categoryDef; } public boolean checkStuendsNotSubmitted(String gradebookUid) { return checkStudentsNotSubmitted(gradebookUid); } /** * * @param session * @param gradebookId * @param studentUids * @return a map of studentUid to a list of that student's AssignmentGradeRecords for the given studentUids list * in the given gradebook. the grade records are all recs for assignments that are not removed and * have a points possible > 0 */ protected Map<String,List<AssignmentGradeRecord>> getGradeRecordMapForStudents(Session session, Long gradebookId, Collection<String> studentUids) { Map<String,List<AssignmentGradeRecord>> filteredGradeRecs = new HashMap<String,List<AssignmentGradeRecord>>(); if (studentUids != null) { List<AssignmentGradeRecord> allGradeRecs = new ArrayList<AssignmentGradeRecord>(); if (studentUids.size() >= MAX_NUMBER_OF_SQL_PARAMETERS_IN_LIST) { allGradeRecs = session.createQuery( "from AssignmentGradeRecord agr where agr.gradableObject.gradebook.id=:gbid " + "and agr.gradableObject.removed=false"). setParameter("gbid", gradebookId). list(); } else { String query = "from AssignmentGradeRecord agr where agr.gradableObject.gradebook.id=:gbid and " + "agr.gradableObject.removed=false and " + "agr.studentId in (:studentUids)"; allGradeRecs = session.createQuery( query). setParameter("gbid", gradebookId). setParameterList("studentUids", studentUids). list(); } if (allGradeRecs != null) { for (AssignmentGradeRecord gradeRec : allGradeRecs) { if (studentUids.contains(gradeRec.getStudentId())) { String studentId = gradeRec.getStudentId(); List<AssignmentGradeRecord> gradeRecList = filteredGradeRecs.get(studentId); if (gradeRecList == null) { gradeRecList = new ArrayList<AssignmentGradeRecord>(); gradeRecList.add(gradeRec); filteredGradeRecs.put(studentId, gradeRecList); } else { gradeRecList.add(gradeRec); filteredGradeRecs.put(studentId, gradeRecList); } } } } } return filteredGradeRecs; } /** * * @param session * @param gradebookId * @return a list of Assignments that have not been removed, are "counted", graded, * and have a points possible > 0 */ protected List<Assignment> getCountedAssignments(Session session, Long gradebookId) { List<Assignment> assignList = new ArrayList<Assignment>(); List <Assignment>results = session.createQuery( "from Assignment as asn where asn.gradebook.id=:gbid and asn.removed=false and " + "asn.notCounted=false and asn.ungraded=false"). setParameter("gbid", gradebookId). list(); if (results != null) { // making sure there's no invalid points possible for normal assignments for (Assignment a : results) { if (a.getPointsPossible()!=null && a.getPointsPossible()>0) { assignList.add(a); } } } return assignList; } /** * set the droppedFromGrade attribute of each * of the n highest and the n lowest scores of a * student based on the assignment's category * @param gradeRecords * @return void */ public void applyDropScores(Collection<AssignmentGradeRecord> gradeRecords) { if(gradeRecords == null || gradeRecords.size() < 1) { return; } long start = System.currentTimeMillis(); List<String> studentIds = new ArrayList<String>(); List<Category> categories = new ArrayList<Category>(); Map<String, List<AssignmentGradeRecord>> gradeRecordMap = new HashMap<String, List<AssignmentGradeRecord>>(); for(AssignmentGradeRecord gradeRecord : gradeRecords) { if(gradeRecord == null || gradeRecord.getPointsEarned() == null) { // don't consider grades that have null pointsEarned (this occurs when a previously entered score for an assignment is removed; record stays in database) continue; } // reset gradeRecord.setDroppedFromGrade(false); Assignment assignment = gradeRecord.getAssignment(); if(assignment.getUngraded() // GradebookService.GRADE_TYPE_LETTER || assignment.isNotCounted() // don't consider grades that are not counted toward course grade || assignment.getItemType().equals(Assignment.item_type_adjustment) || assignment.isRemoved()) { continue; } // get all the students represented String studentId = gradeRecord.getStudentId(); if(!studentIds.contains(studentId)) { studentIds.add(studentId); } // get all the categories represented Category cat = gradeRecord.getAssignment().getCategory(); if(cat != null) { if(!categories.contains(cat)) { categories.add(cat); } List<AssignmentGradeRecord> gradeRecordsByCatAndStudent = gradeRecordMap.get(studentId + cat.getId()); if(gradeRecordsByCatAndStudent == null) { gradeRecordsByCatAndStudent = new ArrayList<AssignmentGradeRecord>(); gradeRecordsByCatAndStudent.add(gradeRecord); gradeRecordMap.put(studentId + cat.getId(), gradeRecordsByCatAndStudent); } else { gradeRecordsByCatAndStudent.add(gradeRecord); } } } if(categories == null || categories.size() < 1) { return; } for(Category cat : categories) { Integer dropHighest = cat.getDropHighest(); Integer dropLowest = cat.getDrop_lowest(); Integer keepHighest = cat.getKeepHighest(); Long catId = cat.getId(); if((dropHighest != null && dropHighest > 0) || (dropLowest != null && dropLowest > 0) || (keepHighest != null && keepHighest > 0)) { for(String studentId : studentIds) { // get the student's gradeRecords for this category List<AssignmentGradeRecord> gradesByCategory = new ArrayList<AssignmentGradeRecord>(); List<AssignmentGradeRecord> gradeRecordsByCatAndStudent = gradeRecordMap.get(studentId + cat.getId()); if(gradeRecordsByCatAndStudent != null) { gradesByCategory.addAll(gradeRecordsByCatAndStudent); int numGrades = gradesByCategory.size(); if(dropHighest > 0 && numGrades > dropHighest + dropLowest) { for(int i=0; i<dropHighest; i++) { AssignmentGradeRecord highest = Collections.max(gradesByCategory, AssignmentGradeRecord.numericComparator); highest.setDroppedFromGrade(true); gradesByCategory.remove(highest); if(log.isDebugEnabled()) log.debug("dropHighest applied to " + highest); } } if(keepHighest > 0 && numGrades > (gradesByCategory.size() - keepHighest)) { dropLowest = gradesByCategory.size() - keepHighest; } if(dropLowest > 0 && numGrades > dropLowest + dropHighest) { for(int i=0; i<dropLowest; i++) { AssignmentGradeRecord lowest = Collections.min(gradesByCategory, AssignmentGradeRecord.numericComparator); lowest.setDroppedFromGrade(true); gradesByCategory.remove(lowest); if(log.isDebugEnabled()) log.debug("dropLowest applied to " + lowest); } } } } if(log.isDebugEnabled()) log.debug("processed " + studentIds.size() + "students in category " + cat.getId()); } } if(log.isDebugEnabled()) log.debug("GradebookManager.applyDropScores took " + (System.currentTimeMillis() - start) + " millis to execute"); } public PointsPossibleValidation isPointsPossibleValid(String gradebookUid, org.sakaiproject.service.gradebook.shared.Assignment gradebookItem, Double pointsPossible) { if (gradebookUid == null) { throw new IllegalArgumentException("Null gradebookUid passed to isPointsPossibleValid"); } if (gradebookItem == null) { throw new IllegalArgumentException("Null gradebookItem passed to isPointsPossibleValid"); } // At this time, all gradebook items follow the same business rules for // points possible (aka relative weight in % gradebooks) so special logic // using the properties of the gradebook item is unnecessary. // In the future, we will have the flexibility to change // that behavior without changing the method signature // the points possible must be a non-null value greater than 0 with // no more than 2 decimal places if (pointsPossible == null) { return PointsPossibleValidation.INVALID_NULL_VALUE; } if (pointsPossible.doubleValue() <= 0) { return PointsPossibleValidation.INVALID_NUMERIC_VALUE; } // ensure there are no more than 2 decimal places BigDecimal bd = new BigDecimal(pointsPossible.doubleValue()); bd = bd.setScale(2, BigDecimal.ROUND_HALF_UP); // Two decimal places double roundedVal = bd.doubleValue(); double diff = pointsPossible - roundedVal; if (diff != 0) { return PointsPossibleValidation.INVALID_DECIMAL; } return PointsPossibleValidation.VALID; } /** * * @param doubleAsString * @return a locale-aware Double value representation of the given String * @throws ParseException */ private Double convertStringToDouble(String doubleAsString) { Double scoreAsDouble = null; if (doubleAsString != null) { try { NumberFormat numberFormat = NumberFormat.getInstance(new ResourceLoader().getLocale()); Number numericScore = numberFormat.parse(doubleAsString.trim()); scoreAsDouble = numericScore.doubleValue(); } catch (ParseException e) { log.error(e); } } return scoreAsDouble; } /** * Get a list of assignments in the gradebook attached to the given category. * Note that each assignment only knows the category by name. * * <p>Note also that this is different to {@link BaseHibernateManager#getAssignmentsForCategory(Long)} because this method returns the shared Assignment object. * * @param gradebookUid * @param categoryName * @return */ private List<org.sakaiproject.service.gradebook.shared.Assignment> getAssignments(String gradebookUid, String categoryName) { List<org.sakaiproject.service.gradebook.shared.Assignment> allAssignments = getAssignments(gradebookUid); List<org.sakaiproject.service.gradebook.shared.Assignment> matchingAssignments = new ArrayList<org.sakaiproject.service.gradebook.shared.Assignment>(); for(org.sakaiproject.service.gradebook.shared.Assignment assignment: allAssignments) { if(StringUtils.equals(assignment.getCategoryName(), categoryName)) { matchingAssignments.add(assignment); } } return matchingAssignments; } }