MOBILE-4281 assign: Display submission grade when using marking workflow
This commit is contained in:
		
							parent
							
								
									c631db2082
								
							
						
					
					
						commit
						d4aab021f0
					
				| @ -346,6 +346,7 @@ | ||||
|   "addon.mod_assign.cannotsubmitduetostatementsubmission": "local_moodlemobileapp", | ||||
|   "addon.mod_assign.confirmstart": "assign", | ||||
|   "addon.mod_assign.confirmsubmission": "assign", | ||||
|   "addon.mod_assign.currentassigngrade": "assign", | ||||
|   "addon.mod_assign.currentattempt": "assign", | ||||
|   "addon.mod_assign.currentattemptof": "assign", | ||||
|   "addon.mod_assign.currentgrade": "assign", | ||||
| @ -702,8 +703,8 @@ | ||||
|   "addon.mod_glossary.entrydeleted": "glossary", | ||||
|   "addon.mod_glossary.entrypendingapproval": "local_moodlemobileapp", | ||||
|   "addon.mod_glossary.entryusedynalink": "glossary", | ||||
|   "addon.mod_glossary.errordeleting": "local_moodlemobileapp", | ||||
|   "addon.mod_glossary.errconceptalreadyexists": "glossary", | ||||
|   "addon.mod_glossary.errordeleting": "local_moodlemobileapp", | ||||
|   "addon.mod_glossary.errorloadingentries": "local_moodlemobileapp", | ||||
|   "addon.mod_glossary.errorloadingentry": "local_moodlemobileapp", | ||||
|   "addon.mod_glossary.errorloadingglossary": "local_moodlemobileapp", | ||||
|  | ||||
| @ -308,6 +308,15 @@ | ||||
|                             <p *ngIf="!canSaveGrades || !outcome.itemNumber">{{ outcome.selected }}</p> | ||||
|                         </ion-item> | ||||
| 
 | ||||
|                         <!-- Assign grade if it wasn't released to gradebook. --> | ||||
|                         <ion-item class="ion-text-wrap" *ngIf="gradeInfo && grade.unreleasedGrade !== undefined"> | ||||
|                             <ion-label> | ||||
|                                 <p class="item-heading">{{ 'addon.mod_assign.currentassigngrade' | translate }}</p> | ||||
|                                 <p *ngIf="grade.method != 'simple' || !grade.scale">{{ grade.unreleasedGrade}} / {{ gradeInfo.grade }}</p> | ||||
|                                 <p *ngIf="grade.method == 'simple' && grade.scale">{{ grade.unreleasedGrade }}</p> | ||||
|                             </ion-label> | ||||
|                         </ion-item> | ||||
| 
 | ||||
|                         <!-- Gradebook grade for simple grading. --> | ||||
|                         <ion-item class="ion-text-wrap" *ngIf="grade.method == 'simple'"> | ||||
|                             <ion-label> | ||||
|  | ||||
| @ -59,6 +59,7 @@ import { AddonModAssignSubmissionPluginComponent } from '../submission-plugin/su | ||||
| import { AddonModAssignModuleHandlerService } from '../../services/handlers/module'; | ||||
| import { CanLeave } from '@guards/can-leave'; | ||||
| import { CoreTime } from '@singletons/time'; | ||||
| import { isSafeNumber, SafeNumber } from '@/core/utils/types'; | ||||
| 
 | ||||
