diff --git a/src/addon/mod/assign/components/index/addon-mod-assign-index.html b/src/addon/mod/assign/components/index/addon-mod-assign-index.html index 96a7e5865..edf43166f 100644 --- a/src/addon/mod/assign/components/index/addon-mod-assign-index.html +++ b/src/addon/mod/assign/components/index/addon-mod-assign-index.html @@ -32,7 +32,15 @@ - + + + {{ 'core.groupsseparate' | translate }} + {{ 'core.groupsvisible' | translate }} + + {{groupOpt.name}} + + +

{{ 'addon.mod_assign.timeremaining' | translate }}

{{ timeRemaining }}

@@ -80,7 +88,7 @@ {{ 'addon.mod_assign.ungroupedusers' | translate }} -
+ diff --git a/src/addon/mod/assign/components/index/index.ts b/src/addon/mod/assign/components/index/index.ts index 23d2ebda0..7cd42a015 100644 --- a/src/addon/mod/assign/components/index/index.ts +++ b/src/addon/mod/assign/components/index/index.ts @@ -14,7 +14,7 @@ import { Component, Optional, Injector, ViewChild } from '@angular/core'; import { Content, NavController } from 'ionic-angular'; -import { CoreGroupsProvider } from '@providers/groups'; +import { CoreGroupsProvider, CoreGroupInfo } from '@providers/groups'; import { CoreTimeUtilsProvider } from '@providers/utils/time'; import { CoreCourseModuleMainActivityComponent } from '@core/course/classes/main-activity-component'; import { AddonModAssignProvider } from '../../providers/assign'; @@ -45,6 +45,12 @@ export class AddonModAssignIndexComponent extends CoreCourseModuleMainActivityCo summary: any; // The summary. needsGradingAvalaible: boolean; // Whether we can see the submissions that need grading. + groupInfo: CoreGroupInfo = { + groups: [], + separateGroups: false, + visibleGroups: false + }; + // Status. submissionStatusSubmitted = AddonModAssignProvider.SUBMISSION_STATUS_SUBMITTED; submissionStatusDraft = AddonModAssignProvider.SUBMISSION_STATUS_DRAFT; @@ -193,15 +199,13 @@ export class AddonModAssignIndexComponent extends CoreCourseModuleMainActivityCo } // Check if groupmode is enabled to avoid showing wrong numbers. - return this.groupsProvider.activityHasGroups(this.assign.cmid).then((hasGroups) => { - this.showNumbers = !hasGroups; + return this.groupsProvider.getActivityGroupInfo(this.assign.cmid, false).then((groupInfo) => { + this.groupInfo = groupInfo; + this.showNumbers = groupInfo.groups.length == 0 || + this.sitesProvider.getCurrentSite().isVersionGreaterEqualThan('3.5'); - return this.assignProvider.getSubmissionStatus(this.assign.id).then((response) => { - this.summary = response.gradingsummary; - - this.needsGradingAvalaible = response.gradingsummary.submissionsneedgradingcount > 0 && - this.sitesProvider.getCurrentSite().isVersionGreaterEqualThan('3.2'); - }); + return this.setGroup(this.group || (groupInfo.groups && groupInfo.groups[0] && groupInfo.groups[0].id) || + 0); }); } @@ -222,6 +226,23 @@ export class AddonModAssignIndexComponent extends CoreCourseModuleMainActivityCo }); } + /** + * Set group to see the summary. + * + * @param {number} groupId Group ID. + * @return {Promise} Resolved when done. + */ + setGroup(groupId: number): Promise { + 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. * @@ -232,6 +253,7 @@ export class AddonModAssignIndexComponent extends CoreCourseModuleMainActivityCo if (typeof status == 'undefined') { this.navCtrl.push('AddonModAssignSubmissionListPage', { courseId: this.courseId, + groupId: this.group || 0, moduleId: this.module.id, moduleName: this.moduleName }); @@ -239,6 +261,7 @@ export class AddonModAssignIndexComponent extends CoreCourseModuleMainActivityCo this.navCtrl.push('AddonModAssignSubmissionListPage', { status: status, courseId: this.courseId, + groupId: this.group || 0, moduleId: this.module.id, moduleName: this.moduleName }); @@ -273,7 +296,7 @@ export class AddonModAssignIndexComponent extends CoreCourseModuleMainActivityCo promises.push(this.assignProvider.invalidateAllSubmissionData(this.assign.id)); if (this.canViewAllSubmissions) { - promises.push(this.assignProvider.invalidateSubmissionStatusData(this.assign.id)); + promises.push(this.assignProvider.invalidateSubmissionStatusData(this.assign.id, undefined, this.group)); } } diff --git a/src/addon/mod/assign/components/submission/submission.ts b/src/addon/mod/assign/components/submission/submission.ts index d50a97a63..371c1bcf2 100644 --- a/src/addon/mod/assign/components/submission/submission.ts +++ b/src/addon/mod/assign/components/submission/submission.ts @@ -338,7 +338,8 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy { promises.push(this.assignProvider.invalidateAssignmentData(this.courseId)); 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.invalidateListParticipantsData(this.assign.id)); } @@ -408,7 +409,7 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy { return Promise.all(promises); }).then(() => { // Get submission status. - return this.assignProvider.getSubmissionStatusWithRetry(this.assign, this.submitId, isBlind); + return this.assignProvider.getSubmissionStatusWithRetry(this.assign, this.submitId, undefined, isBlind); }).then((response) => { const promises = []; diff --git a/src/addon/mod/assign/pages/edit/edit.ts b/src/addon/mod/assign/pages/edit/edit.ts index 3f2ba6c32..f6072f48f 100644 --- a/src/addon/mod/assign/pages/edit/edit.ts +++ b/src/addon/mod/assign/pages/edit/edit.ts @@ -121,9 +121,11 @@ export class AddonModAssignEditPage implements OnInit, OnDestroy { }).then(() => { // 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. - 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); // Check if the user can edit it in offline. diff --git a/src/addon/mod/assign/pages/submission-list/submission-list.html b/src/addon/mod/assign/pages/submission-list/submission-list.html index 8a0ff95ef..cd96434da 100644 --- a/src/addon/mod/assign/pages/submission-list/submission-list.html +++ b/src/addon/mod/assign/pages/submission-list/submission-list.html @@ -15,10 +15,17 @@ + + {{ 'core.groupsseparate' | translate }} + {{ 'core.groupsvisible' | translate }} + + {{groupOpt.name}} + + - - + +

