Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SAK-40851 Assignments: Allow Students to use Rubrics for the Peer #8822

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
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
5 changes: 5 additions & 0 deletions assignment/api/src/resources/assignment.properties
Original file line number Diff line number Diff line change
Expand Up @@ -1117,8 +1117,13 @@ associate.label=Use the following rubric to grade this assignment
option.pointsoverride=Adjust individual student scores
option.hidepoints=Hide point values (feedback only)
option.studentpreview=Hide Rubric from student
option.selfreport=Allow students to self-report their work
grading_rubric=Grading Rubric
asn.list.userubric=This assignment could be graded using a Rubric
youmustrubric=This is a self-report assignment. You must use the following rubric to grade your work before submitting
studentrubric=This is a self-report assignment. You can check the self-report of submitter before grading.
reviewrubric=This is a self-report assignment. You can check your self-report before grading.
peerrubric=Before grading the student, you can check the peer gradings above.
rubrics.use=Use rubric

# table toolbar common messages
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1057,6 +1057,10 @@ public class AssignmentAction extends PagedResourceActionII {
* Site property for forcing anonymous grading in a site
*/
private static final String SAK_PROP_FORCE_ANON_GRADING = "assignment.anon.grading.forced";
/**
* submitter, the student who do a selfreport
*/
private static final String STUDENT_WITH_SELFREPORT = "submitter";

private static final String FLAG_ON = "on";
private static final String FLAG_TRUE = "true";
Expand Down Expand Up @@ -1763,6 +1767,8 @@ private String build_student_view_submission_context(VelocityPortlet portlet, Co
canViewAssignmentIntoContext(context, assignment, s);

addAdditionalNotesToContext(submitter, context, state);

context.put("rubricSelfReport", assignmentToolUtils.hasRubricSelfReview(assignment.getId()));
}

if (taggingManager.isTaggable() && assignment != null) {
Expand Down Expand Up @@ -2287,6 +2293,11 @@ protected String build_student_confirm_submission_context(VelocityPortlet portle
}
}

context.put(STUDENT_WITH_SELFREPORT,
Optional.ofNullable((User) state.getAttribute("student")).orElse(user));

context.put("rubricSelfReport", assignmentToolUtils.hasRubricSelfReview(assignment.getId()));

context.put("text", state.getAttribute(PREVIEW_SUBMISSION_TEXT));
Map<String, Reference> submissionAttachmentReferences = new HashMap<>();
stripInvisibleAttachments(state.getAttribute(PREVIEW_SUBMISSION_ATTACHMENTS)).forEach(r -> submissionAttachmentReferences.put(r.getId(), r));
Expand Down Expand Up @@ -3600,6 +3611,19 @@ protected String build_instructor_grade_submission_context(VelocityPortlet portl
}
context.put("value_grades", grades);
}

// Check if the assignment has a rubric associated or not
context.put(RubricsConstants.RBCS_HAS_ASSOCIATED_RUBRIC, rubricsService.hasAssociatedRubric(RubricsConstants.RBCS_TOOL_ASSIGNMENT, a.getId()));
if (assignmentToolUtils.hasRubricSelfReview(a.getId())) {
s.getSubmitters().stream().findAny().ifPresent(u -> context.put(STUDENT_WITH_SELFREPORT, u.getSubmitter()));
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same block of code :)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hasRubricSelfReport is a bit strange maybe hasRubricSelfReview?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see no group logic here?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi Earle, trying to answer some of these questions as the original design and work was done by myself. Support for grouped submissions wasn't a requirement for these new features, so we believe they should be addressed in SAK-41604. Is this what you mean? Thanks.

// Only one peer review for an assignment submission per student.
if (a.getAllowPeerAssessment()) {
List<PeerAssessmentItem> reviews = assignmentPeerAssessmentService.getPeerAssessmentItems(s.getId(), a.getScaleFactor());
if(reviews.size() > 1) { log.warn("More than one peer review were found for Rubric assignment"); }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There could be reviews for multiple submissions, it's possible. If not now, in future.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The limitation to 1 peer-review per assignment is for two reasons: our client asked us that way and the second reason so that the teacher's screen can be clearly qualified and because in the repository only 1 evaluator allows (already either by submission or by student id).

If in the future someone wants something else, it is already outside the scope of this ticket, it would be a change like any other.

reviews.stream().findFirst().ifPresent(pai -> context.put(STUDENT_WITH_SELFREPORT, pai.getId().getAssessorUserId()));
}

}

