MOBILE-3833 course: Reduce usage of CoreCourseAnyModuleData

main
Pau Ferrer Ocaña 2021-12-17 00:27:04 +01:00
parent 27c7a7a952
commit ed05adffbf
59 changed files with 355 additions and 296 deletions

View File

@ -242,7 +242,7 @@ export class AddonModAssignPrefetchHandlerService extends CoreCourseActivityPref
promises.push(this.prefetchSubmissions(assign, courseId, module.id, userId, siteId)); promises.push(this.prefetchSubmissions(assign, courseId, module.id, userId, siteId));
promises.push(CoreCourse.getModuleBasicInfoByInstance(assign.id, 'assign', siteId)); promises.push(CoreCourse.getModuleBasicInfoByInstance(assign.id, 'assign', { siteId }));
// Get course data, needed to determine upload max size if it's configured to be course limit. // Get course data, needed to determine upload max size if it's configured to be course limit.
promises.push(CoreUtils.ignoreErrors(CoreCourses.getCourseByField('id', courseId, siteId))); promises.push(CoreUtils.ignoreErrors(CoreCourses.getCourseByField('id', courseId, siteId)));
@ -253,7 +253,6 @@ export class AddonModAssignPrefetchHandlerService extends CoreCourseActivityPref
promises.push(CoreFilepool.addFilesToQueue(siteId, files, this.component, module.id)); promises.push(CoreFilepool.addFilesToQueue(siteId, files, this.component, module.id));
await Promise.all(promises); await Promise.all(promises);
} }
/** /**

View File

@ -17,6 +17,7 @@ import { CoreCourse } from '@features/course/services/course';
import { CoreTagFeedComponent } from '@features/tag/components/feed/feed'; import { CoreTagFeedComponent } from '@features/tag/components/feed/feed';
import { CoreTagAreaHandler } from '@features/tag/services/tag-area-delegate'; import { CoreTagAreaHandler } from '@features/tag/services/tag-area-delegate';
import { CoreTagFeedElement, CoreTagHelper } from '@features/tag/services/tag-helper'; import { CoreTagFeedElement, CoreTagHelper } from '@features/tag/services/tag-helper';
import { CoreSitesReadingStrategy } from '@services/sites';
import { CoreUrlUtils } from '@services/utils/url'; import { CoreUrlUtils } from '@services/utils/url';
import { makeSingleton } from '@singletons'; import { makeSingleton } from '@singletons';
import { AddonModBook } from '../book'; import { AddonModBook } from '../book';
@ -49,16 +50,17 @@ export class AddonModBookTagAreaHandlerService implements CoreTagAreaHandler {
const items = CoreTagHelper.parseFeedContent(content); const items = CoreTagHelper.parseFeedContent(content);
// Find module ids of the returned books, they are needed by the link delegate. // Find module ids of the returned books, they are needed by the link delegate.
await Promise.all(items.map((item) => { await Promise.all(items.map(async (item) => {
const params = item.url ? CoreUrlUtils.extractUrlParams(item.url) : {}; const params = item.url ? CoreUrlUtils.extractUrlParams(item.url) : {};
if (params.b && !params.id) { if (params.b && !params.id) {
const bookId = parseInt(params.b, 10); const bookId = parseInt(params.b, 10);
return CoreCourse.getModuleBasicInfoByInstance(bookId, 'book').then((module) => { const module = await CoreCourse.getModuleBasicInfoByInstance(
item.url += '&id=' + module.id; bookId,
'book',
return; { readingStrategy: CoreSitesReadingStrategy.PREFER_CACHE },
}); );
item.url += '&id=' + module.id;
} }
})); }));

View File

@ -197,7 +197,7 @@ export class AddonModChoiceSyncProvider extends CoreCourseActivitySyncBaseProvid
// Data has been sent to server, prefetch choice if needed. // Data has been sent to server, prefetch choice if needed.
try { try {
const module = await CoreCourse.getModuleBasicInfoByInstance(choiceId, 'choice', siteId); const module = await CoreCourse.getModuleBasicInfoByInstance(choiceId, 'choice', { siteId });
await this.prefetchAfterUpdate(AddonModChoicePrefetchHandler.instance, module, courseId, undefined, siteId); await this.prefetchAfterUpdate(AddonModChoicePrefetchHandler.instance, module, courseId, undefined, siteId);
} catch { } catch {

View File

@ -14,7 +14,6 @@
import { Component, OnInit, Input } from '@angular/core'; import { Component, OnInit, Input } from '@angular/core';
import { Params } from '@angular/router'; import { Params } from '@angular/router';
import { CoreCourseModuleData } from '@features/course/services/course-helper';
import { CoreTag } from '@features/tag/services/tag'; import { CoreTag } from '@features/tag/services/tag';
import { CoreUser } from '@features/user/services/user'; import { CoreUser } from '@features/user/services/user';
import { CoreNavigator } from '@services/navigator'; import { CoreNavigator } from '@services/navigator';
@ -44,8 +43,8 @@ export class AddonModDataActionComponent implements OnInit {
@Input() action!: AddonModDataAction; // The field to render. @Input() action!: AddonModDataAction; // The field to render.
@Input() entry!: AddonModDataEntry; // The value of the field. @Input() entry!: AddonModDataEntry; // The value of the field.
@Input() database!: AddonModDataData; // Database object. @Input() database!: AddonModDataData; // Database object.
@Input() module!: CoreCourseModuleData; // Module object. @Input() title = ''; // Name of the module.
@Input() group = 0; // Module object. @Input() group = 0; // Module group.
@Input() offset?: number; // Offset of the entry. @Input() offset?: number; // Offset of the entry.
siteId: string; siteId: string;
@ -92,13 +91,13 @@ export class AddonModDataActionComponent implements OnInit {
* Go to the edit page of the entry. * Go to the edit page of the entry.
*/ */
editEntry(): void { editEntry(): void {
const params = { const params: Params = {
courseId: this.database.course, title: this.title,
module: this.module,
}; };
const basePath = AddonModDataModuleHandlerService.PAGE_NAME;
CoreNavigator.navigateToSitePath( CoreNavigator.navigateToSitePath(
`${AddonModDataModuleHandlerService.PAGE_NAME}/${this.module.course}/${this.module.id}/edit/${this.entry.id}`, `${basePath}/${this.database.course}/${this.database.coursemodule}/edit/${this.entry.id}`,
{ params }, { params },
); );
} }
@ -108,15 +107,14 @@ export class AddonModDataActionComponent implements OnInit {
*/ */
viewEntry(): void { viewEntry(): void {
const params: Params = { const params: Params = {
courseId: this.database.course, title: this.title,
module: this.module,
entryId: this.entry.id,
group: this.group, group: this.group,
offset: this.offset, offset: this.offset,
}; };
const basePath = AddonModDataModuleHandlerService.PAGE_NAME;
CoreNavigator.navigateToSitePath( CoreNavigator.navigateToSitePath(
`${AddonModDataModuleHandlerService.PAGE_NAME}/${this.module.course}/${this.module.id}/${this.entry.id}`, `${basePath}/${this.database.course}/${this.database.coursemodule}/${this.entry.id}`,
{ params }, { params },
); );
} }

View File

@ -19,7 +19,6 @@ import { CoreCommentsProvider } from '@features/comments/services/comments';
import { CoreCourseModuleMainActivityComponent } from '@features/course/classes/main-activity-component'; import { CoreCourseModuleMainActivityComponent } from '@features/course/classes/main-activity-component';
import { CoreCourseContentsPage } from '@features/course/pages/contents/contents'; import { CoreCourseContentsPage } from '@features/course/pages/contents/contents';
import { CoreCourse } from '@features/course/services/course'; import { CoreCourse } from '@features/course/services/course';
import { CoreCourseModuleData } from '@features/course/services/course-helper';
import { CoreRatingProvider } from '@features/rating/services/rating'; import { CoreRatingProvider } from '@features/rating/services/rating';
import { CoreRatingSyncProvider } from '@features/rating/services/rating-sync'; import { CoreRatingSyncProvider } from '@features/rating/services/rating-sync';
import { IonContent } from '@ionic/angular'; import { IonContent } from '@ionic/angular';
@ -95,7 +94,7 @@ export class AddonModDataIndexComponent extends CoreCourseModuleMainActivityComp
fields: Record<number, AddonModDataField>; fields: Record<number, AddonModDataField>;
entries: Record<number, AddonModDataEntry>; entries: Record<number, AddonModDataEntry>;
database: AddonModDataData; database: AddonModDataData;
module: CoreCourseModuleData; title: string;
group: number; group: number;
gotoEntry: (a: number) => void; gotoEntry: (a: number) => void;
}; };
@ -371,7 +370,7 @@ export class AddonModDataIndexComponent extends CoreCourseModuleMainActivityComp
fields: this.fields, fields: this.fields,
entries: entriesById, entries: entriesById,
database: this.database!, database: this.database!,
module: this.module, title: this.module.name,
group: this.selectedGroup, group: this.selectedGroup,
gotoEntry: this.gotoEntry.bind(this), gotoEntry: this.gotoEntry.bind(this),
}; };
@ -474,8 +473,7 @@ export class AddonModDataIndexComponent extends CoreCourseModuleMainActivityComp
*/ */
gotoAddEntries(): void { gotoAddEntries(): void {
const params: Params = { const params: Params = {
module: this.module, title: this.module.name,
courseId: this.courseId,
group: this.selectedGroup, group: this.selectedGroup,
}; };
@ -492,8 +490,7 @@ export class AddonModDataIndexComponent extends CoreCourseModuleMainActivityComp
*/ */
gotoEntry(entryId: number): void { gotoEntry(entryId: number): void {
const params: Params = { const params: Params = {
module: this.module, title: this.module.name,
courseId: this.courseId,
group: this.selectedGroup, group: this.selectedGroup,
}; };

View File

@ -5,7 +5,7 @@
</ion-buttons> </ion-buttons>
<ion-title> <ion-title>
<h1> <h1>
<core-format-text [text]="title" contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId"> <core-format-text [text]="title" contextLevel="module" [contextInstanceId]="moduleId" [courseId]="courseId">
</core-format-text> </core-format-text>
</h1> </h1>
</ion-title> </ion-title>

View File

@ -15,7 +15,6 @@
import { Component, OnInit, ViewChild, ElementRef, Type } from '@angular/core'; import { Component, OnInit, ViewChild, ElementRef, Type } from '@angular/core';
import { FormGroup } from '@angular/forms'; import { FormGroup } from '@angular/forms';
import { CoreError } from '@classes/errors/error'; import { CoreError } from '@classes/errors/error';
import { CoreCourseModuleData } from '@features/course/services/course-helper';
import { CoreFileUploader } from '@features/fileuploader/services/fileuploader'; import { CoreFileUploader } from '@features/fileuploader/services/fileuploader';
import { CoreTag } from '@features/tag/services/tag'; import { CoreTag } from '@features/tag/services/tag';
import { IonContent } from '@ionic/angular'; import { IonContent } from '@ionic/angular';
@ -66,7 +65,7 @@ export class AddonModDataEditPage implements OnInit {
entry?: AddonModDataEntry; entry?: AddonModDataEntry;
fields: Record<number, AddonModDataField> = {}; fields: Record<number, AddonModDataField> = {};
courseId!: number; courseId!: number;
module!: CoreCourseModuleData; moduleId = 0;
database?: AddonModDataData; database?: AddonModDataData;
title = ''; title = '';
component = AddonModDataProvider.COMPONENT; component = AddonModDataProvider.COMPONENT;
@ -97,9 +96,10 @@ export class AddonModDataEditPage implements OnInit {
*/ */
ngOnInit(): void { ngOnInit(): void {
try { try {
this.module = CoreNavigator.getRequiredRouteParam<CoreCourseModuleData>('module'); this.moduleId = CoreNavigator.getRequiredRouteNumberParam('cmId');
this.entryId = CoreNavigator.getRouteNumberParam('entryId') || undefined;
this.courseId = CoreNavigator.getRequiredRouteNumberParam('courseId'); this.courseId = CoreNavigator.getRequiredRouteNumberParam('courseId');
this.title = CoreNavigator.getRouteParam<string>('title') || '';
this.entryId = CoreNavigator.getRouteNumberParam('entryId') || undefined;
this.selectedGroup = CoreNavigator.getRouteNumberParam('group') || 0; this.selectedGroup = CoreNavigator.getRouteNumberParam('group') || 0;
} catch (error) { } catch (error) {
CoreDomUtils.showErrorModal(error); CoreDomUtils.showErrorModal(error);
@ -112,8 +112,6 @@ export class AddonModDataEditPage implements OnInit {
// If entryId is lower than 0 or null, it is a new entry or an offline entry. // If entryId is lower than 0 or null, it is a new entry or an offline entry.
this.isEditing = this.entryId !== undefined && this.entryId > 0; this.isEditing = this.entryId !== undefined && this.entryId > 0;
this.title = this.module.name;
this.fetchEntryData(true); this.fetchEntryData(true);
} }
@ -134,7 +132,7 @@ export class AddonModDataEditPage implements OnInit {
if (changed) { if (changed) {
// Show confirmation if some data has been modified. // Show confirmation if some data has been modified.
await CoreDomUtils.showConfirm(Translate.instant('coentryre.confirmcanceledit')); await CoreDomUtils.showConfirm(Translate.instant('core.confirmcanceledit'));
} }
// Delete the local files from the tmp folder. // Delete the local files from the tmp folder.
@ -154,11 +152,11 @@ export class AddonModDataEditPage implements OnInit {
*/ */
protected async fetchEntryData(refresh = false): Promise<void> { protected async fetchEntryData(refresh = false): Promise<void> {
try { try {
this.database = await AddonModData.getDatabase(this.courseId, this.module.id); this.database = await AddonModData.getDatabase(this.courseId, this.moduleId);
this.title = this.database.name || this.title; this.title = this.database.name || this.title;
this.cssClass = 'addon-data-entries-' + this.database.id; this.cssClass = 'addon-data-entries-' + this.database.id;
this.fieldsArray = await AddonModData.getFields(this.database.id, { cmId: this.module.id }); this.fieldsArray = await AddonModData.getFields(this.database.id, { cmId: this.moduleId });
this.fields = CoreUtils.arrayToObject(this.fieldsArray, 'id'); this.fields = CoreUtils.arrayToObject(this.fieldsArray, 'id');
const entry = await AddonModDataHelper.fetchEntry(this.database, this.fieldsArray, this.entryId || 0); const entry = await AddonModDataHelper.fetchEntry(this.database, this.fieldsArray, this.entryId || 0);
@ -183,7 +181,7 @@ export class AddonModDataEditPage implements OnInit {
await Promise.all(this.groupInfo.groups.map(async (group) => { await Promise.all(this.groupInfo.groups.map(async (group) => {
const accessData = await AddonModData.getDatabaseAccessInformation(this.database!.id, { const accessData = await AddonModData.getDatabaseAccessInformation(this.database!.id, {
cmId: this.module.id, groupId: group.id }); cmId: this.moduleId, groupId: group.id });
canAddGroup[group.id] = accessData.canaddentry; canAddGroup[group.id] = accessData.canaddentry;
})); }));
@ -196,7 +194,7 @@ export class AddonModDataEditPage implements OnInit {
haveAccess = true; haveAccess = true;
} }
} else { } else {
const accessData = await AddonModData.getDatabaseAccessInformation(this.database.id, { cmId: this.module.id }); const accessData = await AddonModData.getDatabaseAccessInformation(this.database.id, { cmId: this.moduleId });
haveAccess = accessData.canaddentry; haveAccess = accessData.canaddentry;
} }

View File

@ -5,7 +5,7 @@
</ion-buttons> </ion-buttons>
<ion-title> <ion-title>
<h1> <h1>
<core-format-text [text]="title" contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId"> <core-format-text [text]="title" contextLevel="module" [contextInstanceId]="moduleId" [courseId]="courseId">
</core-format-text> </core-format-text>
</h1> </h1>
</ion-title> </ion-title>

View File

@ -16,7 +16,6 @@ import { Component, OnDestroy, ViewChild, ChangeDetectorRef, OnInit, Type } from
import { CoreCommentsCommentsComponent } from '@features/comments/components/comments/comments'; import { CoreCommentsCommentsComponent } from '@features/comments/components/comments/comments';
import { CoreComments } from '@features/comments/services/comments'; import { CoreComments } from '@features/comments/services/comments';
import { CoreCourse } from '@features/course/services/course'; import { CoreCourse } from '@features/course/services/course';
import { CoreCourseModuleData } from '@features/course/services/course-helper';
import { CoreRatingInfo } from '@features/rating/services/rating'; import { CoreRatingInfo } from '@features/rating/services/rating';
import { IonContent, IonRefresher } from '@ionic/angular'; import { IonContent, IonRefresher } from '@ionic/angular';
import { CoreGroups, CoreGroupInfo } from '@services/groups'; import { CoreGroups, CoreGroupInfo } from '@services/groups';
@ -57,7 +56,7 @@ export class AddonModDataEntryPage implements OnInit, OnDestroy {
protected fields: Record<number, AddonModDataField> = {}; protected fields: Record<number, AddonModDataField> = {};
protected fieldsArray: AddonModDataField[] = []; protected fieldsArray: AddonModDataField[] = [];
module!: CoreCourseModuleData; moduleId = 0;
courseId!: number; courseId!: number;
offset?: number; offset?: number;
title = ''; title = '';
@ -82,7 +81,7 @@ export class AddonModDataEntryPage implements OnInit, OnDestroy {
fields: Record<number, AddonModDataField>; fields: Record<number, AddonModDataField>;
entries: Record<number, AddonModDataEntry>; entries: Record<number, AddonModDataEntry>;
database: AddonModDataData; database: AddonModDataData;
module: CoreCourseModuleData; title: string;
group: number; group: number;
}; };
@ -133,9 +132,10 @@ export class AddonModDataEntryPage implements OnInit, OnDestroy {
*/ */
async ngOnInit(): Promise<void> { async ngOnInit(): Promise<void> {
try { try {
this.module = CoreNavigator.getRequiredRouteParam<CoreCourseModuleData>('module'); this.moduleId = CoreNavigator.getRequiredRouteNumberParam('cmId');
this.entryId = CoreNavigator.getRouteNumberParam('entryId') || undefined;
this.courseId = CoreNavigator.getRequiredRouteNumberParam('courseId'); this.courseId = CoreNavigator.getRequiredRouteNumberParam('courseId');
this.entryId = CoreNavigator.getRouteNumberParam('entryId') || undefined;
this.title = CoreNavigator.getRouteParam<string>('title') || '';
this.selectedGroup = CoreNavigator.getRouteNumberParam('group') || 0; this.selectedGroup = CoreNavigator.getRouteNumberParam('group') || 0;
this.offset = CoreNavigator.getRouteNumberParam('offset'); this.offset = CoreNavigator.getRouteNumberParam('offset');
} catch (error) { } catch (error) {
@ -146,8 +146,6 @@ export class AddonModDataEntryPage implements OnInit, OnDestroy {
return; return;
} }
this.title = this.module.name;
this.commentsEnabled = !CoreComments.areCommentsDisabledInSite(); this.commentsEnabled = !CoreComments.areCommentsDisabledInSite();
await this.fetchEntryData(); await this.fetchEntryData();
@ -165,15 +163,15 @@ export class AddonModDataEntryPage implements OnInit, OnDestroy {
this.isPullingToRefresh = isPtr; this.isPullingToRefresh = isPtr;
try { try {
this.database = await AddonModData.getDatabase(this.courseId, this.module.id); this.database = await AddonModData.getDatabase(this.courseId, this.moduleId);
this.title = this.database.name || this.title; this.title = this.database.name || this.title;
this.fieldsArray = await AddonModData.getFields(this.database.id, { cmId: this.module.id }); this.fieldsArray = await AddonModData.getFields(this.database.id, { cmId: this.moduleId });
this.fields = CoreUtils.arrayToObject(this.fieldsArray, 'id'); this.fields = CoreUtils.arrayToObject(this.fieldsArray, 'id');
await this.setEntryFromOffset(); await this.setEntryFromOffset();
this.access = await AddonModData.getDatabaseAccessInformation(this.database.id, { cmId: this.module.id }); this.access = await AddonModData.getDatabaseAccessInformation(this.database.id, { cmId: this.moduleId });
this.groupInfo = await CoreGroups.getActivityGroupInfo(this.database.coursemodule); this.groupInfo = await CoreGroups.getActivityGroupInfo(this.database.coursemodule);
this.selectedGroup = CoreGroups.validateGroupId(this.selectedGroup, this.groupInfo); this.selectedGroup = CoreGroups.validateGroupId(this.selectedGroup, this.groupInfo);
@ -200,7 +198,7 @@ export class AddonModDataEntryPage implements OnInit, OnDestroy {
fields: this.fields, fields: this.fields,
entries: entries, entries: entries,
database: this.database, database: this.database,
module: this.module, title: this.title,
group: this.selectedGroup, group: this.selectedGroup,
}; };
} catch (error) { } catch (error) {
@ -363,7 +361,7 @@ export class AddonModDataEntryPage implements OnInit, OnDestroy {
if (this.entryId > 0) { if (this.entryId > 0) {
// Online entry, we need to fetch the the rating info. // Online entry, we need to fetch the the rating info.
const entry = await AddonModData.getEntry(this.database!.id, this.entryId, { cmId: this.module.id }); const entry = await AddonModData.getEntry(this.database!.id, this.entryId, { cmId: this.moduleId });
this.ratingInfo = entry.ratinginfo; this.ratingInfo = entry.ratinginfo;
} }
} }

View File

@ -18,7 +18,7 @@ import { CoreCourse } from '@features/course/services/course';
import { CoreFileUploader, CoreFileUploaderStoreFilesResult } from '@features/fileuploader/services/fileuploader'; import { CoreFileUploader, CoreFileUploaderStoreFilesResult } from '@features/fileuploader/services/fileuploader';
import { CoreRatingOffline } from '@features/rating/services/rating-offline'; import { CoreRatingOffline } from '@features/rating/services/rating-offline';
import { FileEntry } from '@ionic-native/file/ngx'; import { FileEntry } from '@ionic-native/file/ngx';
import { CoreSites } from '@services/sites'; import { CoreSites, CoreSitesReadingStrategy } from '@services/sites';
import { CoreDomUtils } from '@services/utils/dom'; import { CoreDomUtils } from '@services/utils/dom';
import { CoreFormFields } from '@singletons/form'; import { CoreFormFields } from '@singletons/form';
import { CoreTextUtils } from '@services/utils/text'; import { CoreTextUtils } from '@services/utils/text';
@ -230,7 +230,7 @@ export class AddonModDataHelperProvider {
render = Translate.instant('addon.mod_data.' + (entry.approved ? 'approved' : 'notapproved')); render = Translate.instant('addon.mod_data.' + (entry.approved ? 'approved' : 'notapproved'));
} else { } else {
render = '<addon-mod-data-action action="' + action + '" [entry]="entries[' + entry.id + ']" mode="' + mode + render = '<addon-mod-data-action action="' + action + '" [entry]="entries[' + entry.id + ']" mode="' + mode +
'" [database]="database" [module]="module" [offset]="' + offset + '" [group]="group" ></addon-mod-data-action>'; '" [database]="database" [title]="title" [offset]="' + offset + '" [group]="group" ></addon-mod-data-action>';
} }
template = template.replace(replaceRegex, render); template = template.replace(replaceRegex, render);
} else { } else {
@ -437,7 +437,11 @@ export class AddonModDataHelperProvider {
return courseId; return courseId;
} }
const module = await CoreCourse.getModuleBasicInfoByInstance(dataId, 'data', siteId); const module = await CoreCourse.getModuleBasicInfoByInstance(
dataId,
'data',
{ siteId, readingStrategy: CoreSitesReadingStrategy.PREFER_CACHE },
);
return module.course; return module.course;
} }

View File

@ -18,6 +18,7 @@ import { CoreContentLinksHandlerBase } from '@features/contentlinks/classes/base
import { CoreContentLinksAction } from '@features/contentlinks/services/contentlinks-delegate'; import { CoreContentLinksAction } from '@features/contentlinks/services/contentlinks-delegate';
import { CoreCourse } from '@features/course/services/course'; import { CoreCourse } from '@features/course/services/course';
import { CoreNavigator } from '@services/navigator'; import { CoreNavigator } from '@services/navigator';
import { CoreSitesReadingStrategy } from '@services/sites';
import { CoreDomUtils } from '@services/utils/dom'; import { CoreDomUtils } from '@services/utils/dom';
import { makeSingleton } from '@singletons'; import { makeSingleton } from '@singletons';
import { AddonModDataModuleHandlerService } from './module'; import { AddonModDataModuleHandlerService } from './module';
@ -44,10 +45,13 @@ export class AddonModDataEditLinkHandlerService extends CoreContentLinksHandlerB
const rId = params.rid || ''; const rId = params.rid || '';
try { try {
const module = await CoreCourse.getModuleBasicInfoByInstance(dataId, 'data', siteId); const module = await CoreCourse.getModuleBasicInfoByInstance(
dataId,
'data',
{ siteId, readingStrategy: CoreSitesReadingStrategy.PREFER_CACHE },
);
const pageParams: Params = { const pageParams: Params = {
module, title: module.name,
courseId: module.course,
}; };
CoreNavigator.navigateToSitePath( CoreNavigator.navigateToSitePath(

View File

@ -261,7 +261,7 @@ export class AddonModDataPrefetchHandlerService extends CoreCourseActivityPrefet
}); });
// Add Basic Info to manage links. // Add Basic Info to manage links.
promises.push(CoreCourse.getModuleBasicInfoByInstance(database.id, 'data', siteId)); promises.push(CoreCourse.getModuleBasicInfoByInstance(database.id, 'data', { siteId }));
// Get course data, needed to determine upload max size if it's configured to be course limit. // Get course data, needed to determine upload max size if it's configured to be course limit.
promises.push(CoreUtils.ignoreErrors(CoreCourses.getCourseByField('id', courseId, siteId))); promises.push(CoreUtils.ignoreErrors(CoreCourses.getCourseByField('id', courseId, siteId)));

View File

@ -18,6 +18,7 @@ import { CoreContentLinksHandlerBase } from '@features/contentlinks/classes/base
import { CoreContentLinksAction } from '@features/contentlinks/services/contentlinks-delegate'; import { CoreContentLinksAction } from '@features/contentlinks/services/contentlinks-delegate';
import { CoreCourse } from '@features/course/services/course'; import { CoreCourse } from '@features/course/services/course';
import { CoreNavigator } from '@services/navigator'; import { CoreNavigator } from '@services/navigator';
import { CoreSitesReadingStrategy } from '@services/sites';
import { CoreDomUtils } from '@services/utils/dom'; import { CoreDomUtils } from '@services/utils/dom';
import { makeSingleton } from '@singletons'; import { makeSingleton } from '@singletons';
import { AddonModDataModuleHandlerService } from './module'; import { AddonModDataModuleHandlerService } from './module';
@ -47,10 +48,13 @@ export class AddonModDataShowLinkHandlerService extends CoreContentLinksHandlerB
const page = parseInt(params.page, 10) || false; const page = parseInt(params.page, 10) || false;
try { try {
const module = await CoreCourse.getModuleBasicInfoByInstance(dataId, 'data', siteId); const module = await CoreCourse.getModuleBasicInfoByInstance(
dataId,
'data',
{ siteId, readingStrategy: CoreSitesReadingStrategy.PREFER_CACHE },
);
const pageParams: Params = { const pageParams: Params = {
module: module, title: module.name,
courseId: module.course,
}; };
if (group) { if (group) {

View File

@ -176,7 +176,10 @@ export class AddonModFeedbackHelperProvider {
const modal = await CoreDomUtils.showModalLoading(); const modal = await CoreDomUtils.showModalLoading();
try { try {
const module = await CoreCourse.getModuleBasicInfo(Number(params.id), siteId); const module = await CoreCourse.getModuleBasicInfo(
Number(params.id),
{ siteId, readingStrategy: CoreSitesReadingStrategy.PREFER_CACHE },
);
if (params.showcompleted === undefined) { if (params.showcompleted === undefined) {
// Param showcompleted not defined. Show entry list. // Param showcompleted not defined. Show entry list.

View File

@ -223,7 +223,7 @@ export class AddonModFeedbackSyncProvider extends CoreCourseActivitySyncBaseProv
if (result.updated) { if (result.updated) {
// Data has been sent to server, update data. // Data has been sent to server, update data.
try { try {
const module = await CoreCourse.getModuleBasicInfoByInstance(feedbackId, 'feedback', siteId); const module = await CoreCourse.getModuleBasicInfoByInstance(feedbackId, 'feedback', { siteId });
await this.prefetchAfterUpdate(AddonModFeedbackPrefetchHandler.instance, module, courseId, undefined, siteId); await this.prefetchAfterUpdate(AddonModFeedbackPrefetchHandler.instance, module, courseId, undefined, siteId);
} catch { } catch {

View File

@ -43,13 +43,11 @@ export class AddonModFeedbackAnalysisLinkHandlerService extends CoreContentLinks
const moduleId = Number(params.id); const moduleId = Number(params.id);
try { try {
const moduleBasicInfo = await CoreCourse.getModuleBasicInfo(moduleId, siteId);
// Get the module. // Get the module.
const module = await CoreCourse.getModule( const module = await CoreCourse.getModule(
moduleId, moduleId,
moduleBasicInfo.course, undefined,
moduleBasicInfo.section, undefined,
false, false,
false, false,
siteId, siteId,

View File

@ -17,6 +17,7 @@ import { CoreContentLinksHandlerBase } from '@features/contentlinks/classes/base
import { CoreContentLinksAction } from '@features/contentlinks/services/contentlinks-delegate'; import { CoreContentLinksAction } from '@features/contentlinks/services/contentlinks-delegate';
import { CoreCourse } from '@features/course/services/course'; import { CoreCourse } from '@features/course/services/course';
import { CoreNavigator } from '@services/navigator'; import { CoreNavigator } from '@services/navigator';
import { CoreSitesReadingStrategy } from '@services/sites';
import { CoreDomUtils } from '@services/utils/dom'; import { CoreDomUtils } from '@services/utils/dom';
import { makeSingleton } from '@singletons'; import { makeSingleton } from '@singletons';
import { AddonModFeedbackModuleHandlerService } from './module'; import { AddonModFeedbackModuleHandlerService } from './module';
@ -43,7 +44,10 @@ export class AddonModFeedbackCompleteLinkHandlerService extends CoreContentLinks
const moduleId = Number(params.id); const moduleId = Number(params.id);
try { try {
const module = await CoreCourse.getModuleBasicInfo(moduleId, siteId); const module = await CoreCourse.getModuleBasicInfo(
moduleId,
{ siteId, readingStrategy: CoreSitesReadingStrategy.PREFER_CACHE },
);
CoreNavigator.navigateToSitePath( CoreNavigator.navigateToSitePath(
AddonModFeedbackModuleHandlerService.PAGE_NAME + `/${module.course}/${module.id}/form`, AddonModFeedbackModuleHandlerService.PAGE_NAME + `/${module.course}/${module.id}/form`,

View File

@ -17,6 +17,7 @@ import { CoreContentLinksHandlerBase } from '@features/contentlinks/classes/base
import { CoreContentLinksAction } from '@features/contentlinks/services/contentlinks-delegate'; import { CoreContentLinksAction } from '@features/contentlinks/services/contentlinks-delegate';
import { CoreCourse } from '@features/course/services/course'; import { CoreCourse } from '@features/course/services/course';
import { CoreNavigator } from '@services/navigator'; import { CoreNavigator } from '@services/navigator';
import { CoreSitesReadingStrategy } from '@services/sites';
import { CoreDomUtils } from '@services/utils/dom'; import { CoreDomUtils } from '@services/utils/dom';
import { makeSingleton } from '@singletons'; import { makeSingleton } from '@singletons';
import { AddonModFeedbackModuleHandlerService } from './module'; import { AddonModFeedbackModuleHandlerService } from './module';
@ -43,7 +44,10 @@ export class AddonModFeedbackPrintLinkHandlerService extends CoreContentLinksHan
const moduleId = Number(params.id); const moduleId = Number(params.id);
try { try {
const module = await CoreCourse.getModuleBasicInfo(moduleId, siteId); const module = await CoreCourse.getModuleBasicInfo(
moduleId,
{ siteId, readingStrategy: CoreSitesReadingStrategy.PREFER_CACHE },
);
CoreNavigator.navigateToSitePath( CoreNavigator.navigateToSitePath(
AddonModFeedbackModuleHandlerService.PAGE_NAME + `/${module.course}/${module.id}/form`, AddonModFeedbackModuleHandlerService.PAGE_NAME + `/${module.course}/${module.id}/form`,

View File

@ -17,6 +17,7 @@ import { CoreContentLinksHandlerBase } from '@features/contentlinks/classes/base
import { CoreContentLinksAction } from '@features/contentlinks/services/contentlinks-delegate'; import { CoreContentLinksAction } from '@features/contentlinks/services/contentlinks-delegate';
import { CoreCourse } from '@features/course/services/course'; import { CoreCourse } from '@features/course/services/course';
import { CoreNavigator } from '@services/navigator'; import { CoreNavigator } from '@services/navigator';
import { CoreSitesReadingStrategy } from '@services/sites';
import { CoreDomUtils } from '@services/utils/dom'; import { CoreDomUtils } from '@services/utils/dom';
import { makeSingleton } from '@singletons'; import { makeSingleton } from '@singletons';
import { AddonModFeedbackModuleHandlerService } from './module'; import { AddonModFeedbackModuleHandlerService } from './module';
@ -42,7 +43,10 @@ export class AddonModFeedbackShowNonRespondentsLinkHandlerService extends CoreCo
const moduleId = Number(params.id); const moduleId = Number(params.id);
try { try {
const module = await CoreCourse.getModuleBasicInfo(moduleId, siteId); const module = await CoreCourse.getModuleBasicInfo(
moduleId,
{ siteId, readingStrategy: CoreSitesReadingStrategy.PREFER_CACHE },
);
await CoreNavigator.navigateToSitePath( await CoreNavigator.navigateToSitePath(
AddonModFeedbackModuleHandlerService.PAGE_NAME + `/${module.course}/${module.id}/nonrespondents`, AddonModFeedbackModuleHandlerService.PAGE_NAME + `/${module.course}/${module.id}/nonrespondents`,

View File

@ -96,7 +96,7 @@ export class AddonModFolderIndexComponent extends CoreCourseModuleMainResourceCo
try { try {
this.folderInstance = await AddonModFolder.getFolder(this.courseId, this.module.id); this.folderInstance = await AddonModFolder.getFolder(this.courseId, this.module.id);
const contents = await CoreCourse.getModuleContents(this.module, this.courseId, undefined, false, refresh); const contents = await CoreCourse.getModuleContents(this.module, undefined, undefined, false, refresh);
this.dataRetrieved.emit(this.folderInstance || this.module); this.dataRetrieved.emit(this.folderInstance || this.module);

View File

@ -18,6 +18,7 @@ import { CoreContentLinksHandlerBase } from '@features/contentlinks/classes/base
import { CoreContentLinksAction } from '@features/contentlinks/services/contentlinks-delegate'; import { CoreContentLinksAction } from '@features/contentlinks/services/contentlinks-delegate';
import { CoreCourse } from '@features/course/services/course'; import { CoreCourse } from '@features/course/services/course';
import { CoreNavigator } from '@services/navigator'; import { CoreNavigator } from '@services/navigator';
import { CoreSitesReadingStrategy } from '@services/sites';
import { CoreDomUtils } from '@services/utils/dom'; import { CoreDomUtils } from '@services/utils/dom';
import { makeSingleton } from '@singletons'; import { makeSingleton } from '@singletons';
import { AddonModForumModuleHandlerService } from './module'; import { AddonModForumModuleHandlerService } from './module';
@ -53,7 +54,11 @@ export class AddonModForumPostLinkHandlerService extends CoreContentLinksHandler
const forumId = parseInt(params.forum, 10); const forumId = parseInt(params.forum, 10);
try { try {
const module = await CoreCourse.getModuleBasicInfoByInstance(forumId, 'forum', siteId); const module = await CoreCourse.getModuleBasicInfoByInstance(
forumId,
'forum',
{ siteId, readingStrategy: CoreSitesReadingStrategy.PREFER_CACHE },
);
await CoreNavigator.navigateToSitePath( await CoreNavigator.navigateToSitePath(
`${AddonModForumModuleHandlerService.PAGE_NAME}/${module.course}/${module.id}/new/0`, `${AddonModForumModuleHandlerService.PAGE_NAME}/${module.course}/${module.id}/new/0`,

View File

@ -17,6 +17,7 @@ import { CoreContentLinksHandlerBase } from '@features/contentlinks/classes/base
import { CoreContentLinksAction } from '@features/contentlinks/services/contentlinks-delegate'; import { CoreContentLinksAction } from '@features/contentlinks/services/contentlinks-delegate';
import { CoreCourse } from '@features/course/services/course'; import { CoreCourse } from '@features/course/services/course';
import { CoreNavigator } from '@services/navigator'; import { CoreNavigator } from '@services/navigator';
import { CoreSitesReadingStrategy } from '@services/sites';
import { CoreDomUtils } from '@services/utils/dom'; import { CoreDomUtils } from '@services/utils/dom';
import { makeSingleton } from '@singletons'; import { makeSingleton } from '@singletons';
import { AddonModGlossaryModuleHandlerService } from './module'; import { AddonModGlossaryModuleHandlerService } from './module';
@ -44,7 +45,10 @@ export class AddonModGlossaryEditLinkHandlerService extends CoreContentLinksHand
const cmId = Number(params.cmid); const cmId = Number(params.cmid);
try { try {
const module = await CoreCourse.getModuleBasicInfo(cmId, siteId); const module = await CoreCourse.getModuleBasicInfo(
cmId,
{ siteId, readingStrategy: CoreSitesReadingStrategy.PREFER_CACHE },
);
await CoreNavigator.navigateToSitePath( await CoreNavigator.navigateToSitePath(
AddonModGlossaryModuleHandlerService.PAGE_NAME + '/edit/0', AddonModGlossaryModuleHandlerService.PAGE_NAME + '/edit/0',

View File

@ -17,6 +17,7 @@ import { CoreContentLinksHandlerBase } from '@features/contentlinks/classes/base
import { CoreContentLinksAction } from '@features/contentlinks/services/contentlinks-delegate'; import { CoreContentLinksAction } from '@features/contentlinks/services/contentlinks-delegate';
import { CoreCourse } from '@features/course/services/course'; import { CoreCourse } from '@features/course/services/course';
import { CoreNavigator } from '@services/navigator'; import { CoreNavigator } from '@services/navigator';
import { CoreSitesReadingStrategy } from '@services/sites';
import { CoreDomUtils } from '@services/utils/dom'; import { CoreDomUtils } from '@services/utils/dom';
import { makeSingleton } from '@singletons'; import { makeSingleton } from '@singletons';
import { AddonModGlossary } from '../glossary'; import { AddonModGlossary } from '../glossary';
@ -43,12 +44,15 @@ export class AddonModGlossaryEntryLinkHandlerService extends CoreContentLinksHan
try { try {
const entryId = params.mode == 'entry' ? Number(params.hook) : Number(params.eid); const entryId = params.mode == 'entry' ? Number(params.hook) : Number(params.eid);
const response = await AddonModGlossary.getEntry(entryId, { siteId }); const response = await AddonModGlossary.getEntry(
entryId,
{ siteId, readingStrategy: CoreSitesReadingStrategy.PREFER_CACHE },
);
const module = await CoreCourse.getModuleBasicInfoByInstance( const module = await CoreCourse.getModuleBasicInfoByInstance(
response.entry.glossaryid, response.entry.glossaryid,
'glossary', 'glossary',
siteId, { siteId, readingStrategy: CoreSitesReadingStrategy.PREFER_CACHE },
); );
await CoreNavigator.navigateToSitePath( await CoreNavigator.navigateToSitePath(

View File

@ -205,8 +205,8 @@ export class AddonModGlossaryPrefetchHandlerService extends CoreCourseActivityPr
promises.push(AddonModGlossary.getAllCategories(glossary.id, options)); promises.push(AddonModGlossary.getAllCategories(glossary.id, options));
// Prefetch data for link handlers. // Prefetch data for link handlers.
promises.push(CoreCourse.getModuleBasicInfo(module.id, siteId)); promises.push(CoreCourse.getModuleBasicInfo(module.id, { siteId }));
promises.push(CoreCourse.getModuleBasicInfoByInstance(glossary.id, 'glossary', siteId)); promises.push(CoreCourse.getModuleBasicInfoByInstance(glossary.id, 'glossary', { siteId }));
// Get course data, needed to determine upload max size if it's configured to be course limit. // Get course data, needed to determine upload max size if it's configured to be course limit.
promises.push(CoreUtils.ignoreErrors(CoreCourses.getCourseByField('id', courseId, siteId))); promises.push(CoreUtils.ignoreErrors(CoreCourses.getCourseByField('id', courseId, siteId)));

View File

@ -18,7 +18,7 @@ import { CoreContentLinksHandlerBase } from '@features/contentlinks/classes/base
import { CoreContentLinksAction } from '@features/contentlinks/services/contentlinks-delegate'; import { CoreContentLinksAction } from '@features/contentlinks/services/contentlinks-delegate';
import { CoreCourse } from '@features/course/services/course'; import { CoreCourse } from '@features/course/services/course';
import { CoreNavigator } from '@services/navigator'; import { CoreNavigator } from '@services/navigator';
import { CoreSites } from '@services/sites'; import { CoreSites, CoreSitesReadingStrategy } from '@services/sites';
import { CoreDomUtils } from '@services/utils/dom'; import { CoreDomUtils } from '@services/utils/dom';
import { makeSingleton } from '@singletons'; import { makeSingleton } from '@singletons';
import { AddonModH5PActivity } from '../h5pactivity'; import { AddonModH5PActivity } from '../h5pactivity';
@ -41,54 +41,36 @@ export class AddonModH5PActivityReportLinkHandlerService extends CoreContentLink
siteIds: string[], siteIds: string[],
url: string, url: string,
params: Record<string, string>, params: Record<string, string>,
courseId?: number,
): CoreContentLinksAction[] | Promise<CoreContentLinksAction[]> { ): CoreContentLinksAction[] | Promise<CoreContentLinksAction[]> {
courseId = courseId || Number(params.courseid) || Number(params.cid);
return [{ return [{
action: async (siteId) => { action: async (siteId) => {
const modal = await CoreDomUtils.showModalLoading();
try { try {
const instanceId = Number(params.a); const instanceId = Number(params.a);
if (!courseId) { const module = await CoreCourse.getModuleBasicInfoByInstance(
courseId = await this.getCourseId(instanceId, siteId); instanceId,
} 'h5pactivity',
{ siteId, readingStrategy: CoreSitesReadingStrategy.PREFER_CACHE },
const module = await CoreCourse.getModuleBasicInfoByInstance(instanceId, 'h5pactivity', siteId); );
if (params.attemptid !== undefined) { if (params.attemptid !== undefined) {
this.openAttemptResults(module.id, Number(params.attemptid), courseId, siteId); this.openAttemptResults(module.id, Number(params.attemptid), module.course, siteId);
} else { } else {
const userId = params.userid ? Number(params.userid) : undefined; const userId = params.userid ? Number(params.userid) : undefined;
this.openUserAttempts(module.id, courseId, siteId, userId); this.openUserAttempts(module.id, module.course, siteId, userId);
} }
} catch (error) { } catch (error) {
CoreDomUtils.showErrorModalDefault(error, 'Error processing link.'); CoreDomUtils.showErrorModalDefault(error, 'Error processing link.');
} finally {
modal.dismiss();
} }
}, },
}]; }];
} }
/**
* Get course Id for an activity.
*
* @param id Activity ID.
* @param siteId Site ID.
* @return Promise resolved with course ID.
*/
protected async getCourseId(id: number, siteId: string): Promise<number> {
const modal = await CoreDomUtils.showModalLoading();
try {
const module = await CoreCourse.getModuleBasicInfoByInstance(id, 'h5pactivity', siteId);
return module.course;
} finally {
modal.dismiss();
}
}
/** /**
* @inheritdoc * @inheritdoc
*/ */

View File

@ -84,7 +84,7 @@ export class AddonModImscpIndexComponent extends CoreCourseModuleMainResourceCom
this.dataRetrieved.emit(imscp); this.dataRetrieved.emit(imscp);
// Get contents. No need to refresh, it has been done in downloadResourceIfNeeded. // Get contents. No need to refresh, it has been done in downloadResourceIfNeeded.
const contents = await CoreCourse.getModuleContents(this.module, this.courseId); const contents = await CoreCourse.getModuleContents(this.module);
this.items = AddonModImscp.createItemList(contents); this.items = AddonModImscp.createItemList(contents);

View File

@ -18,6 +18,7 @@ import { CoreContentLinksModuleGradeHandler } from '@features/contentlinks/class
import { CoreCourse } from '@features/course/services/course'; import { CoreCourse } from '@features/course/services/course';
import { CoreCourseHelper } from '@features/course/services/course-helper'; import { CoreCourseHelper } from '@features/course/services/course-helper';
import { CoreNavigator } from '@services/navigator'; import { CoreNavigator } from '@services/navigator';
import { CoreSitesReadingStrategy } from '@services/sites';
import { CoreDomUtils } from '@services/utils/dom'; import { CoreDomUtils } from '@services/utils/dom';
import { makeSingleton } from '@singletons'; import { makeSingleton } from '@singletons';
import { AddonModLesson } from '../lesson'; import { AddonModLesson } from '../lesson';
@ -57,8 +58,10 @@ export class AddonModLessonGradeLinkHandlerService extends CoreContentLinksModul
const modal = await CoreDomUtils.showModalLoading(); const modal = await CoreDomUtils.showModalLoading();
try { try {
const module = await CoreCourse.getModuleBasicInfo(moduleId, siteId); const module = await CoreCourse.getModuleBasicInfo(
courseId = Number(module.course || courseId || params.courseid || params.cid); moduleId,
{ siteId, readingStrategy: CoreSitesReadingStrategy.PREFER_CACHE },
);
// Check if the user can see the user reports in the lesson. // Check if the user can see the user reports in the lesson.
const accessInfo = await AddonModLesson.getAccessInformation(module.instance, { cmId: module.id, siteId }); const accessInfo = await AddonModLesson.getAccessInformation(module.instance, { cmId: module.id, siteId });
@ -66,14 +69,14 @@ export class AddonModLessonGradeLinkHandlerService extends CoreContentLinksModul
if (accessInfo.canviewreports) { if (accessInfo.canviewreports) {
// User can view reports, go to view the report. // User can view reports, go to view the report.
CoreNavigator.navigateToSitePath( CoreNavigator.navigateToSitePath(
AddonModLessonModuleHandlerService.PAGE_NAME + `/${courseId}/${module.id}/user-retake/${userId}`, AddonModLessonModuleHandlerService.PAGE_NAME + `/${module.course}/${module.id}/user-retake/${userId}`,
{ {
siteId, siteId,
}, },
); );
} else { } else {
// User cannot view the report, go to lesson index. // User cannot view the report, go to lesson index.
CoreCourseHelper.navigateToModule(moduleId, siteId, courseId, module.section); CoreCourseHelper.navigateToModule(moduleId, siteId, module.course, module.section);
} }
} catch (error) { } catch (error) {
CoreDomUtils.showErrorModalDefault(error, 'core.course.errorgetmodule', true); CoreDomUtils.showErrorModalDefault(error, 'core.course.errorgetmodule', true);

View File

@ -18,6 +18,7 @@ import { CoreContentLinksModuleIndexHandler } from '@features/contentlinks/class
import { CoreContentLinksAction } from '@features/contentlinks/services/contentlinks-delegate'; import { CoreContentLinksAction } from '@features/contentlinks/services/contentlinks-delegate';
import { CoreCourse } from '@features/course/services/course'; import { CoreCourse } from '@features/course/services/course';
import { CoreCourseHelper } from '@features/course/services/course-helper'; import { CoreCourseHelper } from '@features/course/services/course-helper';
import { CoreSitesReadingStrategy } from '@services/sites';
import { CoreDomUtils } from '@services/utils/dom'; import { CoreDomUtils } from '@services/utils/dom';
import { CoreUtils } from '@services/utils/utils'; import { CoreUtils } from '@services/utils/utils';
import { makeSingleton } from '@singletons'; import { makeSingleton } from '@singletons';
@ -85,14 +86,15 @@ export class AddonModLessonIndexLinkHandlerService extends CoreContentLinksModul
try { try {
// Get the module. // Get the module.
const module = await CoreCourse.getModuleBasicInfo(moduleId, siteId); const module = await CoreCourse.getModuleBasicInfo(
moduleId,
courseId = courseId || module.course; { siteId, readingStrategy: CoreSitesReadingStrategy.PREFER_CACHE },
);
// Store the password so it's automatically used. // Store the password so it's automatically used.
await CoreUtils.ignoreErrors(AddonModLesson.storePassword(module.instance, password, siteId)); await CoreUtils.ignoreErrors(AddonModLesson.storePassword(module.instance, password, siteId));
await CoreCourseHelper.navigateToModule(moduleId, siteId, courseId, module.section); await CoreCourseHelper.navigateToModule(moduleId, siteId, module.course, module.section);
} catch { } catch {
// Error, go to index page. // Error, go to index page.
await CoreCourseHelper.navigateToModule(moduleId, siteId, courseId); await CoreCourseHelper.navigateToModule(moduleId, siteId, courseId);

View File

@ -18,6 +18,7 @@ import { CoreContentLinksHandlerBase } from '@features/contentlinks/classes/base
import { CoreContentLinksAction } from '@features/contentlinks/services/contentlinks-delegate'; import { CoreContentLinksAction } from '@features/contentlinks/services/contentlinks-delegate';
import { CoreCourse } from '@features/course/services/course'; import { CoreCourse } from '@features/course/services/course';
import { CoreNavigator } from '@services/navigator'; import { CoreNavigator } from '@services/navigator';
import { CoreSitesReadingStrategy } from '@services/sites';
import { CoreDomUtils } from '@services/utils/dom'; import { CoreDomUtils } from '@services/utils/dom';
import { makeSingleton } from '@singletons'; import { makeSingleton } from '@singletons';
import { AddonModLessonModuleHandlerService } from './module'; import { AddonModLessonModuleHandlerService } from './module';
@ -38,26 +39,20 @@ export class AddonModLessonReportLinkHandlerService extends CoreContentLinksHand
* @param siteIds List of sites the URL belongs to. * @param siteIds List of sites the URL belongs to.
* @param url The URL to treat. * @param url The URL to treat.
* @param params The params of the URL. E.g. 'mysite.com?id=1' -> {id: 1} * @param params The params of the URL. E.g. 'mysite.com?id=1' -> {id: 1}
* @param courseId Course ID related to the URL. Optional but recommended.
* @param data Extra data to handle the URL.
* @return List of (or promise resolved with list of) actions. * @return List of (or promise resolved with list of) actions.
*/ */
getActions( getActions(
siteIds: string[], siteIds: string[],
url: string, url: string,
params: Record<string, string>, params: Record<string, string>,
courseId?: number,
data?: unknown, // eslint-disable-line @typescript-eslint/no-unused-vars
): CoreContentLinksAction[] | Promise<CoreContentLinksAction[]> { ): CoreContentLinksAction[] | Promise<CoreContentLinksAction[]> {
courseId = Number(courseId || params.courseid || params.cid);
return [{ return [{
action: (siteId) => { action: (siteId) => {
if (!params.action || params.action == 'reportoverview') { if (!params.action || params.action == 'reportoverview') {
// Go to overview. // Go to overview.
this.openReportOverview(Number(params.id), courseId, Number(params.group), siteId); this.openReportOverview(Number(params.id), Number(params.group), siteId);
} else if (params.action == 'reportdetail') { } else if (params.action == 'reportdetail') {
this.openUserRetake(Number(params.id), Number(params.userid), Number(params.try), siteId, courseId); this.openUserRetake(Number(params.id), Number(params.userid), Number(params.try), siteId);
} }
}, },
}]; }];
@ -70,11 +65,9 @@ export class AddonModLessonReportLinkHandlerService extends CoreContentLinksHand
* @param siteId The site ID. * @param siteId The site ID.
* @param url The URL to treat. * @param url The URL to treat.
* @param params The params of the URL. E.g. 'mysite.com?id=1' -> {id: 1} * @param params The params of the URL. E.g. 'mysite.com?id=1' -> {id: 1}
* @param courseId Course ID related to the URL. Optional but recommended.
* @return Whether the handler is enabled for the URL and site. * @return Whether the handler is enabled for the URL and site.
*/ */
// eslint-disable-next-line @typescript-eslint/no-unused-vars async isEnabled(siteId: string, url: string, params: Record<string, string>): Promise<boolean> {
async isEnabled(siteId: string, url: string, params: Record<string, string>, courseId?: number): Promise<boolean> {
if (params.action == 'reportdetail' && !params.userid) { if (params.action == 'reportdetail' && !params.userid) {
// Individual details are only available if the teacher is seeing a certain user. // Individual details are only available if the teacher is seeing a certain user.
return false; return false;
@ -87,29 +80,33 @@ export class AddonModLessonReportLinkHandlerService extends CoreContentLinksHand
* Open report overview. * Open report overview.
* *
* @param moduleId Module ID. * @param moduleId Module ID.
* @param courseId Course ID.
* @param groupId Group ID. * @param groupId Group ID.
* @param siteId Site ID. * @param siteId Site ID.
* @param navCtrl The NavController to use to navigate.
* @return Promise resolved when done. * @return Promise resolved when done.
*/ */
protected async openReportOverview(moduleId: number, courseId?: number, groupId?: number, siteId?: string): Promise<void> { protected async openReportOverview(moduleId: number, groupId?: number, siteId?: string): Promise<void> {
const modal = await CoreDomUtils.showModalLoading(); const modal = await CoreDomUtils.showModalLoading();
try { try {
// Get the module object. // Get the module object.
const module = await CoreCourse.getModuleBasicInfo(moduleId, siteId); const module = await CoreCourse.getModule(
moduleId,
undefined,
undefined,
false,
false,
siteId,
);
courseId = courseId || module.course;
const params = { const params = {
module: module, module,
action: 'report', action: 'report',
group: groupId === undefined || isNaN(groupId) ? null : groupId, group: groupId === undefined || isNaN(groupId) ? null : groupId,
}; };
CoreNavigator.navigateToSitePath( CoreNavigator.navigateToSitePath(
`${AddonModLessonModuleHandlerService.PAGE_NAME}/${courseId}/${module.id}`, `${AddonModLessonModuleHandlerService.PAGE_NAME}/${module.course}/${module.id}`,
{ params, siteId }, { params, siteId },
); );
} catch (error) { } catch (error) {
@ -126,7 +123,6 @@ export class AddonModLessonReportLinkHandlerService extends CoreContentLinksHand
* @param userId User ID. * @param userId User ID.
* @param retake Retake to open. * @param retake Retake to open.
* @param siteId Site ID. * @param siteId Site ID.
* @param courseId Course ID.
* @return Promise resolved when done. * @return Promise resolved when done.
*/ */
protected async openUserRetake( protected async openUserRetake(
@ -134,22 +130,22 @@ export class AddonModLessonReportLinkHandlerService extends CoreContentLinksHand
userId: number, userId: number,
retake: number, retake: number,
siteId: string, siteId: string,
courseId?: number,
): Promise<void> { ): Promise<void> {
const modal = await CoreDomUtils.showModalLoading(); const modal = await CoreDomUtils.showModalLoading();
try { try {
// Get the module object. // Get the module object.
const module = await CoreCourse.getModuleBasicInfo(moduleId, siteId); const module = await CoreCourse.getModuleBasicInfo(
moduleId,
courseId = courseId || module.course; { siteId, readingStrategy: CoreSitesReadingStrategy.PREFER_CACHE },
);
const params = { const params = {
retake: retake || 0, retake: retake || 0,
}; };
CoreNavigator.navigateToSitePath( CoreNavigator.navigateToSitePath(
AddonModLessonModuleHandlerService.PAGE_NAME + `/${courseId}/${module.id}/user-retake/${userId}`, AddonModLessonModuleHandlerService.PAGE_NAME + `/${module.course}/${module.id}/user-retake/${userId}`,
{ params, siteId }, { params, siteId },
); );
} catch (error) { } catch (error) {

View File

@ -243,7 +243,7 @@ export class AddonModLessonSyncProvider extends CoreCourseActivitySyncBaseProvid
if (result.updated && result.courseId) { if (result.updated && result.courseId) {
try { try {
// Data has been sent to server, update data. // Data has been sent to server, update data.
const module = await CoreCourse.getModuleBasicInfoByInstance(lessonId, 'lesson', siteId); const module = await CoreCourse.getModuleBasicInfoByInstance(lessonId, 'lesson', { siteId });
await this.prefetchAfterUpdate(AddonModLessonPrefetchHandler.instance, module, result.courseId, undefined, siteId); await this.prefetchAfterUpdate(AddonModLessonPrefetchHandler.instance, module, result.courseId, undefined, siteId);
} catch { } catch {
// Ignore errors. // Ignore errors.

View File

@ -82,7 +82,7 @@ export class AddonModPageIndexComponent extends CoreCourseModuleMainResourceComp
const downloadResult = await this.downloadResourceIfNeeded(refresh); const downloadResult = await this.downloadResourceIfNeeded(refresh);
// Get contents. No need to refresh, it has been done in downloadResourceIfNeeded. // Get contents. No need to refresh, it has been done in downloadResourceIfNeeded.
const contents = await CoreCourse.getModuleContents(this.module, this.courseId); const contents = await CoreCourse.getModuleContents(this.module);
const results = await Promise.all([ const results = await Promise.all([
this.loadPageData(), this.loadPageData(),

View File

@ -62,7 +62,6 @@ export class AddonModQuizPushClickHandlerService implements CorePushNotification
return AddonModQuizHelper.handleReviewLink( return AddonModQuizHelper.handleReviewLink(
Number(contextUrlParams.attempt), Number(contextUrlParams.attempt),
Number(contextUrlParams.page), Number(contextUrlParams.page),
courseId,
Number(data.instance), Number(data.instance),
notification.site, notification.site,
); );

View File

@ -46,17 +46,13 @@ export class AddonModQuizReviewLinkHandlerService extends CoreContentLinksHandle
courseId?: number, courseId?: number,
data?: Record<string, unknown>, data?: Record<string, unknown>,
): CoreContentLinksAction[] | Promise<CoreContentLinksAction[]> { ): CoreContentLinksAction[] | Promise<CoreContentLinksAction[]> {
const quizId = data?.instance ? Number(data.instance) : undefined;
courseId = Number(courseId || params.courseid || params.cid);
data = data || {};
return [{ return [{
action: (siteId): void => { action: (siteId): void => {
const attemptId = parseInt(params.attempt, 10); const attemptId = parseInt(params.attempt, 10);
const page = parseInt(params.page, 10); const page = parseInt(params.page, 10);
const quizId = data!.instance ? Number(data!.instance) : undefined; AddonModQuizHelper.handleReviewLink(attemptId, page, quizId, siteId);
AddonModQuizHelper.handleReviewLink(attemptId, page, courseId, quizId, siteId);
}, },
}]; }];
} }

View File

@ -215,12 +215,11 @@ export class AddonModQuizHelperProvider {
* *
* @param attemptId Attempt ID. * @param attemptId Attempt ID.
* @param page Page to load, -1 to all questions in same page. * @param page Page to load, -1 to all questions in same page.
* @param courseId Course ID.
* @param quizId Quiz ID. * @param quizId Quiz ID.
* @param siteId Site ID. If not defined, current site. * @param siteId Site ID. If not defined, current site.
* @return Promise resolved when done. * @return Promise resolved when done.
*/ */
async handleReviewLink(attemptId: number, page?: number, courseId?: number, quizId?: number, siteId?: string): Promise<void> { async handleReviewLink(attemptId: number, page?: number, quizId?: number, siteId?: string): Promise<void> {
siteId = siteId || CoreSites.getCurrentSiteId(); siteId = siteId || CoreSites.getCurrentSiteId();
const modal = await CoreDomUtils.showModalLoading(); const modal = await CoreDomUtils.showModalLoading();
@ -230,13 +229,15 @@ export class AddonModQuizHelperProvider {
quizId = await this.getQuizIdByAttemptId(attemptId, { siteId }); quizId = await this.getQuizIdByAttemptId(attemptId, { siteId });
} }
const module = await CoreCourse.getModuleBasicInfoByInstance(quizId, 'quiz', siteId); const module = await CoreCourse.getModuleBasicInfoByInstance(
quizId,
courseId = courseId || module.course; 'quiz',
{ siteId, readingStrategy: CoreSitesReadingStrategy.PREFER_CACHE },
);
// Go to the review page. // Go to the review page.
await CoreNavigator.navigateToSitePath( await CoreNavigator.navigateToSitePath(
`${AddonModQuizModuleHandlerService.PAGE_NAME}/${courseId}/${module.id}/review/${attemptId}`, `${AddonModQuizModuleHandlerService.PAGE_NAME}/${module.course}/${module.id}/review/${attemptId}`,
{ {
params: { params: {
page: page == undefined || isNaN(page) ? -1 : page, page: page == undefined || isNaN(page) ? -1 : page,

View File

@ -16,7 +16,7 @@ import { Injectable } from '@angular/core';
import { CoreError } from '@classes/errors/error'; import { CoreError } from '@classes/errors/error';
import { CoreCourseActivitySyncBaseProvider } from '@features/course/classes/activity-sync'; import { CoreCourseActivitySyncBaseProvider } from '@features/course/classes/activity-sync';
import { CoreCourse, CoreCourseAnyModuleData } from '@features/course/services/course'; import { CoreCourse, CoreCourseModuleBasicInfo } from '@features/course/services/course';
import { CoreCourseLogHelper } from '@features/course/services/log-helper'; import { CoreCourseLogHelper } from '@features/course/services/log-helper';
import { CoreCourseModulePrefetchDelegate } from '@features/course/services/module-prefetch-delegate'; import { CoreCourseModulePrefetchDelegate } from '@features/course/services/module-prefetch-delegate';
import { CoreQuestion, CoreQuestionQuestionParsed } from '@features/question/services/question'; import { CoreQuestion, CoreQuestionQuestionParsed } from '@features/question/services/question';
@ -92,9 +92,9 @@ export class AddonModQuizSyncProvider extends CoreCourseActivitySyncBaseProvider
if (options.updated) { if (options.updated) {
try { try {
// Data has been sent. Update prefetched data. // Data has been sent. Update prefetched data.
const module = await CoreCourse.getModuleBasicInfoByInstance(quiz.id, 'quiz', siteId); const module = await CoreCourse.getModuleBasicInfoByInstance(quiz.id, 'quiz', { siteId });
await this.prefetchAfterUpdateQuiz(module, quiz, courseId, undefined, siteId); await this.prefetchAfterUpdateQuiz(module, quiz, courseId, siteId);
} catch { } catch {
// Ignore errors. // Ignore errors.
} }
@ -139,27 +139,25 @@ export class AddonModQuizSyncProvider extends CoreCourseActivitySyncBaseProvider
* @param module Module. * @param module Module.
* @param quiz Quiz. * @param quiz Quiz.
* @param courseId Course ID. * @param courseId Course ID.
* @param regex If regex matches, don't download the data. Defaults to check files.
* @param siteId Site ID. If not defined, current site. * @param siteId Site ID. If not defined, current site.
* @return Promise resolved when done. * @return Promise resolved when done.
*/ */
async prefetchAfterUpdateQuiz( protected async prefetchAfterUpdateQuiz(
module: CoreCourseAnyModuleData, module: CoreCourseModuleBasicInfo,
quiz: AddonModQuizQuizWSData, quiz: AddonModQuizQuizWSData,
courseId: number, courseId: number,
regex?: RegExp,
siteId?: string, siteId?: string,
): Promise<void> { ): Promise<void> {
regex = regex || /^.*files$/;
let shouldDownload = false; let shouldDownload = false;
// Get the module updates to check if the data was updated or not. // Get the module updates to check if the data was updated or not.
const result = await CoreCourseModulePrefetchDelegate.getModuleUpdates(module, courseId, true, siteId); const result = await CoreCourseModulePrefetchDelegate.getModuleUpdates(module, courseId, true, siteId);
if (result?.updates?.length) { if (result?.updates?.length) {
const regex = /^.*files$/;
// Only prefetch if files haven't changed. // Only prefetch if files haven't changed.
shouldDownload = !result.updates.find((entry) => entry.name.match(regex!)); shouldDownload = !result.updates.find((entry) => entry.name.match(regex));
if (shouldDownload) { if (shouldDownload) {
await AddonModQuizPrefetchHandler.download(module, courseId, undefined, false, false); await AddonModQuizPrefetchHandler.download(module, courseId, undefined, false, false);

View File

@ -101,7 +101,7 @@ export class AddonModResourceIndexComponent extends CoreCourseModuleMainResource
*/ */
protected async fetchContent(refresh?: boolean): Promise<void> { protected async fetchContent(refresh?: boolean): Promise<void> {
// Load module contents if needed. Passing refresh is needed to force reloading contents. // Load module contents if needed. Passing refresh is needed to force reloading contents.
const contents = await CoreCourse.getModuleContents(this.module, this.courseId, undefined, false, refresh); const contents = await CoreCourse.getModuleContents(this.module, undefined, undefined, false, refresh);
if (!contents.length) { if (!contents.length) {
throw new CoreError(Translate.instant('core.filenotfound')); throw new CoreError(Translate.instant('core.filenotfound'));
@ -148,7 +148,7 @@ export class AddonModResourceIndexComponent extends CoreCourseModuleMainResource
this.mode = 'embedded'; this.mode = 'embedded';
this.warning = ''; this.warning = '';
this.contentText = await AddonModResourceHelper.getEmbeddedHtml(this.module, this.courseId); this.contentText = await AddonModResourceHelper.getEmbeddedHtml(this.module);
this.mode = this.contentText.length > 0 ? 'embedded' : 'external'; this.mode = this.contentText.length > 0 ? 'embedded' : 'external';
} else { } else {
this.mode = 'external'; this.mode = 'external';

View File

@ -85,7 +85,7 @@ export class AddonModResourceModuleHandlerService extends CoreModuleHandlerBase
icon: openWithPicker ? 'fas-share-square' : 'fas-file', icon: openWithPicker ? 'fas-share-square' : 'fas-file',
label: module.name + ': ' + Translate.instant(openWithPicker ? 'core.openwith' : 'addon.mod_resource.openthefile'), label: module.name + ': ' + Translate.instant(openWithPicker ? 'core.openwith' : 'addon.mod_resource.openthefile'),
action: async (event: Event, module: CoreCourseModuleData, courseId: number): Promise<void> => { action: async (event: Event, module: CoreCourseModuleData, courseId: number): Promise<void> => {
const hide = await this.hideOpenButton(module, courseId); const hide = await this.hideOpenButton(module);
if (!hide) { if (!hide) {
AddonModResourceHelper.openModuleFile(module, courseId); AddonModResourceHelper.openModuleFile(module, courseId);
} }
@ -109,15 +109,14 @@ export class AddonModResourceModuleHandlerService extends CoreModuleHandlerBase
* Returns if contents are loaded to show open button. * Returns if contents are loaded to show open button.
* *
* @param module The module object. * @param module The module object.
* @param courseId The course ID.
* @return Resolved when done. * @return Resolved when done.
*/ */
protected async hideOpenButton(module: CoreCourseModuleData, courseId: number): Promise<boolean> { protected async hideOpenButton(module: CoreCourseModuleData): Promise<boolean> {
if (!('contentsinfo' in module) || !module.contentsinfo) { if (!module.contentsinfo) { // Not informed before 3.7.6.
await CoreCourse.loadModuleContents(module, courseId, undefined, false, false, undefined, this.modName); await CoreCourse.loadModuleContents(module, undefined, undefined, false, false, undefined, this.modName);
} }
const status = await CoreCourseModulePrefetchDelegate.getModuleStatus(module, courseId); const status = await CoreCourseModulePrefetchDelegate.getModuleStatus(module, module.course);
return status !== CoreConstants.DOWNLOADED || AddonModResourceHelper.isDisplayedInIframe(module); return status !== CoreConstants.DOWNLOADED || AddonModResourceHelper.isDisplayedInIframe(module);
} }
@ -138,7 +137,7 @@ export class AddonModResourceModuleHandlerService extends CoreModuleHandlerBase
let options: AddonModResourceCustomData = {}; let options: AddonModResourceCustomData = {};
// Check if the button needs to be shown or not. // Check if the button needs to be shown or not.
promises.push(this.hideOpenButton(module, courseId).then((hideOpenButton) => { promises.push(this.hideOpenButton(module).then((hideOpenButton) => {
if (!handlerData.buttons) { if (!handlerData.buttons) {
return; return;
} }
@ -148,7 +147,7 @@ export class AddonModResourceModuleHandlerService extends CoreModuleHandlerBase
return; return;
})); }));
if ('customdata' in module && module.customdata !== undefined) { if (module.customdata !== undefined) {
options = CoreTextUtils.unserialize(CoreTextUtils.parseJSON(module.customdata)); options = CoreTextUtils.unserialize(CoreTextUtils.parseJSON(module.customdata));
} else { } else {
// Get the resource data. // Get the resource data.
@ -164,7 +163,7 @@ export class AddonModResourceModuleHandlerService extends CoreModuleHandlerBase
let mimetypeIcon = ''; let mimetypeIcon = '';
const extra: string[] = []; const extra: string[] = [];
if ('contentsinfo' in module && module.contentsinfo) { if (module.contentsinfo) {
// No need to use the list of files. // No need to use the list of files.
const mimetype = module.contentsinfo.mimetypes[0]; const mimetype = module.contentsinfo.mimetypes[0];
if (mimetype) { if (mimetype) {
@ -235,7 +234,7 @@ export class AddonModResourceModuleHandlerService extends CoreModuleHandlerBase
} }
let mimetypeIcon = ''; let mimetypeIcon = '';
if ('contentsinfo' in module && module.contentsinfo) { if (module.contentsinfo) {
// No need to use the list of files. // No need to use the list of files.
const mimetype = module.contentsinfo.mimetypes[0]; const mimetype = module.contentsinfo.mimetypes[0];
if (mimetype) { if (mimetype) {

View File

@ -39,15 +39,14 @@ export class AddonModResourceHelperProvider {
* Get the HTML to display an embedded resource. * Get the HTML to display an embedded resource.
* *
* @param module The module object. * @param module The module object.
* @param courseId The course ID.
* @return Promise resolved with the HTML. * @return Promise resolved with the HTML.
*/ */
async getEmbeddedHtml(module: CoreCourseModuleData, courseId: number): Promise<string> { async getEmbeddedHtml(module: CoreCourseModuleData): Promise<string> {
const contents = await CoreCourse.getModuleContents(module, courseId); const contents = await CoreCourse.getModuleContents(module);
const result = await CoreCourseHelper.downloadModuleWithMainFileIfNeeded( const result = await CoreCourseHelper.downloadModuleWithMainFileIfNeeded(
module, module,
courseId, module.course,
AddonModResourceProvider.COMPONENT, AddonModResourceProvider.COMPONENT,
module.id, module.id,
contents, contents,
@ -124,14 +123,14 @@ export class AddonModResourceHelperProvider {
* @param module The module object. * @param module The module object.
* @return Whether the resource should be displayed in an iframe. * @return Whether the resource should be displayed in an iframe.
*/ */
isDisplayedInIframe(module: CoreCourseAnyModuleData): boolean { isDisplayedInIframe(module: CoreCourseModuleData): boolean {
if (!CoreFile.isAvailable()) { if (!CoreFile.isAvailable()) {
return false; return false;
} }
let mimetype: string | undefined; let mimetype: string | undefined;
if ('contentsinfo' in module && module.contentsinfo) { if (module.contentsinfo) {
mimetype = module.contentsinfo.mimetypes[0]; mimetype = module.contentsinfo.mimetypes[0];
} else if (module.contents) { } else if (module.contents) {
const ext = CoreMimetypeUtils.getFileExtension(module.contents[0].filename); const ext = CoreMimetypeUtils.getFileExtension(module.contents[0].filename);

View File

@ -198,7 +198,7 @@ export class AddonModScormSyncProvider extends CoreCourseActivitySyncBaseProvide
if (updated) { if (updated) {
try { try {
// Update downloaded data. // Update downloaded data.
const module = await CoreCourse.getModule(scorm.coursemodule, scorm.course, undefined, false, false, siteId); const module = await CoreCourse.getModuleBasicInfoByInstance(scorm.id, 'scorm', { siteId });
await this.prefetchAfterUpdate(AddonModScormPrefetchHandler.instance, module, scorm.course, undefined, siteId); await this.prefetchAfterUpdate(AddonModScormPrefetchHandler.instance, module, scorm.course, undefined, siteId);
} catch { } catch {

View File

@ -202,7 +202,7 @@ export class AddonModSurveySyncProvider extends CoreCourseActivitySyncBaseProvid
await AddonModSurvey.invalidateSurveyData(result.courseId, siteId); await AddonModSurvey.invalidateSurveyData(result.courseId, siteId);
// Data has been sent to server, update survey data. // Data has been sent to server, update survey data.
const module = await CoreCourse.getModuleBasicInfoByInstance(surveyId, 'survey', siteId); const module = await CoreCourse.getModuleBasicInfoByInstance(surveyId, 'survey', { siteId });
CoreUtils.ignoreErrors( CoreUtils.ignoreErrors(
this.prefetchAfterUpdate(AddonModSurveyPrefetchHandler.instance, module, result.courseId, undefined, siteId), this.prefetchAfterUpdate(AddonModSurveyPrefetchHandler.instance, module, result.courseId, undefined, siteId),

View File

@ -98,7 +98,7 @@ export class AddonModUrlIndexComponent extends CoreCourseModuleMainResourceCompo
// Try to get module contents, it's needed to get the URL with parameters. // Try to get module contents, it's needed to get the URL with parameters.
const contents = await CoreCourse.getModuleContents( const contents = await CoreCourse.getModuleContents(
this.module, this.module,
this.courseId, undefined,
undefined, undefined,
false, false,
refresh, refresh,

View File

@ -54,7 +54,7 @@ export class AddonModUrlModuleHandlerService extends CoreModuleHandlerBase imple
/** /**
* @inheritdoc * @inheritdoc
*/ */
async getData(module: CoreCourseModuleData, courseId: number): Promise<CoreCourseModuleHandlerData> { async getData(module: CoreCourseModuleData): Promise<CoreCourseModuleHandlerData> {
/** /**
* Open the URL. * Open the URL.
@ -62,17 +62,17 @@ export class AddonModUrlModuleHandlerService extends CoreModuleHandlerBase imple
* @param module The module object. * @param module The module object.
* @param courseId The course ID. * @param courseId The course ID.
*/ */
const openUrl = async (module: CoreCourseModuleData, courseId: number): Promise<void> => { const openUrl = async (module: CoreCourseModuleData): Promise<void> => {
try { try {
if (module.instance) { if (module.instance) {
await AddonModUrl.logView(module.instance, module.name); await AddonModUrl.logView(module.instance, module.name);
CoreCourse.checkModuleCompletion(courseId, module.completiondata); CoreCourse.checkModuleCompletion(module.course, module.completiondata);
} }
} catch { } catch {
// Ignore errors. // Ignore errors.
} }
const contents = await CoreCourse.getModuleContents(module, courseId); const contents = await CoreCourse.getModuleContents(module);
AddonModUrlHelper.open(contents[0].fileurl); AddonModUrlHelper.open(contents[0].fileurl);
}; };
@ -85,12 +85,12 @@ export class AddonModUrlModuleHandlerService extends CoreModuleHandlerBase imple
const modal = await CoreDomUtils.showModalLoading(); const modal = await CoreDomUtils.showModalLoading();
try { try {
const shouldOpen = await this.shouldOpenLink(module, courseId); const shouldOpen = await this.shouldOpenLink(module);
if (shouldOpen) { if (shouldOpen) {
openUrl(module, courseId); openUrl(module);
} else { } else {
this.openActivityPage(module, courseId, options); this.openActivityPage(module, module.course, options);
} }
} finally { } finally {
modal.dismiss(); modal.dismiss();
@ -100,13 +100,13 @@ export class AddonModUrlModuleHandlerService extends CoreModuleHandlerBase imple
hidden: true, // Hide it until we calculate if it should be displayed or not. hidden: true, // Hide it until we calculate if it should be displayed or not.
icon: 'fas-link', icon: 'fas-link',
label: 'core.openmodinbrowser', label: 'core.openmodinbrowser',
action: (event: Event, module: CoreCourseModuleData, courseId: number): void => { action: (event: Event, module: CoreCourseModuleData): void => {
openUrl(module, courseId); openUrl(module);
}, },
}], }],
}; };
this.hideLinkButton(module, courseId).then(async (hideButton) => { this.hideLinkButton(module).then(async (hideButton) => {
if (!handlerData.buttons) { if (!handlerData.buttons) {
return; return;
} }
@ -135,9 +135,10 @@ export class AddonModUrlModuleHandlerService extends CoreModuleHandlerBase imple
* @param courseId The course ID. * @param courseId The course ID.
* @return Resolved when done. * @return Resolved when done.
*/ */
protected async hideLinkButton(module: CoreCourseModuleData, courseId: number): Promise<boolean> { protected async hideLinkButton(module: CoreCourseModuleData): Promise<boolean> {
try { try {
const contents = await CoreCourse.getModuleContents(module, courseId, undefined, false, false, undefined, this.modName); const contents =
await CoreCourse.getModuleContents(module, undefined, undefined, false, false, undefined, this.modName);
return !(contents[0] && contents[0].fileurl); return !(contents[0] && contents[0].fileurl);
} catch { } catch {
@ -157,22 +158,22 @@ export class AddonModUrlModuleHandlerService extends CoreModuleHandlerBase imple
* Check whether the link should be opened directly. * Check whether the link should be opened directly.
* *
* @param module Module. * @param module Module.
* @param courseId Course ID.
* @return Promise resolved with boolean. * @return Promise resolved with boolean.
*/ */
protected async shouldOpenLink(module: CoreCourseModuleData, courseId?: number): Promise<boolean> { protected async shouldOpenLink(module: CoreCourseModuleData): Promise<boolean> {
try { try {
const contents = await CoreCourse.getModuleContents(module, courseId, undefined, false, false, undefined, this.modName); const contents =
await CoreCourse.getModuleContents(module, undefined, undefined, false, false, undefined, this.modName);
// Check if the URL can be handled by the app. If so, always open it directly. // Check if the URL can be handled by the app. If so, always open it directly.
const canHandle = await CoreContentLinksHelper.canHandleLink(contents[0].fileurl, courseId, undefined, true); const canHandle = await CoreContentLinksHelper.canHandleLink(contents[0].fileurl, module.course, undefined, true);
if (canHandle) { if (canHandle) {
// URL handled by the app, open it directly. // URL handled by the app, open it directly.
return true; return true;
} else { } else {
// Not handled by the app, check the display type. // Not handled by the app, check the display type.
const url = courseId ? await CoreUtils.ignoreErrors(AddonModUrl.getUrl(courseId, module.id)) : undefined; const url = await CoreUtils.ignoreErrors(AddonModUrl.getUrl(module.course, module.id));
const displayType = AddonModUrl.getFinalDisplayType(url); const displayType = AddonModUrl.getFinalDisplayType(url);
return displayType == CoreConstants.RESOURCELIB_DISPLAY_OPEN || return displayType == CoreConstants.RESOURCELIB_DISPLAY_OPEN ||
@ -187,7 +188,7 @@ export class AddonModUrlModuleHandlerService extends CoreModuleHandlerBase imple
* @inheritdoc * @inheritdoc
*/ */
manualCompletionAlwaysShown(module: CoreCourseModuleData): Promise<boolean> { manualCompletionAlwaysShown(module: CoreCourseModuleData): Promise<boolean> {
return this.shouldOpenLink(module, module.course); return this.shouldOpenLink(module);
} }
} }

View File

@ -18,7 +18,7 @@ import { CoreError } from '@classes/errors/error';
import { CoreCourse } from '@features/course/services/course'; import { CoreCourse } from '@features/course/services/course';
import { CanLeave } from '@guards/can-leave'; import { CanLeave } from '@guards/can-leave';
import { CoreNavigator } from '@services/navigator'; import { CoreNavigator } from '@services/navigator';
import { CoreSites } from '@services/sites'; import { CoreSites, CoreSitesReadingStrategy } from '@services/sites';
import { CoreSync } from '@services/sync'; import { CoreSync } from '@services/sync';
import { CoreDomUtils } from '@services/utils/dom'; import { CoreDomUtils } from '@services/utils/dom';
import { CoreTextUtils } from '@services/utils/text'; import { CoreTextUtils } from '@services/utils/text';
@ -262,7 +262,11 @@ export class AddonModWikiEditPage implements OnInit, OnDestroy, CanLeave {
return; return;
} }
const module = await CoreCourse.getModuleBasicInfoByInstance(this.wikiId, 'wiki'); const module = await CoreCourse.getModuleBasicInfoByInstance(
this.wikiId,
'wiki',
{ readingStrategy: CoreSitesReadingStrategy.PREFER_CACHE },
);
this.cmId = module.id; this.cmId = module.id;
this.courseId = module.course; this.courseId = module.course;

View File

@ -115,7 +115,11 @@ export class AddonModWikiCreateLinkHandlerService extends CoreContentLinksHandle
path = path + `/${route!.snapshot.params.courseId}/${route!.snapshot.params.cmId}/edit`; path = path + `/${route!.snapshot.params.courseId}/${route!.snapshot.params.cmId}/edit`;
} else if (wikiId) { } else if (wikiId) {
// The URL specifies which wiki it belongs to. Get the module. // The URL specifies which wiki it belongs to. Get the module.
const module = await CoreCourse.getModuleBasicInfoByInstance(wikiId, 'wiki', siteId); const module = await CoreCourse.getModuleBasicInfoByInstance(
wikiId,
'wiki',
{ siteId, readingStrategy: CoreSitesReadingStrategy.PREFER_CACHE },
);
path = path + `/${module.course}/${module.id}/edit`; path = path + `/${module.course}/${module.id}/edit`;
} else { } else {

View File

@ -17,6 +17,7 @@ import { CoreContentLinksHandlerBase } from '@features/contentlinks/classes/base
import { CoreContentLinksAction } from '@features/contentlinks/services/contentlinks-delegate'; import { CoreContentLinksAction } from '@features/contentlinks/services/contentlinks-delegate';
import { CoreCourse } from '@features/course/services/course'; import { CoreCourse } from '@features/course/services/course';
import { CoreNavigator } from '@services/navigator'; import { CoreNavigator } from '@services/navigator';
import { CoreSitesReadingStrategy } from '@services/sites';
import { CoreDomUtils } from '@services/utils/dom'; import { CoreDomUtils } from '@services/utils/dom';
import { makeSingleton } from '@singletons'; import { makeSingleton } from '@singletons';
import { AddonModWiki } from '../wiki'; import { AddonModWiki } from '../wiki';
@ -39,7 +40,6 @@ export class AddonModWikiEditLinkHandlerService extends CoreContentLinksHandlerB
siteIds: string[], siteIds: string[],
url: string, url: string,
params: Record<string, string>, params: Record<string, string>,
courseId?: number,
): CoreContentLinksAction[] | Promise<CoreContentLinksAction[]> { ): CoreContentLinksAction[] | Promise<CoreContentLinksAction[]> {
return [{ return [{
@ -51,17 +51,19 @@ export class AddonModWikiEditLinkHandlerService extends CoreContentLinksHandlerB
const pageContents = await AddonModWiki.getPageContents(pageId, { siteId }); const pageContents = await AddonModWiki.getPageContents(pageId, { siteId });
const module = await CoreCourse.getModuleBasicInfoByInstance(pageContents.wikiid, 'wiki', siteId); const module = await CoreCourse.getModuleBasicInfoByInstance(
pageContents.wikiid,
'wiki',
{ siteId, readingStrategy: CoreSitesReadingStrategy.PREFER_CACHE },
);
let section = ''; let section = '';
if (params.section !== undefined) { if (params.section !== undefined) {
section = params.section.replace(/\+/g, ' '); section = params.section.replace(/\+/g, ' ');
} }
courseId = module.course || courseId || Number(params.courseid || params.cid);
CoreNavigator.navigateToSitePath( CoreNavigator.navigateToSitePath(
AddonModWikiModuleHandlerService.PAGE_NAME + `/${courseId}/${module.id}/edit`, AddonModWikiModuleHandlerService.PAGE_NAME + `/${module.course}/${module.id}/edit`,
{ {
params: { params: {
section: section, section: section,

View File

@ -17,6 +17,7 @@ import { CoreContentLinksHandlerBase } from '@features/contentlinks/classes/base
import { CoreContentLinksAction } from '@features/contentlinks/services/contentlinks-delegate'; import { CoreContentLinksAction } from '@features/contentlinks/services/contentlinks-delegate';
import { CoreCourse } from '@features/course/services/course'; import { CoreCourse } from '@features/course/services/course';
import { CoreNavigator } from '@services/navigator'; import { CoreNavigator } from '@services/navigator';
import { CoreSitesReadingStrategy } from '@services/sites';
import { CoreDomUtils } from '@services/utils/dom'; import { CoreDomUtils } from '@services/utils/dom';
import { makeSingleton } from '@singletons'; import { makeSingleton } from '@singletons';
import { Md5 } from 'ts-md5'; import { Md5 } from 'ts-md5';
@ -40,11 +41,8 @@ export class AddonModWikiPageOrMapLinkHandlerService extends CoreContentLinksHan
siteIds: string[], siteIds: string[],
url: string, url: string,
params: Record<string, string>, params: Record<string, string>,
courseId?: number,
): CoreContentLinksAction[] | Promise<CoreContentLinksAction[]> { ): CoreContentLinksAction[] | Promise<CoreContentLinksAction[]> {
courseId = Number(courseId || params.courseid || params.cid);
return [{ return [{
action: async (siteId: string) => { action: async (siteId: string) => {
const modal = await CoreDomUtils.showModalLoading(); const modal = await CoreDomUtils.showModalLoading();
@ -55,7 +53,11 @@ export class AddonModWikiPageOrMapLinkHandlerService extends CoreContentLinksHan
// Get the page data to obtain wikiId, subwikiId, etc. // Get the page data to obtain wikiId, subwikiId, etc.
const page = await AddonModWiki.getPageContents(pageId, { siteId }); const page = await AddonModWiki.getPageContents(pageId, { siteId });
const module = await CoreCourse.getModuleBasicInfoByInstance(page.wikiid, 'wiki', siteId); const module = await CoreCourse.getModuleBasicInfoByInstance(
page.wikiid,
'wiki',
{ siteId, readingStrategy: CoreSitesReadingStrategy.PREFER_CACHE },
);
const hash = <string> Md5.hashAsciiStr(JSON.stringify({ const hash = <string> Md5.hashAsciiStr(JSON.stringify({
pageId: page.id, pageId: page.id,
@ -64,10 +66,9 @@ export class AddonModWikiPageOrMapLinkHandlerService extends CoreContentLinksHan
action: action, action: action,
timestamp: Date.now(), timestamp: Date.now(),
})); }));
courseId = courseId || module.course;
CoreNavigator.navigateToSitePath( CoreNavigator.navigateToSitePath(
AddonModWikiModuleHandlerService.PAGE_NAME + `/${courseId}/${module.id}/page/${hash}`, AddonModWikiModuleHandlerService.PAGE_NAME + `/${module.course}/${module.id}/page/${hash}`,
{ {
params: { params: {
module, module,

View File

@ -189,7 +189,7 @@ export class AddonModWikiPrefetchHandlerService extends CoreCourseActivityPrefet
// Fetch info to provide wiki links. // Fetch info to provide wiki links.
promises.push(AddonModWiki.getWiki(courseId, module.id, { siteId }).then((wiki) => promises.push(AddonModWiki.getWiki(courseId, module.id, { siteId }).then((wiki) =>
CoreCourse.getModuleBasicInfoByInstance(wiki.id, 'wiki', siteId))); CoreCourse.getModuleBasicInfoByInstance(wiki.id, 'wiki', { siteId })));
// Get related page files and fetch them. // Get related page files and fetch them.
promises.push(this.getFiles(module, courseId, single, siteId).then((files) => promises.push(this.getFiles(module, courseId, single, siteId).then((files) =>

View File

@ -363,7 +363,7 @@ export class AddonModWorkshopPrefetchHandlerService extends CoreCourseActivityPr
})); }));
// Add Basic Info to manage links. // Add Basic Info to manage links.
promises.push(CoreCourse.getModuleBasicInfoByInstance(workshop.id, 'workshop', siteId)); promises.push(CoreCourse.getModuleBasicInfoByInstance(workshop.id, 'workshop', { siteId }));
promises.push(CoreCourse.getModuleBasicGradeInfo(module.id, siteId)); promises.push(CoreCourse.getModuleBasicGradeInfo(module.id, siteId));
// Get course data, needed to determine upload max size if it's configured to be course limit. // Get course data, needed to determine upload max size if it's configured to be course limit.

View File

@ -119,7 +119,7 @@ export class CoreCourseActivityPrefetchHandlerBase extends CoreCourseModulePrefe
// Package marked as downloading, get module info to be able to handle links. Get module filters too. // Package marked as downloading, get module info to be able to handle links. Get module filters too.
await Promise.all([ await Promise.all([
CoreCourse.getModuleBasicInfo(module.id, siteId), CoreCourse.getModuleBasicInfo(module.id, { siteId }),
CoreCourse.getModule(module.id, courseId, undefined, false, true, siteId), CoreCourse.getModule(module.id, courseId, undefined, false, true, siteId),
CoreFilterHelper.getFilters('module', module.id, { courseId }), CoreFilterHelper.getFilters('module', module.id, { courseId }),
]); ]);

View File

@ -47,7 +47,7 @@ export class CoreCourseModuleMainActivityPage<ActivityType extends CoreCourseMod
return; return;
} }
this.title = this.module?.name; this.title = this.module.name;
} }
/** /**

View File

@ -394,11 +394,11 @@ export class CoreCourseModuleMainResourceComponent implements OnInit, OnDestroy,
const ignoreCache = refresh && CoreApp.isOnline(); const ignoreCache = refresh && CoreApp.isOnline();
try { try {
await CoreCourse.loadModuleContents(this.module, this.courseId, undefined, false, ignoreCache); await CoreCourse.loadModuleContents(this.module, undefined, undefined, false, ignoreCache);
} catch (error) { } catch (error) {
// Error loading contents. If we ignored cache, try to get the cached value. // Error loading contents. If we ignored cache, try to get the cached value.
if (ignoreCache && !this.module.contents) { if (ignoreCache && !this.module.contents) {
await CoreCourse.loadModuleContents(this.module, this.courseId); await CoreCourse.loadModuleContents(this.module);
} else if (!this.module.contents) { } else if (!this.module.contents) {
// Not able to load contents, throw the error. // Not able to load contents, throw the error.
throw error; throw error;

View File

@ -92,7 +92,7 @@ export class CoreCourseResourcePrefetchHandlerBase extends CoreCourseModulePrefe
dirPath?: string, dirPath?: string,
): Promise<void> { ): Promise<void> {
// Get module info to be able to handle links. // Get module info to be able to handle links.
await CoreCourse.getModuleBasicInfo(module.id, siteId); await CoreCourse.getModuleBasicInfo(module.id, { siteId });
// Load module contents (ignore cache so we always have the latest data). // Load module contents (ignore cache so we always have the latest data).
await this.loadContents(module, courseId, true); await this.loadContents(module, courseId, true);

View File

@ -106,7 +106,7 @@ export class CoreCourseModuleComponent implements OnInit, OnDestroy {
if (this.module.handlerData.showDownloadButton) { if (this.module.handlerData.showDownloadButton) {
// Listen for changes on this module status, even if download isn't enabled. // Listen for changes on this module status, even if download isn't enabled.
this.prefetchHandler = CoreCourseModulePrefetchDelegate.getPrefetchHandlerFor(this.module); this.prefetchHandler = CoreCourseModulePrefetchDelegate.getPrefetchHandlerFor(this.module.name);
this.statusObserver = CoreEvents.on(CoreEvents.PACKAGE_STATUS_CHANGED, (data) => { this.statusObserver = CoreEvents.on(CoreEvents.PACKAGE_STATUS_CHANGED, (data) => {
if (!this.module || data.componentId != this.module.id || !this.prefetchHandler || if (!this.module || data.componentId != this.module.id || !this.prefetchHandler ||
@ -180,14 +180,14 @@ export class CoreCourseModuleComponent implements OnInit, OnDestroy {
try { try {
// Get download size to ask for confirm if it's high. // Get download size to ask for confirm if it's high.
const size = await this.prefetchHandler.getDownloadSize(this.module, this.courseId!, true); const size = await this.prefetchHandler.getDownloadSize(this.module, this.module.course, true);
await CoreCourseHelper.prefetchModule(this.prefetchHandler, this.module, size, this.courseId!, refresh); await CoreCourseHelper.prefetchModule(this.prefetchHandler, this.module, size, this.module.course, refresh);
const eventData = { const eventData = {
sectionId: this.section?.id, sectionId: this.section?.id,
moduleId: this.module.id, moduleId: this.module.id,
courseId: this.courseId!, courseId: this.module.course,
}; };
this.statusChanged.emit(eventData); this.statusChanged.emit(eventData);
} catch (error) { } catch (error) {

View File

@ -16,7 +16,7 @@ import { Injectable } from '@angular/core';
import { Params } from '@angular/router'; import { Params } from '@angular/router';
import moment from 'moment'; import moment from 'moment';
import { CoreSites } from '@services/sites'; import { CoreSites, CoreSitesReadingStrategy } from '@services/sites';
import { import {
CoreCourse, CoreCourse,
CoreCourseCompletionActivityStatus, CoreCourseCompletionActivityStatus,
@ -725,7 +725,7 @@ export class CoreCourseHelperProvider {
if (!files || !files.length) { if (!files || !files.length) {
// Try to use module contents. // Try to use module contents.
files = await CoreCourse.getModuleContents(module, courseId); files = await CoreCourse.getModuleContents(module);
} }
if (!files.length) { if (!files.length) {
@ -1013,7 +1013,7 @@ export class CoreCourseHelperProvider {
): Promise<void> { ): Promise<void> {
siteId = siteId || CoreSites.getCurrentSiteId(); siteId = siteId || CoreSites.getCurrentSiteId();
const prefetchHandler = CoreCourseModulePrefetchDelegate.getPrefetchHandlerFor(module); const prefetchHandler = CoreCourseModulePrefetchDelegate.getPrefetchHandlerFor(module.name);
if (prefetchHandler) { if (prefetchHandler) {
// Use the prefetch handler to download the module. // Use the prefetch handler to download the module.
@ -1429,6 +1429,31 @@ export class CoreCourseHelperProvider {
return CoreConstants.ICON_DOWNLOADING; return CoreConstants.ICON_DOWNLOADING;
} }
/**
* Get the course ID from a module instance ID, showing an error message if it can't be retrieved.
*
* @deprecated since 4.0.
* @param instanceId Instance ID.
* @param moduleName Name of the module. E.g. 'glossary'.
* @param siteId Site ID. If not defined, current site.
* @return Promise resolved with the module's course ID.
*/
async getModuleCourseIdByInstance(instanceId: number, moduleName: string, siteId?: string): Promise<number> {
try {
const cm = await CoreCourse.getModuleBasicInfoByInstance(
instanceId,
moduleName,
{ siteId, readingStrategy: CoreSitesReadingStrategy.PREFER_CACHE },
);
return cm.course;
} catch (error) {
CoreDomUtils.showErrorModalDefault(error, 'core.course.errorgetmodule', true);
throw error;
}
}
/** /**
* Get prefetch info for a module. * Get prefetch info for a module.
* *
@ -1551,7 +1576,7 @@ export class CoreCourseHelperProvider {
const modal = await CoreDomUtils.showModalLoading(); const modal = await CoreDomUtils.showModalLoading();
try { try {
const module = await CoreCourse.getModuleBasicInfoByInstance(instanceId, modName, siteId); const module = await CoreCourse.getModuleBasicInfoByInstance(instanceId, modName, { siteId });
this.navigateToModule( this.navigateToModule(
module.id, module.id,
@ -1594,15 +1619,14 @@ export class CoreCourseHelperProvider {
const modal = await CoreDomUtils.showModalLoading(); const modal = await CoreDomUtils.showModalLoading();
try { try {
if (!courseId) { if (!courseId || !sectionId) {
// We don't have courseId. const module = await CoreCourse.getModuleBasicInfo(
const module = await CoreCourse.getModuleBasicInfo(moduleId, siteId); moduleId,
{ siteId, readingStrategy: CoreSitesReadingStrategy.PREFER_CACHE },
);
courseId = module.course; courseId = module.course;
sectionId = module.section; sectionId = module.section;
} else if (!sectionId) {
// We don't have sectionId but we have courseId.
sectionId = await CoreCourse.getModuleSectionId(moduleId, siteId);
} }
// Get the site. // Get the site.
@ -2024,7 +2048,7 @@ export class CoreCourseHelperProvider {
promises.push(CoreCourseModulePrefetchDelegate.removeModuleFiles(module, courseId)); promises.push(CoreCourseModulePrefetchDelegate.removeModuleFiles(module, courseId));
const handler = CoreCourseModulePrefetchDelegate.getPrefetchHandlerFor(module); const handler = CoreCourseModulePrefetchDelegate.getPrefetchHandlerFor(module.name);
const site = CoreSites.getCurrentSite(); const site = CoreSites.getCurrentSite();
if (handler && site) { if (handler && site) {
promises.push(site.deleteComponentFromCache(handler.component, module.id)); promises.push(site.deleteComponentFromCache(handler.component, module.id));

View File

@ -18,7 +18,7 @@ import { Params } from '@angular/router';
import { CoreApp } from '@services/app'; import { CoreApp } from '@services/app';
import { CoreEvents } from '@singletons/events'; import { CoreEvents } from '@singletons/events';
import { CoreLogger } from '@singletons/logger'; import { CoreLogger } from '@singletons/logger';
import { CoreSitesCommonWSOptions, CoreSites } from '@services/sites'; import { CoreSitesCommonWSOptions, CoreSites, CoreSitesReadingStrategy } from '@services/sites';
import { CoreTimeUtils } from '@services/utils/time'; import { CoreTimeUtils } from '@services/utils/time';
import { CoreUtils } from '@services/utils/utils'; import { CoreUtils } from '@services/utils/utils';
import { CoreSiteWSPreSets, CoreSite } from '@classes/site'; import { CoreSiteWSPreSets, CoreSite } from '@classes/site';
@ -502,8 +502,12 @@ export class CoreCourseProvider {
if (!courseId) { if (!courseId) {
// No courseId passed, try to retrieve it. // No courseId passed, try to retrieve it.
const module = await this.getModuleBasicInfo(moduleId, siteId); const module = await this.getModuleBasicInfo(
moduleId,
{ siteId, readingStrategy: CoreSitesReadingStrategy.PREFER_CACHE },
);
courseId = module.course; courseId = module.course;
sectionId = module.section;
} }
let sections: CoreCourseGetContentsWSSection[]; let sections: CoreCourseGetContentsWSSection[];
@ -530,9 +534,8 @@ export class CoreCourseProvider {
let foundModule: CoreCourseGetContentsWSModule | undefined; let foundModule: CoreCourseGetContentsWSModule | undefined;
const foundSection = sections.some((section) => { const foundSection = sections.some((section) => {
if (sectionId != null && if (section.id != CoreCourseProvider.STEALTH_MODULES_SECTION_ID &&
!isNaN(sectionId) && sectionId !== undefined &&
section.id != CoreCourseProvider.STEALTH_MODULES_SECTION_ID &&
sectionId != section.id sectionId != section.id
) { ) {
return false; return false;
@ -585,17 +588,18 @@ export class CoreCourseProvider {
* Gets a module basic info by module ID. * Gets a module basic info by module ID.
* *
* @param moduleId Module ID. * @param moduleId Module ID.
* @param siteId Site ID. If not defined, current site. * @param options Comon site WS options.
* @return Promise resolved with the module's info. * @return Promise resolved with the module's info.
*/ */
async getModuleBasicInfo(moduleId: number, siteId?: string): Promise<CoreCourseModuleBasicInfo> { async getModuleBasicInfo(moduleId: number, options: CoreSitesCommonWSOptions = {}): Promise<CoreCourseModuleBasicInfo> {
const site = await CoreSites.getSite(siteId); const site = await CoreSites.getSite(options.siteId);
const params: CoreCourseGetCourseModuleWSParams = { const params: CoreCourseGetCourseModuleWSParams = {
cmid: moduleId, cmid: moduleId,
}; };
const preSets: CoreSiteWSPreSets = { const preSets: CoreSiteWSPreSets = {
cacheKey: this.getModuleCacheKey(moduleId), cacheKey: this.getModuleCacheKey(moduleId),
updateFrequency: CoreSite.FREQUENCY_RARELY, updateFrequency: CoreSite.FREQUENCY_RARELY,
...CoreSites.getReadingStrategyPreSets(options.readingStrategy), // Include reading strategy preSets.
}; };
const response = await site.read<CoreCourseGetCourseModuleWSResponse>('core_course_get_course_module', params, preSets); const response = await site.read<CoreCourseGetCourseModuleWSResponse>('core_course_get_course_module', params, preSets);
@ -614,7 +618,7 @@ export class CoreCourseProvider {
* @return Promise resolved with the module's grade info. * @return Promise resolved with the module's grade info.
*/ */
async getModuleBasicGradeInfo(moduleId: number, siteId?: string): Promise<CoreCourseModuleGradeInfo | undefined> { async getModuleBasicGradeInfo(moduleId: number, siteId?: string): Promise<CoreCourseModuleGradeInfo | undefined> {
const info = await this.getModuleBasicInfo(moduleId, siteId); const info = await this.getModuleBasicInfo(moduleId, { siteId });
if ( if (
info.grade !== undefined || info.grade !== undefined ||
@ -636,21 +640,29 @@ export class CoreCourseProvider {
/** /**
* Gets a module basic info by instance. * Gets a module basic info by instance.
* *
* @param id Instance ID. * @param instanceId Instance ID.
* @param module Name of the module. E.g. 'glossary'. * @param moduleName Name of the module. E.g. 'glossary'.
* @param siteId Site ID. If not defined, current site. * @param options Comon site WS options.
* @return Promise resolved with the module's info. * @return Promise resolved with the module's info.
*/ */
async getModuleBasicInfoByInstance(id: number, module: string, siteId?: string): Promise<CoreCourseModuleBasicInfo> { async getModuleBasicInfoByInstance(
const site = await CoreSites.getSite(siteId); instanceId: number,
moduleName: string,
options: CoreSitesCommonWSOptions = {},
): Promise<CoreCourseModuleBasicInfo> {
const site = await CoreSites.getSite(options.siteId);
const params: CoreCourseGetCourseModuleByInstanceWSParams = { const params: CoreCourseGetCourseModuleByInstanceWSParams = {
instance: id, instance: instanceId,
module: module, module: moduleName,
}; };
const preSets = {
cacheKey: this.getModuleBasicInfoByInstanceCacheKey(id, module), const preSets: CoreSiteWSPreSets = {
cacheKey: this.getModuleBasicInfoByInstanceCacheKey(instanceId, moduleName),
updateFrequency: CoreSite.FREQUENCY_RARELY, updateFrequency: CoreSite.FREQUENCY_RARELY,
...CoreSites.getReadingStrategyPreSets(options.readingStrategy), // Include reading strategy preSets.
}; };
const response: CoreCourseGetCourseModuleWSResponse = const response: CoreCourseGetCourseModuleWSResponse =
await site.read('core_course_get_course_module_by_instance', params, preSets); await site.read('core_course_get_course_module_by_instance', params, preSets);
@ -666,12 +678,12 @@ export class CoreCourseProvider {
/** /**
* Get cache key for get module by instance WS calls. * Get cache key for get module by instance WS calls.
* *
* @param id Instance ID. * @param instanceId Instance ID.
* @param module Name of the module. E.g. 'glossary'. * @param moduleName Name of the module. E.g. 'glossary'.
* @return Cache key. * @return Cache key.
*/ */
protected getModuleBasicInfoByInstanceCacheKey(id: number, module: string): string { protected getModuleBasicInfoByInstanceCacheKey(instanceId: number, moduleName: string): string {
return ROOT_CACHE_KEY + 'moduleByInstance:' + module + ':' + id; return ROOT_CACHE_KEY + 'moduleByInstance:' + moduleName + ':' + instanceId;
} }
/** /**
@ -721,13 +733,17 @@ export class CoreCourseProvider {
/** /**
* Get the section ID a module belongs to. * Get the section ID a module belongs to.
* *
* @deprecated since 4.0.
* @param moduleId The module ID. * @param moduleId The module ID.
* @param siteId Site ID. If not defined, current site. * @param siteId Site ID. If not defined, current site.
* @return Promise resolved with the section ID. * @return Promise resolved with the section ID.
*/ */
async getModuleSectionId(moduleId: number, siteId?: string): Promise<number> { async getModuleSectionId(moduleId: number, siteId?: string): Promise<number> {
// Try to get the section using getModuleBasicInfo. // Try to get the section using getModuleBasicInfo.
const module = await this.getModuleBasicInfo(moduleId, siteId); const module = await CoreCourse.getModuleBasicInfo(
moduleId,
{ siteId, readingStrategy: CoreSitesReadingStrategy.PREFER_CACHE },
);
return module.section; return module.section;
} }
@ -974,7 +990,7 @@ export class CoreCourseProvider {
* It will throw an error if contents cannot be loaded. * It will throw an error if contents cannot be loaded.
* *
* @param module Module to get its contents. * @param module Module to get its contents.
* @param courseId The course ID. Recommended to speed up the process and minimize data usage. * @param courseId Not used since 4.0.
* @param sectionId The section ID. * @param sectionId The section ID.
* @param preferCache True if shouldn't call WS if data is cached, false otherwise. * @param preferCache True if shouldn't call WS if data is cached, false otherwise.
* @param ignoreCache True if it should ignore cached data (it will always fail in offline or server down). * @param ignoreCache True if it should ignore cached data (it will always fail in offline or server down).
@ -984,7 +1000,7 @@ export class CoreCourseProvider {
* @return Promise resolved when loaded. * @return Promise resolved when loaded.
*/ */
async getModuleContents( async getModuleContents(
module: CoreCourseAnyModuleData, module: CoreCourseModuleData,
courseId?: number, courseId?: number,
sectionId?: number, sectionId?: number,
preferCache?: boolean, preferCache?: boolean,
@ -993,7 +1009,7 @@ export class CoreCourseProvider {
modName?: string, modName?: string,
): Promise<CoreCourseModuleContentFile[]> { ): Promise<CoreCourseModuleContentFile[]> {
// Make sure contents are loaded. // Make sure contents are loaded.
await this.loadModuleContents(module, courseId, sectionId, preferCache, ignoreCache, siteId, modName); await this.loadModuleContents(module, undefined, sectionId, preferCache, ignoreCache, siteId, modName);
if (!module.contents) { if (!module.contents) {
throw new CoreError(Translate.instant('core.course.modulenotfound')); throw new CoreError(Translate.instant('core.course.modulenotfound'));

View File

@ -95,7 +95,7 @@ export class CoreCourseModulePrefetchDelegateService extends CoreDelegate<CoreCo
* @return Promise resolved with boolean: whether the module can use check updates WS. * @return Promise resolved with boolean: whether the module can use check updates WS.
*/ */
async canModuleUseCheckUpdates(module: CoreCourseAnyModuleData, courseId: number): Promise<boolean> { async canModuleUseCheckUpdates(module: CoreCourseAnyModuleData, courseId: number): Promise<boolean> {
const handler = this.getPrefetchHandlerFor(module); const handler = this.getPrefetchHandlerFor(module.name);
if (!handler) { if (!handler) {
// Module not supported, cannot use check updates. // Module not supported, cannot use check updates.
@ -171,7 +171,7 @@ export class CoreCourseModulePrefetchDelegateService extends CoreDelegate<CoreCo
* @return Module status. * @return Module status.
*/ */
determineModuleStatus(module: CoreCourseAnyModuleData, status: string): string { determineModuleStatus(module: CoreCourseAnyModuleData, status: string): string {
const handler = this.getPrefetchHandlerFor(module); const handler = this.getPrefetchHandlerFor(module.name);
const siteId = CoreSites.getCurrentSiteId(); const siteId = CoreSites.getCurrentSiteId();
if (!handler) { if (!handler) {
@ -203,7 +203,7 @@ export class CoreCourseModulePrefetchDelegateService extends CoreDelegate<CoreCo
*/ */
async downloadModule(module: CoreCourseAnyModuleData, courseId: number, dirPath?: string): Promise<void> { async downloadModule(module: CoreCourseAnyModuleData, courseId: number, dirPath?: string): Promise<void> {
// Check if the module has a prefetch handler. // Check if the module has a prefetch handler.
const handler = this.getPrefetchHandlerFor(module); const handler = this.getPrefetchHandlerFor(module.name);
if (!handler) { if (!handler) {
return; return;
@ -227,7 +227,7 @@ export class CoreCourseModulePrefetchDelegateService extends CoreDelegate<CoreCo
const id = <string> Md5.hashAsciiStr(courseId + '#' + JSON.stringify(modules)); const id = <string> Md5.hashAsciiStr(courseId + '#' + JSON.stringify(modules));
const siteId = CoreSites.getCurrentSiteId(); const siteId = CoreSites.getCurrentSiteId();
if (this.courseUpdatesPromises[siteId] && this.courseUpdatesPromises[siteId][id]) { if (this.courseUpdatesPromises[siteId] && this.courseUpdatesPromises[siteId][id] !== undefined) {
// There's already a get updates ongoing, return the promise. // There's already a get updates ongoing, return the promise.
return this.courseUpdatesPromises[siteId][id]; return this.courseUpdatesPromises[siteId][id];
} else if (!this.courseUpdatesPromises[siteId]) { } else if (!this.courseUpdatesPromises[siteId]) {
@ -381,7 +381,7 @@ export class CoreCourseModulePrefetchDelegateService extends CoreDelegate<CoreCo
* @return Promise resolved with the size. * @return Promise resolved with the size.
*/ */
async getModuleDownloadSize(module: CoreCourseAnyModuleData, courseId: number, single?: boolean): Promise<CoreFileSizeSum> { async getModuleDownloadSize(module: CoreCourseAnyModuleData, courseId: number, single?: boolean): Promise<CoreFileSizeSum> {
const handler = this.getPrefetchHandlerFor(module); const handler = this.getPrefetchHandlerFor(module.name);
if (!handler) { if (!handler) {
return { size: 0, total: false }; return { size: 0, total: false };
@ -419,7 +419,7 @@ export class CoreCourseModulePrefetchDelegateService extends CoreDelegate<CoreCo
* @return Promise resolved with the size. * @return Promise resolved with the size.
*/ */
async getModuleDownloadedSize(module: CoreCourseAnyModuleData, courseId: number): Promise<number> { async getModuleDownloadedSize(module: CoreCourseAnyModuleData, courseId: number): Promise<number> {
const handler = this.getPrefetchHandlerFor(module); const handler = this.getPrefetchHandlerFor(module.name);
if (!handler) { if (!handler) {
return 0; return 0;
} }
@ -492,7 +492,7 @@ export class CoreCourseModulePrefetchDelegateService extends CoreDelegate<CoreCo
} }
const site = CoreSites.getCurrentSite(); const site = CoreSites.getCurrentSite();
const handler = this.getPrefetchHandlerFor(module); const handler = this.getPrefetchHandlerFor(module.name);
if (!handler || !site) { if (!handler || !site) {
// If there is no handler then we can't find out the component name. // If there is no handler then we can't find out the component name.
// We can't work out the cached size, so just return downloaded size. // We can't work out the cached size, so just return downloaded size.
@ -515,7 +515,7 @@ export class CoreCourseModulePrefetchDelegateService extends CoreDelegate<CoreCo
module: CoreCourseAnyModuleData, module: CoreCourseAnyModuleData,
courseId: number, courseId: number,
): Promise<(CoreWSFile | CoreCourseModuleContentFile)[]> { ): Promise<(CoreWSFile | CoreCourseModuleContentFile)[]> {
const handler = this.getPrefetchHandlerFor(module); const handler = this.getPrefetchHandlerFor(module.name);
if (handler?.getFiles) { if (handler?.getFiles) {
// The handler defines a function to get files, use it. // The handler defines a function to get files, use it.
@ -548,7 +548,7 @@ export class CoreCourseModulePrefetchDelegateService extends CoreDelegate<CoreCo
refresh?: boolean, refresh?: boolean,
sectionId?: number, sectionId?: number,
): Promise<string> { ): Promise<string> {
const handler = this.getPrefetchHandlerFor(module); const handler = this.getPrefetchHandlerFor(module.name);
if (!handler) { if (!handler) {
// No handler found, module not downloadable. // No handler found, module not downloadable.
@ -712,7 +712,7 @@ export class CoreCourseModulePrefetchDelegateService extends CoreDelegate<CoreCo
} }
await Promise.all(modules.map(async (module) => { await Promise.all(modules.map(async (module) => {
const handler = this.getPrefetchHandlerFor(module); const handler = this.getPrefetchHandlerFor(module.name);
if (!handler || (onlyToDisplay && handler.skipListStatus)) { if (!handler || (onlyToDisplay && handler.skipListStatus)) {
return; return;
} }
@ -758,7 +758,7 @@ export class CoreCourseModulePrefetchDelegateService extends CoreDelegate<CoreCo
module: CoreCourseAnyModuleData, module: CoreCourseAnyModuleData,
courseId: number, courseId: number,
): Promise<{ status: string; downloadTime?: number }> { ): Promise<{ status: string; downloadTime?: number }> {
const handler = this.getPrefetchHandlerFor(module); const handler = this.getPrefetchHandlerFor(module.name);
const siteId = CoreSites.getCurrentSiteId(); const siteId = CoreSites.getCurrentSiteId();
if (!handler) { if (!handler) {
@ -863,11 +863,11 @@ export class CoreCourseModulePrefetchDelegateService extends CoreDelegate<CoreCo
/** /**
* Get a prefetch handler. * Get a prefetch handler.
* *
* @param module The module to work on. * @param moduleName The module name to work on.
* @return Prefetch handler. * @return Prefetch handler.
*/ */
getPrefetchHandlerFor(module: CoreCourseAnyModuleData): CoreCourseModulePrefetchHandler | undefined { getPrefetchHandlerFor(moduleName: string): CoreCourseModulePrefetchHandler | undefined {
return this.getHandler(module.modname, true); return this.getHandler(moduleName, true);
} }
/** /**
@ -895,7 +895,7 @@ export class CoreCourseModulePrefetchDelegateService extends CoreDelegate<CoreCo
async invalidateModules(modules: CoreCourseModuleData[], courseId: number): Promise<void> { async invalidateModules(modules: CoreCourseModuleData[], courseId: number): Promise<void> {
const promises = modules.map(async (module) => { const promises = modules.map(async (module) => {
const handler = this.getPrefetchHandlerFor(module); const handler = this.getPrefetchHandlerFor(module.name);
if (!handler) { if (!handler) {
return; return;
} }
@ -919,7 +919,7 @@ export class CoreCourseModulePrefetchDelegateService extends CoreDelegate<CoreCo
* @param module Module to be invalidated. * @param module Module to be invalidated.
*/ */
invalidateModuleStatusCache(module: CoreCourseAnyModuleData): void { invalidateModuleStatusCache(module: CoreCourseAnyModuleData): void {
const handler = this.getPrefetchHandlerFor(module); const handler = this.getPrefetchHandlerFor(module.name);
if (handler) { if (handler) {
this.statusCache.invalidate(CoreFilepool.getPackageId(handler.component, module.id)); this.statusCache.invalidate(CoreFilepool.getPackageId(handler.component, module.id));
} }
@ -964,7 +964,7 @@ export class CoreCourseModulePrefetchDelegateService extends CoreDelegate<CoreCo
return false; return false;
} }
const handler = this.getPrefetchHandlerFor(module); const handler = this.getPrefetchHandlerFor(module.name);
if (!handler) { if (!handler) {
return false; return false;
} }
@ -1000,7 +1000,7 @@ export class CoreCourseModulePrefetchDelegateService extends CoreDelegate<CoreCo
* @return Promise resolved with boolean: whether the module has updates. * @return Promise resolved with boolean: whether the module has updates.
*/ */
async moduleHasUpdates(module: CoreCourseAnyModuleData, courseId: number, updates: CourseUpdates): Promise<boolean> { async moduleHasUpdates(module: CoreCourseAnyModuleData, courseId: number, updates: CourseUpdates): Promise<boolean> {
const handler = this.getPrefetchHandlerFor(module); const handler = this.getPrefetchHandlerFor(module.name);
const moduleUpdates = updates[module.id]; const moduleUpdates = updates[module.id];
if (handler?.hasUpdates) { if (handler?.hasUpdates) {
@ -1033,7 +1033,7 @@ export class CoreCourseModulePrefetchDelegateService extends CoreDelegate<CoreCo
* @return Promise resolved when finished. * @return Promise resolved when finished.
*/ */
async prefetchModule(module: CoreCourseAnyModuleData, courseId: number, single?: boolean): Promise<void> { async prefetchModule(module: CoreCourseAnyModuleData, courseId: number, single?: boolean): Promise<void> {
const handler = this.getPrefetchHandlerFor(module); const handler = this.getPrefetchHandlerFor(module.name);
if (!handler) { if (!handler) {
return; return;
} }
@ -1067,7 +1067,7 @@ export class CoreCourseModulePrefetchDelegateService extends CoreDelegate<CoreCo
* @return Promise resolved when finished. * @return Promise resolved when finished.
*/ */
async syncModule<T = unknown>(module: CoreCourseAnyModuleData, courseId: number): Promise<T | undefined> { async syncModule<T = unknown>(module: CoreCourseAnyModuleData, courseId: number): Promise<T | undefined> {
const handler = this.getPrefetchHandlerFor(module); const handler = this.getPrefetchHandlerFor(module.name);
if (!handler?.sync) { if (!handler?.sync) {
return; return;
} }
@ -1124,7 +1124,7 @@ export class CoreCourseModulePrefetchDelegateService extends CoreDelegate<CoreCo
const promises = modules.map(async (module) => { const promises = modules.map(async (module) => {
// Check if the module has a prefetch handler. // Check if the module has a prefetch handler.
const handler = this.getPrefetchHandlerFor(module); const handler = this.getPrefetchHandlerFor(module.name);
if (!handler) { if (!handler) {
return; return;
} }
@ -1170,7 +1170,7 @@ export class CoreCourseModulePrefetchDelegateService extends CoreDelegate<CoreCo
* @return Promise resolved when done. * @return Promise resolved when done.
*/ */
async removeModuleFiles(module: CoreCourseAnyModuleData, courseId: number): Promise<void> { async removeModuleFiles(module: CoreCourseAnyModuleData, courseId: number): Promise<void> {
const handler = this.getPrefetchHandlerFor(module); const handler = this.getPrefetchHandlerFor(module.name);
const siteId = CoreSites.getCurrentSiteId(); const siteId = CoreSites.getCurrentSiteId();
if (handler?.removeFiles) { if (handler?.removeFiles) {

View File

@ -15,7 +15,7 @@
import { Type } from '@angular/core'; import { Type } from '@angular/core';
import { CoreConstants } from '@/core/constants'; import { CoreConstants } from '@/core/constants';
import { CoreCourse, CoreCourseAnyModuleData } from '@features/course/services/course'; import { CoreCourse } from '@features/course/services/course';
import { CoreCourseModuleData } from '@features/course/services/course-helper'; import { CoreCourseModuleData } from '@features/course/services/course-helper';
import { CoreCourseModuleHandler, CoreCourseModuleHandlerData } from '@features/course/services/module-delegate'; import { CoreCourseModuleHandler, CoreCourseModuleHandlerData } from '@features/course/services/module-delegate';
import { CoreSitePluginsModuleIndexComponent } from '@features/siteplugins/components/module-index/module-index'; import { CoreSitePluginsModuleIndexComponent } from '@features/siteplugins/components/module-index/module-index';
@ -64,12 +64,12 @@ export class CoreSitePluginsModuleHandler extends CoreSitePluginsBaseHandler imp
* @inheritdoc * @inheritdoc
*/ */
getData( getData(
module: CoreCourseAnyModuleData, module: CoreCourseModuleData,
courseId: number, courseId: number,
sectionId?: number, sectionId?: number,
forCoursePage?: boolean, forCoursePage?: boolean,
): CoreCourseModuleHandlerData { ): CoreCourseModuleHandlerData {
if ('description' in module && this.shouldOnlyDisplayDescription(module, forCoursePage)) { if (this.shouldOnlyDisplayDescription(module, forCoursePage)) {
const title = module.description; const title = module.description;
module.description = ''; module.description = '';
@ -128,7 +128,7 @@ export class CoreSitePluginsModuleHandler extends CoreSitePluginsBaseHandler imp
* @param forCoursePage Whether the data will be used to render the course page. * @param forCoursePage Whether the data will be used to render the course page.
* @return Bool. * @return Bool.
*/ */
protected shouldOnlyDisplayDescription(module: CoreCourseAnyModuleData, forCoursePage?: boolean): boolean { protected shouldOnlyDisplayDescription(module: CoreCourseModuleData, forCoursePage?: boolean): boolean {
if (forCoursePage && this.handlerSchema.coursepagemethod) { if (forCoursePage && this.handlerSchema.coursepagemethod) {
// The plugin defines a method for course page, don't display just the description. // The plugin defines a method for course page, don't display just the description.
return false; return false;
@ -167,7 +167,7 @@ export class CoreSitePluginsModuleHandler extends CoreSitePluginsBaseHandler imp
* @return Promise resolved when done. * @return Promise resolved when done.
*/ */
protected async loadCoursePageTemplate( protected async loadCoursePageTemplate(
module: CoreCourseAnyModuleData, module: CoreCourseModuleData,
courseId: number, courseId: number,
handlerData: CoreCourseModuleHandlerData, handlerData: CoreCourseModuleHandlerData,
method: string, method: string,

View File

@ -145,7 +145,7 @@ export class CoreSitePluginsModuleIndexComponent implements OnInit, OnDestroy, C
this.refreshIcon = CoreConstants.ICON_REFRESH; this.refreshIcon = CoreConstants.ICON_REFRESH;
// Check if there is a prefetch handler for this type of module. // Check if there is a prefetch handler for this type of module.
if (CoreCourseModulePrefetchDelegate.getPrefetchHandlerFor(this.module)) { if (CoreCourseModulePrefetchDelegate.getPrefetchHandlerFor(this.module.name)) {
CoreCourseHelper.fillContextMenu(this, this.module, this.courseId, refresh, this.component); CoreCourseHelper.fillContextMenu(this, this.module, this.courseId, refresh, this.component);
} }
} }

View File

@ -1,11 +1,13 @@
This files describes API changes in the Moodle Mobile app, This files describes API changes in the Moodle Mobile app,
information provided here is intended especially for developers. information provided here is intended especially for developers.
=== 3.9.6 === === 4.0.0 ===
- The parameters of the functions confirmAndPrefetchCourse and confirmAndPrefetchCourses have changed, they now accept an object with options. - The parameters of the functions confirmAndPrefetchCourse and confirmAndPrefetchCourses have changed, they now accept an object with options.
- Component core-navigation-bar changed to add an slider inside. previous, previousTitle, next, nextTitle, info and title have been removed. - Component core-navigation-bar changed to add an slider inside. previous, previousTitle, next, nextTitle, info and title have been removed.
Now you have to pass all items and 3 optional params have been added. Now you have to pass all items and 3 optional params have been added.
- CoreCourseModulePrefetchDelegate.getPrefetchHandlerFor now admits module name instead of full module object.
- CoreCourse.getModuleBasicInfoByInstance and CoreCourse.getModuleBasicInfo have been modified to accept an "options" parameter instead of only siteId.
=== 3.9.5 === === 3.9.5 ===