{{submission.userfullname}}

{{ 'addon.mod_assign.hiddenuser' | translate }}{{submission.blindid}}

diff --git a/src/addon/mod/assign/pages/submission-list/submission-list.ts b/src/addon/mod/assign/pages/submission-list/submission-list.ts index d5103ccf3..8ce653613 100644 --- a/src/addon/mod/assign/pages/submission-list/submission-list.ts +++ b/src/addon/mod/assign/pages/submission-list/submission-list.ts @@ -18,6 +18,7 @@ import { TranslateService } from '@ngx-translate/core'; import { CoreEventsProvider } from '@providers/events'; import { CoreSitesProvider } from '@providers/sites'; import { CoreDomUtilsProvider } from '@providers/utils/dom'; +import { CoreGroupsProvider, CoreGroupInfo } from '@providers/groups'; import { AddonModAssignProvider } from '../../providers/assign'; import { AddonModAssignOfflineProvider } from '../../providers/assign-offline'; import { AddonModAssignHelperProvider } from '../../providers/helper'; @@ -40,19 +41,28 @@ export class AddonModAssignSubmissionListPage implements OnInit, OnDestroy { loaded: boolean; // Whether data has been loaded. haveAllParticipants: boolean; // Whether all participants have been loaded. 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 courseId: number; // Course ID the assignment belongs to. protected selectedStatus: string; // The status to see. protected gradedObserver; // Observer to refresh data when a grade changes. + protected submissionsData: any; constructor(navParams: NavParams, sitesProvider: CoreSitesProvider, eventsProvider: CoreEventsProvider, protected domUtils: CoreDomUtilsProvider, protected translate: TranslateService, protected assignProvider: AddonModAssignProvider, protected assignOfflineProvider: AddonModAssignOfflineProvider, - protected assignHelper: AddonModAssignHelperProvider) { + protected assignHelper: AddonModAssignHelperProvider, protected groupsProvider: CoreGroupsProvider) { this.moduleId = navParams.get('moduleId'); this.courseId = navParams.get('courseId'); + this.groupId = navParams.get('groupId'); this.selectedStatus = navParams.get('status'); if (this.selectedStatus) { @@ -98,15 +108,11 @@ export class AddonModAssignSubmissionListPage implements OnInit, OnDestroy { * @return {Promise} Promise resolved when done. */ protected fetchAssignment(): Promise { - let participants, - submissionsData, - grades; // Get assignment data. return this.assignProvider.getAssignment(this.courseId, this.moduleId).then((assign) => { this.title = assign.name || this.title; this.assign = assign; - this.haveAllParticipants = true; // Get assignment submissions. return this.assignProvider.getSubmissions(assign.id); @@ -116,15 +122,39 @@ export class AddonModAssignSubmissionListPage implements OnInit, OnDestroy { return Promise.reject(null); } - submissionsData = data; + this.submissionsData = data; - // Get the participants. - return this.assignHelper.getParticipants(this.assign).then((parts) => { - this.haveAllParticipants = true; - participants = parts; - }).catch(() => { - this.haveAllParticipants = false; + // Check if groupmode is enabled to avoid showing wrong numbers. + return this.groupsProvider.getActivityGroupInfo(this.assign.cmid, false).then((groupInfo) => { + this.groupInfo = groupInfo; + + return this.setGroup(this.groupId || (groupInfo.groups && groupInfo.groups[0] && groupInfo.groups[0].id) || 0); }); + }).catch((error) => { + this.domUtils.showErrorModalDefault(error, 'Error getting assigment data.'); + }); + } + + /** + * Set group to see the summary. + * + * @param {number} groupId Group ID. + * @return {Promise} Resolved when done. + */ + setGroup(groupId: number): Promise { + 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(() => { if (!this.assign.markingworkflow) { // Get assignment grades only if workflow is not enabled to check grading date. @@ -134,16 +164,16 @@ export class AddonModAssignSubmissionListPage implements OnInit, OnDestroy { } }).then(() => { // 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); }).then((submissions) => { // Filter the submissions to get only the ones with the right status and add some extra data. const getNeedGrading = this.selectedStatus == AddonModAssignProvider.NEED_GRADING, searchStatus = getNeedGrading ? AddonModAssignProvider.SUBMISSION_STATUS_SUBMITTED : this.selectedStatus, - promises = []; + promises = [], + showSubmissions = []; - this.submissions = []; submissions.forEach((submission) => { if (!searchStatus || searchStatus == submission.status) { promises.push(this.assignOfflineProvider.getSubmissionGrade(this.assign.id, submission.userid).catch(() => { @@ -203,15 +233,15 @@ export class AddonModAssignSubmissionListPage implements OnInit, OnDestroy { submission.gradingStatusTranslationId = false; } - this.submissions.push(submission); + showSubmissions.push(submission); }); })); } }); - return Promise.all(promises); - }).catch((error) => { - this.domUtils.showErrorModalDefault(error, 'Error getting assigment data.'); + return Promise.all(promises).then(() => { + this.submissions = showSubmissions; + }); }); } @@ -221,12 +251,12 @@ export class AddonModAssignSubmissionListPage implements OnInit, OnDestroy { * @param {any} submission The submission to load. */ loadSubmission(submission: any): void { - if (this.selectedSubmissionId === submission.id && this.splitviewCtrl.isOn()) { + if (this.selectedSubmissionId === submission.submitid && this.splitviewCtrl.isOn()) { // Already selected. return; } - this.selectedSubmissionId = submission.id; + this.selectedSubmissionId = submission.submitid; this.splitviewCtrl.push('AddonModAssignSubmissionReviewPage', { courseId: this.courseId, diff --git a/src/addon/mod/assign/pages/submission-review/submission-review.ts b/src/addon/mod/assign/pages/submission-review/submission-review.ts index be53916dc..44b0ca4a9 100644 --- a/src/addon/mod/assign/pages/submission-review/submission-review.ts +++ b/src/addon/mod/assign/pages/submission-review/submission-review.ts @@ -132,7 +132,8 @@ export class AddonModAssignSubmissionReviewPage implements OnInit { if (this.assign) { promises.push(this.assignProvider.invalidateSubmissionData(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(() => { diff --git a/src/addon/mod/assign/providers/assign-sync.ts b/src/addon/mod/assign/providers/assign-sync.ts index 6c1fdd33b..cff8c421a 100644 --- a/src/addon/mod/assign/providers/assign-sync.ts +++ b/src/addon/mod/assign/providers/assign-sync.ts @@ -275,7 +275,7 @@ export class AddonModAssignSyncProvider extends CoreSyncBaseProvider { let discardError, 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 = []; submission = this.assignProvider.getSubmissionObjectFromAttempt(assign, status.lastattempt); @@ -310,7 +310,7 @@ export class AddonModAssignSyncProvider extends CoreSyncBaseProvider { } }).then(() => { // 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) => { if (error && this.utils.isWebServiceError(error)) { @@ -364,7 +364,7 @@ export class AddonModAssignSyncProvider extends CoreSyncBaseProvider { const userId = offlineData.userid; 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); if (timemodified > offlineData.timemodified) { @@ -405,7 +405,7 @@ export class AddonModAssignSyncProvider extends CoreSyncBaseProvider { offlineData.plugindata, siteId).then(() => { // 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) => { if (error && this.utils.isWebServiceError(error)) { // The WebService has thrown an error, this means it cannot be submitted. Discard the offline data. diff --git a/src/addon/mod/assign/providers/assign.ts b/src/addon/mod/assign/providers/assign.ts index cbaa0501a..72320b5f7 100644 --- a/src/addon/mod/assign/providers/assign.ts +++ b/src/addon/mod/assign/providers/assign.ts @@ -21,7 +21,6 @@ import { CoreTextUtilsProvider } from '@providers/utils/text'; import { CoreTimeUtilsProvider } from '@providers/utils/time'; import { CoreUtilsProvider } from '@providers/utils/utils'; import { CoreCommentsProvider } from '@core/comments/providers/comments'; -import { CoreUserProvider } from '@core/user/providers/user'; import { CoreGradesProvider } from '@core/grades/providers/grades'; import { CoreCourseLogHelperProvider } from '@core/course/providers/log-helper'; import { AddonModAssignSubmissionDelegate } from './submission-delegate'; @@ -67,7 +66,7 @@ export class AddonModAssignProvider { constructor(logger: CoreLoggerProvider, private sitesProvider: CoreSitesProvider, private textUtils: CoreTextUtilsProvider, 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 assignOffline: AddonModAssignOfflineProvider, private commentsProvider: CoreCommentsProvider, private logHelper: CoreCourseLogHelperProvider) { @@ -495,31 +494,37 @@ export class AddonModAssignProvider { * Get information about an assignment submission status for a given user. * * @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 {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 {string} [siteId] Site id (empty for current site). * @return {Promise} Promise always resolved with the user submission status. */ - getSubmissionStatus(assignId: number, userId?: number, isBlind?: boolean, filter: boolean = true, ignoreCache?: boolean, - siteId?: string): Promise { + getSubmissionStatus(assignId: number, userId?: number, groupId?: number, isBlind?: boolean, filter: boolean = true, + ignoreCache?: boolean, siteId?: string): Promise { userId = userId || 0; return this.sitesProvider.getSite(siteId).then((site) => { + groupId = site.isVersionGreaterEqualThan('3.5') ? groupId || 0 : 0; const params = { assignid: assignId, userid: userId }, 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. filter: filter, rewriteurls: filter }; + if (groupId) { + params['groupid'] = groupId; + } + if (ignoreCache) { preSets.getFromCache = false; preSets.emergencyCache = false; @@ -541,21 +546,22 @@ export class AddonModAssignProvider { * * @param {any} assign Assignment. * @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 {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 {string} [siteId] Site id (empty for current site). * @return {Promise} Promise always resolved with the user submission status. */ - getSubmissionStatusWithRetry(assign: any, userId?: number, isBlind?: boolean, filter: boolean = true, ignoreCache?: boolean, - siteId?: string): Promise { + getSubmissionStatusWithRetry(assign: any, userId?: number, groupId?: number, isBlind?: boolean, filter: boolean = true, + ignoreCache?: boolean, siteId?: string): Promise { - 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); if (!userSubmission) { // 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. return response; }); @@ -570,16 +576,17 @@ export class AddonModAssignProvider { * * @param {number} assignId Assignment instance id. * @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. * @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) { isBlind = false; 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 = [], hasParticipants = participants && participants.length > 0; + if (!hasParticipants) { + return Promise.resolve([]); + } + submissions.forEach((submission) => { submission.submitid = submission.userid > 0 ? submission.userid : submission.blindid; if (submission.submitid <= 0) { @@ -631,42 +642,30 @@ export class AddonModAssignProvider { } const participant = this.getParticipantFromUserId(participants, submission.submitid); - if (hasParticipants && !participant) { + if (!participant) { // Avoid permission denied error. Participant not found on list. return; } - if (participant) { - if (!blind) { - submission.userfullname = participant.fullname; - submission.userprofileimageurl = participant.profileimageurl; - } + if (!blind) { + submission.userfullname = participant.fullname; + submission.userprofileimageurl = participant.profileimageurl; + } - submission.manyGroups = !!participant.groups && participant.groups.length > 1; - if (participant.groupname) { - submission.groupid = participant.groupid; - submission.groupname = participant.groupname; - } + submission.manyGroups = !!participant.groups && participant.groups.length > 1; + if (participant.groupname) { + submission.groupid = participant.groupid; + submission.groupname = participant.groupname; } let promise; - if (submission.userid > 0) { - if (blind) { - // Blind but not blinded! (Moodle < 3.1.1, 3.2). - delete submission.userid; + if (submission.userid > 0 && blind) { + // Blind but not blinded! (Moodle < 3.1.1, 3.2). + delete submission.userid; - promise = this.getAssignmentUserMappings(assignId, submission.submitid, ignoreCache, siteId).then((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 = this.getAssignmentUserMappings(assignId, submission.submitid, ignoreCache, siteId).then((blindId) => { + submission.blindid = blindId; + }); } promise = promise || Promise.resolve(); @@ -899,13 +898,15 @@ export class AddonModAssignProvider { * * @param {number} assignId Assignment instance id. * @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 {string} [siteId] Site ID. If not defined, current site. * @return {Promise} Promise resolved when the data is invalidated. */ - invalidateSubmissionStatusData(assignId: number, userId?: number, isBlind?: boolean, siteId?: string): Promise { + invalidateSubmissionStatusData(assignId: number, userId?: number, groupId?: number, isBlind?: boolean, siteId?: string): + Promise { 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. - 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) { // Not graded. return true; diff --git a/src/addon/mod/assign/providers/helper.ts b/src/addon/mod/assign/providers/helper.ts index 78478936d..6b64d5c1b 100644 --- a/src/addon/mod/assign/providers/helper.ts +++ b/src/addon/mod/assign/providers/helper.ts @@ -149,21 +149,22 @@ export class AddonModAssignHelperProvider { /** * 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 {string} [siteId] Site ID. If not defined, current site. * @return {Promise { + getParticipants(assign: any, groupId?: number, ignoreCache?: boolean, siteId?: string): Promise { + groupId = groupId || 0; siteId = siteId || this.sitesProvider.getCurrentSiteId(); - // Get the participants without specifying a group. - return this.assignProvider.listParticipants(assign.id, undefined, ignoreCache, siteId).then((participants) => { - if (participants && participants.length > 0) { + return this.assignProvider.listParticipants(assign.id, groupId, ignoreCache, siteId).then((participants) => { + if (groupId || participants && participants.length > 0) { 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) => { const promises = [], participants = {}; diff --git a/src/addon/mod/assign/providers/prefetch-handler.ts b/src/addon/mod/assign/providers/prefetch-handler.ts index 16f91940f..1bc206445 100644 --- a/src/addon/mod/assign/providers/prefetch-handler.ts +++ b/src/addon/mod/assign/providers/prefetch-handler.ts @@ -156,7 +156,7 @@ export class AddonModAssignPrefetchHandler extends CoreCourseActivityPrefetchHan protected getSubmissionFiles(assign: any, submitId: number, blindMarking: boolean, siteId?: string) : Promise { - return this.assignProvider.getSubmissionStatusWithRetry(assign, submitId, blindMarking, true, false, siteId) + return this.assignProvider.getSubmissionStatusWithRetry(assign, submitId, undefined, blindMarking, true, false, siteId) .then((response) => { const promises = []; @@ -287,7 +287,6 @@ export class AddonModAssignPrefetchHandler extends CoreCourseActivityPrefetchHan * @return {Promise} Promise resolved when prefetched, rejected otherwise. */ protected prefetchSubmissions(assign: any, courseId: number, moduleId: number, userId: number, siteId: string): Promise { - // Get submissions. return this.assignProvider.getSubmissions(assign.id, true, siteId).then((data) => { const promises = [], @@ -295,55 +294,67 @@ export class AddonModAssignPrefetchHandler extends CoreCourseActivityPrefetchHan if (data.canviewsubmissions) { // Teacher. Do not send participants to getSubmissionsUserData to retrieve user profiles. - promises.push(this.assignProvider.getSubmissionsUserData(data.submissions, courseId, assign.id, blindMarking, - undefined, true, siteId).then((submissions) => { + promises.push(this.groupsProvider.getActivityGroupInfo(assign.cmid, false, undefined, siteId).then((groupInfo) => { + 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) => { - subPromises.push(this.assignProvider.getSubmissionStatusWithRetry(assign, submission.submitid, - !!submission.blindid, true, true, siteId).then((subm) => { - return this.prefetchSubmission(assign, courseId, moduleId, subm, submission.submitid, siteId); - }).catch((error) => { - if (error && error.errorcode == 'nopermission') { - // The user does not have persmission to view this submission, ignore it. - return Promise.resolve(); + const subPromises = []; + + submissions.forEach((submission) => { + subPromises.push(this.assignProvider.getSubmissionStatusWithRetry(assign, submission.submitid, + group.id, !!submission.blindid, true, true, siteId).then((subm) => { + return this.prefetchSubmission(assign, courseId, moduleId, subm, submission.submitid, siteId); + }).catch((error) => { + 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) { - // 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). + return Promise.all(groupProms); })); } else { // Student. 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); }).catch((error) => { // Ignore if the user can't view their own submission. diff --git a/src/app/app.scss b/src/app/app.scss index 5fe61c0fa..eb0aad801 100644 --- a/src/app/app.scss +++ b/src/app/app.scss @@ -645,7 +645,7 @@ ion-app.app-root { @include padding(null, null, null, 52px); position: relative; - ion-icon { + > ion-icon { color: $color-base; position: absolute; @include position(0, null, null, 16px)