| /** | ||||
|  * Component that displays an assignment submission. | ||||
| @ -476,6 +477,7 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy, Can | ||||
|             )); | ||||
|             promises.push(AddonModAssign.invalidateAssignmentUserMappingsData(this.assign.id)); | ||||
|             promises.push(AddonModAssign.invalidateListParticipantsData(this.assign.id)); | ||||
|             promises.push(AddonModAssign.invalidateAssignmentGradesData(this.assign.id)); | ||||
|         } | ||||
|         promises.push(CoreGradesHelper.invalidateGradeModuleItems(this.courseId, this.submitId)); | ||||
|         promises.push(CoreCourse.invalidateModule(this.moduleId)); | ||||
| @ -691,7 +693,7 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy, Can | ||||
|         } | ||||
| 
 | ||||
|         // Treat the grade info.
 | ||||
|         await this.treatGradeInfo(); | ||||
|         await this.treatGradeInfo(assign); | ||||
| 
 | ||||
|         const isManual = assign.attemptreopenmethod == AddonModAssignAttemptReopenMethodValues.MANUAL; | ||||
|         const isUnlimited = assign.maxattempts == AddonModAssignProvider.UNLIMITED_ATTEMPTS; | ||||
| @ -708,7 +710,10 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy, Can | ||||
|                 AddonModAssign.getSubmissionGradingStatusTranslationId(this.grade.gradingStatus); | ||||
|         } | ||||
| 
 | ||||
|         if (this.lastAttempt?.gradingstatus == 'graded' && !assign.markingworkflow && this.userSubmission && feedback) { | ||||
|         if ( | ||||
|             this.lastAttempt?.gradingstatus === AddonModAssignGradingStates.GRADED && !assign.markingworkflow && | ||||
|             this.userSubmission && feedback | ||||
|         ) { | ||||
|             if (feedback.gradeddate < this.userSubmission.timemodified) { | ||||
|                 this.lastAttempt.gradingstatus = AddonModAssignGradingStates.GRADED_FOLLOWUP_SUBMIT; | ||||
| 
 | ||||
| @ -975,9 +980,10 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy, Can | ||||
|     /** | ||||
|      * Treat the grade info. | ||||
|      * | ||||
|      * @param assign Assign info. | ||||
|      * @returns Promise resolved when done. | ||||
|      */ | ||||
|     protected async treatGradeInfo(): Promise<void> { | ||||
|     protected async treatGradeInfo(assign: AddonModAssignAssign): Promise<void> { | ||||
|         if (!this.gradeInfo) { | ||||
|             return; | ||||
|         } | ||||
| @ -997,12 +1003,33 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy, Can | ||||
| 
 | ||||
|         this.canSaveGrades = this.grade.method == 'simple'; // Grades can be saved if simple grading.
 | ||||
| 
 | ||||
|         const gradeNotReleased = assign.markingworkflow && | ||||
|             this.grade.gradingStatus !== AddonModAssignGradingStates.MARKING_WORKFLOW_STATE_RELEASED; | ||||
| 
 | ||||
|         const [gradebookGrades, assignGrades] = await Promise.all([ | ||||
|             CoreGradesHelper.getGradeModuleItems(this.courseId, this.moduleId, this.submitId), | ||||
|             gradeNotReleased ? | ||||
|                 CoreUtils.ignoreErrors(AddonModAssign.getAssignmentGrades(assign.id, { cmId: assign.cmid })) : | ||||
|                 undefined, | ||||
|         ]); | ||||
| 
 | ||||
|         const unreleasedGrade = Number(assignGrades?.find(grade => grade.userid === this.submitId)?.grade); | ||||
|         this.grade.unreleasedGrade = undefined; | ||||
| 
 | ||||
|         if (gradeInfo.scale) { | ||||
|             this.grade.scale = | ||||
|                 CoreUtils.makeMenuFromList(gradeInfo.scale, Translate.instant('core.nograde')); | ||||
|             this.grade.scale = CoreUtils.makeMenuFromList(gradeInfo.scale, Translate.instant('core.nograde')); | ||||
| 
 | ||||
|             if (isSafeNumber(unreleasedGrade)) { | ||||
|                 const scaleItem = this.grade.scale.find(scaleItem => scaleItem.value === unreleasedGrade); | ||||
|                 this.grade.unreleasedGrade = scaleItem?.label; | ||||
|                 this.grade.grade = (scaleItem ?? this.grade.scale[0])?.value; | ||||
|                 this.originalGrades.grade = this.grade.grade; | ||||
|             } | ||||
|         } else { | ||||
|             this.grade.unreleasedGrade = isSafeNumber(unreleasedGrade) ? unreleasedGrade : undefined; | ||||
| 
 | ||||
|             // Format the grade.
 | ||||
|             this.grade.grade = CoreUtils.formatFloat(this.grade.grade); | ||||
|             this.grade.grade = CoreUtils.formatFloat(this.grade.unreleasedGrade ?? this.grade.grade); | ||||
|             this.originalGrades.grade = this.grade.grade; | ||||
| 
 | ||||
|             // Get current language to format grade input field.
 | ||||
| @ -1024,12 +1051,9 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy, Can | ||||
|             }); | ||||
|         } | ||||
| 
 | ||||
|         // Get grade items.
 | ||||
|         const grades = await CoreGradesHelper.getGradeModuleItems(this.courseId, this.moduleId, this.submitId); | ||||
| 
 | ||||
|         const outcomes: AddonModAssignGradeOutcome[] = []; | ||||
| 
 | ||||
