Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ public class Assignment implements Serializable, Comparable<Assignment> {
*/
private Double points;

private String maxLetterGrade;

/**
* the due date for the assignment, or null if none is defined.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,10 @@

import java.io.Serializable;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

import lombok.Getter;
import lombok.Setter;
Expand Down Expand Up @@ -47,7 +49,7 @@ public class CategoryDefinition implements Serializable {
private Boolean equalWeight;
private Integer categoryOrder;
private Boolean dropKeepEnabled;
private List<Assignment> assignmentList;
private List<Assignment> assignmentList = new ArrayList<>();
public static Comparator<CategoryDefinition> orderComparator;

public CategoryDefinition() { }
Expand Down Expand Up @@ -104,19 +106,31 @@ public int compare(final CategoryDefinition c1, final CategoryDefinition c2) {
}

/**
* Helper method to get the total points associated with a category
* Helper method to get the total points associated with a category.
*
* @return the sum of all assignment totals associated with this category
* For POINTS or PERCENTAGE grade types, returns the sum of each
* assignment’s points as stored on the Assignment.
*
* For LETTER grade type, requires a uniform per-assignment maximum:
* total points = assignmentList.size() * maxPoints.
*
* @param gradeType the grading scheme in use
* @param maxPoints ignored for non-LETTER types; must be non-null and > 0 for LETTER
*
* @return total points for this category under the specified gradeType
*/
public Double getTotalPoints() {
BigDecimal totalPoints = new BigDecimal(0);

if (getAssignmentList() != null) {
for (final Assignment assignment : getAssignmentList()) {
totalPoints = totalPoints.add(BigDecimal.valueOf(assignment.getPoints()));
public Double getTotalPoints(GradeType gradeType, Double maxPoints) {

if (gradeType != GradeType.LETTER) {
return getAssignmentList().stream()
.filter(a -> a.getPoints() != null)
.collect(Collectors.summingDouble(Assignment::getPoints));
} else {
if (maxPoints == null || maxPoints <= 0D) {
throw new IllegalArgumentException("maxPoints must be > 0 for LETTER grade type");
}
return getAssignmentList().size() * maxPoints;
}
return totalPoints.doubleValue();
}

public boolean isAssignmentInThisCategory(String assignmentId) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public class GradeDefinition {
private Date dateRecorded;
private String grade;
private String gradeComment;
private Integer gradeEntryType;
private GradeType gradeEntryType;
private boolean gradeReleased;
private boolean excused;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*
* Copyright (c) 2003-2022 The Apereo Foundation
*
* 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://opensource.org/licenses/ecl2
*
* 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.grading.api;

public enum GradeType {
POINTS,
PERCENTAGE,
LETTER,
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,17 @@ else if (StringUtils.startsWithAny(title, GradingService.INVALID_CHARS_AT_START_
* @return validated name
*/

public static String validateAssignmentNameAndPoints(final org.sakaiproject.grading.api.Assignment assignmentDefinition)
public static String validateAssignmentNameAndPoints(Assignment assignmentDefinition, boolean skipPointsValidation)
throws InvalidGradeItemNameException, AssignmentHasIllegalPointsException, ConflictingAssignmentNameException {
// Ensure that points is > zero.
final Double points = assignmentDefinition.getPoints();
if ((points == null) || (points <= 0)) {
throw new AssignmentHasIllegalPointsException("Points must be > 0");

if (!skipPointsValidation) {
// Ensure that points is > zero.
final Double points = assignmentDefinition.getPoints();
if ((points == null) || (points <= 0)) {
throw new AssignmentHasIllegalPointsException("Points must be > 0");
}
}

return validateGradeItemName(assignmentDefinition.getName());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package org.sakaiproject.grading.api;

import java.io.Serializable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

Expand Down Expand Up @@ -46,11 +47,11 @@ public class GradebookInformation implements Serializable {
/**
* The grading schema map currently in use for the this gradebook. For example A+ = 100 etc.
*/
private Map<String, Double> selectedGradingScaleBottomPercents;
private Map<String, Double> selectedGradingScaleBottomPercents = new HashMap<>();

private Boolean displayReleasedGradeItemsToStudents;

private Integer gradeType = GradingConstants.GRADE_TYPE_POINTS;
private GradeType gradeType = GradeType.POINTS;

private Integer categoryType;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,7 @@ public String toString() {
* @return
*/
public static List<String> getStandardPermissions() {
List<String> rval = new ArrayList<>();
rval.add(GraderPermission.VIEW.toString());
rval.add(GraderPermission.GRADE.toString());
return rval;
return List.of(GraderPermission.VIEW.toString(), GraderPermission.GRADE.toString());
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,6 @@
import java.math.RoundingMode;

public interface GradingConstants {
Integer GRADE_TYPE_POINTS = 1;
Integer GRADE_TYPE_PERCENTAGE = 2;
Integer GRADE_TYPE_LETTER = 3;

Integer CATEGORY_TYPE_NO_CATEGORY = 1;
Integer CATEGORY_TYPE_ONLY_CATEGORY = 2;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -480,7 +480,7 @@ public Map<String,String> transferGradebook(GradebookInformation gradebookInform
* validating a list of student/grade pairs for a single gradebook (more efficient than calling gradeIsValid repeatedly).
* returns empty list if all grades are valid
*/
public List<String> identifyStudentsWithInvalidGrades(String gradebookUid, Map<String, String> studentIdToGradeMap);
public Set<String> identifyStudentsWithInvalidGrades(String gradebookUid, Map<String, String> studentIdToGradeMap);

/**
* Save a student score and comment for a gradebook item. The input score must be valid according to the given gradebook's grade entry
Expand Down Expand Up @@ -523,7 +523,7 @@ public void saveGradeAndExcuseForStudent(String gradebookUid, String siteId, Lon
* @param gradebookUid
* @return the constant representation of the grade entry type (ie points, %, letter grade)
*/
public Integer getGradeEntryType(String gradebookUid);
public GradeType getGradeEntryType(String gradebookUid);

/**
* Get student's assignment's score as string.
Expand Down Expand Up @@ -589,12 +589,11 @@ public void setAssignmentScoreString(String gradebookUid, String siteId, Long as
* @param studentUuid uuid of the student
* @param categoryId id of category
* @param isInstructor will determine whether category score includes non-released items
* @param categoryType category type of the gradebook
* @param equalWeightAssignments whether category is equal-weighting regardless of points
* @return percentage and dropped items, or empty if no calculations were made
*
*/
Optional<CategoryScoreData> calculateCategoryScore(Long gradebookId, String studentUuid, Long categoryId, boolean includeNonReleasedItems, Integer categoryType, Boolean equalWeightAssignments);
Optional<CategoryScoreData> calculateCategoryScore(Long gradebookId, String studentUuid, Long categoryId, boolean includeNonReleasedItems, Boolean equalWeightAssignments);

/**
* Calculate the category score for the given gradebook, category, assignments in the category and grade map. This doesn't do any
Expand All @@ -609,7 +608,7 @@ public void setAssignmentScoreString(String gradebookUid, String siteId, Long as
* @param includeNonReleasedItems relevant for student view
* @return percentage and dropped items, or empty if no calculations were made
*/
Optional<CategoryScoreData> calculateCategoryScore(Object gradebook, String studentUuid, CategoryDefinition category,
Optional<CategoryScoreData> calculateCategoryScore(Gradebook gradebook, String studentUuid, CategoryDefinition category,
final List<Assignment> categoryAssignments, Map<Long, String> gradeMap, boolean includeNonReleasedItems);

/**
Expand Down Expand Up @@ -1004,5 +1003,28 @@ public void updateExternalAssessmentComments(String gradebookUid, String siteId,
public List<String> getGradebookInstancesForUser(String siteId, String userId);
public void initializeGradebooksForSite(String siteId);
public Double convertStringToDouble(final String doubleAsString);

/**
* Fully remove a gradebook from the database. This removes all the associated data and is
* irreversible without a backup.
*
* @param siteId The siteId (aka gradebook uid) to delete.
*/
public void hardDeleteGradebook(String siteId);

/**
* Get the maximum letter grade for the given grade mapping
*
* @param gradeMap
* @return An optional containing the maximum letter grade
*/
public Optional<String> getMaxLetterGrade(Map<String, Double> gradeMap);

/**
* Get the maximum points for the given grade mapping
*
* @param gradeMap
* @return An optional containing the maximum points
*/
public Optional<Double> getMaxPoints(Map<String, Double> gradeMap);
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;

import org.sakaiproject.grading.api.GradeType;
import org.sakaiproject.springframework.data.PersistableEntity;

import lombok.Getter;
Expand Down Expand Up @@ -86,6 +87,12 @@ public abstract class AbstractGradeRecord implements PersistableEntity<Long>, Se
@Column(name = "POINTS_EARNED")
protected Double pointsEarned;

@Column(name = "LETTER_EARNED")
protected String letterEarned;

@Column(name = "GRADE_TYPE", nullable = false)
protected GradeType gradeType = GradeType.POINTS;

public abstract Double getGradeAsPercentage();

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
package org.sakaiproject.grading.api.model;

import java.math.BigDecimal;
import java.util.Comparator;

import javax.persistence.Column;
import javax.persistence.DiscriminatorValue;
Expand All @@ -41,116 +40,35 @@
@Setter
public class AssignmentGradeRecord extends AbstractGradeRecord implements Cloneable {

@Transient
private String letterEarned;

@Transient
private Double percentEarned;

@Transient
private boolean userAbleToView;

@Column(name = "IS_EXCLUDED_FROM_GRADE")
private Boolean excludedFromGrade = Boolean.FALSE;

@Transient
private transient BigDecimal earnedWeightedPercentage;

@Transient
private transient BigDecimal overallWeight;

@Transient
private transient Boolean isDropped = Boolean.FALSE;

// used for drop highest/lowest score functionality
@Transient
private Boolean droppedFromGrade = Boolean.FALSE;

public static Comparator<AssignmentGradeRecord> numericComparator;

static{
numericComparator = new Comparator<AssignmentGradeRecord>() {

@Override
public int compare(AssignmentGradeRecord agr1, AssignmentGradeRecord agr2) {

if (agr1 == null && agr2 == null) {
return 0;
}
if (agr1 == null) {
return -1;
}
if (agr2 == null) {
return 1;
}
Double agr1Points = agr1.getGradeAsPercentage(); // Use percent in case the category is equal weight
Double agr2Points = agr2.getGradeAsPercentage();

if (agr1Points == null && agr2Points == null) {
return 0;
}
if (agr1Points == null && agr2Points != null) {
return -1;
}
if (agr1Points != null && agr2Points == null) {
return 1;
}
try {
return agr1Points.compareTo(agr2Points);
} catch (NumberFormatException e) {
return agr1Points.compareTo(agr2Points); // if not number, default to calcComparator functionality
}
}
};
}

public AssignmentGradeRecord() { }

/**
* The graderId and dateRecorded properties will be set explicitly by the
* grade manager before the database is updated.
* @param assignment The assignment this grade record is associated with
* @param studentId The student id for whom this grade record belongs
* @param grade The grade, or points earned
* @param grade The points grade earned
* @param letterGrade The letter grade earned
*/
public AssignmentGradeRecord(GradebookAssignment assignment, String studentId, Double grade) {
public AssignmentGradeRecord(GradebookAssignment assignment, String studentId, Double pointsGrade, String letterGrade) {

super();
this.gradableObject = assignment;
this.studentId = studentId;
this.pointsEarned = grade;
}

public static Comparator<AssignmentGradeRecord> calcComparator;

static {
calcComparator = new Comparator<AssignmentGradeRecord>() {
@Override
public int compare(AssignmentGradeRecord agr1, AssignmentGradeRecord agr2) {
if(agr1 == null && agr2 == null) {
return 0;
}
if(agr1 == null) {
return -1;
}
if(agr2 == null) {
return 1;
}
Double agr1Points = agr1.getPointsEarned();
Double agr2Points = agr2.getPointsEarned();

if (agr1Points == null && agr2Points == null) {
return 0;
}
if (agr1Points == null && agr2Points != null) {
return -1;
}
if (agr1Points != null && agr2Points == null) {
return 1;
}
return agr1Points.compareTo(agr2Points);
}
};
if (pointsGrade != null) this.pointsEarned = pointsGrade;

if (letterGrade != null) this.letterEarned = letterGrade;
}

/**
Expand Down
Loading
Loading