|
|
|
@ -196,7 +196,11 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy, Can
|
|
|
|
|
* @param response Response of get submission status.
|
|
|
|
|
*/
|
|
|
|
|
protected calculateTimeRemaining(response: AddonModAssignGetSubmissionStatusWSResponse): void {
|
|
|
|
|
if (this.assign!.duedate <= 0) {
|
|
|
|
|
if (!this.assign) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (this.assign.duedate <= 0) {
|
|
|
|
|
this.timeRemaining = '';
|
|
|
|
|
this.timeRemainingClass = '';
|
|
|
|
|
|
|
|
|
@ -206,7 +210,7 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy, Can
|
|
|
|
|
const time = CoreTimeUtils.timestamp();
|
|
|
|
|
const dueDate = response.lastattempt?.extensionduedate
|
|
|
|
|
? response.lastattempt.extensionduedate
|
|
|
|
|
: this.assign!.duedate;
|
|
|
|
|
: this.assign.duedate;
|
|
|
|
|
const timeRemaining = dueDate - time;
|
|
|
|
|
|
|
|
|
|
if (timeRemaining > 0) {
|
|
|
|
@ -276,6 +280,10 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy, Can
|
|
|
|
|
* Copy a previous attempt and then go to edit.
|
|
|
|
|
*/
|
|
|
|
|
async copyPrevious(): Promise<void> {
|
|
|
|
|
if (!this.assign) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!CoreApp.isOnline()) {
|
|
|
|
|
CoreDomUtils.showErrorModal('core.networkerrormsg', true);
|
|
|
|
|
|
|
|
|
@ -291,7 +299,7 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy, Can
|
|
|
|
|
let modal = await CoreDomUtils.showModalLoading();
|
|
|
|
|
|
|
|
|
|
const size = await CoreUtils.ignoreErrors(
|
|
|
|
|
AddonModAssignHelper.getSubmissionSizeForCopy(this.assign!, previousSubmission),
|
|
|
|
|
AddonModAssignHelper.getSubmissionSizeForCopy(this.assign, previousSubmission),
|
|
|
|
|
-1,
|
|
|
|
|
); // Error calculating size, return -1.
|
|
|
|
|
|
|
|
|
@ -309,15 +317,15 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy, Can
|
|
|
|
|
modal = await CoreDomUtils.showModalLoading('core.sending', true);
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
await AddonModAssignHelper.copyPreviousAttempt(this.assign!, previousSubmission);
|
|
|
|
|
await AddonModAssignHelper.copyPreviousAttempt(this.assign, previousSubmission);
|
|
|
|
|
// Now go to edit.
|
|
|
|
|
this.goToEdit();
|
|
|
|
|
|
|
|
|
|
if (!this.assign!.submissiondrafts) {
|
|
|
|
|
if (!this.assign.submissiondrafts && this.userSubmission) {
|
|
|
|
|
// No drafts allowed, so it was submitted. Trigger event.
|
|
|
|
|
CoreEvents.trigger(AddonModAssignProvider.SUBMITTED_FOR_GRADING_EVENT, {
|
|
|
|
|
assignmentId: this.assign!.id,
|
|
|
|
|
submissionId: this.userSubmission!.id,
|
|
|
|
|
assignmentId: this.assign.id,
|
|
|
|
|
submissionId: this.userSubmission.id,
|
|
|
|
|
userId: this.currentUserId,
|
|
|
|
|
}, this.siteId);
|
|
|
|
|
} else {
|
|
|
|
@ -337,8 +345,8 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy, Can
|
|
|
|
|
* @return Promise resolved when done.
|
|
|
|
|
*/
|
|
|
|
|
protected async discardDrafts(): Promise<void> {
|
|
|
|
|
if (this.feedback && this.feedback.plugins) {
|
|
|
|
|
await AddonModAssignHelper.discardFeedbackPluginData(this.assign!.id, this.submitId, this.feedback);
|
|
|
|
|
if (this.assign && this.feedback && this.feedback.plugins) {
|
|
|
|
|
await AddonModAssignHelper.discardFeedbackPluginData(this.assign.id, this.submitId, this.feedback);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -363,7 +371,7 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy, Can
|
|
|
|
|
* @return Promise resolved with boolean: whether there's data to save.
|
|
|
|
|
*/
|
|
|
|
|
protected async hasDataToSave(isSubmit = false): Promise<boolean> {
|
|
|
|
|
if (!this.canSaveGrades || !this.loaded) {
|
|
|
|
|
if (!this.canSaveGrades || !this.loaded || !this.assign) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -379,7 +387,7 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy, Can
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Check if outcomes changed.
|
|
|
|
|
if (this.gradeInfo && this.gradeInfo.outcomes) {
|
|
|
|
|
if (this.gradeInfo?.outcomes) {
|
|
|
|
|
for (const x in this.gradeInfo.outcomes) {
|
|
|
|
|
const outcome = this.gradeInfo.outcomes[x];
|
|
|
|
|
|
|
|
|
@ -396,7 +404,7 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy, Can
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
return AddonModAssignHelper.hasFeedbackDataChanged(
|
|
|
|
|
this.assign!,
|
|
|
|
|
this.assign,
|
|
|
|
|
this.userSubmission,
|
|
|
|
|
this.feedback,
|
|
|
|
|
this.submitId,
|
|
|
|
@ -435,13 +443,13 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy, Can
|
|
|
|
|
promises.push(AddonModAssign.invalidateAssignmentData(this.courseId));
|
|
|
|
|
if (this.assign) {
|
|
|
|
|
promises.push(AddonModAssign.invalidateSubmissionStatusData(
|
|
|
|
|
this.assign!.id,
|
|
|
|
|
this.assign.id,
|
|
|
|
|
this.submitId,
|
|
|
|
|
undefined,
|
|
|
|
|
!!this.blindId,
|
|
|
|
|
));
|
|
|
|
|
promises.push(AddonModAssign.invalidateAssignmentUserMappingsData(this.assign!.id));
|
|
|
|
|
promises.push(AddonModAssign.invalidateListParticipantsData(this.assign!.id));
|
|
|
|
|
promises.push(AddonModAssign.invalidateAssignmentUserMappingsData(this.assign.id));
|
|
|
|
|
promises.push(AddonModAssign.invalidateListParticipantsData(this.assign.id));
|
|
|
|
|
}
|
|
|
|
|
promises.push(CoreGradesHelper.invalidateGradeModuleItems(this.courseId, this.submitId));
|
|
|
|
|
promises.push(CoreCourse.invalidateModule(this.moduleId));
|
|
|
|
@ -534,13 +542,13 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy, Can
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Treat last attempt.
|
|
|
|
|
promises = this.treatLastAttempt(submissionStatus);
|
|
|
|
|
promises = this.treatLastAttempt(submissionStatus, this.lastAttempt);
|
|
|
|
|
|
|
|
|
|
// Calculate the time remaining.
|
|
|
|
|
this.calculateTimeRemaining(submissionStatus);
|
|
|
|
|
|
|
|
|
|
// Load the feedback.
|
|
|
|
|
promises.push(this.loadFeedback(submissionStatus.feedback));
|
|
|
|
|
promises.push(this.loadFeedback(this.assign, submissionStatus.feedback));
|
|
|
|
|
|
|
|
|
|
// Check if there's any unsupported plugin for editing.
|
|
|
|
|
if (!this.userSubmission || !this.userSubmission.plugins) {
|
|
|
|
@ -575,8 +583,12 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy, Can
|
|
|
|
|
* @return Promise resolved when done.
|
|
|
|
|
*/
|
|
|
|
|
protected async loadSubmissionOfflineData(): Promise<void> {
|
|
|
|
|
if (!this.assign) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
const submission = await AddonModAssignOffline.getSubmission(this.assign!.id, this.submitId);
|
|
|
|
|
const submission = await AddonModAssignOffline.getSubmission(this.assign.id, this.submitId);
|
|
|
|
|
|
|
|
|
|
this.hasOffline = submission && submission.plugindata && Object.keys(submission.plugindata).length > 0;
|
|
|
|
|
|
|
|
|
@ -591,10 +603,11 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy, Can
|
|
|
|
|
/**
|
|
|
|
|
* Load the data to render the feedback and grade.
|
|
|
|
|
*
|
|
|
|
|
* @param assign Assign data.
|
|
|
|
|
* @param feedback The feedback data from the submission status.
|
|
|
|
|
* @return Promise resolved when done.
|
|
|
|
|
*/
|
|
|
|
|
protected async loadFeedback(feedback?: AddonModAssignSubmissionFeedback): Promise<void> {
|
|
|
|
|
protected async loadFeedback(assign: AddonModAssignAssign, feedback?: AddonModAssignSubmissionFeedback): Promise<void> {
|
|
|
|
|
this.grade = {
|
|
|
|
|
method: '',
|
|
|
|
|
modified: 0,
|
|
|
|
@ -654,22 +667,22 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy, Can
|
|
|
|
|
// Treat the grade info.
|
|
|
|
|
await this.treatGradeInfo();
|
|
|
|
|
|
|
|
|
|
const isManual = this.assign!.attemptreopenmethod == AddonModAssignAttemptReopenMethodValues.MANUAL;
|
|
|
|
|
const isUnlimited = this.assign!.maxattempts == AddonModAssignProvider.UNLIMITED_ATTEMPTS;
|
|
|
|
|
const isLessThanMaxAttempts = !!this.userSubmission && (this.userSubmission.attemptnumber < (this.assign!.maxattempts - 1));
|
|
|
|
|
const isManual = assign.attemptreopenmethod == AddonModAssignAttemptReopenMethodValues.MANUAL;
|
|
|
|
|
const isUnlimited = assign.maxattempts == AddonModAssignProvider.UNLIMITED_ATTEMPTS;
|
|
|
|
|
const isLessThanMaxAttempts = !!this.userSubmission && (this.userSubmission.attemptnumber < (assign.maxattempts - 1));
|
|
|
|
|
|
|
|
|
|
this.allowAddAttempt = isManual && (!this.userSubmission || isUnlimited || isLessThanMaxAttempts);
|
|
|
|
|
|
|
|
|
|
if (this.assign!.teamsubmission) {
|
|
|
|
|
if (assign.teamsubmission) {
|
|
|
|
|
this.grade.applyToAll = true;
|
|
|
|
|
this.originalGrades.applyToAll = true;
|
|
|
|
|
}
|
|
|
|
|
if (this.assign!.markingworkflow && this.grade.gradingStatus) {
|
|
|
|
|
if (assign.markingworkflow && this.grade.gradingStatus) {
|
|
|
|
|
this.workflowStatusTranslationId =
|
|
|
|
|
AddonModAssign.getSubmissionGradingStatusTranslationId(this.grade.gradingStatus);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (this.lastAttempt?.gradingstatus == 'graded' && !this.assign!.markingworkflow && this.userSubmission && feedback) {
|
|
|
|
|
if (this.lastAttempt?.gradingstatus == 'graded' && !assign.markingworkflow && this.userSubmission && feedback) {
|
|
|
|
|
if (feedback.gradeddate < this.userSubmission.timemodified) {
|
|
|
|
|
this.lastAttempt.gradingstatus = AddonModAssignGradingStates.GRADED_FOLLOWUP_SUBMIT;
|
|
|
|
|
|
|
|
|
@ -685,7 +698,7 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy, Can
|
|
|
|
|
if (!this.feedback || !this.feedback.plugins) {
|
|
|
|
|
// Feedback plugins not present, we have to use assign configs to detect the plugins used.
|
|
|
|
|
this.feedback = AddonModAssignHelper.createEmptyFeedback();
|
|
|
|
|
this.feedback.plugins = AddonModAssignHelper.getPluginsEnabled(this.assign!, 'assignfeedback');
|
|
|
|
|
this.feedback.plugins = AddonModAssignHelper.getPluginsEnabled(assign, 'assignfeedback');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Check if there's any offline data for this submission.
|
|
|
|
@ -700,7 +713,7 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy, Can
|
|
|
|
|
// Submission grades aren't identified by attempt number so it can retrieve the feedback for a previous attempt.
|
|
|
|
|
// The app will not treat that as an special case.
|
|
|
|
|
const submissionGrade = await CoreUtils.ignoreErrors(
|
|
|
|
|
AddonModAssignOffline.getSubmissionGrade(this.assign!.id, this.submitId),
|
|
|
|
|
AddonModAssignOffline.getSubmissionGrade(assign.id, this.submitId),
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
this.hasOfflineGrade = false;
|
|
|
|
@ -725,10 +738,10 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy, Can
|
|
|
|
|
|
|
|
|
|
if (submissionGrade.outcomes && Object.keys(submissionGrade.outcomes).length && this.gradeInfo?.outcomes) {
|
|
|
|
|
this.gradeInfo.outcomes.forEach((outcome) => {
|
|
|
|
|
if (submissionGrade.outcomes[outcome.itemNumber!] !== undefined) {
|
|
|
|
|
if (outcome.itemNumber !== undefined && submissionGrade.outcomes[outcome.itemNumber] !== undefined) {
|
|
|
|
|
// If outcome has been modified from gradebook, do not use offline.
|
|
|
|
|
if (outcome.modified! < submissionGrade.timemodified) {
|
|
|
|
|
outcome.selectedId = submissionGrade.outcomes[outcome.itemNumber!];
|
|
|
|
|
if ((outcome.modified || 0) < submissionGrade.timemodified) {
|
|
|
|
|
outcome.selectedId = submissionGrade.outcomes[outcome.itemNumber];
|
|
|
|
|
this.originalGrades.outcomes[outcome.id] = outcome.selectedId;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -752,11 +765,15 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy, Can
|
|
|
|
|
* @param status Submission status.
|
|
|
|
|
*/
|
|
|
|
|
protected setStatusNameAndClass(status: AddonModAssignGetSubmissionStatusWSResponse): void {
|
|
|
|
|
if (!this.assign) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (this.hasOffline || this.submittedOffline) {
|
|
|
|
|
// Offline data.
|
|
|
|
|
this.statusTranslated = Translate.instant('core.notsent');
|
|
|
|
|
this.statusColor = 'warning';
|
|
|
|
|
} else if (!this.assign!.teamsubmission) {
|
|
|
|
|
} else if (!this.assign.teamsubmission) {
|
|
|
|
|
|
|
|
|
|
// Single submission.
|
|
|
|
|
if (this.userSubmission && this.userSubmission.status != this.statusNew) {
|
|
|
|
@ -775,7 +792,7 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy, Can
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
|
|
// Team submission.
|
|
|
|
|
if (!status.lastattempt?.submissiongroup && this.assign!.preventsubmissionnotingroup) {
|
|
|
|
|
if (!status.lastattempt?.submissiongroup && this.assign.preventsubmissionnotingroup) {
|
|
|
|
|
this.statusTranslated = Translate.instant('addon.mod_assign.nosubmission');
|
|
|
|
|
this.statusColor = AddonModAssign.getSubmissionStatusColor(AddonModAssignSubmissionStatusValues.NO_SUBMISSION);
|
|
|
|
|
} else if (this.userSubmission && this.userSubmission.status != this.statusNew) {
|
|
|
|
@ -816,7 +833,11 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy, Can
|
|
|
|
|
* @param acceptStatement Whether the statement has been accepted.
|
|
|
|
|
*/
|
|
|
|
|
async submitForGrading(acceptStatement: boolean): Promise<void> {
|
|
|
|
|
if (this.assign!.requiresubmissionstatement && !acceptStatement) {
|
|
|
|
|
if (!this.assign || !this.userSubmission) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (this.assign.requiresubmissionstatement && !acceptStatement) {
|
|
|
|
|
CoreDomUtils.showErrorModal('addon.mod_assign.acceptsubmissionstatement', true);
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
@ -830,17 +851,17 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy, Can
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
await AddonModAssign.submitForGrading(
|
|
|
|
|
this.assign!.id,
|
|
|
|
|
this.assign.id,
|
|
|
|
|
this.courseId,
|
|
|
|
|
acceptStatement,
|
|
|
|
|
this.userSubmission!.timemodified,
|
|
|
|
|
this.userSubmission.timemodified,
|
|
|
|
|
this.hasOffline,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// Submitted, trigger event.
|
|
|
|
|
CoreEvents.trigger(AddonModAssignProvider.SUBMITTED_FOR_GRADING_EVENT, {
|
|
|
|
|
assignmentId: this.assign!.id,
|
|
|
|
|
submissionId: this.userSubmission!.id,
|
|
|
|
|
assignmentId: this.assign.id,
|
|
|
|
|
submissionId: this.userSubmission.id,
|
|
|
|
|
userId: this.currentUserId,
|
|
|
|
|
}, this.siteId);
|
|
|
|
|
} catch (error) {
|
|
|
|
@ -861,7 +882,7 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy, Can
|
|
|
|
|
async submitGrade(): Promise<void> {
|
|
|
|
|
// Check if there's something to be saved.
|
|
|
|
|
const modified = await this.hasDataToSave(true);
|
|
|
|
|
if (!modified) {
|
|
|
|
|
if (!modified || !this.assign) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -880,22 +901,21 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy, Can
|
|
|
|
|
const modal = await CoreDomUtils.showModalLoading('core.sending', true);
|
|
|
|
|
|
|
|
|
|
(this.gradeInfo?.outcomes || []).forEach((outcome) => {
|
|
|
|
|
if (outcome.itemNumber) {
|
|
|
|
|
outcomes[outcome.itemNumber] = outcome.selectedId!;
|
|
|
|
|
if (outcome.itemNumber && outcome.selectedId) {
|
|
|
|
|
outcomes[outcome.itemNumber] = outcome.selectedId;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
let pluginData: AddonModAssignSavePluginData = {};
|
|
|
|
|
try {
|
|
|
|
|
if (this.feedback && this.feedback.plugins) {
|
|
|
|
|
pluginData =
|
|
|
|
|
await AddonModAssignHelper.prepareFeedbackPluginData(this.assign!.id, this.submitId, this.feedback);
|
|
|
|
|
pluginData = await AddonModAssignHelper.prepareFeedbackPluginData(this.assign.id, this.submitId, this.feedback);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
// We have all the data, now send it.
|
|
|
|
|
await AddonModAssign.submitGradingForm(
|
|
|
|
|
this.assign!.id,
|
|
|
|
|
this.assign.id,
|
|
|
|
|
this.submitId,
|
|
|
|
|
this.courseId,
|
|
|
|
|
grade || 0,
|
|
|
|
@ -914,7 +934,7 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy, Can
|
|
|
|
|
this.invalidateAndRefresh(true);
|
|
|
|
|
|
|
|
|
|
CoreEvents.trigger(AddonModAssignProvider.GRADED_EVENT, {
|
|
|
|
|
assignmentId: this.assign!.id,
|
|
|
|
|
assignmentId: this.assign.id,
|
|
|
|
|
submissionId: this.submitId,
|
|
|
|
|
userId: this.currentUserId,
|
|
|
|
|
}, this.siteId);
|
|
|
|
@ -939,21 +959,21 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy, Can
|
|
|
|
|
this.isGrading = true;
|
|
|
|
|
|
|
|
|
|
// Make sure outcomes is an array.
|
|
|
|
|
this.gradeInfo.outcomes = this.gradeInfo.outcomes || [];
|
|
|
|
|
const gradeInfo = this.gradeInfo;
|
|
|
|
|
gradeInfo.outcomes = gradeInfo.outcomes || [];
|
|
|
|
|
|
|
|
|
|
// Check if grading method is simple or not.
|
|
|
|
|
if (this.gradeInfo.advancedgrading && this.gradeInfo.advancedgrading[0] &&
|
|
|
|
|
this.gradeInfo.advancedgrading[0].method !== undefined) {
|
|
|
|
|
this.grade.method = this.gradeInfo.advancedgrading[0].method || 'simple';
|
|
|
|
|
if (gradeInfo.advancedgrading && gradeInfo.advancedgrading[0] && gradeInfo.advancedgrading[0].method !== undefined) {
|
|
|
|
|
this.grade.method = gradeInfo.advancedgrading[0].method || 'simple';
|
|
|
|
|
} else {
|
|
|
|
|
this.grade.method = 'simple';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.canSaveGrades = this.grade.method == 'simple'; // Grades can be saved if simple grading.
|
|
|
|
|
|
|
|
|
|
if (this.gradeInfo.scale) {
|
|
|
|
|
if (gradeInfo.scale) {
|
|
|
|
|
this.grade.scale =
|
|
|
|
|
CoreUtils.makeMenuFromList(this.gradeInfo.scale, Translate.instant('core.nograde'));
|
|
|
|
|
CoreUtils.makeMenuFromList(gradeInfo.scale, Translate.instant('core.nograde'));
|
|
|
|
|
} else {
|
|
|
|
|
// Format the grade.
|
|
|
|
|
this.grade.grade = CoreUtils.formatFloat(this.grade.grade);
|
|
|
|
@ -964,8 +984,8 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy, Can
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Treat outcomes.
|
|
|
|
|
if (this.gradeInfo.outcomes) {
|
|
|
|
|
this.gradeInfo.outcomes.forEach((outcome) => {
|
|
|
|
|
if (gradeInfo.outcomes) {
|
|
|
|
|
gradeInfo.outcomes.forEach((outcome) => {
|
|
|
|
|
if (outcome.scale) {
|
|
|
|
|
outcome.options =
|
|
|
|
|
CoreUtils.makeMenuFromList<number>(
|
|
|
|
@ -986,7 +1006,8 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy, Can
|
|
|
|
|
grades.forEach((grade: CoreGradesFormattedItem) => {
|
|
|
|
|
if (!grade.outcomeid && !grade.scaleid) {
|
|
|
|
|
|
|
|
|
|
const gradeFormatted = grade.gradeformatted || '';
|
|
|
|
|
// Clean HTML tags, grade can contain an icon.
|
|
|
|
|
const gradeFormatted = CoreTextUtils.cleanTags(grade.gradeformatted || '');
|
|
|
|
|
// Not using outcomes or scale, get the numeric grade.
|
|
|
|
|
if (this.grade.scale) {
|
|
|
|
|
this.grade.gradebookGrade = CoreUtils.formatFloat(
|
|
|
|
@ -1004,7 +1025,7 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy, Can
|
|
|
|
|
} else if (grade.outcomeid) {
|
|
|
|
|
|
|
|
|
|
// Only show outcomes with info on it, outcomeid could be null if outcomes are disabled on site.
|
|
|
|
|
this.gradeInfo!.outcomes && this.gradeInfo!.outcomes.forEach((outcome) => {
|
|
|
|
|
gradeInfo.outcomes?.forEach((outcome) => {
|
|
|
|
|
if (outcome.id == String(grade.outcomeid)) {
|
|
|
|
|
outcome.selected = grade.gradeformatted;
|
|
|
|
|
outcome.modified = grade.gradedategraded;
|
|
|
|
@ -1017,38 +1038,42 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy, Can
|
|
|
|
|
outcomes.push(outcome);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
this.gradeInfo!.disabled = grade.gradeislocked || grade.gradeisoverridden;
|
|
|
|
|
gradeInfo.disabled = grade.gradeislocked || grade.gradeisoverridden;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
this.gradeInfo.outcomes = outcomes;
|
|
|
|
|
gradeInfo.outcomes = outcomes;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Treat the last attempt.
|
|
|
|
|
*
|
|
|
|
|
* @param submissionStatus Response of get submission status.
|
|
|
|
|
* @param lastAttempt Last attempt (if any).
|
|
|
|
|
* @param promises List where to add the promises.
|
|
|
|
|
*/
|
|
|
|
|
protected treatLastAttempt(submissionStatus: AddonModAssignGetSubmissionStatusWSResponse): Promise<void>[] {
|
|
|
|
|
protected treatLastAttempt(
|
|
|
|
|
submissionStatus: AddonModAssignGetSubmissionStatusWSResponse,
|
|
|
|
|
lastAttempt?: AddonModAssignSubmissionAttemptFormatted,
|
|
|
|
|
): Promise<void>[] {
|
|
|
|
|
const promises: Promise<void>[] =[];
|
|
|
|
|
|
|
|
|
|
if (!submissionStatus.lastattempt) {
|
|
|
|
|
if (!lastAttempt || !this.assign) {
|
|
|
|
|
return [];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const submissionStatementMissing = !!this.assign!.requiresubmissionstatement &&
|
|
|
|
|
this.assign!.submissionstatement === undefined;
|
|
|
|
|
const submissionStatementMissing = !!this.assign.requiresubmissionstatement &&
|
|
|
|
|
this.assign.submissionstatement === undefined;
|
|
|
|
|
|
|
|
|
|
this.canSubmit = !this.isSubmittedForGrading && !this.submittedOffline && (submissionStatus.lastattempt.cansubmit ||
|
|
|
|
|
(this.hasOffline && AddonModAssign.canSubmitOffline(this.assign!, submissionStatus)));
|
|
|
|
|
this.canSubmit = !this.isSubmittedForGrading && !this.submittedOffline && (lastAttempt.cansubmit ||
|
|
|
|
|
(this.hasOffline && AddonModAssign.canSubmitOffline(this.assign, submissionStatus)));
|
|
|
|
|
|
|
|
|
|
this.canEdit = !this.isSubmittedForGrading && submissionStatus.lastattempt.canedit &&
|
|
|
|
|
(!this.submittedOffline || !this.assign!.submissiondrafts);
|
|
|
|
|
this.canEdit = !this.isSubmittedForGrading && lastAttempt.canedit &&
|
|
|
|
|
(!this.submittedOffline || !this.assign.submissiondrafts);
|
|
|
|
|
|
|
|
|
|
// Get submission statement if needed.
|
|
|
|
|
if (this.assign!.requiresubmissionstatement && this.assign!.submissiondrafts && this.submitId == this.currentUserId) {
|
|
|
|
|
this.submissionStatement = this.assign!.submissionstatement;
|
|
|
|
|
if (this.assign.requiresubmissionstatement && this.assign.submissiondrafts && this.submitId == this.currentUserId) {
|
|
|
|
|
this.submissionStatement = this.assign.submissionstatement;
|
|
|
|
|
this.acceptStatement = false;
|
|
|
|
|
} else {
|
|
|
|
|
this.submissionStatement = undefined;
|
|
|
|
@ -1056,26 +1081,26 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy, Can
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Show error if submission statement should be shown but it couldn't be retrieved.
|
|
|
|
|
this.showErrorStatementEdit = submissionStatementMissing && !this.assign!.submissiondrafts &&
|
|
|
|
|
this.showErrorStatementEdit = submissionStatementMissing && !this.assign.submissiondrafts &&
|
|
|
|
|
this.submitId == this.currentUserId;
|
|
|
|
|
|
|
|
|
|
this.showErrorStatementSubmit = submissionStatementMissing && !!this.assign!.submissiondrafts;
|
|
|
|
|
this.showErrorStatementSubmit = submissionStatementMissing && !!this.assign.submissiondrafts;
|
|
|
|
|
|
|
|
|
|
this.userSubmission = AddonModAssign.getSubmissionObjectFromAttempt(this.assign!, submissionStatus.lastattempt);
|
|
|
|
|
this.userSubmission = AddonModAssign.getSubmissionObjectFromAttempt(this.assign, lastAttempt);
|
|
|
|
|
|
|
|
|
|
if (this.assign!.attemptreopenmethod != this.attemptReopenMethodNone && this.userSubmission) {
|
|
|
|
|
if (this.assign.attemptreopenmethod != this.attemptReopenMethodNone && this.userSubmission) {
|
|
|
|
|
this.currentAttempt = this.userSubmission.attemptnumber + 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.setStatusNameAndClass(submissionStatus);
|
|
|
|
|
|
|
|
|
|
if (this.assign!.teamsubmission) {
|
|
|
|
|
if (submissionStatus.lastattempt.submissiongroup) {
|
|
|
|
|
if (this.assign.teamsubmission) {
|
|
|
|
|
if (lastAttempt.submissiongroup) {
|
|
|
|
|
// Get the name of the group.
|
|
|
|
|
promises.push(CoreGroups.getActivityAllowedGroups(this.assign!.cmid).then((result) => {
|
|
|
|
|
const group = result.groups.find((group) => group.id == submissionStatus.lastattempt!.submissiongroup);
|
|
|
|
|
promises.push(CoreGroups.getActivityAllowedGroups(this.assign.cmid).then((result) => {
|
|
|
|
|
const group = result.groups.find((group) => group.id === lastAttempt.submissiongroup);
|
|
|
|
|
if (group) {
|
|
|
|
|
this.lastAttempt!.submissiongroupname = group.name;
|
|
|
|
|
lastAttempt.submissiongroupname = group.name;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
@ -1085,9 +1110,9 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy, Can
|
|
|
|
|
// Get the members that need to submit.
|
|
|
|
|
if (this.userSubmission &&
|
|
|
|
|
this.userSubmission.status != this.statusNew &&
|
|
|
|
|
submissionStatus.lastattempt.submissiongroupmemberswhoneedtosubmit
|
|
|
|
|
lastAttempt.submissiongroupmemberswhoneedtosubmit
|
|
|
|
|
) {
|
|
|
|
|
submissionStatus.lastattempt.submissiongroupmemberswhoneedtosubmit.forEach((member) => {
|
|
|
|
|
lastAttempt.submissiongroupmemberswhoneedtosubmit.forEach((member) => {
|
|
|
|
|
if (!this.blindMarking) {
|
|
|
|
|
promises.push(CoreUser.getProfile(member, this.courseId).then((profile) => {
|
|
|
|
|
this.membersToSubmit.push(profile);
|
|
|
|
@ -1100,23 +1125,20 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy, Can
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Get grading text and color.
|
|
|
|
|
this.gradingStatusTranslationId = AddonModAssign.getSubmissionGradingStatusTranslationId(
|
|
|
|
|
submissionStatus.lastattempt.gradingstatus,
|
|
|
|
|
);
|
|
|
|
|
this.gradingColor = AddonModAssign.getSubmissionGradingStatusColor(submissionStatus.lastattempt.gradingstatus);
|
|
|
|
|
this.gradingStatusTranslationId = AddonModAssign.getSubmissionGradingStatusTranslationId(lastAttempt.gradingstatus);
|
|
|
|
|
this.gradingColor = AddonModAssign.getSubmissionGradingStatusColor(lastAttempt.gradingstatus);
|
|
|
|
|
|
|
|
|
|
// Get the submission plugins.
|
|
|
|
|
if (this.userSubmission) {
|
|
|
|
|
if (!this.assign!.teamsubmission ||
|
|
|
|
|
!submissionStatus.lastattempt.submissiongroup ||
|
|
|
|
|
!this.assign!.preventsubmissionnotingroup
|
|
|
|
|
if (!this.assign.teamsubmission ||
|
|
|
|
|
!lastAttempt.submissiongroup ||
|
|
|
|
|
!this.assign.preventsubmissionnotingroup
|
|
|
|
|
) {
|
|
|
|
|
if (this.previousAttempt && this.previousAttempt.submission!.plugins &&
|
|
|
|
|
this.userSubmission.status == this.statusReopened) {
|
|
|
|
|
if (this.previousAttempt?.submission?.plugins && this.userSubmission.status === this.statusReopened) {
|
|
|
|
|
// Get latest attempt if available.
|
|
|
|
|
this.submissionPlugins = this.previousAttempt.submission!.plugins;
|
|
|
|
|
this.submissionPlugins = this.previousAttempt.submission.plugins;
|
|
|
|
|
} else {
|
|
|
|
|
this.submissionPlugins = this.userSubmission.plugins!;
|
|
|
|
|
this.submissionPlugins = this.userSubmission.plugins || [];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -1134,7 +1156,7 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy, Can
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const syncId = AddonModAssignSync.getGradeSyncId(this.assign!.id, this.submitId);
|
|
|
|
|
const syncId = AddonModAssignSync.getGradeSyncId(this.assign.id, this.submitId);
|
|
|
|
|
|
|
|
|
|
if (block) {
|
|
|
|
|
CoreSync.blockOperation(AddonModAssignProvider.COMPONENT, syncId);
|
|
|
|
|