forked from CIT/Vmeda.Online
		
	Merge pull request #1781 from crazyserver/MOBILE-2871
MOBILE-2871 assign: Add group selector on submission list
This commit is contained in:
		
						commit
						9947f27303
					
				@ -32,7 +32,15 @@
 | 
				
			|||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <!-- User can view all submissions (teacher). -->
 | 
					    <!-- User can view all submissions (teacher). -->
 | 
				
			||||||
    <ion-card *ngIf="assign && canViewAllSubmissions" class="core-list-align-detail-right">
 | 
					    <ion-list *ngIf="assign && canViewAllSubmissions" class="core-list-align-detail-right with-borders">
 | 
				
			||||||
 | 
					        <ion-item text-wrap *ngIf="(groupInfo.separateGroups || groupInfo.visibleGroups)">
 | 
				
			||||||
 | 
					            <ion-label id="addon-assign-groupslabel" *ngIf="groupInfo.separateGroups">{{ 'core.groupsseparate' | translate }}</ion-label>
 | 
				
			||||||
 | 
					            <ion-label id="addon-assign-groupslabel" *ngIf="groupInfo.visibleGroups">{{ 'core.groupsvisible' | translate }}</ion-label>
 | 
				
			||||||
 | 
					            <ion-select [(ngModel)]="group" (ionChange)="setGroup(group)" aria-labelledby="addon-assign-groupslabel" interface="action-sheet">
 | 
				
			||||||
 | 
					                <ion-option *ngFor="let groupOpt of groupInfo.groups" [value]="groupOpt.id">{{groupOpt.name}}</ion-option>
 | 
				
			||||||
 | 
					            </ion-select>
 | 
				
			||||||
 | 
					        </ion-item>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <ion-item text-wrap *ngIf="timeRemaining">
 | 
					        <ion-item text-wrap *ngIf="timeRemaining">
 | 
				
			||||||
            <h2>{{ 'addon.mod_assign.timeremaining' | translate }}</h2>
 | 
					            <h2>{{ 'addon.mod_assign.timeremaining' | translate }}</h2>
 | 
				
			||||||
            <p>{{ timeRemaining }}</p>
 | 
					            <p>{{ timeRemaining }}</p>
 | 
				
			||||||
@ -80,7 +88,7 @@
 | 
				
			|||||||
            <ion-icon name="information-circle"></ion-icon>
 | 
					            <ion-icon name="information-circle"></ion-icon>
 | 
				
			||||||
            {{ 'addon.mod_assign.ungroupedusers' | translate }}
 | 
					            {{ 'addon.mod_assign.ungroupedusers' | translate }}
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
    </ion-card>
 | 
					    </ion-list>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <!-- If it's a student, display his submission. -->
 | 
					    <!-- If it's a student, display his submission. -->
 | 
				
			||||||
    <addon-mod-assign-submission *ngIf="loaded && !canViewAllSubmissions && canViewOwnSubmission" [courseId]="courseId" [moduleId]="module.id"></addon-mod-assign-submission>
 | 
					    <addon-mod-assign-submission *ngIf="loaded && !canViewAllSubmissions && canViewOwnSubmission" [courseId]="courseId" [moduleId]="module.id"></addon-mod-assign-submission>
 | 
				
			||||||
 | 
				
			|||||||
@ -14,7 +14,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import { Component, Optional, Injector, ViewChild } from '@angular/core';
 | 
					import { Component, Optional, Injector, ViewChild } from '@angular/core';
 | 
				
			||||||
import { Content, NavController } from 'ionic-angular';
 | 
					import { Content, NavController } from 'ionic-angular';
 | 
				
			||||||
import { CoreGroupsProvider } from '@providers/groups';
 | 
					import { CoreGroupsProvider, CoreGroupInfo } from '@providers/groups';
 | 
				
			||||||
import { CoreTimeUtilsProvider } from '@providers/utils/time';
 | 
					import { CoreTimeUtilsProvider } from '@providers/utils/time';
 | 
				
			||||||
import { CoreCourseModuleMainActivityComponent } from '@core/course/classes/main-activity-component';
 | 
					import { CoreCourseModuleMainActivityComponent } from '@core/course/classes/main-activity-component';
 | 
				
			||||||
import { AddonModAssignProvider } from '../../providers/assign';
 | 
					import { AddonModAssignProvider } from '../../providers/assign';
 | 
				
			||||||
@ -45,6 +45,12 @@ export class AddonModAssignIndexComponent extends CoreCourseModuleMainActivityCo
 | 
				
			|||||||
    summary: any; // The summary.
 | 
					    summary: any; // The summary.
 | 
				
			||||||
    needsGradingAvalaible: boolean; // Whether we can see the submissions that need grading.
 | 
					    needsGradingAvalaible: boolean; // Whether we can see the submissions that need grading.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    groupInfo: CoreGroupInfo = {
 | 
				
			||||||
 | 
					        groups: [],
 | 
				
			||||||
 | 
					        separateGroups: false,
 | 
				
			||||||
 | 
					        visibleGroups: false
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Status.
 | 
					    // Status.
 | 
				
			||||||
    submissionStatusSubmitted = AddonModAssignProvider.SUBMISSION_STATUS_SUBMITTED;
 | 
					    submissionStatusSubmitted = AddonModAssignProvider.SUBMISSION_STATUS_SUBMITTED;
 | 
				
			||||||
    submissionStatusDraft = AddonModAssignProvider.SUBMISSION_STATUS_DRAFT;
 | 
					    submissionStatusDraft = AddonModAssignProvider.SUBMISSION_STATUS_DRAFT;
 | 
				
			||||||
