MOBILE-3833 course: Use completion enums

main
Pau Ferrer Ocaña 2021-12-16 10:44:09 +01:00
parent efece1d4ac
commit 13fbaf0b0f
8 changed files with 101 additions and 51 deletions

View File

@ -100,7 +100,7 @@ export class CoreCourseModuleMainResourceComponent implements OnInit, OnDestroy,
this.showCompletion = !!CoreSites.getRequiredCurrentSite().isVersionGreaterEqualThan('3.11'); this.showCompletion = !!CoreSites.getRequiredCurrentSite().isVersionGreaterEqualThan('3.11');
if (this.showCompletion) { if (this.showCompletion) {
CoreCourseHelper.calculateModuleCompletionData(this.module, this.courseId); CoreCourseHelper.calculateModuleCompletionData(this.module);
CoreCourseHelper.loadModuleOfflineCompletion(this.courseId, this.module); CoreCourseHelper.loadModuleOfflineCompletion(this.courseId, this.module);
this.completionObserver = CoreEvents.on(CoreEvents.COMPLETION_MODULE_VIEWED, async (data) => { this.completionObserver = CoreEvents.on(CoreEvents.COMPLETION_MODULE_VIEWED, async (data) => {
@ -428,7 +428,7 @@ export class CoreCourseModuleMainResourceComponent implements OnInit, OnDestroy,
protected async fetchModule(): Promise<void> { protected async fetchModule(): Promise<void> {
const module = await CoreCourse.getModule(this.module.id, this.courseId); const module = await CoreCourse.getModule(this.module.id, this.courseId);
CoreCourseHelper.calculateModuleCompletionData(module, this.courseId); CoreCourseHelper.calculateModuleCompletionData(module);
await CoreCourseHelper.loadModuleOfflineCompletion(this.courseId, module); await CoreCourseHelper.loadModuleOfflineCompletion(this.courseId, module);

View File

@ -33,6 +33,7 @@ import { CoreDynamicComponent } from '@components/dynamic-component/dynamic-comp
import { CoreCourseAnyCourseData } from '@features/courses/services/courses'; import { CoreCourseAnyCourseData } from '@features/courses/services/courses';
import { import {
CoreCourse, CoreCourse,
CoreCourseModuleCompletionStatus,
CoreCourseProvider, CoreCourseProvider,
} from '@features/course/services/course'; } from '@features/course/services/course';
import { import {
@ -643,7 +644,7 @@ export class CoreCourseFormatComponent implements OnInit, OnChanges, OnDestroy {
const moduleProgressPercent = 100 / (completionModules || 1); const moduleProgressPercent = 100 / (completionModules || 1);
// Use min/max here to avoid floating point rounding errors over/under-flowing the progress bar. // Use min/max here to avoid floating point rounding errors over/under-flowing the progress bar.
if (completionData.state === CoreCourseProvider.COMPLETION_COMPLETE) { if (completionData.state === CoreCourseModuleCompletionStatus.COMPLETION_COMPLETE) {
this.course.progress = Math.min(100, this.course.progress + moduleProgressPercent); this.course.progress = Math.min(100, this.course.progress + moduleProgressPercent);
} else { } else {
this.course.progress = Math.max(0, this.course.progress - moduleProgressPercent); this.course.progress = Math.max(0, this.course.progress - moduleProgressPercent);

View File

@ -15,7 +15,7 @@
import { Component } from '@angular/core'; import { Component } from '@angular/core';
import { CoreUser } from '@features/user/services/user'; import { CoreUser } from '@features/user/services/user';
import { CoreCourseProvider } from '@features/course/services/course'; import { CoreCourseModuleCompletionStatus, CoreCourseModuleCompletionTracking } from '@features/course/services/course';
import { CoreFilterHelper } from '@features/filter/services/filter-helper'; import { CoreFilterHelper } from '@features/filter/services/filter-helper';
import { Translate } from '@singletons'; import { Translate } from '@singletons';
import { CoreCourseModuleCompletionBaseComponent } from '@features/course/classes/module-completion'; import { CoreCourseModuleCompletionBaseComponent } from '@features/course/classes/module-completion';
@ -52,28 +52,28 @@ export class CoreCourseModuleCompletionLegacyComponent extends CoreCourseModuleC
let langKey: string | undefined; let langKey: string | undefined;
let image: string | undefined; let image: string | undefined;
if (this.completion.tracking === CoreCourseProvider.COMPLETION_TRACKING_MANUAL && if (this.completion.tracking === CoreCourseModuleCompletionTracking.COMPLETION_TRACKING_MANUAL &&
this.completion.state === CoreCourseProvider.COMPLETION_INCOMPLETE) { this.completion.state === CoreCourseModuleCompletionStatus.COMPLETION_INCOMPLETE) {
image = 'completion-manual-n'; image = 'completion-manual-n';
langKey = 'core.completion-alt-manual-n'; langKey = 'core.completion-alt-manual-n';
} else if (this.completion.tracking === CoreCourseProvider.COMPLETION_TRACKING_MANUAL && } else if (this.completion.tracking === CoreCourseModuleCompletionTracking.COMPLETION_TRACKING_MANUAL &&
this.completion.state === CoreCourseProvider.COMPLETION_COMPLETE) { this.completion.state === CoreCourseModuleCompletionStatus.COMPLETION_COMPLETE) {
image = 'completion-manual-y'; image = 'completion-manual-y';
langKey = 'core.completion-alt-manual-y'; langKey = 'core.completion-alt-manual-y';
} else if (this.completion.tracking === CoreCourseProvider.COMPLETION_TRACKING_AUTOMATIC && } else if (this.completion.tracking === CoreCourseModuleCompletionTracking.COMPLETION_TRACKING_AUTOMATIC &&
this.completion.state === CoreCourseProvider.COMPLETION_INCOMPLETE) { this.completion.state === CoreCourseModuleCompletionStatus.COMPLETION_INCOMPLETE) {
image = 'completion-auto-n'; image = 'completion-auto-n';
langKey = 'core.completion-alt-auto-n'; langKey = 'core.completion-alt-auto-n';
} else if (this.completion.tracking === CoreCourseProvider.COMPLETION_TRACKING_AUTOMATIC && } else if (this.completion.tracking === CoreCourseModuleCompletionTracking.COMPLETION_TRACKING_AUTOMATIC &&
this.completion.state === CoreCourseProvider.COMPLETION_COMPLETE) { this.completion.state === CoreCourseModuleCompletionStatus.COMPLETION_COMPLETE) {
image = 'completion-auto-y'; image = 'completion-auto-y';
langKey = 'core.completion-alt-auto-y'; langKey = 'core.completion-alt-auto-y';
} else if (this.completion.tracking === CoreCourseProvider.COMPLETION_TRACKING_AUTOMATIC && } else if (this.completion.tracking === CoreCourseModuleCompletionTracking.COMPLETION_TRACKING_AUTOMATIC &&
this.completion.state === CoreCourseProvider.COMPLETION_COMPLETE_PASS) { this.completion.state === CoreCourseModuleCompletionStatus.COMPLETION_COMPLETE_PASS) {
image = 'completion-auto-pass'; image = 'completion-auto-pass';
langKey = 'core.completion-alt-auto-pass'; langKey = 'core.completion-alt-auto-pass';
} else if (this.completion.tracking === CoreCourseProvider.COMPLETION_TRACKING_AUTOMATIC && } else if (this.completion.tracking === CoreCourseModuleCompletionTracking.COMPLETION_TRACKING_AUTOMATIC &&
this.completion.state === CoreCourseProvider.COMPLETION_COMPLETE_FAIL) { this.completion.state === CoreCourseModuleCompletionStatus.COMPLETION_COMPLETE_FAIL) {
image = 'completion-auto-fail'; image = 'completion-auto-fail';
langKey = 'core.completion-alt-auto-fail'; langKey = 'core.completion-alt-auto-fail';
} }

View File

@ -15,7 +15,7 @@
import { Component, Input } from '@angular/core'; import { Component, Input } from '@angular/core';
import { CoreCourseModuleCompletionBaseComponent } from '@features/course/classes/module-completion'; import { CoreCourseModuleCompletionBaseComponent } from '@features/course/classes/module-completion';
import { CoreCourseModuleWSRuleDetails, CoreCourseProvider } from '@features/course/services/course'; import { CoreCourseModuleCompletionStatus, CoreCourseModuleWSRuleDetails } from '@features/course/services/course';
import { CoreUser } from '@features/user/services/user'; import { CoreUser } from '@features/user/services/user';
import { Translate } from '@singletons'; import { Translate } from '@singletons';
@ -51,10 +51,10 @@ export class CoreCourseModuleCompletionComponent extends CoreCourseModuleComplet
// Format rules. // Format rules.
this.details = await Promise.all(this.completion.details.map(async (rule: CompletionRule) => { this.details = await Promise.all(this.completion.details.map(async (rule: CompletionRule) => {
rule.statuscomplete = rule.rulevalue.status == CoreCourseProvider.COMPLETION_COMPLETE || rule.statuscomplete = rule.rulevalue.status == CoreCourseModuleCompletionStatus.COMPLETION_COMPLETE ||
rule.rulevalue.status == CoreCourseProvider.COMPLETION_COMPLETE_PASS; rule.rulevalue.status == CoreCourseModuleCompletionStatus.COMPLETION_COMPLETE_PASS;
rule.statuscompletefail = rule.rulevalue.status == CoreCourseProvider.COMPLETION_COMPLETE_FAIL; rule.statuscompletefail = rule.rulevalue.status == CoreCourseModuleCompletionStatus.COMPLETION_COMPLETE_FAIL;
rule.statusincomplete = rule.rulevalue.status == CoreCourseProvider.COMPLETION_INCOMPLETE; rule.statusincomplete = rule.rulevalue.status == CoreCourseModuleCompletionStatus.COMPLETION_INCOMPLETE;
rule.accessibleDescription = null; rule.accessibleDescription = null;
if (this.completion!.overrideby) { if (this.completion!.overrideby) {

View File

@ -15,7 +15,11 @@
import { Component, Input, OnInit } from '@angular/core'; import { Component, Input, OnInit } from '@angular/core';
import { CoreCourseSection } from '@features/course/services/course-helper'; import { CoreCourseSection } from '@features/course/services/course-helper';
import { CoreCourseProvider } from '@features/course/services/course'; import {
CoreCourseModuleCompletionStatus,
CoreCourseModuleCompletionTracking,
CoreCourseProvider,
} from '@features/course/services/course';
import { CoreCourseAnyCourseData } from '@features/courses/services/courses'; import { CoreCourseAnyCourseData } from '@features/courses/services/courses';
import { CoreUtils } from '@services/utils/utils'; import { CoreUtils } from '@services/utils/utils';
import { ModalController } from '@singletons'; import { ModalController } from '@singletons';
@ -56,14 +60,14 @@ export class CoreCourseSectionSelectorComponent implements OnInit {
let complete = 0; let complete = 0;
let total = 0; let total = 0;
section.modules.forEach((module) => { section.modules.forEach((module) => {
if (!module.uservisible || module.completiondata === undefined || module.completiondata.tracking === undefined || if (!module.uservisible || module.completiondata === undefined ||
module.completiondata.tracking <= CoreCourseProvider.COMPLETION_TRACKING_NONE) { module.completiondata.tracking == CoreCourseModuleCompletionTracking.COMPLETION_TRACKING_NONE) {
return; return;
} }
total++; total++;
if (module.completiondata.state == CoreCourseProvider.COMPLETION_COMPLETE || if (module.completiondata.state == CoreCourseModuleCompletionStatus.COMPLETION_COMPLETE ||
module.completiondata.state == CoreCourseProvider.COMPLETION_COMPLETE_PASS) { module.completiondata.state == CoreCourseModuleCompletionStatus.COMPLETION_COMPLETE_PASS) {
complete++; complete++;
} }
}); });

View File

@ -73,7 +73,7 @@ export class CoreCourseModulePreviewPage implements OnInit {
this.module = await CoreCourse.getModule(this.module.id, this.courseId); this.module = await CoreCourse.getModule(this.module.id, this.courseId);
} }
CoreCourseHelper.calculateModuleCompletionData(this.module, this.courseId); CoreCourseHelper.calculateModuleCompletionData(this.module);
await CoreCourseHelper.loadModuleOfflineCompletion(this.courseId, this.module); await CoreCourseHelper.loadModuleOfflineCompletion(this.courseId, this.module);

View File

@ -25,6 +25,8 @@ import {
CoreCourseWSModule, CoreCourseWSModule,
CoreCourseProvider, CoreCourseProvider,
CoreCourseWSSection, CoreCourseWSSection,
CoreCourseModuleCompletionTracking,
CoreCourseModuleCompletionStatus,
} from './course'; } from './course';
import { CoreConstants } from '@/core/constants'; import { CoreConstants } from '@/core/constants';
import { CoreLogger } from '@singletons/logger'; import { CoreLogger } from '@singletons/logger';
@ -200,8 +202,8 @@ export class CoreCourseHelperProvider {
); );
if (module.completiondata) { if (module.completiondata) {
this.calculateModuleCompletionData(module, courseId, courseName); this.calculateModuleCompletionData(module, undefined, courseName);
} else if (completionStatus && typeof completionStatus[module.id] != 'undefined') { } else if (completionStatus && completionStatus[module.id] !== undefined) {
// Should not happen on > 3.6. Check if activity has completions and if it's marked. // Should not happen on > 3.6. Check if activity has completions and if it's marked.
const activityStatus = completionStatus[module.id]; const activityStatus = completionStatus[module.id];
@ -229,18 +231,18 @@ export class CoreCourseHelperProvider {
* Calculate completion data of a module. * Calculate completion data of a module.
* *
* @param module Module. * @param module Module.
* @param courseId Course ID of the module. * @param courseId Not used since 4.0
* @param courseName Course name. * @param courseName Course name.
*/ */
calculateModuleCompletionData(module: CoreCourseModule, courseId: number, courseName?: string): void { calculateModuleCompletionData(module: CoreCourseModule, courseId?: number, courseName?: string): void {
if (!module.completiondata || !module.completion) { if (!module.completiondata || !module.completion) {
return; return;
} }
module.completiondata.courseId = courseId; module.completiondata.courseId = module.course;
module.completiondata.courseName = courseName;
module.completiondata.tracking = module.completion; module.completiondata.tracking = module.completion;
module.completiondata.cmid = module.id; module.completiondata.cmid = module.id;
module.completiondata.courseName = courseName;
} }
/** /**
@ -2069,7 +2071,8 @@ export class CoreCourseHelperProvider {
return; return;
} }
if (typeof completion.cmid == 'undefined' || completion.tracking !== 1) { if (completion.cmid === undefined ||
completion.tracking !== CoreCourseModuleCompletionTracking.COMPLETION_TRACKING_MANUAL) {
return; return;
} }
@ -2077,14 +2080,15 @@ export class CoreCourseHelperProvider {
event?.stopPropagation(); event?.stopPropagation();
const modal = await CoreDomUtils.showModalLoading(); const modal = await CoreDomUtils.showModalLoading();
completion.state = completion.state === 1 ? 0 : 1; completion.state = completion.state === CoreCourseModuleCompletionStatus.COMPLETION_COMPLETE
? CoreCourseModuleCompletionStatus.COMPLETION_INCOMPLETE
: CoreCourseModuleCompletionStatus.COMPLETION_COMPLETE;
try { try {
const response = await CoreCourse.markCompletedManually( const response = await CoreCourse.markCompletedManually(
completion.cmid, completion.cmid,
completion.state === 1, completion.state === CoreCourseModuleCompletionStatus.COMPLETION_COMPLETE,
completion.courseId!, completion.courseId!,
completion.courseName,
); );
if (response.offline) { if (response.offline) {
@ -2093,7 +2097,11 @@ export class CoreCourseHelperProvider {
return response; return response;
} catch (error) { } catch (error) {
completion.state = completion.state === 1 ? 0 : 1; // Restore previous state.
completion.state = completion.state === CoreCourseModuleCompletionStatus.COMPLETION_COMPLETE
? CoreCourseModuleCompletionStatus.COMPLETION_INCOMPLETE
: CoreCourseModuleCompletionStatus.COMPLETION_COMPLETE;
CoreDomUtils.showErrorModalDefault(error, 'core.errorchangecompletion', true); CoreDomUtils.showErrorModalDefault(error, 'core.errorchangecompletion', true);
} finally { } finally {
modal.dismiss(); modal.dismiss();
@ -2139,7 +2147,7 @@ export type CoreCourseModule = Omit<CoreCourseWSModule, 'completiondata'> & {
export type CoreCourseModuleCompletionData = CoreCourseModuleWSCompletionData & { export type CoreCourseModuleCompletionData = CoreCourseModuleWSCompletionData & {
courseId?: number; courseId?: number;
courseName?: string; courseName?: string;
tracking?: number; tracking?: CoreCourseModuleCompletionTracking;
cmid?: number; cmid?: number;
offline?: boolean; offline?: boolean;
}; };

View File

@ -61,6 +61,25 @@ declare module '@singletons/events' {
} }
/**
* Completion status valid values.
*/
export enum CoreCourseModuleCompletionStatus {
COMPLETION_INCOMPLETE = 0,
COMPLETION_COMPLETE = 1,
COMPLETION_COMPLETE_PASS = 2,
COMPLETION_COMPLETE_FAIL = 3,
}
/**
* Completion tracking valid values.
*/
export enum CoreCourseModuleCompletionTracking {
COMPLETION_TRACKING_NONE = 0,
COMPLETION_TRACKING_MANUAL = 1,
COMPLETION_TRACKING_AUTOMATIC = 2,
}
/** /**
* Service that provides some features regarding a course. * Service that provides some features regarding a course.
*/ */
@ -73,13 +92,34 @@ export class CoreCourseProvider {
static readonly ACCESS_DEFAULT = 'courses_access_default'; static readonly ACCESS_DEFAULT = 'courses_access_default';
static readonly ALL_COURSES_CLEARED = -1; static readonly ALL_COURSES_CLEARED = -1;
/**
* @deprecated since 4.0, use CoreCourseModuleCompletionTracking.COMPLETION_TRACKING_NONE instead.
*/
static readonly COMPLETION_TRACKING_NONE = 0; static readonly COMPLETION_TRACKING_NONE = 0;
/**
* @deprecated since 4.0, use CoreCourseModuleCompletionTracking.COMPLETION_TRACKING_MANUAL instead.
*/
static readonly COMPLETION_TRACKING_MANUAL = 1; static readonly COMPLETION_TRACKING_MANUAL = 1;
/**
* @deprecated since 4.0, use CoreCourseModuleCompletionTracking.COMPLETION_TRACKING_AUTOMATIC instead.
*/
static readonly COMPLETION_TRACKING_AUTOMATIC = 2; static readonly COMPLETION_TRACKING_AUTOMATIC = 2;
/**
* @deprecated since 4.0, use CoreCourseModuleCompletionStatus.COMPLETION_INCOMPLETE instead.
*/
static readonly COMPLETION_INCOMPLETE = 0; static readonly COMPLETION_INCOMPLETE = 0;
/**
* @deprecated since 4.0, use CoreCourseModuleCompletionStatus.COMPLETION_COMPLETE instead.
*/
static readonly COMPLETION_COMPLETE = 1; static readonly COMPLETION_COMPLETE = 1;
/**
* @deprecated since 4.0, use CoreCourseModuleCompletionStatus.COMPLETION_COMPLETE_PASS instead.
*/
static readonly COMPLETION_COMPLETE_PASS = 2; static readonly COMPLETION_COMPLETE_PASS = 2;
/**
* @deprecated since 4.0, use CoreCourseModuleCompletionStatus.COMPLETION_COMPLETE_FAIL instead.
*/
static readonly COMPLETION_COMPLETE_FAIL = 3; static readonly COMPLETION_COMPLETE_FAIL = 3;
static readonly COMPONENT = 'CoreCourse'; static readonly COMPONENT = 'CoreCourse';
@ -151,7 +191,8 @@ export class CoreCourseProvider {
* @param completion Completion status of the module. * @param completion Completion status of the module.
*/ */
checkModuleCompletion(courseId: number, completion?: CoreCourseModuleCompletionData): void { checkModuleCompletion(courseId: number, completion?: CoreCourseModuleCompletionData): void {
if (completion && completion.tracking === CoreCourseProvider.COMPLETION_TRACKING_AUTOMATIC && completion.state === 0) { if (completion && completion.tracking === CoreCourseModuleCompletionTracking.COMPLETION_TRACKING_AUTOMATIC &&
completion.state === CoreCourseModuleCompletionStatus.COMPLETION_INCOMPLETE) {
this.invalidateSections(courseId).finally(() => { this.invalidateSections(courseId).finally(() => {
CoreEvents.trigger(CoreEvents.COMPLETION_MODULE_VIEWED, { CoreEvents.trigger(CoreEvents.COMPLETION_MODULE_VIEWED, {
courseId: courseId, courseId: courseId,
@ -256,7 +297,7 @@ export class CoreCourseProvider {
const onlineCompletion = completionStatus[offlineCompletion.cmid]; const onlineCompletion = completionStatus[offlineCompletion.cmid];
// If the activity uses manual completion, override the value with the offline one. // If the activity uses manual completion, override the value with the offline one.
if (onlineCompletion.tracking === 1) { if (onlineCompletion.tracking === CoreCourseModuleCompletionTracking.COMPLETION_TRACKING_MANUAL) {
onlineCompletion.state = offlineCompletion.completed; onlineCompletion.state = offlineCompletion.completed;
onlineCompletion.offline = true; onlineCompletion.offline = true;
} }
@ -986,7 +1027,7 @@ export class CoreCourseProvider {
CoreCourseOffline.markCompletedManually(cmId, completed, courseId, courseName, siteId); CoreCourseOffline.markCompletedManually(cmId, completed, courseId, courseName, siteId);
// The offline function requires a courseId and it could be missing because it's a calculated field. // The offline function requires a courseId and it could be missing because it's a calculated field.
if (!CoreApp.isOnline() && courseId) { if (!CoreApp.isOnline()) {
// App is offline, store the action. // App is offline, store the action.
return storeOffline(); return storeOffline();
} }
@ -996,18 +1037,14 @@ export class CoreCourseProvider {
const result = await this.markCompletedManuallyOnline(cmId, completed, siteId); const result = await this.markCompletedManuallyOnline(cmId, completed, siteId);
// Data sent to server, if there is some offline data delete it now. // Data sent to server, if there is some offline data delete it now.
try { await CoreUtils.ignoreErrors(CoreCourseOffline.deleteManualCompletion(cmId, siteId));
await CoreCourseOffline.deleteManualCompletion(cmId, siteId);
} catch {
// Ignore errors, shouldn't happen.
}
// Invalidate module now, completion has changed. // Invalidate module now, completion has changed.
await this.invalidateModule(cmId, siteId); await this.invalidateModule(cmId, siteId);
return result; return result;
} catch (error) { } catch (error) {
if (CoreUtils.isWebServiceError(error) || !courseId) { if (CoreUtils.isWebServiceError(error)) {
// The WebService has thrown an error, this means that responses cannot be submitted. // The WebService has thrown an error, this means that responses cannot be submitted.
throw error; throw error;
} else { } else {
@ -1346,7 +1383,7 @@ export type CoreCourseCompletionActivityStatus = {
instance: number; // Instance ID. instance: number; // Instance ID.
state: number; // Completion state value: 0 means incomplete, 1 complete, 2 complete pass, 3 complete fail. state: number; // Completion state value: 0 means incomplete, 1 complete, 2 complete pass, 3 complete fail.
timecompleted: number; // Timestamp for completed activity. timecompleted: number; // Timestamp for completed activity.
tracking: number; // Type of tracking: 0 means none, 1 manual, 2 automatic. tracking: CoreCourseModuleCompletionTracking; // Type of tracking: 0 means none, 1 manual, 2 automatic.
overrideby?: number | null; // The user id who has overriden the status, or null. overrideby?: number | null; // The user id who has overriden the status, or null.
valueused?: boolean; // Whether the completion status affects the availability of another activity. valueused?: boolean; // Whether the completion status affects the availability of another activity.
hascompletion?: boolean; // @since 3.11. Whether this activity module has completion enabled. hascompletion?: boolean; // @since 3.11. Whether this activity module has completion enabled.
@ -1497,7 +1534,7 @@ export type CoreCourseWSModule = {
afterlink?: string; // After link info to be displayed. afterlink?: string; // After link info to be displayed.
customdata?: string; // Custom data (JSON encoded). customdata?: string; // Custom data (JSON encoded).
noviewlink?: boolean; // Whether the module has no view page. noviewlink?: boolean; // Whether the module has no view page.
completion?: number; // Type of completion tracking: 0 means none, 1 manual, 2 automatic. completion?: CoreCourseModuleCompletionTracking; // Type of completion tracking: 0 means none, 1 manual, 2 automatic.
completiondata?: CoreCourseModuleWSCompletionData; // Module completion data. completiondata?: CoreCourseModuleWSCompletionData; // Module completion data.
contents?: CoreCourseModuleContentFile[]; contents?: CoreCourseModuleContentFile[];
dates?: { dates?: {
@ -1517,7 +1554,7 @@ export type CoreCourseWSModule = {
* Module completion data. * Module completion data.
*/ */
export type CoreCourseModuleWSCompletionData = { export type CoreCourseModuleWSCompletionData = {
state: number; // Completion state value: 0 means incomplete, 1 complete, 2 complete pass, 3 complete fail. state: CoreCourseModuleCompletionStatus; // Completion state value.
timecompleted: number; // Timestamp for completion status. timecompleted: number; // Timestamp for completion status.
overrideby: number | null; // The user id who has overriden the status. overrideby: number | null; // The user id who has overriden the status.
valueused?: boolean; // Whether the completion status affects the availability of another activity. valueused?: boolean; // Whether the completion status affects the availability of another activity.