|         grades.forEach((grade: CoreGradesFormattedItem) => { | ||||
|         gradebookGrades.forEach((grade: CoreGradesFormattedItem) => { | ||||
|             if (!grade.outcomeid && !grade.scaleid) { | ||||
| 
 | ||||
|                 // Clean HTML tags, grade can contain an icon.
 | ||||
| @ -1245,6 +1269,7 @@ type AddonModAssignSubmissionGrade = { | ||||
|     scale?: CoreMenuItem<number>[]; | ||||
|     lang: string; | ||||
|     disabled: boolean; | ||||
|     unreleasedGrade?: SafeNumber | string; | ||||
| }; | ||||
| 
 | ||||
| type AddonModAssignSubmissionOriginalGrades = { | ||||
|  | ||||
| @ -22,6 +22,7 @@ | ||||
|     "cannotsubmitduetostatementsubmission": "You can't make a submission in the app because the submission statement could not be retrieved from the site.", | ||||
|     "confirmstart": "You have {{$a}} to complete this assignment. When you begin, the timer will start to count down and can't be paused.", | ||||
|     "confirmsubmission": "Are you sure you want to submit your work for grading? You will not be able to make any more changes.", | ||||
|     "currentassigngrade": "Current grade in assignment", | ||||
|     "currentattempt": "This is attempt {{$a}}.", | ||||
|     "currentattemptof": "This is attempt {{$a.attemptnumber}} ( {{$a.maxattempts}} attempts allowed ).", | ||||
|     "currentgrade": "Current grade in gradebook", | ||||
|  | ||||
| @ -374,10 +374,7 @@ export class AddonModAssignPrefetchHandlerService extends CoreCourseActivityPref | ||||
|                         return this.prefetchSubmission(assign, courseId, moduleId, submissionOptions, true); | ||||
|                     }); | ||||
| 
 | ||||
|                     if (!assign.markingworkflow) { | ||||
|                         // Get assignment grades only if workflow is not enabled to check grading date.
 | ||||
|                         subPromises.push(AddonModAssign.getAssignmentGrades(assign.id, modOptions)); | ||||
|                     } | ||||
|                     subPromises.push(AddonModAssign.getAssignmentGrades(assign.id, modOptions)); | ||||
| 
 | ||||
|                     // Prefetch the submission of the current user even if it does not exist, this will be create it.
 | ||||
|                     if (!submissions || !submissions.find((subm: AddonModAssignSubmissionFormatted) => subm.submitid == userId)) { | ||||
|  | ||||
| @ -9,6 +9,7 @@ Feature: Test marking workflow in assignment activity in app | ||||
|       | student2 | Student2  | student2 | student2@example.com | | ||||
|       | student3 | Student3  | student3 | student3@example.com | | ||||
|       | student4 | Student4  | student4 | student4@example.com | | ||||
|       | student5 | Student5  | student5 | student5@example.com | | ||||
|     And the following "courses" exist: | ||||
|       | fullname | shortname | category | | ||||
|       | Course 1 | C1        | 0        | | ||||
| @ -19,15 +20,18 @@ Feature: Test marking workflow in assignment activity in app | ||||
|       | student2 | C1     | student | | ||||
|       | student3 | C1     | student | | ||||
|       | student4 | C1     | student | | ||||
|       | student5 | C1     | student | | ||||
|       And the following "groups" exist: | ||||
|       | name    | course | idnumber | | ||||
|       | Group 1 | C1     | G1       | | ||||
|       | Group 2 | C1     | G2       | | ||||
|       | Group 3 | C1     | G3       | | ||||
|     And the following "group members" exist: | ||||
|       | user     | group | | ||||
|       | student1 | G1    | | ||||
|       | student2 | G1    | | ||||
|       | student3 | G2    | | ||||
|       | student4 | G3    | | ||||
|     And the following "activities" exist: | ||||
|       | activity | course | idnumber | name         | assignsubmission_onlinetext_enabled | assignfeedback_comments_enabled | markingworkflow | teamsubmission | groupmode | submissiondrafts | | ||||
|       | assign   | C1     | assign1  | Group Assign | 1                                   | 1                               | 1               | 1              | 1         | 0                | | ||||
| @ -35,7 +39,8 @@ Feature: Test marking workflow in assignment activity in app | ||||
|       | assign  | user      | onlinetext | | ||||
|       | assign1 | student1  | Lorem      | | ||||
|       | assign1 | student3  | Ipsum      | | ||||
|     # Mark a submission. | ||||
|       | assign1 | student4  | Dolor      | | ||||
|     # Mark submissions. | ||||
|     And I am on the "Group Assign" "assign activity" page logged in as teacher1 | ||||
|     And I follow "View all submissions" | ||||
|     And I click on "Grade" "link" in the "Student1" "table_row" | ||||
| @ -44,16 +49,72 @@ Feature: Test marking workflow in assignment activity in app | ||||
|     And I set the field "Feedback comments" to "Great job! Lol, not really." | ||||
|     And I set the field "Notify student" to "0" | ||||
|     And I press "Save changes" | ||||
|     And I am on the "Group Assign" "assign activity" page | ||||
|     And I follow "View all submissions" | ||||
|     And I click on "Grade" "link" in the "Student3" "table_row" | ||||
|     And I set the field "Grade out of 100" to "30" | ||||
|     And I set the field "Marking workflow state" to "Released" | ||||
|     And I set the field "Feedback comments" to "Needs to be improved." | ||||
|     And I set the field "Notify student" to "0" | ||||
|     And I press "Save changes" | ||||
|     And I log out | ||||
| 
 | ||||
|   Scenario: View submissions with marking workflow as teacher | ||||
|   Scenario: View submissions with marking workflow and using points as teacher | ||||
|     Given I entered the assign activity "Group Assign" on course "Course 1" as "teacher1" in the app | ||||
|     And I press "Groups" in the app | ||||
|     When I press "Groups" in the app | ||||
|     Then I should find "Submitted for grading" within "Student1" "ion-item" in the app | ||||
|     And I should find "In review" within "Student1" "ion-item" in the app | ||||
|     And I should find "Submitted for grading" within "Student2" "ion-item" in the app | ||||
|     And I should find "In review" within "Student2" "ion-item" in the app | ||||
|     And I should find "Submitted for grading" within "Student3" "ion-item" in the app | ||||
|     And I should find "Not marked" within "Student3" "ion-item" in the app | ||||
|     And I should find "No submission" within "Student4" "ion-item" in the app | ||||
|     And I should not find "Not marked" within "Student4" "ion-item" in the app | ||||
|     And I should find "Released" within "Student3" "ion-item" in the app | ||||
|     And I should find "Submitted for grading" within "Student4" "ion-item" in the app | ||||
|     And I should find "Not marked" within "Student4" "ion-item" in the app | ||||
|     And I should find "No submission" within "Student5" "ion-item" in the app | ||||
|     And I should not find "Not marked" within "Student5" "ion-item" in the app | ||||
| 
 | ||||
|     When I press "Student1" in the app | ||||
|     And I press "Grade" in the app | ||||
|     Then I should find "Submitted for grading" in the app | ||||
|     And I should find "50 / 100" within "Current grade in assignment" "ion-item" in the app | ||||
|     And I should find "-" within "Current grade in gradebook" "ion-item" in the app | ||||
|     And I should find "In review" within "Marking workflow state" "ion-item" in the app | ||||
|     And the field "Grade out of 100" matches value "50" in the app | ||||
|     And I should not find "Graded by" in the app | ||||
| 
 | ||||
|     When I press the back button in the app | ||||
|     And I press "Student3" in the app | ||||
|     And I press "Grade" in the app | ||||
|     Then I should find "Submitted for grading" in the app | ||||
|     And I should find "30" within "Current grade in gradebook" "ion-item" in the app | ||||
|     And I should find "Released" within "Marking workflow state" "ion-item" in the app | ||||
|     And I should find "Teacher teacher" within "Graded by" "ion-item" in the app | ||||
|     And the field "Grade out of 100" matches value "30" in the app | ||||
|     And I should not find "Current grade in assignment" in the app | ||||
| 
 | ||||
|   Scenario: Grade submissions with marking workflow and using points | ||||
|     Given I entered the assign activity "Group Assign" on course "Course 1" as "teacher1" in the app | ||||
|     And I press "Groups" in the app | ||||
|     And I press "Student1" in the app | ||||
|     And I press "Grade" in the app | ||||
|     When I set the field "Grade out of 100" to "60" in the app | ||||
|     And I press "Done" in the app | ||||
|     And I press "Student1" in the app | ||||
|     And I press "Grade" in the app | ||||
|     Then I should find "60 / 100" within "Current grade in assignment" "ion-item" in the app | ||||
|     And I should find "-" within "Current grade in gradebook" "ion-item" in the app | ||||
|     And I should find "In review" within "Marking workflow state" "ion-item" in the app | ||||
|     And the field "Grade out of 100" matches value "60" in the app | ||||
| 
 | ||||
|     When I press the back button in the app | ||||
|     And I press "Student3" in the app | ||||
|     And I press "Grade" in the app | ||||
|     When I set the field "Grade out of 100" to "80" in the app | ||||
|     And I press "Done" in the app | ||||
|     And I press "Student3" in the app | ||||
|     And I press "Grade" in the app | ||||
|     Then I should find "80" within "Current grade in gradebook" "ion-item" in the app | ||||
|     And I should find "Released" within "Marking workflow state" "ion-item" in the app | ||||
|     And I should find "Teacher teacher" within "Graded by" "ion-item" in the app | ||||
|     And the field "Grade out of 100" matches value "80" in the app | ||||
|     And I should not find "Current grade in assignment" in the app | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user