@ -193,15 +199,13 @@ export class AddonModAssignIndexComponent extends CoreCourseModuleMainActivityCo
 | 
				
			|||||||
                    }
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    // Check if groupmode is enabled to avoid showing wrong numbers.
 | 
					                    // Check if groupmode is enabled to avoid showing wrong numbers.
 | 
				
			||||||
                    return this.groupsProvider.activityHasGroups(this.assign.cmid).then((hasGroups) => {
 | 
					                    return this.groupsProvider.getActivityGroupInfo(this.assign.cmid, false).then((groupInfo) => {
 | 
				
			||||||
                        this.showNumbers = !hasGroups;
 | 
					                        this.groupInfo = groupInfo;
 | 
				
			||||||
 | 
					                        this.showNumbers = groupInfo.groups.length == 0 ||
 | 
				
			||||||
 | 
					                            this.sitesProvider.getCurrentSite().isVersionGreaterEqualThan('3.5');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                        return this.assignProvider.getSubmissionStatus(this.assign.id).then((response) => {
 | 
					                        return this.setGroup(this.group || (groupInfo.groups && groupInfo.groups[0] && groupInfo.groups[0].id) ||
 | 
				
			||||||
                            this.summary = response.gradingsummary;
 | 
					                            0);
 | 
				
			||||||
 | 
					 | 
				
			||||||
                            this.needsGradingAvalaible = response.gradingsummary.submissionsneedgradingcount > 0 &&
 | 
					 | 
				
			||||||
                                    this.sitesProvider.getCurrentSite().isVersionGreaterEqualThan('3.2');
 | 
					 | 
				
			||||||
                        });
 | 
					 | 
				
			||||||
                    });
 | 
					                    });
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -222,6 +226,23 @@ export class AddonModAssignIndexComponent extends CoreCourseModuleMainActivityCo
 | 
				
			|||||||
        });
 | 
					        });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Set group to see the summary.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param  {number}       groupId Group ID.
 | 
				
			||||||
 | 
					     * @return {Promise<any>}         Resolved when done.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    setGroup(groupId: number): Promise<any> {
 | 
				
			||||||
 | 
					        this.group = groupId;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return this.assignProvider.getSubmissionStatus(this.assign.id, undefined, this.group).then((response) => {
 | 
				
			||||||
 | 
					            this.summary = response.gradingsummary;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            this.needsGradingAvalaible = response.gradingsummary && response.gradingsummary.submissionsneedgradingcount > 0 &&
 | 
				
			||||||
 | 
					                    this.sitesProvider.getCurrentSite().isVersionGreaterEqualThan('3.2');
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Go to view a list of submissions.
 | 
					     * Go to view a list of submissions.
 | 
				
			||||||
     *
 | 
					     *
 | 
				
			||||||
@ -232,6 +253,7 @@ export class AddonModAssignIndexComponent extends CoreCourseModuleMainActivityCo
 | 
				
			|||||||
        if (typeof status == 'undefined') {
 | 
					        if (typeof status == 'undefined') {
 | 
				
			||||||
            this.navCtrl.push('AddonModAssignSubmissionListPage', {
 | 
					            this.navCtrl.push('AddonModAssignSubmissionListPage', {
 | 
				
			||||||
                courseId: this.courseId,
 | 
					                courseId: this.courseId,
 | 
				
			||||||
 | 
					                groupId: this.group || 0,
 | 
				
			||||||
                moduleId: this.module.id,
 | 
					                moduleId: this.module.id,
 | 
				
			||||||
                moduleName: this.moduleName
 | 
					                moduleName: this.moduleName
 | 
				
			||||||
            });
 | 
					            });
 | 
				
			||||||
@ -239,6 +261,7 @@ export class AddonModAssignIndexComponent extends CoreCourseModuleMainActivityCo
 | 
				
			|||||||
            this.navCtrl.push('AddonModAssignSubmissionListPage', {
 | 
					            this.navCtrl.push('AddonModAssignSubmissionListPage', {
 | 
				
			||||||
                status: status,
 | 
					                status: status,
 | 
				
			||||||
                courseId: this.courseId,
 | 
					                courseId: this.courseId,
 | 
				
			||||||
 | 
					                groupId: this.group || 0,
 | 
				
			||||||
                moduleId: this.module.id,
 | 
					                moduleId: this.module.id,
 | 
				
			||||||
                moduleName: this.moduleName
 | 
					                moduleName: this.moduleName
 | 
				
			||||||
            });
 | 
					            });
 | 
				
			||||||
@ -273,7 +296,7 @@ export class AddonModAssignIndexComponent extends CoreCourseModuleMainActivityCo
 | 
				
			|||||||
            promises.push(this.assignProvider.invalidateAllSubmissionData(this.assign.id));
 | 
					            promises.push(this.assignProvider.invalidateAllSubmissionData(this.assign.id));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (this.canViewAllSubmissions) {
 | 
					            if (this.canViewAllSubmissions) {
 | 
				
			||||||
                promises.push(this.assignProvider.invalidateSubmissionStatusData(this.assign.id));
 | 
					                promises.push(this.assignProvider.invalidateSubmissionStatusData(this.assign.id, undefined, this.group));
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -338,7 +338,8 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        promises.push(this.assignProvider.invalidateAssignmentData(this.courseId));
 | 
					        promises.push(this.assignProvider.invalidateAssignmentData(this.courseId));
 | 
				
			||||||
        if (this.assign) {
 | 
					        if (this.assign) {
 | 
				
			||||||
            promises.push(this.assignProvider.invalidateSubmissionStatusData(this.assign.id, this.submitId, !!this.blindId));
 | 
					            promises.push(this.assignProvider.invalidateSubmissionStatusData(this.assign.id, this.submitId, undefined,
 | 
				
			||||||
 | 
					                !!this.blindId));
 | 
				
			||||||
            promises.push(this.assignProvider.invalidateAssignmentUserMappingsData(this.assign.id));
 | 
					            promises.push(this.assignProvider.invalidateAssignmentUserMappingsData(this.assign.id));
 | 
				
			||||||
            promises.push(this.assignProvider.invalidateListParticipantsData(this.assign.id));
 | 
					            promises.push(this.assignProvider.invalidateListParticipantsData(this.assign.id));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@ -408,7 +409,7 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy {
 | 
				
			|||||||
            return Promise.all(promises);
 | 
					            return Promise.all(promises);
 | 
				
			||||||
        }).then(() => {
 | 
					        }).then(() => {
 | 
				
			||||||
            // Get submission status.
 | 
					            // Get submission status.
 | 
				
			||||||
            return this.assignProvider.getSubmissionStatusWithRetry(this.assign, this.submitId, isBlind);
 | 
					            return this.assignProvider.getSubmissionStatusWithRetry(this.assign, this.submitId, undefined, isBlind);
 | 
				
			||||||
        }).then((response) => {
 | 
					        }).then((response) => {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            const promises = [];
 | 
					            const promises = [];
 | 
				
			||||||
 | 
				
			|||||||
@ -121,9 +121,11 @@ export class AddonModAssignEditPage implements OnInit, OnDestroy {
 | 
				
			|||||||
        }).then(() => {
 | 
					        }).then(() => {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // Get submission status. Ignore cache to get the latest data.
 | 
					            // Get submission status. Ignore cache to get the latest data.
 | 
				
			||||||
            return this.assignProvider.getSubmissionStatus(this.assign.id, this.userId, this.isBlind, false, true).catch((err) => {
 | 
					            return this.assignProvider.getSubmissionStatus(this.assign.id, this.userId, undefined, this.isBlind, false, true)
 | 
				
			||||||
 | 
					                    .catch((err) => {
 | 
				
			||||||
                // Cannot connect. Get cached data.
 | 
					                // Cannot connect. Get cached data.
 | 
				
			||||||
                return this.assignProvider.getSubmissionStatus(this.assign.id, this.userId, this.isBlind).then((response) => {
 | 
					                return this.assignProvider.getSubmissionStatus(this.assign.id, this.userId, undefined, this.isBlind)
 | 
				
			||||||
 | 
					                        .then((response) => {
 | 
				
			||||||
                    const userSubmission = this.assignProvider.getSubmissionObjectFromAttempt(this.assign, response.lastattempt);
 | 
					                    const userSubmission = this.assignProvider.getSubmissionObjectFromAttempt(this.assign, response.lastattempt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    // Check if the user can edit it in offline.
 | 
					                    // Check if the user can edit it in offline.
 | 
				
			||||||
 | 
				
			|||||||
@ -15,10 +15,17 @@
 | 
				
			|||||||
            </core-empty-box>
 | 
					            </core-empty-box>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            <ion-list>
 | 
					            <ion-list>
 | 
				
			||||||
 | 
					                <ion-item text-wrap *ngIf="(groupInfo.separateGroups || groupInfo.visibleGroups)">
 | 
				
			||||||
 | 
					                    <ion-label id="addon-assign-groupslabel" *ngIf="groupInfo.separateGroups">{{ 'core.groupsseparate' | translate }}</ion-label>
 | 
				
			||||||
 | 
					                    <ion-label id="addon-assign-groupslabel" *ngIf="groupInfo.visibleGroups">{{ 'core.groupsvisible' | translate }}</ion-label>
 | 
				
			||||||
 | 
					                    <ion-select [(ngModel)]="groupId" (ionChange)="setGroup(groupId)" aria-labelledby="addon-assign-groupslabel" interface="action-sheet">
 | 
				
			||||||
 | 
					                        <ion-option *ngFor="let groupOpt of groupInfo.groups" [value]="groupOpt.id">{{groupOpt.name}}</ion-option>
 | 
				
			||||||
 | 
					                    </ion-select>
 | 
				
			||||||
 | 
					                </ion-item>
 | 
				
			||||||
                <!-- List of submissions. -->
 | 
					                <!-- List of submissions. -->
 | 
				
			||||||
                <ng-container *ngFor="let submission of submissions">
 | 
					                <ng-container *ngFor="let submission of submissions">
 | 
				
			||||||
                    <a ion-item text-wrap (click)="loadSubmission(submission)" [class.core-split-item-selected]="submission.id == selectedSubmissionId">
 | 
					                    <a ion-item text-wrap (click)="loadSubmission(submission)" [class.core-split-item-selected]="submission.submitid == selectedSubmissionId">
 | 
				
			||||||
                        <ion-avatar core-user-avatar [user]="submission" item-start></ion-avatar>
 | 
					                        <ion-avatar core-user-avatar [user]="submission" [linkProfile]="false" item-start></ion-avatar>
 | 
				
			||||||
                        <h2 *ngIf="submission.userfullname">{{submission.userfullname}}</h2>
 | 
					                        <h2 *ngIf="submission.userfullname">{{submission.userfullname}}</h2>
 | 
				
			||||||
                        <h2 *ngIf="!submission.userfullname">{{ 'addon.mod_assign.hiddenuser' | translate }}{{submission.blindid}}</h2>
 | 
					                        <h2 *ngIf="!submission.userfullname">{{ 'addon.mod_assign.hiddenuser' | translate }}{{submission.blindid}}</h2>
 | 
				
			||||||
                        <p *ngIf="assign.teamsubmission">
 | 
					                        <p *ngIf="assign.teamsubmission">
 | 
				
			||||||
 | 
				
			|||||||
@ -18,6 +18,7 @@ import { TranslateService } from '@ngx-translate/core';
 | 
				
			|||||||
import { CoreEventsProvider } from '@providers/events';
 | 
					import { CoreEventsProvider } from '@providers/events';
 | 
				
			||||||
import { CoreSitesProvider } from '@providers/sites';
 | 
					import { CoreSitesProvider } from '@providers/sites';
 | 
				
			||||||
import { CoreDomUtilsProvider } from '@providers/utils/dom';
 | 
					import { CoreDomUtilsProvider } from '@providers/utils/dom';
 | 
				
			||||||
 | 
					import { CoreGroupsProvider, CoreGroupInfo } from '@providers/groups';
 | 
				
			||||||
import { AddonModAssignProvider } from '../../providers/assign';
 | 
					import { AddonModAssignProvider } from '../../providers/assign';
 | 
				
			||||||
import { AddonModAssignOfflineProvider } from '../../providers/assign-offline';
 | 
					import { AddonModAssignOfflineProvider } from '../../providers/assign-offline';
 | 
				
			||||||
import { AddonModAssignHelperProvider } from '../../providers/helper';
 | 
					import { AddonModAssignHelperProvider } from '../../providers/helper';
 | 
				
			||||||
@ -40,19 +41,28 @@ export class AddonModAssignSubmissionListPage implements OnInit, OnDestroy {
 | 
				
			|||||||
    loaded: boolean; // Whether data has been loaded.
 | 
					    loaded: boolean; // Whether data has been loaded.
 | 
				
			||||||
    haveAllParticipants: boolean; // Whether all participants have been loaded.
 | 
					    haveAllParticipants: boolean; // Whether all participants have been loaded.
 | 
				
			||||||
    selectedSubmissionId: number; // Selected submission ID.
 | 
					    selectedSubmissionId: number; // Selected submission ID.
 | 
				
			||||||
 | 
					    groupId = 0; // Group ID to show.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    groupInfo: CoreGroupInfo = {
 | 
				
			||||||
 | 
					        groups: [],
 | 
				
			||||||
 | 
					        separateGroups: false,
 | 
				
			||||||
 | 
					        visibleGroups: false
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    protected moduleId: number; // Module ID the submission belongs to.
 | 
					    protected moduleId: number; // Module ID the submission belongs to.
 | 
				
			||||||
    protected courseId: number; // Course ID the assignment belongs to.
 | 
					    protected courseId: number; // Course ID the assignment belongs to.
 | 
				
			||||||
    protected selectedStatus: string; // The status to see.
 | 
					    protected selectedStatus: string; // The status to see.
 | 
				
			||||||
    protected gradedObserver; // Observer to refresh data when a grade changes.
 | 
					    protected gradedObserver; // Observer to refresh data when a grade changes.
 | 
				
			||||||
 | 
					    protected submissionsData: any;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    constructor(navParams: NavParams, sitesProvider: CoreSitesProvider, eventsProvider: CoreEventsProvider,
 | 
					    constructor(navParams: NavParams, sitesProvider: CoreSitesProvider, eventsProvider: CoreEventsProvider,
 | 
				
			||||||
            protected domUtils: CoreDomUtilsProvider, protected translate: TranslateService,
 | 
					            protected domUtils: CoreDomUtilsProvider, protected translate: TranslateService,
 | 
				
			||||||
            protected assignProvider: AddonModAssignProvider, protected assignOfflineProvider: AddonModAssignOfflineProvider,
 | 
					            protected assignProvider: AddonModAssignProvider, protected assignOfflineProvider: AddonModAssignOfflineProvider,
 | 
				
			||||||
            protected assignHelper: AddonModAssignHelperProvider) {
 | 
					            protected assignHelper: AddonModAssignHelperProvider, protected groupsProvider: CoreGroupsProvider) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        this.moduleId = navParams.get('moduleId');
 | 
					        this.moduleId = navParams.get('moduleId');
 | 
				
			||||||
        this.courseId = navParams.get('courseId');
 | 
					        this.courseId = navParams.get('courseId');
 | 
				
			||||||
 | 
					        this.groupId = navParams.get('groupId');
 | 
				
			||||||
        this.selectedStatus = navParams.get('status');
 | 
					        this.selectedStatus = navParams.get('status');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (this.selectedStatus) {
 | 
					        if (this.selectedStatus) {
 | 
				
			||||||
@ -98,15 +108,11 @@ export class AddonModAssignSubmissionListPage implements OnInit, OnDestroy {
 | 
				
			|||||||
     * @return {Promise<any>} Promise resolved when done.
 | 
					     * @return {Promise<any>} Promise resolved when done.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    protected fetchAssignment(): Promise<any> {
 | 
					    protected fetchAssignment(): Promise<any> {
 | 
				
			||||||
        let participants,
 | 
					 | 
				
			||||||
            submissionsData,
 | 
					 | 
				
			||||||
            grades;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Get assignment data.
 | 
					        // Get assignment data.
 | 
				
			||||||
        return this.assignProvider.getAssignment(this.courseId, this.moduleId).then((assign) => {
 | 
					        return this.assignProvider.getAssignment(this.courseId, this.moduleId).then((assign) => {
 | 
				
			||||||
            this.title = assign.name || this.title;
 | 
					            this.title = assign.name || this.title;
 | 
				
			||||||
            this.assign = assign;
 | 
					            this.assign = assign;
 | 
				
			||||||
            this.haveAllParticipants = true;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // Get assignment submissions.
 | 
					            // Get assignment submissions.
 | 
				
			||||||
            return this.assignProvider.getSubmissions(assign.id);
 | 
					            return this.assignProvider.getSubmissions(assign.id);
 | 
				
			||||||
@ -116,15 +122,39 @@ export class AddonModAssignSubmissionListPage implements OnInit, OnDestroy {
 | 
				
			|||||||
                return Promise.reject(null);
 | 
					                return Promise.reject(null);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            submissionsData = data;
 | 
					            this.submissionsData = data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // Get the participants.
 | 
					            // Check if groupmode is enabled to avoid showing wrong numbers.
 | 
				
			||||||
            return this.assignHelper.getParticipants(this.assign).then((parts) => {
 | 
					            return this.groupsProvider.getActivityGroupInfo(this.assign.cmid, false).then((groupInfo) => {
 | 
				
			||||||
                this.haveAllParticipants = true;
 | 
					                this.groupInfo = groupInfo;
 | 
				
			||||||
                participants = parts;
 | 
					
 | 
				
			||||||
            }).catch(() => {
 | 
					                return this.setGroup(this.groupId || (groupInfo.groups && groupInfo.groups[0] && groupInfo.groups[0].id) || 0);
 | 
				
			||||||
                this.haveAllParticipants = false;
 | 
					 | 
				
			||||||
            });
 | 
					            });
 | 
				
			||||||
 | 
					        }).catch((error) => {
 | 
				
			||||||
 | 
					            this.domUtils.showErrorModalDefault(error, 'Error getting assigment data.');
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Set group to see the summary.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param  {number}       groupId Group ID.
 | 
				
			||||||
 | 
					     * @return {Promise<any>}         Resolved when done.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    setGroup(groupId: number): Promise<any> {
 | 
				
			||||||
 | 
					        let participants,
 | 
				
			||||||
 | 
					            grades;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this.groupId = groupId;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this.haveAllParticipants = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Get the participants.
 | 
				
			||||||
 | 
					        return this.assignHelper.getParticipants(this.assign, this.groupId).then((parts) => {
 | 
				
			||||||
 | 
					            this.haveAllParticipants = true;
 | 
				
			||||||
 | 
					            participants = parts;
 | 
				
			||||||
 | 
					        }).catch(() => {
 | 
				
			||||||
 | 
					            this.haveAllParticipants = false;
 | 
				
			||||||
        }).then(() => {
 | 
					        }).then(() => {
 | 
				
			||||||
            if (!this.assign.markingworkflow) {
 | 
					            if (!this.assign.markingworkflow) {
 | 
				
			||||||
                // Get assignment grades only if workflow is not enabled to check grading date.
 | 
					                // Get assignment grades only if workflow is not enabled to check grading date.
 | 
				
			||||||
@ -134,16 +164,16 @@ export class AddonModAssignSubmissionListPage implements OnInit, OnDestroy {
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        }).then(() => {
 | 
					        }).then(() => {
 | 
				
			||||||
            // We want to show the user data on each submission.
 | 
					            // We want to show the user data on each submission.
 | 
				
			||||||
            return this.assignProvider.getSubmissionsUserData(submissionsData.submissions, this.courseId, this.assign.id,
 | 
					            return this.assignProvider.getSubmissionsUserData(this.submissionsData.submissions, this.courseId, this.assign.id,
 | 
				
			||||||
                    this.assign.blindmarking && !this.assign.revealidentities, participants);
 | 
					                    this.assign.blindmarking && !this.assign.revealidentities, participants);
 | 
				
			||||||
        }).then((submissions) => {
 | 
					        }).then((submissions) => {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // Filter the submissions to get only the ones with the right status and add some extra data.
 | 
					            // Filter the submissions to get only the ones with the right status and add some extra data.
 | 
				
			||||||
            const getNeedGrading = this.selectedStatus == AddonModAssignProvider.NEED_GRADING,
 | 
					            const getNeedGrading = this.selectedStatus == AddonModAssignProvider.NEED_GRADING,
 | 
				
			||||||
                searchStatus = getNeedGrading ? AddonModAssignProvider.SUBMISSION_STATUS_SUBMITTED : this.selectedStatus,
 | 
					                searchStatus = getNeedGrading ? AddonModAssignProvider.SUBMISSION_STATUS_SUBMITTED : this.selectedStatus,
 | 
				
			||||||
                promises = [];
 | 
					                promises = [],
 | 
				
			||||||
 | 
					                showSubmissions = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            this.submissions = [];
 | 
					 | 
				
			||||||
            submissions.forEach((submission) => {
 | 
					            submissions.forEach((submission) => {
 | 
				
			||||||
                if (!searchStatus || searchStatus == submission.status) {
 | 
					                if (!searchStatus || searchStatus == submission.status) {
 | 
				
			||||||
                    promises.push(this.assignOfflineProvider.getSubmissionGrade(this.assign.id, submission.userid).catch(() => {
 | 
					                    promises.push(this.assignOfflineProvider.getSubmissionGrade(this.assign.id, submission.userid).catch(() => {
 | 
				
			||||||
@ -203,15 +233,15 @@ export class AddonModAssignSubmissionListPage implements OnInit, OnDestroy {
 | 
				
			|||||||
                                submission.gradingStatusTranslationId = false;
 | 
					                                submission.gradingStatusTranslationId = false;
 | 
				
			||||||
                            }
 | 
					                            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                            this.submissions.push(submission);
 | 
					                            showSubmissions.push(submission);
 | 
				
			||||||
                        });
 | 
					                        });
 | 
				
			||||||
                    }));
 | 
					                    }));
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            });
 | 
					            });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            return Promise.all(promises);
 | 
					            return Promise.all(promises).then(() => {
 | 
				
			||||||
        }).catch((error) => {
 | 
					                this.submissions = showSubmissions;
 | 
				
			||||||
            this.domUtils.showErrorModalDefault(error, 'Error getting assigment data.');
 | 
					            });
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -221,12 +251,12 @@ export class AddonModAssignSubmissionListPage implements OnInit, OnDestroy {
 | 
				
			|||||||
     * @param {any} submission The submission to load.
 | 
					     * @param {any} submission The submission to load.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    loadSubmission(submission: any): void {
 | 
					    loadSubmission(submission: any): void {
 | 
				
			||||||
        if (this.selectedSubmissionId === submission.id && this.splitviewCtrl.isOn()) {
 | 
					        if (this.selectedSubmissionId === submission.submitid && this.splitviewCtrl.isOn()) {
 | 
				
			||||||
            // Already selected.
 | 
					            // Already selected.
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        this.selectedSubmissionId = submission.id;
 | 
					        this.selectedSubmissionId = submission.submitid;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        this.splitviewCtrl.push('AddonModAssignSubmissionReviewPage', {
 | 
					        this.splitviewCtrl.push('AddonModAssignSubmissionReviewPage', {
 | 
				
			||||||
            courseId: this.courseId,
 | 
					            courseId: this.courseId,
 | 
				
			||||||
 | 
				
			|||||||
@ -132,7 +132,8 @@ export class AddonModAssignSubmissionReviewPage implements OnInit {
 | 
				
			|||||||
        if (this.assign) {
 | 
					        if (this.assign) {
 | 
				
			||||||
            promises.push(this.assignProvider.invalidateSubmissionData(this.assign.id));
 | 
					            promises.push(this.assignProvider.invalidateSubmissionData(this.assign.id));
 | 
				
			||||||
            promises.push(this.assignProvider.invalidateAssignmentUserMappingsData(this.assign.id));
 | 
					            promises.push(this.assignProvider.invalidateAssignmentUserMappingsData(this.assign.id));
 | 
				
			||||||
            promises.push(this.assignProvider.invalidateSubmissionStatusData(this.assign.id, this.submitId, this.blindMarking));
 | 
					            promises.push(this.assignProvider.invalidateSubmissionStatusData(this.assign.id, this.submitId, undefined,
 | 
				
			||||||
 | 
					                this.blindMarking));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return Promise.all(promises).finally(() => {
 | 
					        return Promise.all(promises).finally(() => {
 | 
				
			||||||
 | 
				
			|||||||
@ -275,7 +275,7 @@ export class AddonModAssignSyncProvider extends CoreSyncBaseProvider {
 | 
				
			|||||||
        let discardError,
 | 
					        let discardError,
 | 
				
			||||||
            submission;
 | 
					            submission;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return this.assignProvider.getSubmissionStatus(assign.id, userId, false, true, true, siteId).then((status) => {
 | 
					        return this.assignProvider.getSubmissionStatus(assign.id, userId, undefined, false, true, true, siteId).then((status) => {
 | 
				
			||||||
            const promises = [];
 | 
					            const promises = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            submission = this.assignProvider.getSubmissionObjectFromAttempt(assign, status.lastattempt);
 | 
					            submission = this.assignProvider.getSubmissionObjectFromAttempt(assign, status.lastattempt);
 | 
				
			||||||
@ -310,7 +310,7 @@ export class AddonModAssignSyncProvider extends CoreSyncBaseProvider {
 | 
				
			|||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }).then(() => {
 | 
					                }).then(() => {
 | 
				
			||||||
                    // Submission data sent, update cached data. No need to block the user for this.
 | 
					                    // Submission data sent, update cached data. No need to block the user for this.
 | 
				
			||||||
                    this.assignProvider.getSubmissionStatus(assign.id, userId, false, true, true, siteId);
 | 
					                    this.assignProvider.getSubmissionStatus(assign.id, userId, undefined, false, true, true, siteId);
 | 
				
			||||||
                });
 | 
					                });
 | 
				
			||||||
            }).catch((error) => {
 | 
					            }).catch((error) => {
 | 
				
			||||||
                if (error && this.utils.isWebServiceError(error)) {
 | 
					                if (error && this.utils.isWebServiceError(error)) {
 | 
				
			||||||
@ -364,7 +364,7 @@ export class AddonModAssignSyncProvider extends CoreSyncBaseProvider {
 | 
				
			|||||||
        const userId = offlineData.userid;
 | 
					        const userId = offlineData.userid;
 | 
				
			||||||
        let discardError;
 | 
					        let discardError;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return this.assignProvider.getSubmissionStatus(assign.id, userId, false, true, true, siteId).then((status) => {
 | 
					        return this.assignProvider.getSubmissionStatus(assign.id, userId, undefined, false, true, true, siteId).then((status) => {
 | 
				
			||||||
            const timemodified = status.feedback && (status.feedback.gradeddate || status.feedback.grade.timemodified);
 | 
					            const timemodified = status.feedback && (status.feedback.gradeddate || status.feedback.grade.timemodified);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (timemodified > offlineData.timemodified) {
 | 
					            if (timemodified > offlineData.timemodified) {
 | 
				
			||||||
@ -405,7 +405,7 @@ export class AddonModAssignSyncProvider extends CoreSyncBaseProvider {
 | 
				
			|||||||
                        offlineData.plugindata, siteId).then(() => {
 | 
					                        offlineData.plugindata, siteId).then(() => {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    // Grades sent, update cached data. No need to block the user for this.
 | 
					                    // Grades sent, update cached data. No need to block the user for this.
 | 
				
			||||||
                    this.assignProvider.getSubmissionStatus(assign.id, userId, false, true, true, siteId);
 | 
					                    this.assignProvider.getSubmissionStatus(assign.id, userId, undefined, false, true, true, siteId);
 | 
				
			||||||
                }).catch((error) => {
 | 
					                }).catch((error) => {
 | 
				
			||||||
                    if (error && this.utils.isWebServiceError(error)) {
 | 
					                    if (error && this.utils.isWebServiceError(error)) {
 | 
				
			||||||
                        // The WebService has thrown an error, this means it cannot be submitted. Discard the offline data.
 | 
					                        // The WebService has thrown an error, this means it cannot be submitted. Discard the offline data.
 | 
				
			||||||
 | 
				
			|||||||
@ -21,7 +21,6 @@ import { CoreTextUtilsProvider } from '@providers/utils/text';
 | 
				
			|||||||
import { CoreTimeUtilsProvider } from '@providers/utils/time';
 | 
					import { CoreTimeUtilsProvider } from '@providers/utils/time';
 | 
				
			||||||
import { CoreUtilsProvider } from '@providers/utils/utils';
 | 
					import { CoreUtilsProvider } from '@providers/utils/utils';
 | 
				
			||||||
import { CoreCommentsProvider } from '@core/comments/providers/comments';
 | 
					import { CoreCommentsProvider } from '@core/comments/providers/comments';
 | 
				
			||||||
import { CoreUserProvider } from '@core/user/providers/user';
 | 
					 | 
				
			||||||
import { CoreGradesProvider } from '@core/grades/providers/grades';
 | 
					import { CoreGradesProvider } from '@core/grades/providers/grades';
 | 
				
			||||||
import { CoreCourseLogHelperProvider } from '@core/course/providers/log-helper';
 | 
					import { CoreCourseLogHelperProvider } from '@core/course/providers/log-helper';
 | 
				
			||||||
import { AddonModAssignSubmissionDelegate } from './submission-delegate';
 | 
					import { AddonModAssignSubmissionDelegate } from './submission-delegate';
 | 
				
			||||||
@ -67,7 +66,7 @@ export class AddonModAssignProvider {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    constructor(logger: CoreLoggerProvider, private sitesProvider: CoreSitesProvider, private textUtils: CoreTextUtilsProvider,
 | 
					    constructor(logger: CoreLoggerProvider, private sitesProvider: CoreSitesProvider, private textUtils: CoreTextUtilsProvider,
 | 
				
			||||||
            private timeUtils: CoreTimeUtilsProvider, private appProvider: CoreAppProvider, private utils: CoreUtilsProvider,
 | 
					            private timeUtils: CoreTimeUtilsProvider, private appProvider: CoreAppProvider, private utils: CoreUtilsProvider,
 | 
				
			||||||
            private userProvider: CoreUserProvider, private submissionDelegate: AddonModAssignSubmissionDelegate,
 | 
					            private submissionDelegate: AddonModAssignSubmissionDelegate,
 | 
				
			||||||
            private gradesProvider: CoreGradesProvider, private filepoolProvider: CoreFilepoolProvider,
 | 
					            private gradesProvider: CoreGradesProvider, private filepoolProvider: CoreFilepoolProvider,
 | 
				
			||||||
            private assignOffline: AddonModAssignOfflineProvider, private commentsProvider: CoreCommentsProvider,
 | 
					            private assignOffline: AddonModAssignOfflineProvider, private commentsProvider: CoreCommentsProvider,
 | 
				
			||||||
            private logHelper: CoreCourseLogHelperProvider) {
 | 
					            private logHelper: CoreCourseLogHelperProvider) {
 | 
				
			||||||
@ -495,31 +494,37 @@ export class AddonModAssignProvider {
 | 
				
			|||||||
     * Get information about an assignment submission status for a given user.
 | 
					     * Get information about an assignment submission status for a given user.
 | 
				
			||||||
     *
 | 
					     *
 | 
				
			||||||
     * @param {number} assignId Assignment instance id.
 | 
					     * @param {number} assignId Assignment instance id.
 | 
				
			||||||
     * @param {number} [userId] User id (empty for current user).
 | 
					     * @param {number} [userId] User Id (empty for current user).
 | 
				
			||||||
 | 
					     * @param {number} [groupId] Group Id (empty for all participants).
 | 
				
			||||||
     * @param {boolean} [isBlind] If blind marking is enabled or not.
 | 
					     * @param {boolean} [isBlind] If blind marking is enabled or not.
 | 
				
			||||||
     * @param {number} [filter=true] True to filter WS response and rewrite URLs, false otherwise.
 | 
					     * @param {number} [filter=true] True to filter WS response and rewrite URLs, false otherwise.
 | 
				
			||||||
     * @param {boolean} [ignoreCache] True if it should ignore cached data (it will always fail in offline or server down).
 | 
					     * @param {boolean} [ignoreCache] True if it should ignore cached data (it will always fail in offline or server down).
 | 
				
			||||||
     * @param {string} [siteId] Site id (empty for current site).
 | 
					     * @param {string} [siteId] Site id (empty for current site).
 | 
				
			||||||
     * @return {Promise<any>} Promise always resolved with the user submission status.
 | 
					     * @return {Promise<any>} Promise always resolved with the user submission status.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    getSubmissionStatus(assignId: number, userId?: number, isBlind?: boolean, filter: boolean = true, ignoreCache?: boolean,
 | 
					    getSubmissionStatus(assignId: number, userId?: number, groupId?: number, isBlind?: boolean, filter: boolean = true,
 | 
				
			||||||
            siteId?: string): Promise<any> {
 | 
					            ignoreCache?: boolean, siteId?: string): Promise<any> {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        userId = userId || 0;
 | 
					        userId = userId || 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return this.sitesProvider.getSite(siteId).then((site) => {
 | 
					        return this.sitesProvider.getSite(siteId).then((site) => {
 | 
				
			||||||
 | 
					            groupId = site.isVersionGreaterEqualThan('3.5') ? groupId || 0 : 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            const params = {
 | 
					            const params = {
 | 
				
			||||||
                    assignid: assignId,
 | 
					                    assignid: assignId,
 | 
				
			||||||
                    userid: userId
 | 
					                    userid: userId
 | 
				
			||||||
                },
 | 
					                },
 | 
				
			||||||
                preSets: CoreSiteWSPreSets = {
 | 
					                preSets: CoreSiteWSPreSets = {
 | 
				
			||||||
                    cacheKey: this.getSubmissionStatusCacheKey(assignId, userId, isBlind),
 | 
					                    cacheKey: this.getSubmissionStatusCacheKey(assignId, userId, groupId, isBlind),
 | 
				
			||||||
                    getCacheUsingCacheKey: true, // We use the cache key to take isBlind into account.
 | 
					                    getCacheUsingCacheKey: true, // We use the cache key to take isBlind into account.
 | 
				
			||||||
                    filter: filter,
 | 
					                    filter: filter,
 | 
				
			||||||
                    rewriteurls: filter
 | 
					                    rewriteurls: filter
 | 
				
			||||||
                };
 | 
					                };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (groupId) {
 | 
				
			||||||
 | 
					                params['groupid'] = groupId;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (ignoreCache) {
 | 
					            if (ignoreCache) {
 | 
				
			||||||
                preSets.getFromCache = false;
 | 
					                preSets.getFromCache = false;
 | 
				
			||||||
                preSets.emergencyCache = false;
 | 
					                preSets.emergencyCache = false;
 | 
				
			||||||
@ -541,21 +546,22 @@ export class AddonModAssignProvider {
 | 
				
			|||||||
     *
 | 
					     *
 | 
				
			||||||
     * @param {any} assign Assignment.
 | 
					     * @param {any} assign Assignment.
 | 
				
			||||||
     * @param {number} [userId] User id (empty for current user).
 | 
					     * @param {number} [userId] User id (empty for current user).
 | 
				
			||||||
 | 
					     * @param {number} [groupId] Group Id (empty for all participants).
 | 
				
			||||||
     * @param {boolean} [isBlind] If blind marking is enabled or not.
 | 
					     * @param {boolean} [isBlind] If blind marking is enabled or not.
 | 
				
			||||||
     * @param {number} [filter=true] True to filter WS response and rewrite URLs, false otherwise.
 | 
					     * @param {number} [filter=true] True to filter WS response and rewrite URLs, false otherwise.
 | 
				
			||||||
     * @param {boolean} [ignoreCache] True if it should ignore cached data (it will always fail in offline or server down).
 | 
					     * @param {boolean} [ignoreCache] True if it should ignore cached data (it will always fail in offline or server down).
 | 
				
			||||||
     * @param {string} [siteId] Site id (empty for current site).
 | 
					     * @param {string} [siteId] Site id (empty for current site).
 | 
				
			||||||
     * @return {Promise<any>} Promise always resolved with the user submission status.
 | 
					     * @return {Promise<any>} Promise always resolved with the user submission status.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    getSubmissionStatusWithRetry(assign: any, userId?: number, isBlind?: boolean, filter: boolean = true, ignoreCache?: boolean,
 | 
					    getSubmissionStatusWithRetry(assign: any, userId?: number, groupId?: number, isBlind?: boolean, filter: boolean = true,
 | 
				
			||||||
            siteId?: string): Promise<any> {
 | 
					            ignoreCache?: boolean, siteId?: string): Promise<any> {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return this.getSubmissionStatus(assign.id, userId, isBlind, filter, ignoreCache, siteId).then((response) => {
 | 
					        return this.getSubmissionStatus(assign.id, userId, groupId, isBlind, filter, ignoreCache, siteId).then((response) => {
 | 
				
			||||||
            const userSubmission = this.getSubmissionObjectFromAttempt(assign, response.lastattempt);
 | 
					            const userSubmission = this.getSubmissionObjectFromAttempt(assign, response.lastattempt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (!userSubmission) {
 | 
					            if (!userSubmission) {
 | 
				
			||||||
                // Try again, ignoring cache.
 | 
					                // Try again, ignoring cache.
 | 
				
			||||||
                return this.getSubmissionStatus(assign.id, userId, isBlind, filter, true, siteId).catch(() => {
 | 
					                return this.getSubmissionStatus(assign.id, userId, groupId, isBlind, filter, true, siteId).catch(() => {
 | 
				
			||||||
                    // Error, return the first result even if it doesn't have the user submission.
 | 
					                    // Error, return the first result even if it doesn't have the user submission.
 | 
				
			||||||
                    return response;
 | 
					                    return response;
 | 
				
			||||||
                });
 | 
					                });
 | 
				
			||||||
@ -570,16 +576,17 @@ export class AddonModAssignProvider {
 | 
				
			|||||||
     *
 | 
					     *
 | 
				
			||||||
     * @param {number} assignId Assignment instance id.
 | 
					     * @param {number} assignId Assignment instance id.
 | 
				
			||||||
     * @param {number} [userId] User id (empty for current user).
 | 
					     * @param {number} [userId] User id (empty for current user).
 | 
				
			||||||
 | 
					     * @param {number} [groupId] Group Id (empty for all participants).
 | 
				
			||||||
     * @param {number} [isBlind] If blind marking is enabled or not.
 | 
					     * @param {number} [isBlind] If blind marking is enabled or not.
 | 
				
			||||||
     * @return {string} Cache key.
 | 
					     * @return {string} Cache key.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    protected getSubmissionStatusCacheKey(assignId: number, userId: number, isBlind?: boolean): string {
 | 
					    protected getSubmissionStatusCacheKey(assignId: number, userId: number, groupId?: number, isBlind?: boolean): string {
 | 
				
			||||||
        if (!userId) {
 | 
					        if (!userId) {
 | 
				
			||||||
            isBlind = false;
 | 
					            isBlind = false;
 | 
				
			||||||
            userId = this.sitesProvider.getCurrentSiteUserId();
 | 
					            userId = this.sitesProvider.getCurrentSiteUserId();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return this.getSubmissionsCacheKey(assignId) + ':' + userId + ':' + (isBlind ? 1 : 0);
 | 
					        return this.getSubmissionsCacheKey(assignId) + ':' + userId + ':' + (isBlind ? 1 : 0) + ':' + groupId;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
@ -624,6 +631,10 @@ export class AddonModAssignProvider {
 | 
				
			|||||||
            subs = [],
 | 
					            subs = [],
 | 
				
			||||||
            hasParticipants = participants && participants.length > 0;
 | 
					            hasParticipants = participants && participants.length > 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (!hasParticipants) {
 | 
				
			||||||
 | 
					            return Promise.resolve([]);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        submissions.forEach((submission) => {
 | 
					        submissions.forEach((submission) => {
 | 
				
			||||||
            submission.submitid = submission.userid > 0 ? submission.userid : submission.blindid;
 | 
					            submission.submitid = submission.userid > 0 ? submission.userid : submission.blindid;
 | 
				
			||||||
            if (submission.submitid <= 0) {
 | 
					            if (submission.submitid <= 0) {
 | 
				
			||||||
@ -631,42 +642,30 @@ export class AddonModAssignProvider {
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            const participant = this.getParticipantFromUserId(participants, submission.submitid);
 | 
					            const participant = this.getParticipantFromUserId(participants, submission.submitid);
 | 
				
			||||||
            if (hasParticipants && !participant) {
 | 
					            if (!participant) {
 | 
				
			||||||
                // Avoid permission denied error. Participant not found on list.
 | 
					                // Avoid permission denied error. Participant not found on list.
 | 
				
			||||||
                return;
 | 
					                return;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (participant) {
 | 
					            if (!blind) {
 | 
				
			||||||
                if (!blind) {
 | 
					                submission.userfullname = participant.fullname;
 | 
				
			||||||
                    submission.userfullname = participant.fullname;
 | 
					                submission.userprofileimageurl = participant.profileimageurl;
 | 
				
			||||||
                    submission.userprofileimageurl = participant.profileimageurl;
 | 
					            }
 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                submission.manyGroups = !!participant.groups && participant.groups.length > 1;
 | 
					            submission.manyGroups = !!participant.groups && participant.groups.length > 1;
 | 
				
			||||||
                if (participant.groupname) {
 | 
					            if (participant.groupname) {
 | 
				
			||||||
                    submission.groupid = participant.groupid;
 | 
					                submission.groupid = participant.groupid;
 | 
				
			||||||
                    submission.groupname = participant.groupname;
 | 
					                submission.groupname = participant.groupname;
 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            let promise;
 | 
					            let promise;
 | 
				
			||||||
            if (submission.userid > 0) {
 | 
					            if (submission.userid > 0 && blind) {
 | 
				
			||||||
                if (blind) {
 | 
					                // Blind but not blinded! (Moodle < 3.1.1, 3.2).
 | 
				
			||||||
                    // Blind but not blinded! (Moodle < 3.1.1, 3.2).
 | 
					                delete submission.userid;
 | 
				
			||||||
                    delete submission.userid;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    promise = this.getAssignmentUserMappings(assignId, submission.submitid, ignoreCache, siteId).then((blindId) => {
 | 
					                promise = this.getAssignmentUserMappings(assignId, submission.submitid, ignoreCache, siteId).then((blindId) => {
 | 
				
			||||||
                        submission.blindid = blindId;
 | 
					                    submission.blindid = blindId;
 | 
				
			||||||
                    });
 | 
					                });
 | 
				
			||||||
                } else if (!participant) {
 | 
					 | 
				
			||||||
                    // No blind, no participant.
 | 
					 | 
				
			||||||
                    promise = this.userProvider.getProfile(submission.userid, courseId, true).then((user) => {
 | 
					 | 
				
			||||||
                        submission.userfullname = user.fullname;
 | 
					 | 
				
			||||||
                        submission.userprofileimageurl = user.profileimageurl;
 | 
					 | 
				
			||||||
                    }).catch(() => {
 | 
					 | 
				
			||||||
                        // Error getting profile, resolve promise without adding any extra data.
 | 
					 | 
				
			||||||
                    });
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            promise = promise || Promise.resolve();
 | 
					            promise = promise || Promise.resolve();
 | 
				
			||||||
@ -899,13 +898,15 @@ export class AddonModAssignProvider {
 | 
				
			|||||||
     *
 | 
					     *
 | 
				
			||||||
     * @param {number} assignId Assignment instance id.
 | 
					     * @param {number} assignId Assignment instance id.
 | 
				
			||||||
     * @param {number} [userId] User id (empty for current user).
 | 
					     * @param {number} [userId] User id (empty for current user).
 | 
				
			||||||
 | 
					     * @param {number} [groupId] Group Id (empty for all participants).
 | 
				
			||||||
     * @param {boolean} [isBlind] Whether blind marking is enabled or not.
 | 
					     * @param {boolean} [isBlind] Whether blind marking is enabled or not.
 | 
				
			||||||
     * @param {string} [siteId] Site ID. If not defined, current site.
 | 
					     * @param {string} [siteId] Site ID. If not defined, current site.
 | 
				
			||||||
     * @return {Promise<any>} Promise resolved when the data is invalidated.
 | 
					     * @return {Promise<any>} Promise resolved when the data is invalidated.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    invalidateSubmissionStatusData(assignId: number, userId?: number, isBlind?: boolean, siteId?: string): Promise<any> {
 | 
					    invalidateSubmissionStatusData(assignId: number, userId?: number, groupId?: number, isBlind?: boolean, siteId?: string):
 | 
				
			||||||
 | 
					            Promise<any> {
 | 
				
			||||||
        return this.sitesProvider.getSite(siteId).then((site) => {
 | 
					        return this.sitesProvider.getSite(siteId).then((site) => {
 | 
				
			||||||
            return site.invalidateWsCacheForKey(this.getSubmissionStatusCacheKey(assignId, userId, isBlind));
 | 
					            return site.invalidateWsCacheForKey(this.getSubmissionStatusCacheKey(assignId, userId, groupId, isBlind));
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -1087,7 +1088,7 @@ export class AddonModAssignProvider {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // We need more data to decide that.
 | 
					        // We need more data to decide that.
 | 
				
			||||||
        return this.getSubmissionStatus(assignId, submission.submitid, submission.blindid).then((response) => {
 | 
					        return this.getSubmissionStatus(assignId, submission.submitid, undefined, submission.blindid).then((response) => {
 | 
				
			||||||
            if (!response.feedback || !response.feedback.gradeddate) {
 | 
					            if (!response.feedback || !response.feedback.gradeddate) {
 | 
				
			||||||
                // Not graded.
 | 
					                // Not graded.
 | 
				
			||||||
                return true;
 | 
					                return true;
 | 
				
			||||||
 | 
				
			|||||||
@ -149,21 +149,22 @@ export class AddonModAssignHelperProvider {
 | 
				
			|||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * List the participants for a single assignment, with some summary info about their submissions.
 | 
					     * List the participants for a single assignment, with some summary info about their submissions.
 | 
				
			||||||
     *
 | 
					     *
 | 
				
			||||||
     * @param {any} assign Assignment object
 | 
					     * @param {any} assign Assignment object.
 | 
				
			||||||
 | 
					     * @param {number} [groupId] Group Id.
 | 
				
			||||||
     * @param {boolean} [ignoreCache] True if it should ignore cached data (it will always fail in offline or server down).
 | 
					     * @param {boolean} [ignoreCache] True if it should ignore cached data (it will always fail in offline or server down).
 | 
				
			||||||
     * @param {string} [siteId] Site ID. If not defined, current site.
 | 
					     * @param {string} [siteId] Site ID. If not defined, current site.
 | 
				
			||||||
     * @return {Promise<any[]} Promise resolved with the list of participants and summary of submissions.
 | 
					     * @return {Promise<any[]} Promise resolved with the list of participants and summary of submissions.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    getParticipants(assign: any, ignoreCache?: boolean, siteId?: string): Promise<any[]> {
 | 
					    getParticipants(assign: any, groupId?: number, ignoreCache?: boolean, siteId?: string): Promise<any[]> {
 | 
				
			||||||
 | 
					        groupId = groupId || 0;
 | 
				
			||||||
        siteId = siteId || this.sitesProvider.getCurrentSiteId();
 | 
					        siteId = siteId || this.sitesProvider.getCurrentSiteId();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Get the participants without specifying a group.
 | 
					        return this.assignProvider.listParticipants(assign.id, groupId, ignoreCache, siteId).then((participants) => {
 | 
				
			||||||
        return this.assignProvider.listParticipants(assign.id, undefined, ignoreCache, siteId).then((participants) => {
 | 
					            if (groupId || participants && participants.length > 0) {
 | 
				
			||||||
            if (participants && participants.length > 0) {
 | 
					 | 
				
			||||||
                return participants;
 | 
					                return participants;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // If no participants returned, get participants by groups.
 | 
					            // If no participants returned and all groups specified, get participants by groups.
 | 
				
			||||||
            return this.groupsProvider.getActivityAllowedGroupsIfEnabled(assign.cmid, undefined, siteId).then((userGroups) => {
 | 
					            return this.groupsProvider.getActivityAllowedGroupsIfEnabled(assign.cmid, undefined, siteId).then((userGroups) => {
 | 
				
			||||||
                const promises = [],
 | 
					                const promises = [],
 | 
				
			||||||
                    participants = {};
 | 
					                    participants = {};
 | 
				
			||||||
 | 
				
			|||||||
@ -156,7 +156,7 @@ export class AddonModAssignPrefetchHandler extends CoreCourseActivityPrefetchHan
 | 
				
			|||||||
    protected getSubmissionFiles(assign: any, submitId: number, blindMarking: boolean, siteId?: string)
 | 
					    protected getSubmissionFiles(assign: any, submitId: number, blindMarking: boolean, siteId?: string)
 | 
				
			||||||
            : Promise<any[]> {
 | 
					            : Promise<any[]> {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return this.assignProvider.getSubmissionStatusWithRetry(assign, submitId, blindMarking, true, false, siteId)
 | 
					        return this.assignProvider.getSubmissionStatusWithRetry(assign, submitId, undefined, blindMarking, true, false, siteId)
 | 
				
			||||||
                .then((response) => {
 | 
					                .then((response) => {
 | 
				
			||||||
            const promises = [];
 | 
					            const promises = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -287,7 +287,6 @@ export class AddonModAssignPrefetchHandler extends CoreCourseActivityPrefetchHan
 | 
				
			|||||||
     * @return {Promise<any>} Promise resolved when prefetched, rejected otherwise.
 | 
					     * @return {Promise<any>} Promise resolved when prefetched, rejected otherwise.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    protected prefetchSubmissions(assign: any, courseId: number, moduleId: number, userId: number, siteId: string): Promise<any> {
 | 
					    protected prefetchSubmissions(assign: any, courseId: number, moduleId: number, userId: number, siteId: string): Promise<any> {
 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Get submissions.
 | 
					        // Get submissions.
 | 
				
			||||||
        return this.assignProvider.getSubmissions(assign.id, true, siteId).then((data) => {
 | 
					        return this.assignProvider.getSubmissions(assign.id, true, siteId).then((data) => {
 | 
				
			||||||
            const promises = [],
 | 
					            const promises = [],
 | 
				
			||||||
@ -295,55 +294,67 @@ export class AddonModAssignPrefetchHandler extends CoreCourseActivityPrefetchHan
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            if (data.canviewsubmissions) {
 | 
					            if (data.canviewsubmissions) {
 | 
				
			||||||
                // Teacher. Do not send participants to getSubmissionsUserData to retrieve user profiles.
 | 
					                // Teacher. Do not send participants to getSubmissionsUserData to retrieve user profiles.
 | 
				
			||||||
                promises.push(this.assignProvider.getSubmissionsUserData(data.submissions, courseId, assign.id, blindMarking,
 | 
					                promises.push(this.groupsProvider.getActivityGroupInfo(assign.cmid, false, undefined, siteId).then((groupInfo) => {
 | 
				
			||||||
                        undefined, true, siteId).then((submissions) => {
 | 
					                    const groupProms = [];
 | 
				
			||||||
 | 
					                    if (!groupInfo.groups || groupInfo.groups.length == 0) {
 | 
				
			||||||
 | 
					                        groupInfo.groups = [{id: 0}];
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    const subPromises = [];
 | 
					                    groupInfo.groups.forEach((group) => {
 | 
				
			||||||
 | 
					                        groupProms.push(this.assignProvider.getSubmissionsUserData(data.submissions, courseId, assign.id,
 | 
				
			||||||
 | 
					                                blindMarking, undefined, true, siteId).then((submissions) => {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    submissions.forEach((submission) => {
 | 
					                            const subPromises = [];
 | 
				
			||||||
                        subPromises.push(this.assignProvider.getSubmissionStatusWithRetry(assign, submission.submitid,
 | 
					
 | 
				
			||||||
                                !!submission.blindid, true, true, siteId).then((subm) => {
 | 
					                            submissions.forEach((submission) => {
 | 
				
			||||||
                            return this.prefetchSubmission(assign, courseId, moduleId, subm, submission.submitid, siteId);
 | 
					                                subPromises.push(this.assignProvider.getSubmissionStatusWithRetry(assign, submission.submitid,
 | 
				
			||||||
                        }).catch((error) => {
 | 
					                                        group.id, !!submission.blindid, true, true, siteId).then((subm) => {
 | 
				
			||||||
                            if (error && error.errorcode == 'nopermission') {
 | 
					                                    return this.prefetchSubmission(assign, courseId, moduleId, subm, submission.submitid, siteId);
 | 
				
			||||||
                                // The user does not have persmission to view this submission, ignore it.
 | 
					                                }).catch((error) => {
 | 
				
			||||||
                                return Promise.resolve();
 | 
					                                    if (error && error.errorcode == 'nopermission') {
 | 
				
			||||||
 | 
					                                        // The user does not have persmission to view this submission, ignore it.
 | 
				
			||||||
 | 
					                                        return Promise.resolve();
 | 
				
			||||||
 | 
					                                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                    return Promise.reject(error);
 | 
				
			||||||
 | 
					                                }));
 | 
				
			||||||
 | 
					                            });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            if (!assign.markingworkflow) {
 | 
				
			||||||
 | 
					                                // Get assignment grades only if workflow is not enabled to check grading date.
 | 
				
			||||||
 | 
					                                subPromises.push(this.assignProvider.getAssignmentGrades(assign.id, true, siteId));
 | 
				
			||||||
                            }
 | 
					                            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                            return Promise.reject(error);
 | 
					                            // Prefetch the submission of the current user even if it does not exist, this will be create it.
 | 
				
			||||||
 | 
					                            if (!data.submissions || !data.submissions.find((subm) => subm.submitid == userId)) {
 | 
				
			||||||
 | 
					                                subPromises.push(this.assignProvider.getSubmissionStatusWithRetry(assign, userId, group.id,
 | 
				
			||||||
 | 
					                                        false, true, true, siteId).then((subm) => {
 | 
				
			||||||
 | 
					                                    return this.prefetchSubmission(assign, courseId, moduleId, subm, userId, siteId);
 | 
				
			||||||
 | 
					                                }));
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            return Promise.all(subPromises);
 | 
				
			||||||
 | 
					                        }));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        // Get list participants.
 | 
				
			||||||
 | 
					                        groupProms.push(this.assignHelper.getParticipants(assign, group.id, true, siteId).then((participants) => {
 | 
				
			||||||
 | 
					                            participants.forEach((participant) => {
 | 
				
			||||||
 | 
					                                if (participant.profileimageurl) {
 | 
				
			||||||
 | 
					                                    this.filepoolProvider.addToQueueByUrl(siteId, participant.profileimageurl);
 | 
				
			||||||
 | 
					                                }
 | 
				
			||||||
 | 
					                            });
 | 
				
			||||||
 | 
					                        }).catch(() => {
 | 
				
			||||||
 | 
					                            // Fail silently (Moodle < 3.2).
 | 
				
			||||||
                        }));
 | 
					                        }));
 | 
				
			||||||
                    });
 | 
					                    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    if (!assign.markingworkflow) {
 | 
					                    return Promise.all(groupProms);
 | 
				
			||||||
                        // Get assignment grades only if workflow is not enabled to check grading date.
 | 
					 | 
				
			||||||
                        subPromises.push(this.assignProvider.getAssignmentGrades(assign.id, true, siteId));
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    // Prefetch the submission of the current user even if it does not exist, this will be create it.
 | 
					 | 
				
			||||||
                    if (!data.submissions || !data.submissions.find((subm) => subm.submitid == userId)) {
 | 
					 | 
				
			||||||
                        subPromises.push(this.assignProvider.getSubmissionStatusWithRetry(assign, userId, false, true, true, siteId)
 | 
					 | 
				
			||||||
                                .then((subm) => {
 | 
					 | 
				
			||||||
                            return this.prefetchSubmission(assign, courseId, moduleId, subm, userId, siteId);
 | 
					 | 
				
			||||||
                        }));
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    return Promise.all(subPromises);
 | 
					 | 
				
			||||||
                }));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                // Get list participants.
 | 
					 | 
				
			||||||
                promises.push(this.assignHelper.getParticipants(assign, true, siteId).then((participants) => {
 | 
					 | 
				
			||||||
                    participants.forEach((participant) => {
 | 
					 | 
				
			||||||
                        if (participant.profileimageurl) {
 | 
					 | 
				
			||||||
                            this.filepoolProvider.addToQueueByUrl(siteId, participant.profileimageurl);
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                    });
 | 
					 | 
				
			||||||
                }).catch(() => {
 | 
					 | 
				
			||||||
                    // Fail silently (Moodle < 3.2).
 | 
					 | 
				
			||||||
                }));
 | 
					                }));
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                // Student.
 | 
					                // Student.
 | 
				
			||||||
                promises.push(
 | 
					                promises.push(
 | 
				
			||||||
                    this.assignProvider.getSubmissionStatusWithRetry(assign, userId, false, true, true, siteId).then((subm) => {
 | 
					                    this.assignProvider.getSubmissionStatusWithRetry(assign, userId, undefined, false, true, true, siteId)
 | 
				
			||||||
 | 
					                            .then((subm) => {
 | 
				
			||||||
                        return this.prefetchSubmission(assign, courseId, moduleId, subm, userId, siteId);
 | 
					                        return this.prefetchSubmission(assign, courseId, moduleId, subm, userId, siteId);
 | 
				
			||||||
                    }).catch((error) => {
 | 
					                    }).catch((error) => {
 | 
				
			||||||
                        // Ignore if the user can't view their own submission.
 | 
					                        // Ignore if the user can't view their own submission.
 | 
				
			||||||
 | 
				
			|||||||
@ -645,7 +645,7 @@ ion-app.app-root {
 | 
				
			|||||||
        @include padding(null, null, null, 52px);
 | 
					        @include padding(null, null, null, 52px);
 | 
				
			||||||
        position: relative;
 | 
					        position: relative;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        ion-icon {
 | 
					        > ion-icon {
 | 
				
			||||||
          color: $color-base;
 | 
					          color: $color-base;
 | 
				
			||||||
          position: absolute;
 | 
					          position: absolute;
 | 
				
			||||||
          @include position(0, null, null, 16px)
 | 
					          @include position(0, null, null, 16px)
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user