// show alert if student is working on a draft
Expand Down Expand Up @@ -3844,6 +3868,10 @@ protected String build_instructor_grade_submission_context(VelocityPortlet portl
// Check if the assignment has a rubric associated or not
context.put("hasAssociatedRubric", assignment.isPresent() && rubricsService.hasAssociatedRubric(RubricsConstants.RBCS_TOOL_ASSIGNMENT, assignment.get().getId()));

if (state.getAttribute(RUBRIC_STATE_DETAILS) != null) {
context.put(RUBRIC_STATE_DETAILS, state.getAttribute(RUBRIC_STATE_DETAILS));
}

String siteId = (String) state.getAttribute(STATE_CONTEXT_STRING);
String toolId = toolManager.getCurrentPlacement().getId();

Expand Down Expand Up @@ -4859,6 +4887,9 @@ private String build_student_review_edit_context(VelocityPortlet portlet, Contex
securityService.popAdvisor(secAdv);
}
}

context.put(RubricsConstants.RBCS_HAS_ASSOCIATED_RUBRIC, rubricsService.hasAssociatedRubric(RubricsConstants.RBCS_TOOL_ASSIGNMENT, assignment.getId()));

if (s != null) {
submissionId = s.getId();
context.put("submission", s);
Expand Down Expand Up @@ -4919,7 +4950,7 @@ private String build_student_review_edit_context(VelocityPortlet portlet, Contex
} else {
context.put("view_only", false);
}

context.put(RubricsConstants.RBCS_ASSESSOR_ID, peerAssessmentItem.getId().getAssessorUserId());
// get attachments for peer review item
List<PeerAssessmentAttachment> attachments = assignmentPeerAssessmentService.getPeerAssessmentAttachments(peerAssessmentItem.getId().getSubmissionId(), peerAssessmentItem.getId().getAssessorUserId());
List<Reference> attachmentRefList = new ArrayList<>();
Expand Down Expand Up @@ -7035,6 +7066,8 @@ private void setNewAssignmentParameters(RunData data, boolean validify) {
} catch (Exception e) {
addAlert(state, rb.getString("peerassessment.invalidNumReview"));
}
} else if (params.get(RubricsConstants.RBCS_ASSOCIATE).equals("1")) {
state.setAttribute(NEW_ASSIGNMENT_PEER_ASSESSMENT_NUM_REVIEWS, 1);
} else {
addAlert(state, rb.getString("peerassessment.specifyNumReview"));
}
Expand Down Expand Up @@ -9285,7 +9318,7 @@ public void doView_assignment_as_student(RunData data) {
public void doView_submissionReviews(RunData data) {
String submissionId = data.getParameters().getString("submissionId");
SessionState state = ((JetspeedRunData) data).getPortletSessionState(((JetspeedRunData) data).getJs_peid());
String assessorId = data.getParameters().getString("assessorId");
String assessorId = data.getParameters().getString(RubricsConstants.RBCS_ASSESSOR_ID);
String assignmentId = StringUtils.trimToNull(data.getParameters().getString("assignmentId"));
Assignment a = getAssignment(assignmentId, "doEdit_assignment", state);
if (submissionId != null && !"".equals(submissionId) && a != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,15 @@
import org.sakaiproject.util.ResourceLoader;
import org.sakaiproject.util.api.FormattedText;

import org.apache.commons.lang3.StringUtils;
import org.sakaiproject.assignment.api.AssignmentReferenceReckoner;
import org.sakaiproject.assignment.api.AssignmentService;
import org.sakaiproject.assignment.api.model.Assignment;
import org.sakaiproject.assignment.api.model.AssignmentSubmission;
import org.sakaiproject.assignment.api.model.AssignmentSubmissionSubmitter;
import org.sakaiproject.entity.api.Reference;
import org.sakaiproject.exception.PermissionException;
import org.sakaiproject.rubrics.logic.RubricsConstants;
import org.sakaiproject.rubrics.logic.RubricsService;
import org.sakaiproject.rubrics.logic.model.ToolItemRubricAssociation;
import org.sakaiproject.service.gradebook.shared.AssignmentHasIllegalPointsException;
import org.sakaiproject.service.gradebook.shared.ConflictingAssignmentNameException;
import org.sakaiproject.service.gradebook.shared.GradebookExternalAssessmentService;
Expand All @@ -56,11 +57,7 @@
import org.sakaiproject.service.gradebook.shared.InvalidGradeItemNameException;
import org.sakaiproject.service.gradebook.shared.AssessmentNotFoundException;
import org.sakaiproject.tool.api.ToolManager;
import org.sakaiproject.tool.api.ToolManager;
import org.sakaiproject.lti.api.LTIService;
import org.sakaiproject.user.api.UserDirectoryService;
import org.sakaiproject.util.ResourceLoader;
import org.sakaiproject.util.api.FormattedText;
import org.sakaiproject.lti13.LineItemUtil;
import org.sakaiproject.lti13.util.SakaiLineItem;

Expand Down Expand Up @@ -88,6 +85,7 @@ public class AssignmentToolUtils {
private TimeService timeService;
private ToolManager toolManager;
private LTIService ltiService;
private RubricsService rubricsService;

private static ResourceLoader rb = new ResourceLoader("assignment");

Expand Down Expand Up @@ -892,4 +890,16 @@ private void removeNonAssociatedExternalGradebookEntry(String context, String as
}
}

public boolean hasRubricSelfReview(String assignmentId) {
try {
Optional<ToolItemRubricAssociation> rubricAssociation = rubricsService.getRubricAssociation(RubricsConstants.RBCS_TOOL_ASSIGNMENT, assignmentId);
if (rubricAssociation.isPresent() && rubricAssociation.get().getParameter(RubricsConstants.RBCS_STUDENT_SELF_REPORT)) {
return true;
}
} catch (Exception e) {
log.warn("Error trying to retrieve rubrics association for assignment : {}", e.getMessage());
}
return false;
}

}
1 change: 1 addition & 0 deletions assignment/tool/src/webapp/WEB-INF/applicationContext.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
<property name="userDirectoryService" ref="org.sakaiproject.user.api.UserDirectoryService" />
<property name="timeService" ref="org.sakaiproject.time.api.TimeService" />
<property name="ltiService" ref="org.sakaiproject.lti.api.LTIService" />
<property name="rubricsService" ref="org.sakaiproject.rubrics.logic.RubricsService"/>
</bean>

<!-- entity providers -->
Expand Down
37 changes: 35 additions & 2 deletions assignment/tool/src/webapp/js/assignments.js
Original file line number Diff line number Diff line change
Expand Up @@ -717,11 +717,11 @@ ASN.enableSubmitUnlessNoFile = function(checkForFile)

if (doEnable)
{
btnPost.removeAttribute('disabled');
btnPost.disabled = false;
}
else
{
btnPost.setAttribute('disabled', 'disabled');
btnPost.disabled = true;
}
};

Expand Down Expand Up @@ -962,6 +962,34 @@ ASN.changeVisibleDate = function()

$(document).ready(() => {

//peer-review and self-report
$('body').on('rubric-association-loaded', e => {
if($('#dont-associate-radio').length) {
const dontAssociateCheck = document.getElementById("dont-associate-radio");
const doAssociateCheck = document.getElementById("do-associate-radio");
const numberReviews = document.getElementById("new_assignment_peer_assessment_num_reviews");

//page-loading
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Identation

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

if (dontAssociateCheck.checked) {
numberReviews.disabled = false;
}

if (doAssociateCheck.checked) {
numberReviews.disabled = true;
numberReviews.value = 1;
}

//event manage
dontAssociateCheck.addEventListener("change", function() {
numberReviews.disabled = false;
});
doAssociateCheck.addEventListener("change", function() {
numberReviews.disabled = true;
numberReviews.value = 1;
});
}
});

ottenhoff marked this conversation as resolved.
Show resolved Hide resolved
$("#infoImg").popover({html : true});

const saveRubric = e => {
Expand All @@ -985,4 +1013,9 @@ $(document).ready(() => {
[...document.getElementsByTagName("sakai-rubric-student-button")].forEach(b => promises.push(b.releaseEvaluation()));
Promise.all(promises).then(() => ASN.submitForm('viewForm', 'releaseGrades', null, null));
});

const confirmButton = document.getElementById("confirm");
confirmButton && confirmButton.addEventListener("click", saveRubric);
const postButton = document.getElementById("post");
postButton && postButton.addEventListener("click", saveRubric);
});
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,22 @@
#if ($!hasAssociatedRubric)
</div>
<div role="tabpanel" class="tab-pane" id="rubric">
#if($assignment.getAllowPeerAssessment() || $!rubricSelfReport)
<sakai-rubric-student
token="$!rbcs-token"
tool-id="sakai.assignment"
entity-id="$assignment.Id"
evaluated-item-id="$submitter"
></sakai-rubric-student>
<p class="help-block">
#if($assignment.getAllowPeerAssessment())
$tlang.getString("peerrubric")
#elseif($!rubricSelfReport)
$tlang.getString("studentrubric")
#end
</p>
<hr class="itemSeparator" />
#end
<sakai-rubric-grading
## grade-field-id="grade"
token="$!rbcs-token"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -538,6 +538,13 @@ function printView(url) {
#end
</span>
</a>
<sakai-rubric-student-button
token="$!rbcs-token"
tool-id="sakai.assignment"
evaluated-item-id="$!item.getId().getAssessorUserId()"
entity-id="$assignment.Id"
instructor="true">
</sakai-rubric-student-button>
#if($!item.getScoreDisplay().length() > 0 || ($!item.getComment() && $!item.getComment().trim().length() > 0))
<span class="highlight" #if($item.Removed) style="text-decoration: line-through" #end>
#if($item.isDraft())
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<!-- start: chef_assignments_student_confirm_submission.vm -->
#rubricsRequirements
###header_append("<script type=${quote}text/javascript${quote}>includeWebjarLibrary(${quote}bootstrap${quote});</script>")

<script>
Expand Down Expand Up @@ -115,6 +116,19 @@
</tr>
#end
</table>
#if ($!rubricSelfReport)
<sakai-rubric-student
token="$!rbcs-token"
tool-id="sakai.assignment"
entity-id="$assignment.Id"
evaluated-item-id="$submitter.Id"
is-peer-or-self="$rubricSelfReport"
></sakai-rubric-student>
<p class="instruction">
$tlang.getString("reviewrubric")
</p>
#end

<h4>
$tlang.getString("gen.submission")
</h4>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,22 @@
<!-- start: check_assignments_instructor_grading_submission.vm -->
#rubricsRequirements
#module("/rubrics-service/webcomponents/rubric-association-requirements.js")
<script type="text/javascript">
focus_path = [ '$fField' ];
$(document).ready(function(){
ASN.setupPeerReviewAttachment();

document.body.addEventListener('total-points-updated', (e) => {
e.stopPropagation();
const gradeField = document.getElementById('grade');
if(gradeField) {
gradeField.value = e.detail.value;
}
});

});
</script>

<div class="portletBody">
#navBarOnClick( $allowAddAssignment $withGrade $allowGradeSubmission $allowAddAssignment $allowRecoverAssignment $allowAllGroups $assignmentscheck $allowUpdateSite $enableViewOption $view "gradeForm" "" )
## confirmation
Expand Down Expand Up @@ -158,6 +170,24 @@
#end

#if ($withGrade)
#if ($!hasAssociatedRubric)
#if ($!view_only)
<sakai-rubric-student
token="$!rbcs-token"
tool-id="sakai.assignment"
entity-id="$assignment.Id"
evaluated-item-id="$assessorId"
></sakai-rubric-student>
#else
<sakai-rubric-grading
token="$!rbcs-token"
tool-id="sakai.assignment"
entity-id="$assignment.Id"
evaluated-item-id="$assessorId"
is-peer-or-self="true"
></sakai-rubric-grading>
#end
#end
<div class="highlightPanel" style="width:80%">
#set ($gradeType = $assignment.TypeOfGrade.ordinal())
<p class="shorttext">
Expand Down Expand Up @@ -319,7 +349,7 @@
<input type="button" accesskey="s" name="return" value="$tlang.getString('peerassessment.removereview')" onclick="SPNR.disableControlsAndSpin( this, null ); ASN.submitForm( 'gradeForm', 'toggleremove_review', '$formattedText.escapeUrl($submissionReference)', null ); return false;" title="$tlang.getString("peerassessment.removereview")" />
#end
#else
<input type="button" accesskey="s" name="return" value="$tlang.getString('gen.sav')" onclick="SPNR.disableControlsAndSpin( this, null ); ASN.submitForm( 'gradeForm', 'savegrade_review', '$formattedText.escapeUrl($submissionReference)', null ); return false;" title="$tlang.getString("gen.sav")" />
<input type="button" id="save" accesskey="s" name="return" value="$tlang.getString('gen.sav')" onclick="SPNR.disableControlsAndSpin( this, null ); ASN.submitForm( 'gradeForm', 'savegrade_review', '$formattedText.escapeUrl($submissionReference)', null ); return false;" title="$tlang.getString("gen.sav")" />
<input type="button" accesskey="x" name="cancel" value="$tlang.getString('cancel_changes')" onclick="SPNR.disableControlsAndSpin( this, null ); ASN.submitForm( 'gradeForm', 'cancelgrade_review', null, null ); return false;" />
<input type="button" id="post" name="returnSubmit" value="$tlang.getString('gen.subm3')" onclick="SPNR.disableControlsAndSpin( this, null ); ASN.submitForm( 'gradeForm', 'submitgrade_review', '$formattedText.escapeUrl($submissionReference)', null ); return false;" title="$tlang.getString("gen.subm3")" />
#end
Expand Down
Loading