Index: assignment-api/api/src/java/org/sakaiproject/assignment/api/model/PeerAssessmentItem.java =================================================================== --- assignment-api/api/src/java/org/sakaiproject/assignment/api/model/PeerAssessmentItem.java (revision 0) +++ assignment-api/api/src/java/org/sakaiproject/assignment/api/model/PeerAssessmentItem.java (revision 0) @@ -0,0 +1,78 @@ +package org.sakaiproject.assignment.api.model; + +import java.io.Serializable; + +public class PeerAssessmentItem implements Serializable{ + + private static final long serialVersionUID = -8376570648172966170L; + private String assignmentId; + private String submissionId; + private String assessorUserId; + private Integer score; + private String comment; + private boolean removed; + //submitted is only a flag to help with the UI show/hide reviews + //that the user still needs to complete (more of a hide flag than a submit) + private boolean submitted; + //transient variables for displaying information in the UI + private String assessorDisplayName; + + public String getSubmissionId() { + return submissionId; + } + public void setSubmissionId(String submissionId) { + this.submissionId = submissionId; + } + public Integer getScore() { + return score; + } + public void setScore(Integer score) { + this.score = score; + } + public String getComment() { + return comment; + } + public void setComment(String comment) { + this.comment = comment; + } + public boolean isRemoved() { + return removed; + } + public void setRemoved(boolean removed) { + this.removed = removed; + } + public String getAssessorUserId() { + return assessorUserId; + } + public void setAssessorUserId(String assessorUserId) { + this.assessorUserId = assessorUserId; + } + public String getAssignmentId() { + return assignmentId; + } + public void setAssignmentId(String assignmentId) { + this.assignmentId = assignmentId; + } + //score is stored as a integer value in the DB, but is really a decimal value (divide by 10) + public String getScoreDisplay(){ + return getScore() == null ? "" : "" + score/10.0; + } + //transient variable that is only set for UI + public String getAssessorDisplayName(){ + return assessorDisplayName; + } + //transient variable that is only set for UI + public void setAssessorDisplayName(String assessorDisplayName) { + this.assessorDisplayName = assessorDisplayName; + } + public boolean isSubmitted() { + return submitted; + } + public void setSubmitted(boolean submitted) { + this.submitted = submitted; + } + + public boolean isDraft(){ + return !submitted && (getScore() != null || (getComment() != null && !"".equals(getComment().trim()))); + } +} Index: assignment-api/api/src/java/org/sakaiproject/assignment/api/model/PeerAssessmentItem.hbm.xml =================================================================== --- assignment-api/api/src/java/org/sakaiproject/assignment/api/model/PeerAssessmentItem.hbm.xml (revision 0) +++ assignment-api/api/src/java/org/sakaiproject/assignment/api/model/PeerAssessmentItem.hbm.xml (revision 0) @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + create index PEER_ASSESSOR_I on ASN_PEER_ASSESSMENT_ITEM_T (SUBMISSION_ID, ASSESSOR_USER_ID); + + + + + + create index PEER_ASSESSOR2_I on ASN_PEER_ASSESSMENT_ITEM_T (ASSIGNMENT_ID, ASSESSOR_USER_ID); + + + + + Index: assignment-api/api/src/java/org/sakaiproject/assignment/api/AssignmentSubmission.java =================================================================== --- assignment-api/api/src/java/org/sakaiproject/assignment/api/AssignmentSubmission.java (revision 311684) +++ assignment-api/api/src/java/org/sakaiproject/assignment/api/AssignmentSubmission.java (working copy) @@ -63,6 +63,8 @@ * @return String - the Assignment id */ public String getAssignmentId(); + + public String getSubmitterId(); /** * Access the list of Users who submitted this response to the Assignment. @@ -163,6 +165,12 @@ public boolean getGraded(); /** + * Get the grader id (this can be used to track between auto grades or instructor grades) + * + * @return + */ + public String getGradedBy(); + /** * Get whether the grade has been released. * * @return True if the Submissions's grade has been released, false otherwise. Index: assignment-api/api/src/java/org/sakaiproject/assignment/api/Assignment.java =================================================================== --- assignment-api/api/src/java/org/sakaiproject/assignment/api/Assignment.java (revision 311684) +++ assignment-api/api/src/java/org/sakaiproject/assignment/api/Assignment.java (working copy) @@ -278,8 +278,45 @@ * @return The AssignmentAccess access mode for the Assignment. */ AssignmentAccess getAccess(); + + public Time getPeerAssessmentPeriod(); + + public boolean getPeerAssessmentAnonEval(); + public boolean getPeerAssessmentStudentViewReviews(); + + public int getPeerAssessmentNumReviews(); + + public String getPeerAssessmentInstructions(); /** + * Access whether this AssignmentContent allows peer assessment. + * + * @return true if the AssignmentContent allows peer assessment, false otherwise. + */ + public boolean getAllowPeerAssessment(); + + /** + * peer assessment is set for this assignment and the current time + * falls between the assignment close time and the peer asseessment period time + * @return + */ + public boolean isPeerAssessmentOpen(); + + /** + * peer assessment is set for this assignment but the close time hasn't passed + * @return + */ + public boolean isPeerAssessmentPending(); + + /** + * peer assessment is set for this assignment but the current time is passed + * the peer assessment period + * @return + */ + public boolean isPeerAssessmentClosed(); + + + /** *

* AssignmentAccess enumerates different access modes for the assignment: site-wide or grouped. *

Index: assignment-api/api/src/java/org/sakaiproject/assignment/api/AssignmentSubmissionEdit.java =================================================================== --- assignment-api/api/src/java/org/sakaiproject/assignment/api/AssignmentSubmissionEdit.java (revision 311684) +++ assignment-api/api/src/java/org/sakaiproject/assignment/api/AssignmentSubmissionEdit.java (working copy) @@ -169,6 +169,12 @@ * true if the submission has been graded, false otherwise. */ public void setGraded(boolean graded); + + /** + * Set the grader id (this can be used to track between auto grades or instructor grades) + * @param id + */ + public void setGradedBy(String id); /** * Set the review Score for this assignment Index: assignment-api/api/src/java/org/sakaiproject/assignment/api/AssignmentPeerAssessmentService.java =================================================================== --- assignment-api/api/src/java/org/sakaiproject/assignment/api/AssignmentPeerAssessmentService.java (revision 0) +++ assignment-api/api/src/java/org/sakaiproject/assignment/api/AssignmentPeerAssessmentService.java (revision 0) @@ -0,0 +1,33 @@ +package org.sakaiproject.assignment.api; + +import java.util.Collection; +import java.util.List; + +import org.sakaiproject.api.app.scheduler.ScheduledInvocationCommand; +import org.sakaiproject.assignment.api.model.PeerAssessmentItem; + +public interface AssignmentPeerAssessmentService extends ScheduledInvocationCommand{ + + public void schedulePeerReview(String assignmentId); + + public void removeScheduledPeerReview(String assignmentId); + + public List getPeerAssessmentItems(String assignmentId, String assessorUserId); + + public PeerAssessmentItem getPeerAssessmentItem(String submissionId, String assessorUserId); + + public void savePeerAssessmentItem(PeerAssessmentItem item); + + public List getPeerAssessmentItems(String submissionId); + + public List getPeerAssessmentItemsByAssignmentId(String assignmentId); + + public List getPeerAssessmentItems(Collection submissionsIds); + + /** + * returns true if the score was updated and saved + * @param submissionId + * @return + */ + public boolean updateScore(String submissionId); +} Index: assignment-api/api/src/java/org/sakaiproject/assignment/api/AssignmentEdit.java =================================================================== --- assignment-api/api/src/java/org/sakaiproject/assignment/api/AssignmentEdit.java (revision 311684) +++ assignment-api/api/src/java/org/sakaiproject/assignment/api/AssignmentEdit.java (working copy) @@ -165,4 +165,23 @@ * The Assignment's order. */ public void setPosition_order(int position_order); + + /** + * Does this Assignment allow using the peer assessment? + * + * @param allow - + * true if the Assignment allows peer assessment, false otherwise? + */ + public void setAllowPeerAssessment(boolean allow); + + public void setPeerAssessmentPeriod(Time time); + + public void setPeerAssessmentAnonEval(boolean anonEval); + + public void setPeerAssessmentStudentViewReviews(boolean studentViewReviews); + + public void setPeerAssessmentNumReviews(int numReviews); + + public void setPeerAssessmentInstructions(String instructions); + } Index: assignment-api/api/pom.xml =================================================================== --- assignment-api/api/pom.xml (revision 311684) +++ assignment-api/api/pom.xml (working copy) @@ -40,5 +40,9 @@ org.sakaiproject.taggable sakai-taggable-api + + org.sakaiproject.scheduler + scheduler-api + Index: assignment-bundles/resources/assignment.properties =================================================================== --- assignment-bundles/resources/assignment.properties (revision 311684) +++ assignment-bundles/resources/assignment.properties (working copy) @@ -106,6 +106,7 @@ gen.grading = Grading gen.checked = Checked gen.commented = Commented +gen.comments = Comments gen.regra = Re-grade gen.regrading = Re-grading gen.grarep = Grade Report @@ -143,6 +144,7 @@ gen.orisub2 = Original submission text with the instructor's comments inserted if applicable gen.orisub3 = Last submission text with instructor comments inserted if applicable gen.outof = out of +gen.peerReviews = Peer Reviews gen.pf = P/F gen.pos = Post gen.position = Position @@ -152,6 +154,9 @@ gen.retu = Return gen.backtolist = Back to list gen.reorder = Reorder +gen.review = Review +gen.peerreview = Peer Review +gen.reviewer = Reviewer gen.reordertitle = Organize Default Assignment List View gen.retustud = Save and Release to Student gen.retustudtit = Save and return comments and grade to student @@ -162,6 +167,7 @@ gen.savdragra = Save and Don't Release to Student gen.savdratit = Save comments and grade, but do not return to student yet gen.sca = Scale +gen.score = Score gen.sect = Section gen.settfor = Settings for gen.sorasc = Sort ascending @@ -544,6 +550,7 @@ grading.alert.multiTab=Your grade, comments and feedback have not been saved. You will need to enter them again. You can only open one student submission at a time. If you open a second student's work before leaving the first student's submission, the first submission cannot be graded until you close all the submissions, and then open it. To avoid this problem, please do not open multiple browser-windows or tabs while you are grading. We recommend that you close and restart your browser, and then log back into the system, before continuing with your grading. grading.reminder=Important Reminder: grading.reminder.body=Please do not grade assignments with multiple browser windows or tabs. Grade assignments and navigate the system with only one browser window. +grading.reminder.anon=Grading for this peer review is anonymous, so do not post your name in the reviewer comments section. allow.resubmit.number=Number of resubmissions allowed allow.resubmit.number.unlimited=Unlimited allow.resubmit.closeTime=Accept Resubmission Until @@ -803,3 +810,50 @@ send.submission.releasereturn.email.options=Released Resubmission Notification Email Options: send.submission.releasereturn.email.none=Do not send notification email to student when the grade is released and resubmission is available send.submission.releasereturn.email=Send notification email to student when the grade is released and resubmission is available + +# Peer Review +peerAssessmentSavedGrading=Comments and/or grade have been saved but not submitted. If you don't submit your review before the due date, it will be submitted for you. +peerAssessmentSavedSubmission=Comments and/or grade have been saved and submitted. +peerAssessmentName=Peer Assessment +peerAssessmentUse=Use peer assessment +peerassessment.note=Peer assessment requires a points grading scale and do not allow group assignments. +peerassessment.periodfinishes=Evaluation Period Finishes: +peerassessment.anonymousEvaluation=Anonymous evaluation +peerassessment.studentViewReviews=Allow students to see reviews of their submissions +peerassessment.numSubmissions=Number of submissions students must review +peerassessment.reviewInstructions=Instructions for reviewers: +peerassessment.specifyNumReview=Please enter a value for the number of submissions a student must review for peer assessment. +peerassessment.invalidNumReview=You must enter a valid number greater than 0 for the number of submissions a student must review for peer assessment. +peerassessment.invliadPeriodTime=You must enter a peer review period date that is at least 10 minutes after the accept until date. +peerassessment.reviewStarts=Review starts on +peerassessment.notavailable=Peer assessment is not available for the assignment you selected. +peerassessment.allSubmitted=You have submitted all of your peer reviews. +peerassessment.instructionsForReviewer=Instructions for the Reviewer +peerassessment.reviewerComments=Reviewer Comments +peerassessment.alert.saveerrorunkown=An error has occurred while saving, please refresh and try again. +peerassessment.alert.saveinvalidscore=You must enter a valid number greater than 0 for the score. +peerassessment.alert.savenoscorecomment=You must enter a grade or a comment in order to submit your peer assessment. +peerassessment.instructions.reviewer=Instructions for the Reviewer +peerassessment.invliadGroupAssignment=Peer assessments are not available for group assignments. +peerassessment.invliadSubmissionTypeAssignment=Peer assessments are not available for non-electronic assignments. +peerassessment.invliadGradeTypeAssignment=Peer assessments are only available when Grade Scale is set to Points. +peerassessment.reviewedby=Reviewed By +peerassessment.reviewergrade=Reviewer Grade +peerassessment.noscore=No score +peerassessment.nocomments=No comments +peerassessment.removereview=Remove Review +peerassessment.restorereview=Restore Review +peerassessment.cantgrade=Instructor grading is disabled until after the review period: +peerassessment.removed=Successfully removed review for student's submission +peerassessment.restored=Successfully restored review for student's submission +peerassessment.peerReviewDueDate=Peer review due date: +aeerassessment.peerGradeInfo=You are able to accept or override the averaged peer review grade in this section. Once this grade is released, this is the grade that will appear in the gradebook. +stuviewsubm.peerreview=Once submitted, this assignment will be part of a peer review. +stuviewsubm.peerreviewanon=Once submitted, this assignment will be part of an anonymous peer review. Make sure not to include your name in any submission text, files or file names. +peerassessment.submissionReq=Assignment submission required +peerassessment.notOpen=Not open +peerassessment.notStarted=Not started +peerassessment.incomplete=Incomplete +peerassessment.submitted=Submitted +peerassessment.student=Student {0} +peerassessment.draftInProgress=Draft - in progress Index: assignment-tool/tool/src/java/org/sakaiproject/assignment/tool/AssignmentAction.java =================================================================== --- assignment-tool/tool/src/java/org/sakaiproject/assignment/tool/AssignmentAction.java (revision 311684) +++ assignment-tool/tool/src/java/org/sakaiproject/assignment/tool/AssignmentAction.java (working copy) @@ -69,6 +69,7 @@ import org.sakaiproject.assignment.api.AssignmentContent; import org.sakaiproject.assignment.api.AssignmentContentEdit; import org.sakaiproject.assignment.api.AssignmentEdit; +import org.sakaiproject.assignment.api.AssignmentPeerAssessmentService; import org.sakaiproject.assignment.api.AssignmentSubmission; import org.sakaiproject.assignment.api.AssignmentSubmissionEdit; import org.sakaiproject.assignment.api.model.AssignmentAllPurposeItem; @@ -78,6 +79,7 @@ import org.sakaiproject.assignment.api.model.AssignmentSupplementItemAttachment; import org.sakaiproject.assignment.api.model.AssignmentSupplementItemService; import org.sakaiproject.assignment.api.model.AssignmentSupplementItemWithAttachment; +import org.sakaiproject.assignment.api.model.PeerAssessmentItem; import org.sakaiproject.assignment.cover.AssignmentService; import org.sakaiproject.assignment.taggable.api.AssignmentActivityProducer; import org.sakaiproject.assignment.taggable.tool.DecoratedTaggingProvider; @@ -171,10 +173,23 @@ private static final String ASSIGNMENT_TOOL_ID = "sakai.assignment.grades"; private static final Boolean allowReviewService = ServerConfigurationService.getBoolean("assignment.useContentReview", false); + private static final Boolean allowPeerAssessment = ServerConfigurationService.getBoolean("assignment.usePeerAssessment", true); /** Is the review service available? */ private static final String ALLOW_REVIEW_SERVICE = "allow_review_service"; - + //Peer Assessment + private static final String NEW_ASSIGNMENT_USE_PEER_ASSESSMENT= "new_assignment_use_peer_assessment"; + private static final String NEW_ASSIGNMENT_PEERPERIODMONTH = "new_assignment_peerperiodmonth"; + private static final String NEW_ASSIGNMENT_PEERPERIODDAY = "new_assignment_peerperiodday"; + private static final String NEW_ASSIGNMENT_PEERPERIODYEAR = "new_assignment_peerperiodyear"; + private static final String NEW_ASSIGNMENT_PEERPERIODHOUR = "new_assignment_peerperiodhour"; + private static final String NEW_ASSIGNMENT_PEERPERIODMIN = "new_assignment_peerperiodmin"; + private static final String NEW_ASSIGNMENT_PEERPERIODAMPM = "new_assignment_peerperiodampm"; + private static final String NEW_ASSIGNMENT_PEER_ASSESSMENT_ANON_EVAL= "new_assignment_peer_assessment_anon_eval"; + private static final String NEW_ASSIGNMENT_PEER_ASSESSMENT_STUDENT_VIEW_REVIEWS= "new_assignment_peer_assessment_student_view_review"; + private static final String NEW_ASSIGNMENT_PEER_ASSESSMENT_NUM_REVIEWS= "new_assignment_peer_assessment_num_reviews"; + private static final String NEW_ASSIGNMENT_PEER_ASSESSMENT_INSTRUCTIONS = "new_assignment_peer_assessment_instructions"; + private static final String NEW_ASSIGNMENT_USE_REVIEW_SERVICE = "new_assignment_use_review_service"; private static final String NEW_ASSIGNMENT_ALLOW_STUDENT_VIEW = "new_assignment_allow_student_view"; @@ -420,6 +435,7 @@ private static final String GRADE_SUBMISSION_ALLOW_RESUBMIT = "grade_submission_allow_resubmit"; private static final String GRADE_SUBMISSION_DONE = "grade_submission_done"; + private static final String GRADE_SUBMISSION_SUBMIT = "grade_submission_submit"; /** ******************* instructor's export assignment ***************************** */ private static final String EXPORT_ASSIGNMENT_REF = "export_assignment_ref"; @@ -606,6 +622,10 @@ /** The option view */ private static final String MODE_OPTIONS= "options"; // set in velocity template + + /** Review Edit page for students */ + private static final String MODE_STUDENT_REVIEW_EDIT= "Assignment.mode_student_review_edit"; // set in velocity template + /** ************************* vm names ************************** */ /** The list view of assignments */ private static final String TEMPLATE_LIST_ASSIGNMENTS = "_list_assignments"; @@ -658,6 +678,9 @@ /** The instructor view to upload all information from archive file */ private static final String TEMPLATE_INSTRUCTOR_UPLOAD_ALL = "_instructor_uploadAll"; + /** The student view to edit reviews **/ + private static final String TEMPLATE_STUDENT_REVIEW_EDIT = "_student_review_edit"; + /** The options page */ private static final String TEMPLATE_OPTIONS = "_options"; @@ -691,6 +714,12 @@ /** the user and submission list for list of submissions page */ private static final String USER_SUBMISSIONS = "user_submissions"; + /** the items for storing the comments and grades for peer assessment **/ + private static final String PEER_ASSESSMENT_ITEMS = "peer_assessment_items"; + + private static final String PEER_ASSESSMENT_ASSESSOR_ID = "peer_assessment_assesor_id"; + private static final String PEER_ASSESSMENT_REMOVED_STATUS = "peer_assessment_removed_status"; + /** ************************* Taggable constants ************************** */ /** identifier of tagging provider that will provide the appropriate helper */ private static final String PROVIDER_ID = "providerId"; @@ -793,6 +822,11 @@ /** To know if grade_submission go from view_students_assignment view or not **/ private static final String FROM_VIEW = "from_view"; + private AssignmentPeerAssessmentService assignmentPeerAssessmentService; + public void setAssignmentPeerAssessmentService(AssignmentPeerAssessmentService assignmentPeerAssessmentService){ + this.assignmentPeerAssessmentService = assignmentPeerAssessmentService; + } + /** * central place for dispatching the build routines based on the state name */ @@ -847,6 +881,13 @@ context.put("reviewServiceUse", reviewServiceUse); } + //Peer Assessment + context.put("allowPeerAssessment", allowPeerAssessment); + if(allowPeerAssessment){ + context.put("peerAssessmentName", rb.getString("peerAssessmentName")); + context.put("peerAssessmentUse", rb.getString("peerAssessmentUse")); + } + // grading option context.put("withGrade", state.getAttribute(WITH_GRADES)); @@ -1021,8 +1062,12 @@ template = build_options_context(portlet, context, data, state); } } + + else if (mode.equals(MODE_STUDENT_REVIEW_EDIT)) + { + template = build_student_review_edit_context(portlet, context, data, state); + } - if (template == null) { // default to student list view @@ -1592,8 +1637,44 @@ context.put("submission", submission); // can the student view model answer or not - canViewAssignmentIntoContext(context, assignment, submission); - } + canViewAssignmentIntoContext(context, assignment, submission); + + + //peer review + if(assignment.getAllowPeerAssessment() + && assignment.getPeerAssessmentStudentViewReviews() + && assignment.isPeerAssessmentClosed()){ + List reviews = assignmentPeerAssessmentService.getPeerAssessmentItems(submission.getId()); + if(reviews != null){ + List completedReviews = new ArrayList(); + for(PeerAssessmentItem review : reviews){ + if(!review.isRemoved() && (review.getScore() != null || (review.getComment() != null && !"".equals(review.getComment().trim())))){ + //only show peer reviews that have either a score or a comment saved + if(assignment.getPeerAssessmentAnonEval()){ + //annonymous eval + review.setAssessorDisplayName(rb.get("gen.reviewer").toString() + " " + (completedReviews.size() + 1)); + }else{ + //need to set the assessor's display name + try { + review.setAssessorDisplayName(UserDirectoryService.getUser(review.getAssessorUserId()).getDisplayName()); + } catch (UserNotDefinedException e) { + //reviewer doesn't exist or userId is wrong + M_log.error(e.getMessage(), e); + //set a default one: + review.setAssessorDisplayName(rb.get("gen.reviewer").toString() + " " + (completedReviews.size() + 1)); + } + } + completedReviews.add(review); + + } + } + if(completedReviews.size() > 0){ + context.put("peerReviews", completedReviews); + } + } + } + + } TaggingManager taggingManager = (TaggingManager) ComponentManager .get("org.sakaiproject.taggable.api.TaggingManager"); @@ -1680,7 +1761,20 @@ List assignments = prepPage(state); context.put("assignments", assignments.iterator()); - + // allow add assignment? + Map> peerAssessmentItemsMap = new HashMap>(); + boolean allowAddAssignment = AssignmentService.allowAddAssignment(contextString); + if(!allowAddAssignment){ + //this is the same requirement for displaying the assignment link for students + //now lets create a map for peer reviews for each eligible assignment + for(Assignment assignment : (List) assignments){ + if(assignment.getAllowPeerAssessment() && (assignment.isPeerAssessmentOpen() || assignment.isPeerAssessmentClosed())){ + peerAssessmentItemsMap.put(assignment.getId(), assignmentPeerAssessmentService.getPeerAssessmentItems(assignment.getId(), UserDirectoryService.getCurrentUser().getId())); + } + } + } + context.put("peerAssessmentItemsMap", peerAssessmentItemsMap); + // allow get assignment context.put("allowGetAssignment", Boolean.valueOf(AssignmentService.allowGetAssignment(contextString))); @@ -1817,7 +1911,11 @@ { // put the names and values into vm file - + context.put("name_UsePeerAssessment", NEW_ASSIGNMENT_USE_PEER_ASSESSMENT); + context.put("name_PeerAssessmentAnonEval", NEW_ASSIGNMENT_PEER_ASSESSMENT_ANON_EVAL); + context.put("name_PeerAssessmentStudentViewReviews", NEW_ASSIGNMENT_PEER_ASSESSMENT_STUDENT_VIEW_REVIEWS); + context.put("name_PeerAssessmentNumReviews", NEW_ASSIGNMENT_PEER_ASSESSMENT_NUM_REVIEWS); + context.put("name_PeerAssessmentInstructions", NEW_ASSIGNMENT_PEER_ASSESSMENT_INSTRUCTIONS); context.put("name_UseReviewService", NEW_ASSIGNMENT_USE_REVIEW_SERVICE); context.put("name_AllowStudentView", NEW_ASSIGNMENT_ALLOW_STUDENT_VIEW); context.put("name_NEW_ASSIGNMENT_REVIEW_SERVICE_SUBMIT_RADIO", NEW_ASSIGNMENT_REVIEW_SERVICE_SUBMIT_RADIO); @@ -1891,7 +1989,14 @@ context.put("value_GradePoints", displayGrade(state, maxGrade)); context.put("value_Description", state.getAttribute(NEW_ASSIGNMENT_DESCRIPTION)); - + //Peer Assessment + context.put("value_UsePeerAssessment", state.getAttribute(NEW_ASSIGNMENT_USE_PEER_ASSESSMENT)); + context.put("value_PeerAssessmentAnonEval", state.getAttribute(NEW_ASSIGNMENT_PEER_ASSESSMENT_ANON_EVAL)); + context.put("value_PeerAssessmentStudentViewReviews", state.getAttribute(NEW_ASSIGNMENT_PEER_ASSESSMENT_STUDENT_VIEW_REVIEWS)); + context.put("value_PeerAssessmentNumReviews", state.getAttribute(NEW_ASSIGNMENT_PEER_ASSESSMENT_NUM_REVIEWS)); + context.put("value_PeerAssessmentInstructions", state.getAttribute(NEW_ASSIGNMENT_PEER_ASSESSMENT_INSTRUCTIONS)); + putTimePropertiesInContext(context, state, "PeerPeriod", NEW_ASSIGNMENT_PEERPERIODMONTH, NEW_ASSIGNMENT_PEERPERIODDAY, NEW_ASSIGNMENT_PEERPERIODYEAR, NEW_ASSIGNMENT_PEERPERIODHOUR, NEW_ASSIGNMENT_PEERPERIODMIN, NEW_ASSIGNMENT_PEERPERIODAMPM); + // Keep the use review service setting context.put("value_UseReviewService", state.getAttribute(NEW_ASSIGNMENT_USE_REVIEW_SERVICE)); context.put("value_AllowStudentView", state.getAttribute(NEW_ASSIGNMENT_ALLOW_STUDENT_VIEW) == null ? Boolean.toString(ServerConfigurationService.getBoolean("turnitin.allowStudentView.default", false)) : state.getAttribute(NEW_ASSIGNMENT_ALLOW_STUDENT_VIEW)); @@ -2581,6 +2686,13 @@ state.removeAttribute(GRADE_SUBMISSION_DONE); } + // put the grade confirmation message if applicable + if (state.getAttribute(GRADE_SUBMISSION_SUBMIT) != null) + { + context.put("gradingSubmit", Boolean.TRUE); + state.removeAttribute(GRADE_SUBMISSION_SUBMIT); + } + // letter grading letterGradeOptionsIntoContext(context); @@ -2608,6 +2720,54 @@ return time; } + public void doPrev_back_next_submission_review(RunData rundata, String option, boolean submit) + { + SessionState state = ((JetspeedRunData) rundata).getPortletSessionState(((JetspeedRunData) rundata).getJs_peid()); + // save the instructor input + boolean hasChange = saveReviewGradeForm(rundata, state, submit ? "submit" : "save"); + + if (state.getAttribute(STATE_MESSAGE) == null) + { + ParameterParser params = rundata.getParameters(); + List submissionIds = new ArrayList(); + if(state.getAttribute(USER_SUBMISSIONS) != null){ + submissionIds = (List) state.getAttribute(USER_SUBMISSIONS); + } + + String submissionId = null; + String assessorId = null; + if ("next".equals(option)) + { + submissionId = params.get("nextSubmissionId"); + assessorId = params.get("nextAssessorId"); + } + else if ("prev".equals(option)) + { + submissionId = params.get("prevSubmissionId"); + assessorId = params.get("prevAssessorId"); + } + else if ("back".equals(option)) + { + String assignmentId = (String) state.getAttribute(VIEW_ASSIGNMENT_ID); + List userSubmissionsState = state.getAttribute(STATE_PAGEING_TOTAL_ITEMS) != null ? (List) state.getAttribute(STATE_PAGEING_TOTAL_ITEMS):null; + if(userSubmissionsState != null && userSubmissionsState.size() > 0 && userSubmissionsState.get(0) instanceof UserSubmission + && AssignmentService.allowGradeSubmission(assignmentId)){ + //coming from instructor view submissions page + state.setAttribute(STATE_MODE, MODE_INSTRUCTOR_GRADE_ASSIGNMENT); + }else{ + state.setAttribute(STATE_MODE, MODE_LIST_ASSIGNMENTS); + } + } + if(submissionId != null && submissionIds.contains(submissionId)){ + state.setAttribute(GRADE_SUBMISSION_SUBMISSION_ID, submissionId); + } + if(assessorId != null){ + state.setAttribute(PEER_ASSESSMENT_ASSESSOR_ID, assessorId); + } + } + } + + /** * Responding to the request of submission navigation * @param rundata @@ -2872,6 +3032,52 @@ state.setAttribute(USER_SUBMISSIONS, userSubmissions); context.put("userSubmissions", state.getAttribute(USER_SUBMISSIONS)); + + //find peer assessment grades if exist + if(assignment.getAllowPeerAssessment()){ + List submissionIds = new ArrayList(); + //get list of submission ids to look up reviews in db + for(UserSubmission s : userSubmissions){ + submissionIds.add(s.getSubmission().getId()); + } + //look up reviews for these submissions + List items = assignmentPeerAssessmentService.getPeerAssessmentItems(submissionIds); + //create a map for velocity to use in displaying the submission reviews + Map> itemsMap = new HashMap>(); + Map reviewersMap = new HashMap(); + if(items != null){ + for(PeerAssessmentItem item : items){ + //update items map + List sItems = itemsMap.get(item.getSubmissionId()); + if(sItems == null){ + sItems = new ArrayList(); + } + sItems.add(item); + itemsMap.put(item.getSubmissionId(), sItems); + //update users map: + User u = reviewersMap.get(item.getAssessorUserId()); + if(u == null){ + try { + u = UserDirectoryService.getUser(item.getAssessorUserId()); + reviewersMap.put(item.getAssessorUserId(), u); + } catch (UserNotDefinedException e) { + M_log.warn(e.getMessage(), e); + } + } + } + } + //go through all the submissions and make sure there aren't any nulls + for(String id : submissionIds){ + List sItems = itemsMap.get(id); + if(sItems == null){ + sItems = new ArrayList(); + itemsMap.put(id, sItems); + } + } + context.put("peerAssessmentItems", itemsMap); + context.put("reviewersMap", reviewersMap); + } + // whether to show the resubmission choice if (state.getAttribute(SHOW_ALLOW_RESUBMISSION) != null) { @@ -3111,9 +3317,323 @@ String template = (String) getContext(data).get("template"); return template + TEMPLATE_INSTRUCTOR_REORDER_ASSIGNMENT; - + } // build_instructor_reorder_assignment_context + protected String build_student_review_edit_context(VelocityPortlet portlet, Context context, RunData data, SessionState state){ + int gradeType = -1; + context.put("context", state.getAttribute(STATE_CONTEXT_STRING)); + List peerAssessmentItems = (List) state.getAttribute(PEER_ASSESSMENT_ITEMS); + String assignmentId = (String) state.getAttribute(VIEW_ASSIGNMENT_ID); + User sessionUser = (User) state.getAttribute(STATE_USER); + String assessorId = sessionUser.getId(); + if(state.getAttribute(PEER_ASSESSMENT_ASSESSOR_ID) != null){ + assessorId = (String) state.getAttribute(PEER_ASSESSMENT_ASSESSOR_ID); + } + Assignment assignment = getAssignment(assignmentId, "build_student_review_edit_context", state); + if (assignment != null){ + context.put("assignment", assignment); + if (assignment.getContent() != null) + { + gradeType = assignment.getContent().getTypeOfGrade(); + } + context.put("peerAssessmentInstructions", assignment.getPeerAssessmentInstructions() == null ? "" : assignment.getPeerAssessmentInstructions()); + } + String submissionId = ""; + SecurityAdvisor secAdv = new SecurityAdvisor(){ + @Override + public SecurityAdvice isAllowed(String userId, String function, + String reference) { + if("asn.submit".equals(function) || "asn.submit".equals(function) || "asn.grade".equals(function)){ + return SecurityAdvice.ALLOWED; + } + return null; + } + }; + AssignmentSubmission s = null; + try{ + //surround with a try/catch/finally for the security advisor + m_securityService.pushAdvisor(secAdv); + s = getSubmission((String) state.getAttribute(GRADE_SUBMISSION_SUBMISSION_ID), "build_student_review_edit_context", state); + m_securityService.popAdvisor(secAdv); + }catch(Exception e){ + M_log.error(e.getMessage(), e); + }finally{ + if(secAdv != null){ + m_securityService.popAdvisor(secAdv); + } + } + if (s != null) + { + submissionId = s.getId(); + context.put("submission", s); + + ResourceProperties p = s.getProperties(); + if (p.getProperty(ResourceProperties.PROP_SUBMISSION_PREVIOUS_FEEDBACK_TEXT) != null) + { + context.put("prevFeedbackText", p.getProperty(ResourceProperties.PROP_SUBMISSION_PREVIOUS_FEEDBACK_TEXT)); + } + + if (p.getProperty(ResourceProperties.PROP_SUBMISSION_PREVIOUS_FEEDBACK_COMMENT) != null) + { + context.put("prevFeedbackComment", p.getProperty(ResourceProperties.PROP_SUBMISSION_PREVIOUS_FEEDBACK_COMMENT)); + } + + if (p.getProperty(PROP_SUBMISSION_PREVIOUS_FEEDBACK_ATTACHMENTS) != null) + { + context.put("prevFeedbackAttachments", getPrevFeedbackAttachments(p)); + } + if ((s.getFeedbackText() == null) || (s.getFeedbackText().length() == 0)) + { + context.put("value_feedback_text", s.getSubmittedText()); + } + else + { + context.put("value_feedback_text", s.getFeedbackFormattedText()); + } + List v = EntityManager.newReferenceList(); + Iterator attachments = s.getFeedbackAttachments().iterator(); + while (attachments.hasNext()) + { + v.add(attachments.next()); + } + context.put("value_feedback_attachment", v); + state.setAttribute(ATTACHMENTS, v); + } + if(peerAssessmentItems != null && submissionId != null){ + //find the peerAssessmentItem for this submission: + PeerAssessmentItem peerAssessmentItem = null; + for(PeerAssessmentItem item : peerAssessmentItems){ + if(submissionId.equals(item.getSubmissionId()) + && assessorId.equals(item.getAssessorUserId())){ + peerAssessmentItem = item; + break; + } + } + if(peerAssessmentItem != null){ + //check if current user is the peer assessor, if not, only display data (no editing) + if(!sessionUser.getId().equals(peerAssessmentItem.getAssessorUserId())){ + context.put("view_only", true); + try { + User reviewer = UserDirectoryService.getUser(peerAssessmentItem.getAssessorUserId()); + context.put("reviewer", reviewer); + } catch (UserNotDefinedException e) { + M_log.warn(e.getMessage(), e); + } + }else{ + context.put("view_only", false); + } + + //scores are saved as whole values + //so a score of 1.3 would be stored as 13 + //so a DB score of 13 needs to be 1.3: + if(peerAssessmentItem.getScore() != null){ + double score = peerAssessmentItem.getScore()/10.0; + context.put("value_grade", score); + }else{ + context.put("value_grade", null); + } + context.put("display_grade", peerAssessmentItem.getScoreDisplay()); + context.put("item_removed", peerAssessmentItem.isRemoved()); + context.put("value_feedback_comment", peerAssessmentItem.getComment()); + + //set previous/next values + List userSubmissionsState = state.getAttribute(STATE_PAGEING_TOTAL_ITEMS) != null ? (List) state.getAttribute(STATE_PAGEING_TOTAL_ITEMS):null; + List userSubmissions = new ArrayList(); + boolean instructorView = false; + if(userSubmissionsState != null && userSubmissionsState.size() > 0 && userSubmissionsState.get(0) instanceof UserSubmission){ + //from instructor view/ + //dd + for(UserSubmission userSubmission : (List) userSubmissionsState){ + if(!userSubmissions.contains(userSubmission.getSubmission().getId()) + && userSubmission.getSubmission().getSubmitted()){ + userSubmissions.add(userSubmission.getSubmission().getId()); + } + } + }else{ + //student view + for(PeerAssessmentItem item : peerAssessmentItems){ + if(!userSubmissions.contains(item.getSubmissionId()) && !item.isSubmitted()){ + userSubmissions.add(item.getSubmissionId()); + } + } + } + if(userSubmissions != null){ + context.put("totalReviews", userSubmissions.size()); + //first setup map to make the navigation logic easier: + Map> itemMap = new HashMap>(); + for(String userSubmissionId : userSubmissions){ + for (PeerAssessmentItem item : peerAssessmentItems){ + if(userSubmissionId.equals(item.getSubmissionId())){ + List items = itemMap.get(userSubmissionId); + if(items == null){ + items = new ArrayList(); + } + items.add(item); + itemMap.put(item.getSubmissionId(), items); + } + } + } + for(int i = 0; i < userSubmissions.size(); i++){ + String userSubmissionId = userSubmissions.get(i); + if(userSubmissionId.equals(submissionId)){ + //we found the right submission, now find the items + context.put("reviewNumber", (i + 1)); + List submissionItems = itemMap.get(submissionId); + if(submissionItems != null){ + for (int j = 0; j < submissionItems.size(); j++){ + PeerAssessmentItem item = submissionItems.get(j); + if(item.getAssessorUserId().equals(assessorId)){ + context.put("anonNumber", i + 1); + boolean goPT = false; + boolean goNT = false; + if ((i - 1) >= 0 || (j - 1) >= 0) + { + goPT = true; + } + if ((i + 1) < userSubmissions.size() || (j + 1) < submissionItems.size()) + { + goNT = true; + } + context.put("goPTButton", Boolean.valueOf(goPT)); + context.put("goNTButton", Boolean.valueOf(goNT)); + + if (j>0) + { + // retrieve the previous submission id + context.put("prevSubmissionId", (submissionItems.get(j-1).getSubmissionId())); + context.put("prevAssessorId", (submissionItems.get(j-1).getAssessorUserId())); + }else if(i > 0){ + //go to previous submission and grab the last item in that list + int k = i - 1; + while(k >= 0 && !itemMap.containsKey(userSubmissions.get(k))){ + k--; + } + if(k >= 0 && itemMap.get(userSubmissions.get(k)).size() > 0){ + List pItems = itemMap.get(userSubmissions.get(k)); + PeerAssessmentItem pItem = pItems.get(pItems.size() - 1); + context.put("prevSubmissionId", (pItem.getSubmissionId())); + context.put("prevAssessorId", (pItem.getAssessorUserId())); + }else{ + //no previous option, set to false + context.put("goPTButton", Boolean.valueOf(false)); + } + } + + if (j < submissionItems.size() - 1) + { + // retrieve the next submission id + context.put("nextSubmissionId", (submissionItems.get(j+1).getSubmissionId())); + context.put("nextAssessorId", (submissionItems.get(j+1).getAssessorUserId())); + }else if (i < userSubmissions.size() - 1){ + //go to previous submission and grab the last item in that list + int k = i + 1; + while(k < userSubmissions.size() && !itemMap.containsKey(userSubmissions.get(k))){ + k++; + } + if(k < userSubmissions.size() && itemMap.get(userSubmissions.get(k)).size() > 0){ + List pItems = itemMap.get(userSubmissions.get(k)); + PeerAssessmentItem pItem = pItems.get(0); + context.put("nextSubmissionId", (pItem.getSubmissionId())); + context.put("nextAssessorId", (pItem.getAssessorUserId())); + }else{ + //no next option, set to false + context.put("goNTButton", Boolean.valueOf(false)); + } + } + } + } + } + } + } + } + /*else{ + //not an instructor, so no need to worry about submission order + for (int i = 0; i < peerAssessmentItems.size(); i++) + { + if (peerAssessmentItems.get(i).getSubmissionId().equals(submissionId) + && assessorId.equals(peerAssessmentItems.get(i).getAssessorUserId())) + { + context.put("anonNumber", i + 1); + boolean goPT = false; + boolean goNT = false; + if ((i - 1) >= 0) + { + goPT = true; + } + if ((i + 1) < peerAssessmentItems.size()) + { + goNT = true; + } + context.put("goPTButton", Boolean.valueOf(goPT)); + context.put("goNTButton", Boolean.valueOf(goNT)); + + if (i>0) + { + // retrieve the previous submission id + context.put("prevSubmissionId", (peerAssessmentItems.get(i-1).getSubmissionId())); + context.put("prevAssessorId", (peerAssessmentItems.get(i-1).getAssessorUserId())); + } + + if (i < peerAssessmentItems.size() - 1) + { + // retrieve the next submission id + context.put("nextSubmissionId", (peerAssessmentItems.get(i+1).getSubmissionId())); + context.put("nextAssessorId", (peerAssessmentItems.get(i+1).getAssessorUserId())); + } + } + } + }*/ + } + + } + + context.put("assignment_expand_flag", state.getAttribute(GRADE_SUBMISSION_ASSIGNMENT_EXPAND_FLAG)); + context.put("user", sessionUser); + context.put("submissionTypeTable", submissionTypeTable()); + context.put("instructorAttachments", state.getAttribute(ATTACHMENTS)); + context.put("contentTypeImageService", state.getAttribute(STATE_CONTENT_TYPE_IMAGE_SERVICE)); + context.put("service", AssignmentService.getInstance()); + // names + context.put("name_grade_assignment_id", GRADE_SUBMISSION_ASSIGNMENT_ID); + context.put("name_feedback_comment", GRADE_SUBMISSION_FEEDBACK_COMMENT); + context.put("name_feedback_text", GRADE_SUBMISSION_FEEDBACK_TEXT); + context.put("name_feedback_attachment", GRADE_SUBMISSION_FEEDBACK_ATTACHMENT); + context.put("name_grade", GRADE_SUBMISSION_GRADE); + context.put("name_allowResubmitNumber", AssignmentSubmission.ALLOW_RESUBMIT_NUMBER); + // put supplement item into context + try{ + //surround with a try/catch/finally for the security advisor + m_securityService.pushAdvisor(secAdv); + supplementItemIntoContext(state, context, assignment, null); + }catch(Exception e){ + M_log.error(e.getMessage(), e); + }finally{ + if(secAdv != null){ + m_securityService.popAdvisor(secAdv); + } + } + // put the grade confirmation message if applicable + if (state.getAttribute(GRADE_SUBMISSION_DONE) != null) + { + context.put("gradingDone", Boolean.TRUE); + state.removeAttribute(GRADE_SUBMISSION_DONE); + if(state.getAttribute(PEER_ASSESSMENT_REMOVED_STATUS) != null){ + context.put("itemRemoved", state.getAttribute(PEER_ASSESSMENT_REMOVED_STATUS)); + state.removeAttribute(PEER_ASSESSMENT_REMOVED_STATUS); + } + } + // put the grade confirmation message if applicable + if (state.getAttribute(GRADE_SUBMISSION_SUBMIT) != null) + { + context.put("gradingSubmit", Boolean.TRUE); + state.removeAttribute(GRADE_SUBMISSION_SUBMIT); + } + + String template = (String) getContext(data).get("template"); + return template + TEMPLATE_STUDENT_REVIEW_EDIT; + } + /** * build the instructor view to view the list of students for an assignment */ @@ -3904,6 +4424,7 @@ state.removeAttribute(GRADE_SUBMISSION_SUBMISSION_ID); state.removeAttribute(GRADE_GREATER_THAN_MAX_ALERT); state.removeAttribute(GRADE_SUBMISSION_DONE); + state.removeAttribute(GRADE_SUBMISSION_SUBMIT); state.removeAttribute(AssignmentSubmission.ALLOW_RESUBMIT_NUMBER); resetAllowResubmitParams(state); } @@ -3984,6 +4505,73 @@ } // doSave_grade_submission + public void doSave_grade_submission_review(RunData data) + { + SessionState state = ((JetspeedRunData) data).getPortletSessionState(((JetspeedRunData) data).getJs_peid()); + saveReviewGradeForm(data, state, "save"); + } + + public void doSave_toggle_remove_review(RunData data) + { + SessionState state = ((JetspeedRunData) data).getPortletSessionState(((JetspeedRunData) data).getJs_peid()); + if(state.getAttribute(PEER_ASSESSMENT_ASSESSOR_ID) != null){ + String peerAssessor = (String) state.getAttribute(PEER_ASSESSMENT_ASSESSOR_ID); + ParameterParser params = data.getParameters(); + String submissionRef = params.getString("submissionId"); + String submissionId = null; + if(submissionRef != null){ + int i = submissionRef.lastIndexOf(Entity.SEPARATOR); + if (i == -1){ + submissionId = submissionRef; + }else{ + submissionId = submissionRef.substring(i + 1); + } + } + if(submissionId != null){ + //call the DB to make sure this user can edit this assessment, otherwise it wouldn't exist + PeerAssessmentItem item = assignmentPeerAssessmentService.getPeerAssessmentItem(submissionId, peerAssessor); + if(item != null){ + item.setRemoved(!item.isRemoved()); + assignmentPeerAssessmentService.savePeerAssessmentItem(item); + if(item.getScore() != null){ + //item was part of the calculation, re-calculate + boolean saved = assignmentPeerAssessmentService.updateScore(submissionId); + if(saved){ + //we need to make sure the GB is updated correctly (or removed) + String assignmentId = item.getAssignmentId(); + if(assignmentId != null){ + Assignment a = getAssignment(assignmentId, "saveReviewGradeForm", state); + if(a != null){ + String aReference = a.getReference(); + String associateGradebookAssignment = StringUtils.trimToNull(a.getProperties().getProperty(AssignmentService.PROP_ASSIGNMENT_ASSOCIATE_GRADEBOOK_ASSIGNMENT)); + // update grade in gradebook + integrateGradebook(state, aReference, associateGradebookAssignment, null, null, null, -1, null, submissionId, "update", -1); + } + } + } + } + state.setAttribute(GRADE_SUBMISSION_DONE, Boolean.TRUE); + state.setAttribute(PEER_ASSESSMENT_REMOVED_STATUS, item.isRemoved()); + //update session state: + List peerAssessmentItems = (List) state.getAttribute(PEER_ASSESSMENT_ITEMS); + if(peerAssessmentItems != null){ + for(int i = 0; i < peerAssessmentItems.size(); i++) { + PeerAssessmentItem sItem = peerAssessmentItems.get(i); + if(sItem.getSubmissionId().equals(item.getSubmissionId()) + && sItem.getAssessorUserId().equals(item.getAssessorUserId())){ + //found it, just update it + peerAssessmentItems.set(i, item); + state.setAttribute(PEER_ASSESSMENT_ITEMS, peerAssessmentItems); + break; + } + } + } + } + } + } + } + + /** * Action is to release the grade to submission */ @@ -4048,6 +4636,18 @@ AssignmentSubmissionEdit sEdit = editSubmission(sId, "grade_submission_option", state); if (sEdit != null) { + //This logic could be done in one line, but would be harder to read, so break it out to make it easier to follow + boolean gradeChanged = false; + if((sEdit.getGrade() == null || "".equals(sEdit.getGrade().trim())) + && (grade == null || "".equals(grade.trim()))){ + //both are null, keep grade changed = false + }else if((sEdit.getGrade() == null || "".equals(sEdit.getGrade().trim()) + || (grade == null || "".equals(grade.trim())))){ + //one is null the other isn't + gradeChanged = true; + }else if(!grade.trim().equals(sEdit.getGrade().trim())){ + gradeChanged = true; + } Assignment a = sEdit.getAssignment(); int typeOfGrade = a.getContent().getTypeOfGrade(); @@ -4055,6 +4655,9 @@ { // no grade input needed for the without-grade version of assignment tool sEdit.setGraded(true); + if(gradeChanged){ + sEdit.setGradedBy(UserDirectoryService.getCurrentUser() == null ? null : UserDirectoryService.getCurrentUser().getId()); + } if ("return".equals(gradeOption) || "release".equals(gradeOption)) { sEdit.setGradeReleased(true); @@ -4064,19 +4667,28 @@ { sEdit.setGrade(""); sEdit.setGraded(false); + if(gradeChanged){ + sEdit.setGradedBy(null); + } sEdit.setGradeReleased(false); } else { sEdit.setGrade(grade); - + if (grade.length() != 0) { sEdit.setGraded(true); + if(gradeChanged){ + sEdit.setGradedBy(UserDirectoryService.getCurrentUser() == null ? null : UserDirectoryService.getCurrentUser().getId()); + } } else { sEdit.setGraded(false); + if(gradeChanged){ + sEdit.setGradedBy(null); + } } } @@ -4084,6 +4696,9 @@ { sEdit.setGradeReleased(true); sEdit.setGraded(true); + if(gradeChanged){ + sEdit.setGradedBy(UserDirectoryService.getCurrentUser() == null ? null : UserDirectoryService.getCurrentUser().getId()); + } // clear the returned flag sEdit.setReturned(false); sEdit.setTimeReturned(null); @@ -4092,6 +4707,9 @@ { sEdit.setGradeReleased(true); sEdit.setGraded(true); + if(gradeChanged){ + sEdit.setGradedBy(UserDirectoryService.getCurrentUser() == null ? null : UserDirectoryService.getCurrentUser().getId()); + } sEdit.setReturned(true); sEdit.setTimeReturned(TimeService.newTime()); sEdit.setHonorPledgeFlag(Boolean.FALSE.booleanValue()); @@ -4392,6 +5010,7 @@ // clear the current grade and make the submission ungraded sEdit.setGraded(false); + sEdit.setGradedBy(null); sEdit.setGrade(""); sEdit.setGradeReleased(false); @@ -4740,6 +5359,8 @@ state.setAttribute(NEW_ASSIGNMENT_SECTION, sections_string); state.setAttribute(NEW_ASSIGNMENT_SUBMISSION_TYPE, Integer.valueOf(params.getString(NEW_ASSIGNMENT_SUBMISSION_TYPE))); + Integer submissionType = Integer.valueOf(params.getString(NEW_ASSIGNMENT_SUBMISSION_TYPE)); + state.setAttribute(NEW_ASSIGNMENT_SUBMISSION_TYPE, submissionType); // Skip category if it was never set. Long catInt = Long.valueOf(-1); @@ -4756,9 +5377,72 @@ state.setAttribute(NEW_ASSIGNMENT_GRADE_TYPE, Integer.valueOf(gradeType)); } + //Peer Assessment + boolean peerAssessment = false; + String r = params.getString(NEW_ASSIGNMENT_USE_PEER_ASSESSMENT); + String b; + if (r == null){ + b = Boolean.FALSE.toString(); + }else{ + b = Boolean.TRUE.toString(); + peerAssessment = true; + } + state.setAttribute(NEW_ASSIGNMENT_USE_PEER_ASSESSMENT, b); + if(peerAssessment){ + //do not allow non-electronic assignments + if(Assignment.NON_ELECTRONIC_ASSIGNMENT_SUBMISSION == submissionType){ + addAlert(state, rb.getString("peerassessment.invliadSubmissionTypeAssignment")); + } + if (gradeType != Assignment.SCORE_GRADE_TYPE){ + addAlert(state, rb.getString("peerassessment.invliadGradeTypeAssignment")); + } - String r = params.getString(NEW_ASSIGNMENT_USE_REVIEW_SERVICE); - String b; + + Time peerPeriodTime = putTimeInputInState(params, state, NEW_ASSIGNMENT_PEERPERIODMONTH, NEW_ASSIGNMENT_PEERPERIODDAY, NEW_ASSIGNMENT_PEERPERIODYEAR, NEW_ASSIGNMENT_PEERPERIODHOUR, NEW_ASSIGNMENT_PEERPERIODMIN, NEW_ASSIGNMENT_PEERPERIODAMPM, "newassig.opedat"); + GregorianCalendar peerPeriodMinTimeCal = new GregorianCalendar(); + peerPeriodMinTimeCal.setTimeInMillis(closeTime.getTime()); + peerPeriodMinTimeCal.add(GregorianCalendar.MINUTE, 10); + GregorianCalendar peerPeriodTimeCal = new GregorianCalendar(); + peerPeriodTimeCal.setTimeInMillis(peerPeriodTime.getTime()); + //peer assessment must complete at a minimum of 10 mins after close time + if(peerPeriodTimeCal.before(peerPeriodMinTimeCal)){ + addAlert(state, rb.getString("peerassessment.invliadPeriodTime")); + } + } + + + r = params.getString(NEW_ASSIGNMENT_PEER_ASSESSMENT_ANON_EVAL); + if (r == null) b = Boolean.FALSE.toString(); + else b = Boolean.TRUE.toString(); + state.setAttribute(NEW_ASSIGNMENT_PEER_ASSESSMENT_ANON_EVAL, b); + + r = params.getString(NEW_ASSIGNMENT_PEER_ASSESSMENT_STUDENT_VIEW_REVIEWS); + if (r == null) b = Boolean.FALSE.toString(); + else b = Boolean.TRUE.toString(); + state.setAttribute(NEW_ASSIGNMENT_PEER_ASSESSMENT_STUDENT_VIEW_REVIEWS, b); + if(peerAssessment){ + if(params.get(NEW_ASSIGNMENT_PEER_ASSESSMENT_NUM_REVIEWS) != null && !"".equals(params.get(NEW_ASSIGNMENT_PEER_ASSESSMENT_NUM_REVIEWS))){ + try{ + int peerAssessmentNumOfReviews = Integer.parseInt(params.getString(NEW_ASSIGNMENT_PEER_ASSESSMENT_NUM_REVIEWS)); + if(peerAssessmentNumOfReviews > 0){ + state.setAttribute(NEW_ASSIGNMENT_PEER_ASSESSMENT_NUM_REVIEWS, Integer.valueOf(peerAssessmentNumOfReviews)); + }else{ + addAlert(state, rb.getString("peerassessment.invalidNumReview")); + } + }catch(Exception e){ + addAlert(state, rb.getString("peerassessment.invalidNumReview")); + } + }else{ + addAlert(state, rb.getString("peerassessment.specifyNumReview")); + } + } + + String peerAssessmentInstructions = processFormattedTextFromBrowser(state, params.getString(NEW_ASSIGNMENT_PEER_ASSESSMENT_INSTRUCTIONS), true); + state.setAttribute(NEW_ASSIGNMENT_PEER_ASSESSMENT_INSTRUCTIONS, peerAssessmentInstructions); + + //REVIEW SERVICE + r = params.getString(NEW_ASSIGNMENT_USE_REVIEW_SERVICE); + // set whether we use the review service or not if (r == null) b = Boolean.FALSE.toString(); else b = Boolean.TRUE.toString(); @@ -5290,6 +5974,28 @@ } // doHide_preview_assignment_student_view /** + *Action is to hide the preview assignment student view + */ + public void doHide_submission_assignment_instruction_review(RunData data) + { + SessionState state = ((JetspeedRunData) data).getPortletSessionState(((JetspeedRunData) data).getJs_peid()); + state.setAttribute(GRADE_SUBMISSION_ASSIGNMENT_EXPAND_FLAG, Boolean.valueOf(false)); + + // save user input + saveReviewGradeForm(data, state, "read"); + + } + + public void doShow_submission_assignment_instruction_review(RunData data) + { + SessionState state = ((JetspeedRunData) data).getPortletSessionState(((JetspeedRunData) data).getJs_peid()); + state.setAttribute(GRADE_SUBMISSION_ASSIGNMENT_EXPAND_FLAG, Boolean.valueOf(true)); + + // save user input + saveReviewGradeForm(data, state, "read"); + } + + /** * Action is to show the preview assignment student view */ public void doShow_submission_assignment_instruction(RunData data) @@ -5588,7 +6294,18 @@ // resubmit option is not allowed for non-electronic type allowResubmitNumber = null; } - + //Peer Assessment + boolean usePeerAssessment = "true".equalsIgnoreCase((String) state.getAttribute(NEW_ASSIGNMENT_USE_PEER_ASSESSMENT)); + Time peerPeriodTime = getTimeFromState(state, NEW_ASSIGNMENT_PEERPERIODMONTH, NEW_ASSIGNMENT_PEERPERIODDAY, NEW_ASSIGNMENT_PEERPERIODYEAR, NEW_ASSIGNMENT_PEERPERIODHOUR, NEW_ASSIGNMENT_PEERPERIODMIN, NEW_ASSIGNMENT_PEERPERIODAMPM); + boolean peerAssessmentAnonEval = "true".equalsIgnoreCase((String) state.getAttribute(NEW_ASSIGNMENT_PEER_ASSESSMENT_ANON_EVAL)); + boolean peerAssessmentStudentViewReviews = "true".equalsIgnoreCase((String) state.getAttribute(NEW_ASSIGNMENT_PEER_ASSESSMENT_STUDENT_VIEW_REVIEWS)); + int peerAssessmentNumReviews = 0; + if(state.getAttribute(NEW_ASSIGNMENT_PEER_ASSESSMENT_NUM_REVIEWS) != null){ + peerAssessmentNumReviews = ((Integer) state.getAttribute(NEW_ASSIGNMENT_PEER_ASSESSMENT_NUM_REVIEWS)).intValue(); + } + String peerAssessmentInstructions = (String) state.getAttribute(NEW_ASSIGNMENT_PEER_ASSESSMENT_INSTRUCTIONS); + + //Review Service boolean useReviewService = "true".equalsIgnoreCase((String) state.getAttribute(NEW_ASSIGNMENT_USE_REVIEW_SERVICE)); boolean allowStudentViewReport = "true".equalsIgnoreCase((String) state.getAttribute(NEW_ASSIGNMENT_ALLOW_STUDENT_VIEW)); @@ -5667,8 +6384,8 @@ } // comment the changes to Assignment object - commitAssignmentEdit(state, post, ac, a, title, openTime, dueTime, closeTime, enableCloseDate, section, range, groups); - + commitAssignmentEdit(state, post, ac, a, title, openTime, dueTime, closeTime, enableCloseDate, section, range, groups, + usePeerAssessment,peerPeriodTime, peerAssessmentAnonEval, peerAssessmentStudentViewReviews, peerAssessmentNumReviews, peerAssessmentInstructions); if (post) { // we need to update the submission @@ -5695,6 +6412,7 @@ // set the grade to be empty for now sEdit.setGrade(""); sEdit.setGraded(false); + sEdit.setGradedBy(null); sEdit.setGradeReleased(false); sEdit.setReturned(false); } @@ -6555,7 +7273,8 @@ } } - private void commitAssignmentEdit(SessionState state, boolean post, AssignmentContentEdit ac, AssignmentEdit a, String title, Time openTime, Time dueTime, Time closeTime, boolean enableCloseDate, String s, String range, Collection groups) + private void commitAssignmentEdit(SessionState state, boolean post, AssignmentContentEdit ac, AssignmentEdit a, String title, Time openTime, Time dueTime, Time closeTime, boolean enableCloseDate, String s, String range, Collection groups, + boolean usePeerAssessment, Time peerPeriodTime, boolean peerAssessmentAnonEval, boolean peerAssessmentStudentViewReviews, int peerAssessmentNumReviews, String peerAssessmentInstructions) { a.setTitle(title); a.setContent(ac); @@ -6577,7 +7296,14 @@ a.setCloseTime(null); } } - + + a.setAllowPeerAssessment(usePeerAssessment); + a.setPeerAssessmentPeriod(peerPeriodTime); + a.setPeerAssessmentAnonEval(peerAssessmentAnonEval); + a.setPeerAssessmentStudentViewReviews(peerAssessmentStudentViewReviews); + a.setPeerAssessmentNumReviews(peerAssessmentNumReviews); + a.setPeerAssessmentInstructions(peerAssessmentInstructions); + // post the assignment a.setDraft(!post); @@ -6971,6 +7697,79 @@ } // doView_assignment_as_student + 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 assignmentId = StringUtils.trimToNull(data.getParameters().getString("assignmentId")); + Assignment a = getAssignment(assignmentId, "doEdit_assignment", state); + if (submissionId != null && !"".equals(submissionId) && a != null){ + //set the page to go to + state.setAttribute(VIEW_ASSIGNMENT_ID, assignmentId); + List peerAssessmentItems = assignmentPeerAssessmentService.getPeerAssessmentItemsByAssignmentId(a.getId()); + state.setAttribute(PEER_ASSESSMENT_ITEMS, peerAssessmentItems); + List submissionIds = new ArrayList(); + if(peerAssessmentItems != null){ + for(PeerAssessmentItem item : peerAssessmentItems){ + submissionIds.add(item.getSubmissionId()); + } + } + state.setAttribute(USER_SUBMISSIONS, submissionIds); + state.setAttribute(GRADE_SUBMISSION_SUBMISSION_ID, submissionId); + state.setAttribute(PEER_ASSESSMENT_ASSESSOR_ID, assessorId); + state.setAttribute(STATE_MODE, MODE_STUDENT_REVIEW_EDIT); + }else{ + addAlert(state, rb.getString("peerassessment.notavailable")); + } + } + + public void doEdit_review(RunData data){ + SessionState state = ((JetspeedRunData) data).getPortletSessionState(((JetspeedRunData) data).getJs_peid()); + ParameterParser params = data.getParameters(); + + String assignmentId = StringUtils.trimToNull(params.getString("assignmentId")); + Assignment a = getAssignment(assignmentId, "doEdit_assignment", state); + if (a != null && a.isPeerAssessmentOpen()){ + //set the page to go to + state.setAttribute(VIEW_ASSIGNMENT_ID, assignmentId); + String submissionId = null; + List peerAssessmentItems = assignmentPeerAssessmentService.getPeerAssessmentItems(a.getId(), UserDirectoryService.getCurrentUser().getId()); + state.setAttribute(PEER_ASSESSMENT_ITEMS, peerAssessmentItems); + List submissionIds = new ArrayList(); + if(peerAssessmentItems != null){ + for(PeerAssessmentItem item : peerAssessmentItems){ + if(!item.isSubmitted()){ + submissionIds.add(item.getSubmissionId()); + } + } + } + if(params.getString("submissionId") != null && submissionIds.contains(params.getString("submissionId"))){ + submissionId = StringUtils.trimToNull(params.getString("submissionId")); + }else if(submissionIds.size() > 0){ + //submission Id wasn't passed in, let's find one for this user + //grab the first one: + submissionId = submissionIds.get(0); + } + + if(submissionId != null){ + state.setAttribute(USER_SUBMISSIONS, submissionIds); + state.setAttribute(GRADE_SUBMISSION_SUBMISSION_ID, submissionId); + state.setAttribute(STATE_MODE, MODE_STUDENT_REVIEW_EDIT); + }else{ + if(peerAssessmentItems != null && peerAssessmentItems.size() > 0){ + //student has submitted all their peer reviews, nothing left to review + //(student really shouldn't get to this warning) + addAlert(state, rb.getString("peerassessment.allSubmitted")); + }else{ + //wasn't able to find a submission id, throw error + addAlert(state, rb.getString("peerassessment.notavailable")); + } + } + }else{ + addAlert(state, rb.getString("peerassessment.notavailable")); + } + } + /** * Action is to show the edit assignment screen */ @@ -7114,6 +7913,17 @@ // put the resubmission option into state assignment_resubmission_option_into_state(a, null, state); + // set whether we use peer assessment or not + if(a.getPeerAssessmentPeriod() != null){ + + state.setAttribute(NEW_ASSIGNMENT_USE_PEER_ASSESSMENT, Boolean.valueOf(a.getAllowPeerAssessment()).toString()); + putTimePropertiesInState(state, a.getPeerAssessmentPeriod(), NEW_ASSIGNMENT_PEERPERIODMONTH, NEW_ASSIGNMENT_PEERPERIODDAY, NEW_ASSIGNMENT_PEERPERIODYEAR, NEW_ASSIGNMENT_PEERPERIODHOUR, NEW_ASSIGNMENT_PEERPERIODMIN, NEW_ASSIGNMENT_PEERPERIODAMPM); + state.setAttribute(NEW_ASSIGNMENT_PEER_ASSESSMENT_ANON_EVAL, Boolean.valueOf(a.getPeerAssessmentAnonEval()).toString()); + state.setAttribute(NEW_ASSIGNMENT_PEER_ASSESSMENT_STUDENT_VIEW_REVIEWS, Boolean.valueOf(a.getPeerAssessmentStudentViewReviews()).toString()); + state.setAttribute(NEW_ASSIGNMENT_PEER_ASSESSMENT_NUM_REVIEWS, a.getPeerAssessmentNumReviews()); + state.setAttribute(NEW_ASSIGNMENT_PEER_ASSESSMENT_INSTRUCTIONS, a.getPeerAssessmentInstructions()); + } + // set whether we use the review service or not state.setAttribute(NEW_ASSIGNMENT_USE_REVIEW_SERVICE, Boolean.valueOf(a.getContent().getAllowReviewService()).toString()); @@ -8075,6 +8885,28 @@ // save grading doSave_grade_submission(data); } + else if ("savegrade_review".equals(option)) + { + // save review grading + doSave_grade_submission_review(data); + }else if("submitgrade_review".equals(option)){ + //we basically need to submit, save, and move the user to the next review (if available) + if(data.getParameters().get("nextSubmissionId") != null){ + //go next + doPrev_back_next_submission_review(data, "next", true); + }else if(data.getParameters().get("prevSubmissionId") != null){ + //go previous + doPrev_back_next_submission_review(data, "prev", true); + }else{ + //go back to the list + doPrev_back_next_submission_review(data, "back", true); + } + } + else if ("toggleremove_review".equals(option)) + { + // save review grading + doSave_toggle_remove_review(data); + } else if ("previewgrade".equals(option)) { // preview grading @@ -8085,6 +8917,11 @@ // cancel grading doCancel_grade_submission(data); } + else if ("cancelgrade_review".equals(option)) + { + // cancel grade review + // no need to do anything, session will have original values and refresh + } else if ("cancelreorder".equals(option)) { // cancel reordering @@ -8111,11 +8948,21 @@ // hide the assignment instruction doHide_submission_assignment_instruction(data); } + else if ("hide_instruction_review".equals(option)) + { + // hide the assignment instruction + doHide_submission_assignment_instruction_review(data); + } else if ("show_instruction".equals(option)) { // show the assignment instruction doShow_submission_assignment_instruction(data); } + else if ("show_instruction_review".equals(option)) + { + // show the assignment instruction + doShow_submission_assignment_instruction_review(data); + } else if ("sortbygroupdescription".equals(option)) { // show the assignment instruction @@ -8136,6 +8983,16 @@ // save and navigate to previous submission doPrev_back_next_submission(data, "next"); } + else if ("prevsubmission_review".equals(option)) + { + // save and navigate to previous submission + doPrev_back_next_submission_review(data, "prev", false); + } + else if ("nextsubmission_review".equals(option)) + { + // save and navigate to previous submission + doPrev_back_next_submission_review(data, "next", false); + } else if ("cancelgradesubmission".equals(option)) { if (MODE_INSTRUCTOR_VIEW_STUDENTS_ASSIGNMENT.equals(fromView)) { @@ -8146,6 +9003,11 @@ doPrev_back_next_submission(data, "back"); } } + else if ("cancelgradesubmission_review".equals(option)) + { + // save and navigate to previous submission + doPrev_back_next_submission_review(data, "back", false); + } else if ("reorderNavigation".equals(option)) { // save and do reorder @@ -8343,7 +9205,159 @@ state.setAttribute(VIEW_SUBMISSION_HONOR_PLEDGE_YES, "true"); } } + + /** + * read review grade information form and see if any grading information has been changed + * @param data + * @param state + * @param gradeOption + * @return + */ +public boolean saveReviewGradeForm(RunData data, SessionState state, String gradeOption){ + String assessorUserId = UserDirectoryService.getCurrentUser().getId(); + if(state.getAttribute(PEER_ASSESSMENT_ASSESSOR_ID) != null && !assessorUserId.equals(state.getAttribute(PEER_ASSESSMENT_ASSESSOR_ID))){ + //this is only set during the read only view, so just return + return false; + } + ParameterParser params = data.getParameters(); + String submissionRef = params.getString("submissionId"); + String submissionId = null; + if(submissionRef != null){ + int i = submissionRef.lastIndexOf(Entity.SEPARATOR); + if (i == -1){ + submissionId = submissionRef; + }else{ + submissionId = submissionRef.substring(i + 1); + } + } + if(submissionId != null){ + //call the DB to make sure this user can edit this assessment, otherwise it wouldn't exist + PeerAssessmentItem item = assignmentPeerAssessmentService.getPeerAssessmentItem(submissionId, assessorUserId); + if(item != null){ + //find the original assessment item and compare to see if it has changed + //if so, save it + boolean changed = false; + + if(submissionId.equals(item.getSubmissionId()) + && assessorUserId.equals(item.getAssessorUserId())){ + //Grade + String g = StringUtils.trimToNull(params.getCleanString(GRADE_SUBMISSION_GRADE)); + Integer score = item.getScore(); + if(g != null && !"".equals(g)){ + try{ + Double dScore = Double.parseDouble(g); + if(dScore < 0){ + addAlert(state, rb.getString("peerassessment.alert.saveinvalidscore")); + }else{ + String assignmentId = (String) state.getAttribute(VIEW_ASSIGNMENT_ID); + if(assignmentId != null){ + Assignment a = getAssignment(assignmentId, "saveReviewGradeForm", state); + if(a != null){ + if(dScore <= a.getContent().getMaxGradePoint()/10.0){ + //scores are saved as whole values + //so a score of 1.3 would be stored as 13 + score = (int) Math.round(dScore * 10); + }else{ + addAlert(state, rb.getFormattedMessage("plesuse4", new Object[]{g, a.getContent().getMaxGradePoint()/10.0})); + } + }else{ + addAlert(state, rb.getString("peerassessment.alert.saveerrorunkown")); + } + }else{ + addAlert(state, rb.getString("peerassessment.alert.saveerrorunkown")); + } + } + }catch(Exception e){ + addAlert(state, rb.getString("peerassessment.alert.saveinvalidscore")); + } + } + boolean scoreChanged = false; + if(score != null && item.getScore() == null + || score == null && item.getScore() != null + || (score != null && item.getScore() != null && !score.equals(item.getScore()))){ + //Score changed + changed = true; + scoreChanged = true; + item.setScore(score); + } + + //Comment: + boolean checkForFormattingErrors = true; + String feedbackComment = processFormattedTextFromBrowser(state, params.getCleanString(GRADE_SUBMISSION_FEEDBACK_COMMENT), + checkForFormattingErrors); + if(feedbackComment != null && item.getComment() == null + || feedbackComment == null && item.getComment() != null + || (feedbackComment != null && item.getComment() != null && !feedbackComment.equals(item.getComment()))){ + //comment changed + changed = true; + item.setComment(feedbackComment); + } + //Submitted + if("submit".equals(gradeOption)){ + if(item.getScore() != null || (item.getComment() != null && !"".equals(item.getComment().trim()))){ + item.setSubmitted(true); + changed = true; + }else{ + addAlert(state, rb.getString("peerassessment.alert.savenoscorecomment")); + } + } + if(("submit".equals(gradeOption) || "save".equals(gradeOption)) && state.getAttribute(STATE_MESSAGE) == null){ + if(changed){ + //save this in the DB + assignmentPeerAssessmentService.savePeerAssessmentItem(item); + if(scoreChanged){ + //need to re-calcuate the overall score: + boolean saved = assignmentPeerAssessmentService.updateScore(submissionId); + if(saved){ + //we need to make sure the GB is updated correctly (or removed) + String assignmentId = (String) state.getAttribute(VIEW_ASSIGNMENT_ID); + if(assignmentId != null){ + Assignment a = getAssignment(assignmentId, "saveReviewGradeForm", state); + if(a != null){ + String aReference = a.getReference(); + String associateGradebookAssignment = StringUtils.trimToNull(a.getProperties().getProperty(AssignmentService.PROP_ASSIGNMENT_ASSOCIATE_GRADEBOOK_ASSIGNMENT)); + // update grade in gradebook + integrateGradebook(state, aReference, associateGradebookAssignment, null, null, null, -1, null, submissionId, "update", -1); + } + } + } + } + state.setAttribute(GRADE_SUBMISSION_DONE, Boolean.TRUE); + if("submit".equals(gradeOption)){ + state.setAttribute(GRADE_SUBMISSION_SUBMIT, Boolean.TRUE); + } + } + } + + //update session state: + List peerAssessmentItems = (List) state.getAttribute(PEER_ASSESSMENT_ITEMS); + if(peerAssessmentItems != null){ + for(int i = 0; i < peerAssessmentItems.size(); i++) { + PeerAssessmentItem sItem = peerAssessmentItems.get(i); + if(sItem.getSubmissionId().equals(item.getSubmissionId()) + && sItem.getAssessorUserId().equals(item.getAssessorUserId())){ + //found it, just update it + peerAssessmentItems.set(i, item); + state.setAttribute(PEER_ASSESSMENT_ITEMS, peerAssessmentItems); + break; + } + } + } + + } + + return changed; + }else{ + addAlert(state, rb.getString("peerassessment.alert.saveerrorunkown")); + } + }else{ + addAlert(state, rb.getString("peerassessment.alert.saveerrorunkown")); + + } + return false; + } + /** * read grade information form and see if any grading information has been changed * @param data @@ -8682,6 +9696,9 @@ m_securityService = (SecurityService) ComponentManager.get("org.sakaiproject.authz.api.SecurityService"); } + if(assignmentPeerAssessmentService == null){ + assignmentPeerAssessmentService = (AssignmentPeerAssessmentService) ComponentManager.get("org.sakaiproject.assignment.api.AssignmentPeerAssessmentService"); + } String siteId = ToolManager.getCurrentPlacement().getContext(); @@ -9030,7 +10047,18 @@ state.setAttribute(ALLPURPOSE_RETRACT_HOUR, Integer.valueOf(5)); state.setAttribute(ALLPURPOSE_RETRACT_MIN, Integer.valueOf(0)); state.setAttribute(ALLPURPOSE_RETRACT_AMPM, "PM"); - + + // set the peer period time to be 10 mins after accept until date + state.setAttribute(NEW_ASSIGNMENT_PEERPERIODMONTH, Integer.valueOf(month)); + state.setAttribute(NEW_ASSIGNMENT_PEERPERIODDAY, Integer.valueOf(day)); + state.setAttribute(NEW_ASSIGNMENT_PEERPERIODYEAR, Integer.valueOf(year)); + state.setAttribute(NEW_ASSIGNMENT_PEERPERIODHOUR, Integer.valueOf(5)); + state.setAttribute(NEW_ASSIGNMENT_PEERPERIODMIN, Integer.valueOf(10)); + state.setAttribute(NEW_ASSIGNMENT_PEERPERIODAMPM, "PM"); + state.setAttribute(NEW_ASSIGNMENT_PEER_ASSESSMENT_ANON_EVAL, Boolean.TRUE.toString()); + state.setAttribute(NEW_ASSIGNMENT_PEER_ASSESSMENT_STUDENT_VIEW_REVIEWS, Boolean.TRUE.toString()); + state.setAttribute(NEW_ASSIGNMENT_PEER_ASSESSMENT_NUM_REVIEWS, 1); + state.setAttribute(NEW_ASSIGNMENT_SECTION, "001"); state.setAttribute(NEW_ASSIGNMENT_SUBMISSION_TYPE, Integer.valueOf(Assignment.TEXT_AND_ATTACHMENT_ASSIGNMENT_SUBMISSION)); state.setAttribute(NEW_ASSIGNMENT_GRADE_TYPE, Integer.valueOf(Assignment.UNGRADED_GRADE_TYPE)); @@ -9175,11 +10203,37 @@ state.removeAttribute(ALLPURPOSE_ACCESS); state.removeAttribute(ALLPURPOSE_ATTACHMENTS); + //revmoew peer assessment settings + state.removeAttribute(NEW_ASSIGNMENT_USE_PEER_ASSESSMENT); + state.removeAttribute(NEW_ASSIGNMENT_PEERPERIODMONTH); + state.removeAttribute(NEW_ASSIGNMENT_PEERPERIODDAY); + state.removeAttribute(NEW_ASSIGNMENT_PEERPERIODYEAR); + state.removeAttribute(NEW_ASSIGNMENT_PEERPERIODHOUR); + state.removeAttribute(NEW_ASSIGNMENT_PEERPERIODMIN); + state.removeAttribute(NEW_ASSIGNMENT_PEERPERIODAMPM); + state.removeAttribute(NEW_ASSIGNMENT_PEER_ASSESSMENT_ANON_EVAL); + state.removeAttribute(NEW_ASSIGNMENT_PEER_ASSESSMENT_STUDENT_VIEW_REVIEWS); + state.removeAttribute(NEW_ASSIGNMENT_PEER_ASSESSMENT_NUM_REVIEWS); + state.removeAttribute(NEW_ASSIGNMENT_PEER_ASSESSMENT_INSTRUCTIONS); + // remove content-review setting state.removeAttribute(NEW_ASSIGNMENT_USE_REVIEW_SERVICE); state.removeAttribute(AssignmentService.PROP_ASSIGNMENT_ASSOCIATE_GRADEBOOK_ASSIGNMENT); + //remove peer assessment state: + state.removeAttribute(NEW_ASSIGNMENT_USE_PEER_ASSESSMENT); + state.removeAttribute(NEW_ASSIGNMENT_PEERPERIODMONTH); + state.removeAttribute(NEW_ASSIGNMENT_PEERPERIODDAY); + state.removeAttribute(NEW_ASSIGNMENT_PEERPERIODYEAR); + state.removeAttribute(NEW_ASSIGNMENT_PEERPERIODHOUR); + state.removeAttribute(NEW_ASSIGNMENT_PEERPERIODMIN); + state.removeAttribute(NEW_ASSIGNMENT_PEERPERIODAMPM); + state.removeAttribute(NEW_ASSIGNMENT_PEER_ASSESSMENT_ANON_EVAL); + state.removeAttribute(NEW_ASSIGNMENT_PEER_ASSESSMENT_STUDENT_VIEW_REVIEWS); + state.removeAttribute(NEW_ASSIGNMENT_PEER_ASSESSMENT_NUM_REVIEWS); + state.removeAttribute(NEW_ASSIGNMENT_PEER_ASSESSMENT_INSTRUCTIONS); + } // resetNewAssignment /** @@ -11563,6 +12617,7 @@ { sEdit.setGrade(grade); sEdit.setGraded(true); + sEdit.setGradedBy(UserDirectoryService.getCurrentUser() == null ? null : UserDirectoryService.getCurrentUser().getId()); AssignmentService.commitEdit(sEdit); } } @@ -11652,6 +12707,7 @@ sEdit.setGrade(grade); sEdit.setSubmitted(true); sEdit.setGraded(true); + sEdit.setGradedBy(UserDirectoryService.getCurrentUser() == null ? null : UserDirectoryService.getCurrentUser().getId()); AssignmentService.commitEdit(sEdit); } } @@ -11662,6 +12718,7 @@ if (sEdit != null) { sEdit.setGraded(true); + sEdit.setGradedBy(UserDirectoryService.getCurrentUser() == null ? null : UserDirectoryService.getCurrentUser().getId()); AssignmentService.commitEdit(sEdit); } } @@ -12213,8 +13270,10 @@ // set grade String grade = StringUtils.trimToNull(w.getGrade()); sEdit.setGrade(grade); - if (grade != null && !grade.equals(rb.getString("gen.nograd")) && !"ungraded".equals(grade)) + if (grade != null && !grade.equals(rb.getString("gen.nograd")) && !"ungraded".equals(grade)){ sEdit.setGraded(true); + sEdit.setGradedBy(UserDirectoryService.getCurrentUser() == null ? null : UserDirectoryService.getCurrentUser().getId()); + } } // release or not Index: assignment-tool/tool/src/webapp/vm/assignment/chef_assignments_instructor_list_submissions.vm =================================================================== --- assignment-tool/tool/src/webapp/vm/assignment/chef_assignments_instructor_list_submissions.vm (revision 311684) +++ assignment-tool/tool/src/webapp/vm/assignment/chef_assignments_instructor_list_submissions.vm (working copy) @@ -149,7 +149,12 @@ #end - #set ($submissionType = $assignment.getContent().getTypeOfSubmission()) + + #set($disableGrade=false) + #if($assignment.getAllowPeerAssessment() == true && $assignment.isPeerAssessmentClosed() == false) + #set($disableGrade=true) + #end + #set ($submissionType = $assignment.getContent().getTypeOfSubmission()) #set ($showMsg = false) #set ($showMsg = $!allMsgNumber) #if (!$!showMsg || $showMsg ==0) @@ -161,14 +166,16 @@
## download all $!tlang.getString('downall') - ## upload all + #if(!$disableGrade) + ## upload all | $!tlang.getString('uploadall.title') | $!tlang.getString('relgrad') - #else - title="$!tlang.getString('relcommented')">$!tlang.getString('relcommented') - #end + #if ($withGrade) + title="$!tlang.getString('relgrad')">$!tlang.getString('relgrad') + #else + title="$!tlang.getString('relcommented')">$!tlang.getString('relcommented') + #end + #end #if ($taggable) #foreach ($provider in $providers) #set ($helperInfo = false) @@ -190,9 +197,9 @@ #else