Skip to content

Commit

Permalink
Merge pull request sakaiproject#1709 from steveswinsburg/bug/1369_cou…
Browse files Browse the repository at this point in the history
…rse_grade_override

Bug/1369 course grade override
  • Loading branch information
payten committed Feb 14, 2016
2 parents 593718a + 5ab4a2b commit 8d159c2
Show file tree
Hide file tree
Showing 16 changed files with 560 additions and 92 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,25 @@ public class CourseGrade implements Serializable {

private static final long serialVersionUID = 1L;

private Long id;
private String enteredGrade;
private String calculatedGrade;
private String mappedGrade;

public CourseGrade() {}

/**
* ID of this course grade record. This will be null if the course grade is calculated, and non null if we have an override (as it then refers to the course grade assignment id).
* @return
*/
public Long getId() {
return id;
}

public void setId(Long id) {
this.id = id;
}

public String getEnteredGrade() {
return enteredGrade;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,12 @@ public class GradebookInformation implements Serializable {
*/
private List<GradeMappingDefinition> gradeMappings;

/**
* The grading schema map currently in use for the this gradebook. For example A+ = 100 etc.
*/
private Map<String, Double> selectedGradingScaleBottomPercents;
private boolean displayReleasedGradeItemsToStudents;

private boolean displayReleasedGradeItemsToStudents;
private int gradeType;
private int categoryType;
private List<CategoryDefinition> categories;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -806,4 +806,12 @@ public void finalizeGrades(String gradebookUid)
* @return Set of GradeMappings for the gradebook
*/
Set getGradebookGradeMappings(String gradebookUid);

/**
* Allows an instructor to set a course grade override for the given student
* @param gradebookUid uuid of the gradebook
* @param studentUuid uuid of the student
* @param grade the new course grade
*/
void updateCourseGradeForStudent(String gradebookUid, String studentUuid, String grade);
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@
import java.util.TreeSet;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;
import org.apache.commons.lang.math.NumberUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
Expand Down Expand Up @@ -3005,19 +3007,25 @@ public org.sakaiproject.service.gradebook.shared.CourseGrade getCourseGradeForSt
}

CourseGradeRecord gradeRecord = gradeRecords.get(0);


//ID of the course grade item
rval.setId(gradeRecord.getCourseGrade().getId());

//set entered grade
rval.setEnteredGrade(gradeRecord.getEnteredGrade());

if(!assignments.isEmpty()) {

//calculated grade
//may be null if no grade entries to calculate
Double calculatedGrade = gradeRecord.getAutoCalculatedGrade();
rval.setCalculatedGrade(calculatedGrade.toString());
if(calculatedGrade != null) {
rval.setCalculatedGrade(calculatedGrade.toString());
}

//mapped grade
GradeMapping gradeMap = gradebook.getSelectedGradeMapping();
String mappedGrade = (String)gradeMap.getGrade(calculatedGrade);
String mappedGrade = gradeMap.getGrade(calculatedGrade);
rval.setMappedGrade(mappedGrade);
}
}
Expand Down Expand Up @@ -3193,6 +3201,60 @@ public Set getGradebookGradeMappings(final String gradebookUid) {
return this.getGradebookGradeMappings(gradebookId);
}

@Override
public void updateCourseGradeForStudent(final String gradebookUid, final String studentUuid, final String grade) {

//must be instructor type person
if (!currentUserHasEditPerm(gradebookUid)) {
log.error("AUTHORIZATION FAILURE: User " + getUserUid() + " in gradebook " + gradebookUid + " attempted to update course grade for student: " + studentUuid);
throw new SecurityException("You do not have permission to update course grades in " + gradebookUid);
}

final Gradebook gradebook = getGradebook(gradebookUid);
if(gradebook==null) {
throw new IllegalArgumentException("There is no gradebook associated with this id: " + gradebookUid);
}

//get course grade for the student
CourseGradeRecord courseGradeRecord = (CourseGradeRecord)getHibernateTemplate().execute(new HibernateCallback() {
@Override
public Object doInHibernate(Session session) throws HibernateException {
return getCourseGradeRecord(gradebook, studentUuid, session);
}
});

//if user doesn't have an entered course grade, we need to find the course grade and create a record
if(courseGradeRecord == null) {

CourseGrade courseGrade = this.getCourseGrade(gradebook.getId());

courseGradeRecord = new CourseGradeRecord(courseGrade, studentUuid);
courseGradeRecord.setGraderId(getUserUid());
courseGradeRecord.setDateRecorded(new Date());

} else {
//if passed in grade override is same as existing grade override, nothing to do
if(StringUtils.equals(courseGradeRecord.getEnteredGrade(), grade)) {
return;
}
}

//set the grade override
courseGradeRecord.setEnteredGrade(grade);

//create a grading event
GradingEvent gradingEvent = new GradingEvent();
gradingEvent.setGradableObject(courseGradeRecord.getCourseGrade());
gradingEvent.setGraderId(getUserUid());
gradingEvent.setStudentId(studentUuid);
gradingEvent.setGrade(courseGradeRecord.getEnteredGrade());

//save
getHibernateTemplate().saveOrUpdate(courseGradeRecord);
getHibernateTemplate().saveOrUpdate(gradingEvent);
}


/**
* Map a set of GradeMapping to a list of GradeMappingDefinition
* @param gradeMappings set of GradeMapping
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ button.clear = Clear Changes
button.remove = Remove
button.settingsexpandall = Expand All
button.settingscollapseall = Collapse All
button.saveoverride = Save Course Grade Override

heading.addgradeitem = Add Gradebook Item
heading.editgradeitem = Edit Gradebook Item
Expand All @@ -76,6 +77,8 @@ heading.updateungradeditems = Set Score for Empty Cells
heading.gradelog = Grade Log for {0} ({1})
heading.editcomment = Comment for {0} ({1}) - {2}
heading.studentpage = Grade Report for {0}
heading.coursegrade = Course Grade Override for {0} ({1})
heading.coursegradelog = Course Grade Override Log for {0} ({1})
heading.zeroungradeditems = Set Zero Score for Empty Cells

# note these are not standard wicket style properties as we format this one slightly differently
Expand Down Expand Up @@ -196,6 +199,10 @@ assignment.option.setungraded = Set Score for Empty Cells
message.edititem.success=Gradebook item ''{0}'' has been updated.
message.edititem.error=An error occurred updating the gradebook item.
message.editcomment.error=An error occurred editing the comment.
message.addcoursegradeoverride.success = The course grade was updated.
message.addcoursegradeoverride.error = An error occurred updating the course grade.
message.addcoursegradeoverride.invalid = The course grade entered is invalid according to the grading schema currently in use by this gradebook.


message.updateungradeditems.success=The ungraded items were updated.

Expand Down Expand Up @@ -330,3 +337,19 @@ coursegrade.option.setungraded = Set Zero Score For Empty Cells
label.zeroungradeditems.instructions.1 = The Gradebook automatically calculates the course grade for students as items are graded. To accurately calculate the course grades, all gradable items must be assigned a grade. Continuing will assign zero to any grade items that do not have a grade. Not zeroing may result in higher course grades than intended.
label.zeroungradeditems.instructions.2 = <b>Note:</b> Clicking Update will assign a grade of zero to all ungraded items in this gradebook. <b>This can not be undone!</b>

coursegrade.option.viewlog = Course Grade Override Log
coursegrade.log.entry.set = {0} - Course Grade set to <b>{1}</b> by {2}
coursegrade.log.entry.unset = {0} - Course Grade Override removed by {1}
coursegrade.log.none = No course grade overrides have been entered.

coursegrade.override.instructions.1 = To provide a final course grade override, enter the desired letter grade into the field below. You may enter both + and - grades.
coursegrade.override.calculated.format.one = {0}
coursegrade.override.calculated.format.both = {0} ({1})
coursegrade.override.calculated.format.none = -

column.header.coursegradeoverride.studentname = Student Name
column.header.coursegradeoverride.studentid = Student ID
column.header.coursegradeoverride.points = Points
column.header.coursegradeoverride.calculated = Calculated Grade
column.header.coursegradeoverride.gradeoverride = Grade Override

Original file line number Diff line number Diff line change
Expand Up @@ -1943,6 +1943,28 @@ public GbCategoryType getGradebookCategoryType() {
return GbCategoryType.valueOf(configuredType);
}

/**
* Update the course grade (override) for this student
*
* @param studentUuid uuid of the student
* @param grade the new grade
* @return
*/
public boolean updateCourseGrade(final String studentUuid, final String grade) {

final String siteId = getCurrentSiteId();
final Gradebook gradebook = getGradebook(siteId);

try {
this.gradebookService.updateCourseGradeForStudent(gradebook.getUid(), studentUuid, grade);
return true;
} catch (final Exception e) {
log.error("An error occurred saving the course grade. " + e.getClass() + ": " + e.getMessage());
}

return false;
}

/**
* Comparator class for sorting a list of AssignmentOrders
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import lombok.Getter;

/**
* DTO for the grade log
* DTO for grade log events.
*
* @author Steve Swinsburg ([email protected])
*
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* Copyright (c) Orchestral Developments Ltd and the Orion Health group of companies (2001 - 2016).
*
* This document is copyright. Except for the purpose of fair reviewing, no part
* of this publication may be reproduced or transmitted in any form or by any
* means, electronic or mechanical, including photocopying, recording, or any
* information storage and retrieval system, without permission in writing from
* the publisher. Infringers of copyright render themselves liable for
* prosecution.
*/
package org.sakaiproject.gradebookng.tool.component;

import org.apache.wicket.AttributeModifier;
import org.apache.wicket.Component;
import org.apache.wicket.feedback.FeedbackMessage;
import org.apache.wicket.markup.html.panel.FeedbackPanel;

/**
* Feedback panel used and reused by GradebookNG so that the messages are styled consistently. Markup ID is automatically output.
*/
public class GbFeedbackPanel extends FeedbackPanel {

private static final long serialVersionUID = 1L;

public GbFeedbackPanel(final String id) {
super(id);

setOutputMarkupId(true);
}

@Override
protected Component newMessageDisplayComponent(final String id, final FeedbackMessage message) {
final Component newMessageDisplayComponent = super.newMessageDisplayComponent(id, message);

if (message.getLevel() == FeedbackMessage.ERROR ||
message.getLevel() == FeedbackMessage.DEBUG ||
message.getLevel() == FeedbackMessage.FATAL ||
message.getLevel() == FeedbackMessage.WARNING) {
add(AttributeModifier.replace("class", "messageError"));
add(AttributeModifier.append("class", "feedback"));
} else if (message.getLevel() == FeedbackMessage.INFO) {
add(AttributeModifier.replace("class", "messageSuccess"));
add(AttributeModifier.append("class", "feedback"));
}

return newMessageDisplayComponent;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,7 @@

import org.apache.log4j.Logger;
import org.apache.wicket.AttributeModifier;
import org.apache.wicket.Component;
import org.apache.wicket.behavior.AttributeAppender;
import org.apache.wicket.feedback.FeedbackMessage;
import org.apache.wicket.markup.head.IHeaderResponse;
import org.apache.wicket.markup.head.JavaScriptHeaderItem;
import org.apache.wicket.markup.head.OnLoadHeaderItem;
Expand All @@ -20,6 +18,7 @@
import org.apache.wicket.spring.injection.annot.SpringBean;
import org.sakaiproject.gradebookng.business.GbRole;
import org.sakaiproject.gradebookng.business.GradebookNgBusinessService;
import org.sakaiproject.gradebookng.tool.component.GbFeedbackPanel;

/**
* Base page for our app
Expand Down Expand Up @@ -142,27 +141,7 @@ public boolean isVisible() {
add(nav);

// Add a FeedbackPanel for displaying our messages
this.feedbackPanel = new FeedbackPanel("feedback") {

private static final long serialVersionUID = 1L;

@Override
protected Component newMessageDisplayComponent(final String id, final FeedbackMessage message) {
final Component newMessageDisplayComponent = super.newMessageDisplayComponent(id, message);

if (message.getLevel() == FeedbackMessage.ERROR ||
message.getLevel() == FeedbackMessage.DEBUG ||
message.getLevel() == FeedbackMessage.FATAL ||
message.getLevel() == FeedbackMessage.WARNING) {
newMessageDisplayComponent.add(AttributeModifier.replace("class", "messageError"));
} else if (message.getLevel() == FeedbackMessage.INFO) {
newMessageDisplayComponent.add(AttributeModifier.replace("class", "messageSuccess"));
}

return newMessageDisplayComponent;
}
};
this.feedbackPanel.setOutputMarkupId(true);
this.feedbackPanel = new GbFeedbackPanel("feedback");
add(this.feedbackPanel);

}
Expand Down Expand Up @@ -228,7 +207,6 @@ public WebMarkupContainer buildFlagWithPopover(final String componentId, final S
return flagWithPopover;
}


/**
* Helper to generate content for a Bootstrap popover with close button
*/
Expand Down
Loading

0 comments on commit 8d159c2

Please sign in to comment.