1860 lines
66 KiB
TypeScript
1860 lines
66 KiB
TypeScript
// (C) Copyright 2015 Moodle Pty Ltd.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
import { Injectable } from '@angular/core';
|
|
import { CoreSites, CoreSitesCommonWSOptions, CoreSitesReadingStrategy } from '@services/sites';
|
|
import { CoreSite, CoreSiteWSPreSets } from '@classes/site';
|
|
import { makeSingleton } from '@singletons';
|
|
import { CoreStatusWithWarningsWSResponse, CoreWarningsWSResponse, CoreWSExternalFile, CoreWSExternalWarning } from '@services/ws';
|
|
import { CoreEvents } from '@singletons/events';
|
|
import { CoreWSError } from '@classes/errors/wserror';
|
|
import { CoreCourseAnyCourseDataWithExtraInfoAndOptions, CoreCourseWithImageAndColor } from './courses-helper';
|
|
import { asyncObservable, firstValueFrom, ignoreErrors, zipIncludingComplete } from '@/core/utils/rxjs';
|
|
import { of, Observable } from 'rxjs';
|
|
import { map } from 'rxjs/operators';
|
|
|
|
const ROOT_CACHE_KEY = 'mmCourses:';
|
|
|
|
declare module '@singletons/events' {
|
|
|
|
/**
|
|
* Augment CoreEventsData interface with events specific to this service.
|
|
*
|
|
* @see https://www.typescriptlang.org/docs/handbook/declaration-merging.html#module-augmentation
|
|
*/
|
|
export interface CoreEventsData {
|
|
[CoreCoursesProvider.EVENT_MY_COURSES_CHANGED]: CoreCoursesMyCoursesChangedEventData;
|
|
[CoreCoursesProvider.EVENT_MY_COURSES_UPDATED]: CoreCoursesMyCoursesUpdatedEventData;
|
|
[CoreCoursesProvider.EVENT_DASHBOARD_DOWNLOAD_ENABLED_CHANGED]: CoreCoursesDashboardDownloadEnabledChangedEventData;
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* Service that provides some features regarding lists of courses and categories.
|
|
*/
|
|
@Injectable({ providedIn: 'root' })
|
|
export class CoreCoursesProvider {
|
|
|
|
static readonly SEARCH_PER_PAGE = 20;
|
|
static readonly RECENT_PER_PAGE = 10;
|
|
static readonly ENROL_INVALID_KEY = 'CoreCoursesEnrolInvalidKey';
|
|
static readonly EVENT_MY_COURSES_CHANGED = 'courses_my_courses_changed'; // User course list changed while app is running.
|
|
// A course was hidden/favourite, or user enroled in a course.
|
|
static readonly EVENT_MY_COURSES_UPDATED = 'courses_my_courses_updated';
|
|
static readonly EVENT_MY_COURSES_REFRESHED = 'courses_my_courses_refreshed';
|
|
static readonly EVENT_DASHBOARD_DOWNLOAD_ENABLED_CHANGED = 'dashboard_download_enabled_changed';
|
|
|
|
// Actions for event EVENT_MY_COURSES_UPDATED.
|
|
static readonly ACTION_ENROL = 'enrol'; // User enrolled in a course.
|
|
static readonly ACTION_STATE_CHANGED = 'state_changed'; // Course state changed (hidden, favourite).
|
|
static readonly ACTION_VIEW = 'view'; // Course viewed.
|
|
|
|
// Possible states changed.
|
|
static readonly STATE_HIDDEN = 'hidden';
|
|
static readonly STATE_FAVOURITE = 'favourite';
|
|
|
|
protected userCoursesIds?: Set<number>;
|
|
protected downloadOptionsEnabled = false;
|
|
|
|
/**
|
|
* Whether current site supports getting course options.
|
|
*
|
|
* @return Whether current site supports getting course options.
|
|
* @deprecated since app 4.0
|
|
*/
|
|
canGetAdminAndNavOptions(): boolean {
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Get categories. They can be filtered by id.
|
|
*
|
|
* @param categoryId Category ID to get.
|
|
* @param addSubcategories If it should add subcategories to the list.
|
|
* @param siteId Site to get the courses from. If not defined, use current site.
|
|
* @return Promise resolved with the categories.
|
|
*/
|
|
async getCategories(
|
|
categoryId: number,
|
|
addSubcategories: boolean = false,
|
|
siteId?: string,
|
|
): Promise<CoreCourseGetCategoriesWSResponse> {
|
|
const site = await CoreSites.getSite(siteId);
|
|
|
|
// Get parent when id is the root category.
|
|
const criteriaKey = categoryId == 0 ? 'parent' : 'id';
|
|
const params: CoreCourseGetCategoriesWSParams = {
|
|
criteria: [
|
|
{
|
|
key: criteriaKey,
|
|
value: categoryId,
|
|
},
|
|
],
|
|
addsubcategories: addSubcategories,
|
|
};
|
|
|
|
const preSets = {
|
|
cacheKey: this.getCategoriesCacheKey(categoryId, addSubcategories),
|
|
updateFrequency: CoreSite.FREQUENCY_RARELY,
|
|
};
|
|
|
|
return site.read('core_course_get_categories', params, preSets);
|
|
}
|
|
|
|
/**
|
|
* Get cache key for get categories methods WS call.
|
|
*
|
|
* @param categoryId Category ID to get.
|
|
* @param addSubcategories If add subcategories to the list.
|
|
* @return Cache key.
|
|
*/
|
|
protected getCategoriesCacheKey(categoryId: number, addSubcategories?: boolean): string {
|
|
return ROOT_CACHE_KEY + 'categories:' + categoryId + ':' + !!addSubcategories;
|
|
}
|
|
|
|
/**
|
|
* Given a list of course IDs to get course admin and nav options, return the list of courseIds to use.
|
|
*
|
|
* @param courseIds Course IDs.
|
|
* @param siteId Site Id. If not defined, use current site.
|
|
* @return Promise resolved with the list of course IDs.
|
|
*/
|
|
protected async getCourseIdsForAdminAndNavOptions(courseIds: number[], siteId?: string): Promise<number[]> {
|
|
const site = await CoreSites.getSite(siteId);
|
|
|
|
const siteHomeId = site.getSiteHomeId();
|
|
if (courseIds.length == 1) {
|
|
// Only 1 course, check if it belongs to the user courses. If so, use all user courses.
|
|
return this.getCourseIdsIfEnrolled(courseIds[0], siteId);
|
|
} else {
|
|
if (courseIds.length > 1 && courseIds.indexOf(siteHomeId) == -1) {
|
|
courseIds.push(siteHomeId);
|
|
}
|
|
|
|
// Sort the course IDs.
|
|
courseIds.sort((a, b) => b - a);
|
|
|
|
return courseIds;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Given a course ID, if user is enrolled in the course it will return the IDs of all enrolled courses and site home.
|
|
* Return only the course ID otherwise.
|
|
*
|
|
* @param courseIds Course IDs.
|
|
* @param siteId Site Id. If not defined, use current site.
|
|
* @return Promise resolved with the list of course IDs.
|
|
*/
|
|
async getCourseIdsIfEnrolled(courseId: number, siteId?: string): Promise<number[]> {
|
|
const site = await CoreSites.getSite(siteId);
|
|
const siteHomeId = site.getSiteHomeId();
|
|
|
|
try {
|
|
// Check if user is enrolled in the course.
|
|
const courses = await this.getUserCourses(true, siteId);
|
|
let useAllCourses = false;
|
|
|
|
if (courseId == siteHomeId) {
|
|
// It's site home, use all courses.
|
|
useAllCourses = true;
|
|
} else {
|
|
useAllCourses = !!courses.find((course) => course.id == courseId);
|
|
}
|
|
|
|
if (useAllCourses) {
|
|
// User is enrolled, return all the courses.
|
|
const courseIds = courses.map((course) => course.id);
|
|
|
|
// Always add the site home ID.
|
|
courseIds.push(siteHomeId);
|
|
|
|
// Sort the course IDs.
|
|
courseIds.sort((a, b) => b - a);
|
|
|
|
return courseIds;
|
|
}
|
|
} catch {
|
|
// Ignore errors.
|
|
}
|
|
|
|
return [courseId];
|
|
}
|
|
|
|
/**
|
|
* Check if download a whole course is disabled in a certain site.
|
|
*
|
|
* @param siteId Site Id. If not defined, use current site.
|
|
* @return Promise resolved with true if disabled, rejected or resolved with false otherwise.
|
|
*/
|
|
async isDownloadCourseDisabled(siteId?: string): Promise<boolean> {
|
|
const site = await CoreSites.getSite(siteId);
|
|
|
|
return this.isDownloadCoursesDisabledInSite(site);
|
|
}
|
|
|
|
/**
|
|
* Check if download a whole course is disabled in a certain site.
|
|
*
|
|
* @param site Site. If not defined, use current site.
|
|
* @return Whether it's disabled.
|
|
*/
|
|
isDownloadCourseDisabledInSite(site?: CoreSite): boolean {
|
|
site = site || CoreSites.getCurrentSite();
|
|
|
|
return !site || site.isOfflineDisabled() || site.isFeatureDisabled('NoDelegate_CoreCourseDownload');
|
|
}
|
|
|
|
/**
|
|
* Check if download all courses is disabled in a certain site.
|
|
*
|
|
* @param siteId Site Id. If not defined, use current site.
|
|
* @return Promise resolved with true if disabled, rejected or resolved with false otherwise.
|
|
*/
|
|
async isDownloadCoursesDisabled(siteId?: string): Promise<boolean> {
|
|
const site = await CoreSites.getSite(siteId);
|
|
|
|
return this.isDownloadCoursesDisabledInSite(site);
|
|
}
|
|
|
|
/**
|
|
* Check if download all courses is disabled in a certain site.
|
|
*
|
|
* @param site Site. If not defined, use current site.
|
|
* @return Whether it's disabled.
|
|
*/
|
|
isDownloadCoursesDisabledInSite(site?: CoreSite): boolean {
|
|
site = site || CoreSites.getCurrentSite();
|
|
|
|
return !site || site.isOfflineDisabled() || site.isFeatureDisabled('NoDelegate_CoreCoursesDownload');
|
|
}
|
|
|
|
/**
|
|
* Check if My Courses is disabled in a certain site.
|
|
*
|
|
* @param siteId Site Id. If not defined, use current site.
|
|
* @return Promise resolved with true if disabled, rejected or resolved with false otherwise.
|
|
*/
|
|
async isMyCoursesDisabled(siteId?: string): Promise<boolean> {
|
|
const site = await CoreSites.getSite(siteId);
|
|
|
|
return this.isMyCoursesDisabledInSite(site);
|
|
}
|
|
|
|
/**
|
|
* Check if My Courses is disabled in a certain site.
|
|
*
|
|
* @param site Site. If not defined, use current site.
|
|
* @return Whether it's disabled.
|
|
*/
|
|
isMyCoursesDisabledInSite(site?: CoreSite): boolean {
|
|
site = site || CoreSites.getCurrentSite();
|
|
|
|
return !site || site.isFeatureDisabled('CoreMainMenuDelegate_CoreCourses');
|
|
}
|
|
|
|
/**
|
|
* Check if Search Courses is disabled in a certain site.
|
|
*
|
|
* @param siteId Site Id. If not defined, use current site.
|
|
* @return Promise resolved with true if disabled, rejected or resolved with false otherwise.
|
|
*/
|
|
async isSearchCoursesDisabled(siteId?: string): Promise<boolean> {
|
|
const site = await CoreSites.getSite(siteId);
|
|
|
|
return this.isSearchCoursesDisabledInSite(site);
|
|
}
|
|
|
|
/**
|
|
* Check if Search Courses is disabled in a certain site.
|
|
*
|
|
* @param site Site. If not defined, use current site.
|
|
* @return Whether it's disabled.
|
|
*/
|
|
isSearchCoursesDisabledInSite(site?: CoreSite): boolean {
|
|
site = site || CoreSites.getCurrentSite();
|
|
|
|
return !site || site.isFeatureDisabled('CoreCourseOptionsDelegate_search');
|
|
}
|
|
|
|
/**
|
|
* Get course.
|
|
*
|
|
* @param id ID of the course to get.
|
|
* @param siteId Site to get the courses from. If not defined, use current site.
|
|
* @return Promise resolved with the course.
|
|
*/
|
|
async getCourse(id: number, siteId?: string): Promise<CoreCourseGetCoursesData> {
|
|
const courses = await this.getCourses([id], siteId);
|
|
|
|
if (courses && courses.length > 0) {
|
|
return courses[0];
|
|
}
|
|
|
|
throw Error('Course not found on core_course_get_courses');
|
|
}
|
|
|
|
/**
|
|
* Get the enrolment methods from a course.
|
|
*
|
|
* @param id ID of the course.
|
|
* @param siteId Site ID. If not defined, use current site.
|
|
* @return Promise resolved with the methods.
|
|
*/
|
|
async getCourseEnrolmentMethods(id: number, siteId?: string): Promise<CoreCourseEnrolmentMethod[]> {
|
|
const site = await CoreSites.getSite(siteId);
|
|
|
|
const params: CoreEnrolGetCourseEnrolmentMethodsWSParams = {
|
|
courseid: id,
|
|
};
|
|
const preSets = {
|
|
cacheKey: this.getCourseEnrolmentMethodsCacheKey(id),
|
|
updateFrequency: CoreSite.FREQUENCY_RARELY,
|
|
};
|
|
|
|
return site.read('core_enrol_get_course_enrolment_methods', params, preSets);
|
|
}
|
|
|
|
/**
|
|
* Get cache key for get course enrolment methods WS call.
|
|
*
|
|
* @param id Course ID.
|
|
* @return Cache key.
|
|
*/
|
|
protected getCourseEnrolmentMethodsCacheKey(id: number): string {
|
|
return ROOT_CACHE_KEY + 'enrolmentmethods:' + id;
|
|
}
|
|
|
|
/**
|
|
* Get info from a course guest enrolment method.
|
|
*
|
|
* @param instanceId Guest instance ID.
|
|
* @param siteId Site ID. If not defined, use current site.
|
|
* @return Promise resolved when the info is retrieved.
|
|
*/
|
|
async getCourseGuestEnrolmentInfo(instanceId: number, siteId?: string): Promise<CoreCourseEnrolmentGuestMethod> {
|
|
const site = await CoreSites.getSite(siteId);
|
|
const params: EnrolGuestGetInstanceInfoWSParams = {
|
|
instanceid: instanceId,
|
|
};
|
|
const preSets: CoreSiteWSPreSets = {
|
|
cacheKey: this.getCourseGuestEnrolmentInfoCacheKey(instanceId),
|
|
updateFrequency: CoreSite.FREQUENCY_RARELY,
|
|
};
|
|
const response = await site.read<EnrolGuestGetInstanceInfoWSResponse>('enrol_guest_get_instance_info', params, preSets);
|
|
|
|
return response.instanceinfo;
|
|
}
|
|
|
|
/**
|
|
* Get cache key for get course guest enrolment methods WS call.
|
|
*
|
|
* @param instanceId Guest instance ID.
|
|
* @return Cache key.
|
|
*/
|
|
protected getCourseGuestEnrolmentInfoCacheKey(instanceId: number): string {
|
|
return ROOT_CACHE_KEY + 'guestinfo:' + instanceId;
|
|
}
|
|
|
|
/**
|
|
* Get courses.
|
|
* Warning: if the user doesn't have permissions to view some of the courses passed the WS call will fail.
|
|
* The user must be able to view ALL the courses passed.
|
|
*
|
|
* @param ids List of IDs of the courses to get.
|
|
* @param siteId Site to get the courses from. If not defined, use current site.
|
|
* @return Promise resolved with the courses.
|
|
*/
|
|
async getCourses(ids: number[], siteId?: string): Promise<CoreCourseGetCoursesWSResponse> {
|
|
if (!Array.isArray(ids)) {
|
|
throw Error('ids parameter should be an array');
|
|
}
|
|
|
|
if (ids.length === 0) {
|
|
return [];
|
|
}
|
|
|
|
const site = await CoreSites.getSite(siteId);
|
|
|
|
const params: CoreCourseGetCoursesWSParams = {
|
|
options: {
|
|
ids: ids,
|
|
},
|
|
};
|
|
const preSets: CoreSiteWSPreSets = {
|
|
cacheKey: this.getCoursesCacheKey(ids),
|
|
updateFrequency: CoreSite.FREQUENCY_RARELY,
|
|
};
|
|
|
|
return site.read('core_course_get_courses', params, preSets);
|
|
}
|
|
|
|
/**
|
|
* Get cache key for get courses WS call.
|
|
*
|
|
* @param ids Courses IDs.
|
|
* @return Cache key.
|
|
*/
|
|
protected getCoursesCacheKey(ids: number[]): string {
|
|
return ROOT_CACHE_KEY + 'course:' + JSON.stringify(ids);
|
|
}
|
|
|
|
/**
|
|
* This function is meant to decrease WS calls.
|
|
* When requesting a single course that belongs to enrolled courses, request all enrolled courses because
|
|
* the WS call is probably cached.
|
|
*
|
|
* @param field The field to search.
|
|
* @param value The value to match.
|
|
* @param siteId Site ID. If not defined, use current site.
|
|
* @return Promise resolved with the field and value to use.
|
|
*/
|
|
protected async fixCoursesByFieldParams(
|
|
field: string = '',
|
|
value: number | string = '',
|
|
siteId?: string,
|
|
): Promise<{ field: string; value: number | string }> {
|
|
|
|
if (field == 'id' || field == 'ids') {
|
|
let courseIds: number[];
|
|
if (typeof value == 'string') {
|
|
courseIds = value.split(',').map((id) => parseInt(id, 10));
|
|
} else {
|
|
courseIds = [value];
|
|
}
|
|
|
|
// Use the same optimization as in get admin and nav options. This will return the course IDs to use.
|
|
courseIds = await this.getCourseIdsForAdminAndNavOptions(courseIds, siteId);
|
|
|
|
if (courseIds.length > 1) {
|
|
return { field: 'ids', value: courseIds.join(',') };
|
|
} else {
|
|
return { field: 'id', value: Number(courseIds[0]) };
|
|
}
|
|
} else {
|
|
// Nothing to do.
|
|
return { field: field, value: value };
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get the first course returned by getCoursesByField.
|
|
*
|
|
* @param field The field to search. Can be left empty for all courses or:
|
|
* id: course id.
|
|
* ids: comma separated course ids.
|
|
* shortname: course short name.
|
|
* idnumber: course id number.
|
|
* category: category id the course belongs to.
|
|
* @param value The value to match.
|
|
* @param siteId Site ID. If not defined, use current site.
|
|
* @return Promise resolved with the first course.
|
|
*/
|
|
async getCourseByField(field?: string, value?: string | number, siteId?: string): Promise<CoreCourseSearchedData> {
|
|
const courses = await this.getCoursesByField(field, value, siteId);
|
|
|
|
if (courses && courses.length > 0) {
|
|
return courses[0];
|
|
}
|
|
|
|
throw Error('Course not found on core_course_get_courses_by_field');
|
|
}
|
|
|
|
/**
|
|
* Get courses. They can be filtered by field.
|
|
*
|
|
* @param field The field to search. Can be left empty for all courses or:
|
|
* id: course id.
|
|
* ids: comma separated course ids.
|
|
* shortname: course short name.
|
|
* idnumber: course id number.
|
|
* category: category id the course belongs to.
|
|
* @param value The value to match.
|
|
* @param siteId Site ID. If not defined, use current site.
|
|
* @return Promise resolved with the courses.
|
|
*/
|
|
getCoursesByField(
|
|
field: string = '',
|
|
value: string | number = '',
|
|
siteId?: string,
|
|
): Promise<CoreCourseSearchedData[]> {
|
|
return firstValueFrom(this.getCoursesByFieldObservable(field, value, { siteId }));
|
|
}
|
|
|
|
/**
|
|
* Get courses. They can be filtered by field.
|
|
*
|
|
* @param field The field to search. Can be left empty for all courses or:
|
|
* id: course id.
|
|
* ids: comma separated course ids.
|
|
* shortname: course short name.
|
|
* idnumber: course id number.
|
|
* category: category id the course belongs to.
|
|
* @param value The value to match.
|
|
* @param options Other options.
|
|
* @return Observable that returns the courses.
|
|
*/
|
|
getCoursesByFieldObservable(
|
|
field: string = '',
|
|
value: string | number = '',
|
|
options: CoreSitesCommonWSOptions = {},
|
|
): Observable<CoreCourseSearchedData[]> {
|
|
return asyncObservable(async () => {
|
|
const siteId = options.siteId || CoreSites.getCurrentSiteId();
|
|
const originalValue = value;
|
|
|
|
const site = await CoreSites.getSite(siteId);
|
|
|
|
// Fix params. Tries to use cached data, no need to use observer.
|
|
const fieldParams = await this.fixCoursesByFieldParams(field, value, siteId);
|
|
|
|
const hasChanged = fieldParams.field != field || fieldParams.value != value;
|
|
field = fieldParams.field;
|
|
value = fieldParams.value;
|
|
const data: CoreCourseGetCoursesByFieldWSParams = {
|
|
field: field,
|
|
value: field ? value : '',
|
|
};
|
|
const preSets: CoreSiteWSPreSets = {
|
|
cacheKey: this.getCoursesByFieldCacheKey(field, value),
|
|
updateFrequency: CoreSite.FREQUENCY_RARELY,
|
|
...CoreSites.getReadingStrategyPreSets(options.readingStrategy),
|
|
};
|
|
|
|
const observable = site.readObservable<CoreCourseGetCoursesByFieldWSResponse>(
|
|
'core_course_get_courses_by_field',
|
|
data,
|
|
preSets,
|
|
);
|
|
|
|
return observable.pipe(map(response => {
|
|
if (!response.courses) {
|
|
throw Error('WS core_course_get_courses_by_field failed');
|
|
}
|
|
|
|
if (field == 'ids' && hasChanged) {
|
|
// The list of courses requestes was changed to optimize it.
|
|
// Return only the ones that were being requested.
|
|
const courseIds = String(originalValue).split(',').map((id) => parseInt(id, 10));
|
|
|
|
// Only courses from the original selection.
|
|
response.courses = response.courses.filter((course) => courseIds.indexOf(course.id) >= 0);
|
|
}
|
|
|
|
// Courses will be sorted using sortorder if available.
|
|
return response.courses.sort((a, b) => {
|
|
if (a.sortorder === undefined && b.sortorder === undefined) {
|
|
return b.id - a.id;
|
|
}
|
|
|
|
if (a.sortorder === undefined) {
|
|
return 1;
|
|
}
|
|
|
|
if (b.sortorder === undefined) {
|
|
return -1;
|
|
}
|
|
|
|
return a.sortorder - b.sortorder;
|
|
});
|
|
}));
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Get cache key for get courses WS call.
|
|
*
|
|
* @param field The field to search.
|
|
* @param value The value to match.
|
|
* @return Cache key.
|
|
*/
|
|
protected getCoursesByFieldCacheKey(field: string = '', value: string | number = ''): string {
|
|
return ROOT_CACHE_KEY + 'coursesbyfield:' + field + ':' + value;
|
|
}
|
|
|
|
/**
|
|
* Get courses matching the given custom field. By default it will try not to use cache.
|
|
*
|
|
* @param customFieldName Custom field name.
|
|
* @param customFieldValue Custom field value.
|
|
* @param siteId Site ID. If not defined, current site.
|
|
* @return Promise resolved with the list of courses.
|
|
* @since 3.8
|
|
*/
|
|
getEnrolledCoursesByCustomField(
|
|
customFieldName: string,
|
|
customFieldValue: string,
|
|
siteId?: string,
|
|
): Promise<CoreCourseSummaryData[]> {
|
|
return firstValueFrom(this.getEnrolledCoursesByCustomFieldObservable(customFieldName, customFieldValue, {
|
|
readingStrategy: CoreSitesReadingStrategy.PREFER_NETWORK,
|
|
siteId,
|
|
}));
|
|
}
|
|
|
|
/**
|
|
* Get courses matching the given custom field.
|
|
*
|
|
* @param customFieldName Custom field name.
|
|
* @param customFieldValue Custom field value.
|
|
* @param options Common options.
|
|
* @return Promise resolved with the list of courses.
|
|
* @since 3.8
|
|
*/
|
|
getEnrolledCoursesByCustomFieldObservable(
|
|
customFieldName: string,
|
|
customFieldValue: string,
|
|
options: CoreSitesCommonWSOptions,
|
|
): Observable<CoreCourseSummaryData[]> {
|
|
return asyncObservable(async () => {
|
|
const site = await CoreSites.getSite(options. siteId);
|
|
|
|
const params: CoreCourseGetEnrolledCoursesByTimelineClassificationWSParams = {
|
|
classification: 'customfield',
|
|
customfieldname: customFieldName,
|
|
customfieldvalue: customFieldValue,
|
|
};
|
|
const preSets: CoreSiteWSPreSets = {
|
|
...CoreSites.getReadingStrategyPreSets(options.readingStrategy ?? CoreSitesReadingStrategy.PREFER_NETWORK),
|
|
};
|
|
|
|
return site.readObservable<CoreCourseGetEnrolledCoursesByTimelineClassificationWSResponse>(
|
|
'core_course_get_enrolled_courses_by_timeline_classification',
|
|
params,
|
|
preSets,
|
|
).pipe(map(response => response.courses));
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Check if get courses by field WS is available in a certain site.
|
|
*
|
|
* @return Whether get courses by field is available.
|
|
* @deprecated since app 4.0
|
|
*/
|
|
isGetCoursesByFieldAvailable(): boolean {
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Check if get courses by field WS is available in a certain site, by site ID.
|
|
*
|
|
* @return Promise resolved with boolean: whether get courses by field is available.
|
|
* @deprecated since app 4.0
|
|
*/
|
|
async isGetCoursesByFieldAvailableInSite(): Promise<boolean> {
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Get the navigation and administration options for the given courses.
|
|
*
|
|
* @param courseIds IDs of courses to get.
|
|
* @param siteId Site ID. If not defined, current site.
|
|
* @return Promise resolved with the options for each course.
|
|
*/
|
|
getCoursesAdminAndNavOptions(
|
|
courseIds: number[],
|
|
siteId?: string,
|
|
): Promise<{
|
|
navOptions: CoreCourseUserAdminOrNavOptionCourseIndexed;
|
|
admOptions: CoreCourseUserAdminOrNavOptionCourseIndexed;
|
|
}> {
|
|
return firstValueFrom(this.getCoursesAdminAndNavOptionsObservable(courseIds, { siteId }));
|
|
}
|
|
|
|
/**
|
|
* Get the navigation and administration options for the given courses.
|
|
*
|
|
* @param courseIds IDs of courses to get.
|
|
* @param options Options.
|
|
* @return Observable that returns the options for each course.
|
|
*/
|
|
getCoursesAdminAndNavOptionsObservable(
|
|
courseIds: number[],
|
|
options: CoreSitesCommonWSOptions = {},
|
|
): Observable<{
|
|
navOptions: CoreCourseUserAdminOrNavOptionCourseIndexed;
|
|
admOptions: CoreCourseUserAdminOrNavOptionCourseIndexed;
|
|
}> {
|
|
|
|
return asyncObservable(async () => {
|
|
const siteId = options.siteId || CoreSites.getCurrentSiteId();
|
|
|
|
// Get the list of courseIds to use based on the param. Tries to use cached data, no need to use observer.
|
|
courseIds = await this.getCourseIdsForAdminAndNavOptions(courseIds, siteId);
|
|
|
|
// Get user navigation and administration options.
|
|
return zipIncludingComplete(
|
|
ignoreErrors(this.getUserNavigationOptionsObservable(courseIds, options), {}),
|
|
ignoreErrors(this.getUserAdministrationOptionsObservable(courseIds, options), {}),
|
|
).pipe(
|
|
map(([navOptions, admOptions]) => ({ navOptions, admOptions })),
|
|
);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Get cache key for get recent courses WS call.
|
|
*
|
|
* @param userId User ID.
|
|
* @return Cache key.
|
|
*/
|
|
protected getRecentCoursesCacheKey(userId: number): string {
|
|
return `${ROOT_CACHE_KEY}:recentcourses:${userId}`;
|
|
}
|
|
|
|
/**
|
|
* Get recent courses.
|
|
*
|
|
* @param options Options.
|
|
* @return Promise resolved with courses.
|
|
* @since 3.6
|
|
*/
|
|
async getRecentCourses(options: CoreCourseGetRecentCoursesOptions = {}): Promise<CoreCourseSummaryData[]> {
|
|
const site = await CoreSites.getSite(options.siteId);
|
|
|
|
const userId = options.userId || site.getUserId();
|
|
const params: CoreCourseGetRecentCoursesWSParams = {
|
|
userid: userId,
|
|
offset: options.offset || 0,
|
|
limit: options.limit || CoreCoursesProvider.RECENT_PER_PAGE,
|
|
sort: options.sort,
|
|
};
|
|
const preSets: CoreSiteWSPreSets = {
|
|
cacheKey: this.getRecentCoursesCacheKey(userId),
|
|
};
|
|
|
|
return site.read<CoreCourseSummaryData[]>('core_course_get_recent_courses', params, preSets);
|
|
}
|
|
|
|
/**
|
|
* Get the common part of the cache keys for user administration options WS calls.
|
|
*
|
|
* @return Cache key.
|
|
*/
|
|
protected getUserAdministrationOptionsCommonCacheKey(): string {
|
|
return ROOT_CACHE_KEY + 'administrationOptions:';
|
|
}
|
|
|
|
/**
|
|
* Get cache key for get user administration options WS call.
|
|
*
|
|
* @param courseIds IDs of courses to get.
|
|
* @return Cache key.
|
|
*/
|
|
protected getUserAdministrationOptionsCacheKey(courseIds: number[]): string {
|
|
return this.getUserAdministrationOptionsCommonCacheKey() + courseIds.join(',');
|
|
}
|
|
|
|
/**
|
|
* Get user administration options for a set of courses.
|
|
*
|
|
* @param courseIds IDs of courses to get.
|
|
* @param siteId Site ID. If not defined, current site.
|
|
* @return Promise resolved with administration options for each course.
|
|
*/
|
|
getUserAdministrationOptions(courseIds: number[], siteId?: string): Promise<CoreCourseUserAdminOrNavOptionCourseIndexed> {
|
|
return firstValueFrom(this.getUserAdministrationOptionsObservable(courseIds, { siteId }));
|
|
}
|
|
|
|
/**
|
|
* Get user administration options for a set of courses.
|
|
*
|
|
* @param courseIds IDs of courses to get.
|
|
* @param options Options.
|
|
* @return Observable that returns administration options for each course.
|
|
*/
|
|
getUserAdministrationOptionsObservable(
|
|
courseIds: number[],
|
|
options: CoreSitesCommonWSOptions = {},
|
|
): Observable<CoreCourseUserAdminOrNavOptionCourseIndexed> {
|
|
if (!courseIds || courseIds.length == 0) {
|
|
return of({});
|
|
}
|
|
|
|
return asyncObservable(async () => {
|
|
const site = await CoreSites.getSite(options.siteId);
|
|
|
|
const params: CoreCourseGetUserAdminOrNavOptionsWSParams = {
|
|
courseids: courseIds,
|
|
};
|
|
const preSets: CoreSiteWSPreSets = {
|
|
cacheKey: this.getUserAdministrationOptionsCacheKey(courseIds),
|
|
updateFrequency: CoreSite.FREQUENCY_RARELY,
|
|
...CoreSites.getReadingStrategyPreSets(options.readingStrategy),
|
|
};
|
|
|
|
const observable = site.readObservable<CoreCourseGetUserAdminOrNavOptionsWSResponse>(
|
|
'core_course_get_user_administration_options',
|
|
params,
|
|
preSets,
|
|
);
|
|
|
|
// Format returned data.
|
|
return observable.pipe(map(response => this.formatUserAdminOrNavOptions(response.courses)));
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Get the common part of the cache keys for user navigation options WS calls.
|
|
*
|
|
* @return Cache key.
|
|
*/
|
|
protected getUserNavigationOptionsCommonCacheKey(): string {
|
|
return ROOT_CACHE_KEY + 'navigationOptions:';
|
|
}
|
|
|
|
/**
|
|
* Get cache key for get user navigation options WS call.
|
|
*
|
|
* @return Cache key.
|
|
*/
|
|
protected getUserNavigationOptionsCacheKey(courseIds: number[]): string {
|
|
return this.getUserNavigationOptionsCommonCacheKey() + courseIds.join(',');
|
|
}
|
|
|
|
/**
|
|
* Get user navigation options for a set of courses.
|
|
*
|
|
* @param courseIds IDs of courses to get.
|
|
* @param siteId Site ID. If not defined, current site.
|
|
* @return Promise resolved with navigation options for each course.
|
|
*/
|
|
async getUserNavigationOptions(courseIds: number[], siteId?: string): Promise<CoreCourseUserAdminOrNavOptionCourseIndexed> {
|
|
return firstValueFrom(this.getUserNavigationOptionsObservable(courseIds, { siteId }));
|
|
}
|
|
|
|
/**
|
|
* Get user navigation options for a set of courses.
|
|
*
|
|
* @param courseIds IDs of courses to get.
|
|
* @param options Options.
|
|
* @return Observable that returns navigation options for each course.
|
|
*/
|
|
getUserNavigationOptionsObservable(
|
|
courseIds: number[],
|
|
options: CoreSitesCommonWSOptions = {},
|
|
): Observable<CoreCourseUserAdminOrNavOptionCourseIndexed> {
|
|
if (!courseIds || courseIds.length == 0) {
|
|
return of({});
|
|
}
|
|
|
|
return asyncObservable(async () => {
|
|
const site = await CoreSites.getSite(options.siteId);
|
|
|
|
const params: CoreCourseGetUserAdminOrNavOptionsWSParams = {
|
|
courseids: courseIds,
|
|
};
|
|
const preSets: CoreSiteWSPreSets = {
|
|
cacheKey: this.getUserNavigationOptionsCacheKey(courseIds),
|
|
updateFrequency: CoreSite.FREQUENCY_RARELY,
|
|
...CoreSites.getReadingStrategyPreSets(options.readingStrategy),
|
|
};
|
|
|
|
const observable = site.readObservable<CoreCourseGetUserAdminOrNavOptionsWSResponse>(
|
|
'core_course_get_user_navigation_options',
|
|
params,
|
|
preSets,
|
|
);
|
|
|
|
// Format returned data.
|
|
return observable.pipe(map(response => this.formatUserAdminOrNavOptions(response.courses)));
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Format user navigation or administration options.
|
|
*
|
|
* @param courses Navigation or administration options for each course.
|
|
* @return Formatted options.
|
|
*/
|
|
protected formatUserAdminOrNavOptions(courses: CoreCourseUserAdminOrNavOption[]): CoreCourseUserAdminOrNavOptionCourseIndexed {
|
|
const result = {};
|
|
|
|
courses.forEach((course) => {
|
|
const options = {};
|
|
|
|
if (course.options) {
|
|
course.options.forEach((option) => {
|
|
options[option.name] = option.available;
|
|
});
|
|
}
|
|
|
|
result[course.id] = options;
|
|
});
|
|
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Get a course the user is enrolled in. This function relies on getUserCourses.
|
|
* preferCache=true will try to speed up the response, but the data returned might not be updated.
|
|
*
|
|
* @param id ID of the course to get.
|
|
* @param preferCache True if shouldn't call WS if data is cached, false otherwise.
|
|
* @param siteId Site to get the courses from. If not defined, use current site.
|
|
* @return Promise resolved with the course.
|
|
*/
|
|
async getUserCourse(id: number, preferCache?: boolean, siteId?: string): Promise<CoreEnrolledCourseData> {
|
|
if (!id) {
|
|
throw Error('Invalid id parameter on getUserCourse');
|
|
}
|
|
|
|
const courses = await this.getUserCourses(preferCache, siteId);
|
|
|
|
const course = courses.find((course) => course.id == id);
|
|
|
|
if (course) {
|
|
return course;
|
|
}
|
|
|
|
throw Error('Course not found on core_enrol_get_users_courses');
|
|
}
|
|
|
|
/**
|
|
* Get user courses.
|
|
*
|
|
* @param preferCache True if shouldn't call WS if data is cached, false otherwise.
|
|
* @param siteId Site to get the courses from. If not defined, use current site.
|
|
* @param strategy Reading strategy.
|
|
* @return Promise resolved with the courses.
|
|
*/
|
|
getUserCourses(
|
|
preferCache: boolean = false,
|
|
siteId?: string,
|
|
strategy?: CoreSitesReadingStrategy,
|
|
): Promise<CoreEnrolledCourseData[]> {
|
|
strategy = strategy ?? (preferCache ? CoreSitesReadingStrategy.PREFER_CACHE : undefined);
|
|
|
|
return this.getUserCoursesObservable({
|
|
readingStrategy: strategy,
|
|
siteId,
|
|
}).toPromise();
|
|
}
|
|
|
|
/**
|
|
* Get user courses.
|
|
*
|
|
* @param options Options.
|
|
* @return Observable that returns the courses.
|
|
*/
|
|
getUserCoursesObservable(options: CoreSitesCommonWSOptions = {}): Observable<CoreEnrolledCourseData[]> {
|
|
return asyncObservable(async () => {
|
|
const site = await CoreSites.getSite(options.siteId);
|
|
|
|
const userId = site.getUserId();
|
|
const wsParams: CoreEnrolGetUsersCoursesWSParams = {
|
|
userid: userId,
|
|
};
|
|
|
|
const preSets: CoreSiteWSPreSets = {
|
|
cacheKey: this.getUserCoursesCacheKey(),
|
|
getCacheUsingCacheKey: true,
|
|
updateFrequency: CoreSite.FREQUENCY_RARELY,
|
|
...CoreSites.getReadingStrategyPreSets(options.readingStrategy),
|
|
};
|
|
|
|
if (site.isVersionGreaterEqualThan('3.7')) {
|
|
wsParams.returnusercount = false;
|
|
}
|
|
|
|
const observable = site.readObservable<CoreEnrolGetUsersCoursesWSResponse>(
|
|
'core_enrol_get_users_courses',
|
|
wsParams,
|
|
preSets,
|
|
);
|
|
|
|
return observable.pipe(map(courses => {
|
|
if (this.userCoursesIds) {
|
|
// Check if the list of courses has changed.
|
|
const added: number[] = [];
|
|
const removed: number[] = [];
|
|
const previousIds = this.userCoursesIds;
|
|
const currentIds = new Set<number>();
|
|
|
|
courses.forEach((course) => {
|
|
// Move category field to categoryid on a course.
|
|
course.categoryid = course.category;
|
|
delete course.category;
|
|
|
|
currentIds.add(course.id);
|
|
|
|
if (!previousIds.has(course.id)) {
|
|
// Course added.
|
|
added.push(course.id);
|
|
}
|
|
});
|
|
|
|
if (courses.length - added.length !== previousIds.size) {
|
|
// A course was removed, check which one.
|
|
previousIds.forEach((id) => {
|
|
if (!currentIds.has(id)) {
|
|
// Course removed.
|
|
removed.push(Number(id));
|
|
}
|
|
});
|
|
}
|
|
|
|
if (added.length || removed.length) {
|
|
// At least 1 course was added or removed, trigger the event.
|
|
CoreEvents.trigger(CoreCoursesProvider.EVENT_MY_COURSES_CHANGED, {
|
|
added: added,
|
|
removed: removed,
|
|
}, site.getId());
|
|
}
|
|
|
|
this.userCoursesIds = currentIds;
|
|
} else {
|
|
const coursesIds = new Set<number>();
|
|
|
|
// Store the list of courses.
|
|
courses.forEach((course) => {
|
|
coursesIds.add(course.id);
|
|
|
|
// Move category field to categoryid on a course.
|
|
course.categoryid = course.category;
|
|
delete course.category;
|
|
});
|
|
|
|
this.userCoursesIds = coursesIds;
|
|
}
|
|
|
|
return courses;
|
|
}));
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Get cache key for get user courses WS call.
|
|
*
|
|
* @return Cache key.
|
|
*/
|
|
protected getUserCoursesCacheKey(): string {
|
|
return ROOT_CACHE_KEY + 'usercourses';
|
|
}
|
|
|
|
/**
|
|
* Invalidates get categories WS call.
|
|
*
|
|
* @param categoryId Category ID to get.
|
|
* @param addSubcategories If it should add subcategories to the list.
|
|
* @param siteId Site Id. If not defined, use current site.
|
|
* @return Promise resolved when the data is invalidated.
|
|
*/
|
|
async invalidateCategories(categoryId: number, addSubcategories?: boolean, siteId?: string): Promise<void> {
|
|
const site = await CoreSites.getSite(siteId);
|
|
|
|
await site.invalidateWsCacheForKey(this.getCategoriesCacheKey(categoryId, addSubcategories));
|
|
}
|
|
|
|
/**
|
|
* Invalidates get course WS call.
|
|
*
|
|
* @param id Course ID.
|
|
* @param siteId Site Id. If not defined, use current site.
|
|
* @return Promise resolved when the data is invalidated.
|
|
*/
|
|
invalidateCourse(id: number, siteId?: string): Promise<void> {
|
|
return this.invalidateCourses([id], siteId);
|
|
}
|
|
|
|
/**
|
|
* Invalidates get course enrolment methods WS call.
|
|
*
|
|
* @param id Course ID.
|
|
* @param siteId Site Id. If not defined, use current site.
|
|
* @return Promise resolved when the data is invalidated.
|
|
*/
|
|
async invalidateCourseEnrolmentMethods(id: number, siteId?: string): Promise<void> {
|
|
const site = await CoreSites.getSite(siteId);
|
|
|
|
await site.invalidateWsCacheForKey(this.getCourseEnrolmentMethodsCacheKey(id));
|
|
}
|
|
|
|
/**
|
|
* Invalidates get course guest enrolment info WS call.
|
|
*
|
|
* @param instanceId Guest instance ID.
|
|
* @param siteId Site Id. If not defined, use current site.
|
|
* @return Promise resolved when the data is invalidated.
|
|
*/
|
|
async invalidateCourseGuestEnrolmentInfo(instanceId: number, siteId?: string): Promise<void> {
|
|
const site = await CoreSites.getSite(siteId);
|
|
|
|
await site.invalidateWsCacheForKey(this.getCourseGuestEnrolmentInfoCacheKey(instanceId));
|
|
}
|
|
|
|
/**
|
|
* Invalidates the navigation and administration options for the given courses.
|
|
*
|
|
* @param courseIds IDs of courses to get.
|
|
* @param siteId Site ID to invalidate. If not defined, use current site.
|
|
* @return Promise resolved when the data is invalidated.
|
|
*/
|
|
async invalidateCoursesAdminAndNavOptions(courseIds: number[], siteId?: string): Promise<void> {
|
|
siteId = siteId || CoreSites.getCurrentSiteId();
|
|
|
|
const ids = await this.getCourseIdsForAdminAndNavOptions(courseIds, siteId);
|
|
|
|
const promises: Promise<void>[] = [];
|
|
promises.push(this.invalidateUserAdministrationOptionsForCourses(ids, siteId));
|
|
promises.push(this.invalidateUserNavigationOptionsForCourses(ids, siteId));
|
|
|
|
await Promise.all(promises);
|
|
}
|
|
|
|
/**
|
|
* Invalidates get courses WS call.
|
|
*
|
|
* @param ids Courses IDs.
|
|
* @param siteId Site Id. If not defined, use current site.
|
|
* @return Promise resolved when the data is invalidated.
|
|
*/
|
|
async invalidateCourses(ids: number[], siteId?: string): Promise<void> {
|
|
const site = await CoreSites.getSite(siteId);
|
|
|
|
await site.invalidateWsCacheForKey(this.getCoursesCacheKey(ids));
|
|
}
|
|
|
|
/**
|
|
* Invalidates get courses by field WS call.
|
|
*
|
|
* @param field See getCoursesByField for info.
|
|
* @param value The value to match.
|
|
* @param siteId Site Id. If not defined, use current site.
|
|
* @return Promise resolved when the data is invalidated.
|
|
*/
|
|
async invalidateCoursesByField(field: string = '', value: number | string = '', siteId?: string): Promise<void> {
|
|
if (typeof value === 'string' && value.length === 0) {
|
|
return;
|
|
}
|
|
|
|
siteId = siteId || CoreSites.getCurrentSiteId();
|
|
|
|
const result = await this.fixCoursesByFieldParams(field, value, siteId);
|
|
field = result.field;
|
|
value = result.value;
|
|
|
|
const site = await CoreSites.getSite(siteId);
|
|
|
|
return site.invalidateWsCacheForKey(this.getCoursesByFieldCacheKey(field, value));
|
|
}
|
|
|
|
/**
|
|
* Invalidates get recent courses WS call.
|
|
*
|
|
* @param userId User ID. If not defined, current user.
|
|
* @param siteId Site Id. If not defined, use current site.
|
|
* @return Promise resolved when the data is invalidated.
|
|
*/
|
|
async invalidateRecentCourses(userId?: number, siteId?: string): Promise<void> {
|
|
const site = await CoreSites.getSite(siteId);
|
|
|
|
await site.invalidateWsCacheForKey(this.getRecentCoursesCacheKey(userId || site.getUserId()));
|
|
}
|
|
|
|
/**
|
|
* Invalidates all user administration options.
|
|
*
|
|
* @param siteId Site ID to invalidate. If not defined, use current site.
|
|
* @return Promise resolved when the data is invalidated.
|
|
*/
|
|
async invalidateUserAdministrationOptions(siteId?: string): Promise<void> {
|
|
const site = await CoreSites.getSite(siteId);
|
|
|
|
await site.invalidateWsCacheForKeyStartingWith(this.getUserAdministrationOptionsCommonCacheKey());
|
|
}
|
|
|
|
/**
|
|
* Invalidates user administration options for certain courses.
|
|
*
|
|
* @param courseIds IDs of courses.
|
|
* @param siteId Site ID to invalidate. If not defined, use current site.
|
|
* @return Promise resolved when the data is invalidated.
|
|
*/
|
|
async invalidateUserAdministrationOptionsForCourses(courseIds: number[], siteId?: string): Promise<void> {
|
|
const site = await CoreSites.getSite(siteId);
|
|
|
|
await site.invalidateWsCacheForKey(this.getUserAdministrationOptionsCacheKey(courseIds));
|
|
}
|
|
|
|
/**
|
|
* Invalidates get user courses WS call.
|
|
*
|
|
* @param siteId Site ID to invalidate. If not defined, use current site.
|
|
* @return Promise resolved when the data is invalidated.
|
|
*/
|
|
async invalidateUserCourses(siteId?: string): Promise<void> {
|
|
const site = await CoreSites.getSite(siteId);
|
|
|
|
await site.invalidateWsCacheForKey(this.getUserCoursesCacheKey());
|
|
}
|
|
|
|
/**
|
|
* Invalidates all user navigation options.
|
|
*
|
|
* @param siteId Site ID to invalidate. If not defined, use current site.
|
|
* @return Promise resolved when the data is invalidated.
|
|
*/
|
|
async invalidateUserNavigationOptions(siteId?: string): Promise<void> {
|
|
const site = await CoreSites.getSite(siteId);
|
|
|
|
await site.invalidateWsCacheForKeyStartingWith(this.getUserNavigationOptionsCommonCacheKey());
|
|
}
|
|
|
|
/**
|
|
* Invalidates user navigation options for certain courses.
|
|
*
|
|
* @param courseIds IDs of courses.
|
|
* @param siteId Site ID to invalidate. If not defined, use current site.
|
|
* @return Promise resolved when the data is invalidated.
|
|
*/
|
|
async invalidateUserNavigationOptionsForCourses(courseIds: number[], siteId?: string): Promise<void> {
|
|
const site = await CoreSites.getSite(siteId);
|
|
|
|
await site.invalidateWsCacheForKey(this.getUserNavigationOptionsCacheKey(courseIds));
|
|
}
|
|
|
|
/**
|
|
* Check if WS to retrieve guest enrolment data is available.
|
|
*
|
|
* @return Whether guest WS is available.
|
|
* @deprecated since app 3.9.5
|
|
*/
|
|
isGuestWSAvailable(): boolean {
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Search courses.
|
|
*
|
|
* @param text Text to search.
|
|
* @param page Page to get.
|
|
* @param perPage Number of courses per page. Defaults to CoreCoursesProvider.SEARCH_PER_PAGE.
|
|
* @param limitToEnrolled Limit to enrolled courses.
|
|
* @param siteId Site ID. If not defined, use current site.
|
|
* @return Promise resolved with the courses and the total of matches.
|
|
*/
|
|
async search(
|
|
text: string,
|
|
page: number = 0,
|
|
perPage: number = CoreCoursesProvider.SEARCH_PER_PAGE,
|
|
limitToEnrolled: boolean = false,
|
|
siteId?: string,
|
|
): Promise<{ total: number; courses: CoreCourseBasicSearchedData[] }> {
|
|
const site = await CoreSites.getSite(siteId);
|
|
const params: CoreCourseSearchCoursesWSParams = {
|
|
criterianame: 'search',
|
|
criteriavalue: text,
|
|
page: page,
|
|
perpage: perPage,
|
|
limittoenrolled: limitToEnrolled,
|
|
};
|
|
const preSets: CoreSiteWSPreSets = {
|
|
getFromCache: false,
|
|
};
|
|
|
|
const response = await site.read<CoreCourseSearchCoursesWSResponse>('core_course_search_courses', params, preSets);
|
|
|
|
return ({ total: response.total, courses: response.courses });
|
|
}
|
|
|
|
/**
|
|
* Self enrol current user in a certain course.
|
|
*
|
|
* @param courseId Course ID.
|
|
* @param password Password to use.
|
|
* @param instanceId Enrol instance ID.
|
|
* @param siteId Site ID. If not defined, use current site.
|
|
* @return Promise resolved if the user is enrolled. If the password is invalid, the promise is rejected
|
|
* with an object with errorcode = CoreCoursesProvider.ENROL_INVALID_KEY.
|
|
*/
|
|
async selfEnrol(courseId: number, password: string = '', instanceId?: number, siteId?: string): Promise<boolean> {
|
|
|
|
const site = await CoreSites.getSite(siteId);
|
|
|
|
const params: EnrolSelfEnrolUserWSParams = {
|
|
courseid: courseId,
|
|
password: password,
|
|
};
|
|
if (instanceId) {
|
|
params.instanceid = instanceId;
|
|
}
|
|
|
|
const response = await site.write<CoreStatusWithWarningsWSResponse>('enrol_self_enrol_user', params);
|
|
|
|
if (!response) {
|
|
throw Error('WS enrol_self_enrol_user failed');
|
|
}
|
|
|
|
if (response.status) {
|
|
return true;
|
|
}
|
|
|
|
if (response.warnings && response.warnings.length) {
|
|
// Invalid password warnings.
|
|
const warning = response.warnings.find((warning) =>
|
|
warning.warningcode == '2' || warning.warningcode == '3' || warning.warningcode == '4');
|
|
|
|
if (warning) {
|
|
throw new CoreWSError({ errorcode: CoreCoursesProvider.ENROL_INVALID_KEY, message: warning.message });
|
|
} else {
|
|
throw new CoreWSError(response.warnings[0]);
|
|
}
|
|
}
|
|
|
|
throw Error('WS enrol_self_enrol_user failed without warnings');
|
|
}
|
|
|
|
/**
|
|
* Set favourite property on a course.
|
|
*
|
|
* @param courseId Course ID.
|
|
* @param favourite If favourite or unfavourite.
|
|
* @param siteId Site ID. If not defined, use current site.
|
|
* @return Promise resolved when done.
|
|
*/
|
|
async setFavouriteCourse(courseId: number, favourite: boolean, siteId?: string): Promise<CoreWarningsWSResponse> {
|
|
const site = await CoreSites.getSite(siteId);
|
|
|
|
const params: CoreCourseSetFavouriteCoursesWSParams = {
|
|
courses: [
|
|
{
|
|
id: courseId,
|
|
favourite: favourite,
|
|
},
|
|
],
|
|
};
|
|
|
|
return site.write('core_course_set_favourite_courses', params);
|
|
}
|
|
|
|
/**
|
|
* Get download options enabled option.
|
|
*
|
|
* @return True if enabled, false otherwise.
|
|
*/
|
|
getCourseDownloadOptionsEnabled(): boolean {
|
|
return this.downloadOptionsEnabled;
|
|
}
|
|
|
|
/**
|
|
* Set trigger and save the download option.
|
|
*
|
|
* @param enable True to enable, false to disable.
|
|
*/
|
|
setCourseDownloadOptionsEnabled(enable: boolean): void {
|
|
if (this.downloadOptionsEnabled == enable) {
|
|
return;
|
|
}
|
|
|
|
this.downloadOptionsEnabled = enable;
|
|
CoreEvents.trigger(CoreCoursesProvider.EVENT_DASHBOARD_DOWNLOAD_ENABLED_CHANGED, { enabled: enable });
|
|
}
|
|
|
|
}
|
|
|
|
export const CoreCourses = makeSingleton(CoreCoursesProvider);
|
|
|
|
/**
|
|
* Data sent to the EVENT_MY_COURSES_UPDATED.
|
|
*/
|
|
export type CoreCoursesMyCoursesUpdatedEventData = {
|
|
action: string; // Action performed.
|
|
courseId?: number; // Course ID affected (if any).
|
|
course?: CoreCourseAnyCourseData; // Course affected (if any).
|
|
state?: string; // Only for ACTION_STATE_CHANGED. The state that changed (hidden, favourite).
|
|
value?: boolean; // The new value for the state changed.
|
|
};
|
|
|
|
/**
|
|
* Data sent to the EVENT_MY_COURSES_CHANGED.
|
|
*/
|
|
export type CoreCoursesMyCoursesChangedEventData = {
|
|
added: number[];
|
|
removed: number[];
|
|
};
|
|
|
|
/**
|
|
* Data sent to the EVENT_DASHBOARD_DOWNLOAD_ENABLED_CHANGED.
|
|
*/
|
|
export type CoreCoursesDashboardDownloadEnabledChangedEventData = {
|
|
enabled: boolean;
|
|
};
|
|
|
|
/**
|
|
* Params of core_enrol_get_users_courses WS.
|
|
*/
|
|
type CoreEnrolGetUsersCoursesWSParams = {
|
|
userid: number; // User id.
|
|
returnusercount?: boolean; // Include count of enrolled users for each course? This can add several seconds to the response
|
|
// time if a user is on several large courses, so set this to false if the value will not be used to improve performance.
|
|
};
|
|
|
|
/**
|
|
* Data returned by core_enrol_get_users_courses WS.
|
|
*/
|
|
type CoreEnrolGetUsersCoursesWSResponse = (CoreEnrolledCourseData & {
|
|
category?: number; // Course category id.
|
|
})[];
|
|
|
|
/**
|
|
* Basic data obtained form any course.
|
|
*/
|
|
export type CoreCourseBasicData = {
|
|
id: number; // Course id.
|
|
fullname: string; // Course full name.
|
|
displayname?: string; // Course display name.
|
|
shortname: string; // Course short name.
|
|
summary: string; // Summary.
|
|
summaryformat: number; // Summary format (1 = HTML, 0 = MOODLE, 2 = PLAIN or 4 = MARKDOWN).
|
|
categoryid?: number; // Course category id.
|
|
};
|
|
|
|
/**
|
|
* Basic data obtained from a course when the user is enrolled.
|
|
*/
|
|
export type CoreEnrolledCourseBasicData = CoreCourseBasicData & {
|
|
idnumber?: string; // Id number of course.
|
|
visible?: number; // 1 means visible, 0 means not yet visible course.
|
|
format?: string; // Course format: weeks, topics, social, site.
|
|
showgrades?: boolean; // True if grades are shown, otherwise false.
|
|
lang?: string; // Forced course language.
|
|
enablecompletion?: boolean; // True if completion is enabled, otherwise false.
|
|
startdate?: number; // Timestamp when the course start.
|
|
enddate?: number; // Timestamp when the course end.
|
|
};
|
|
|
|
/**
|
|
* Course Data model received when the user is enrolled.
|
|
*/
|
|
export type CoreEnrolledCourseData = CoreEnrolledCourseBasicData & {
|
|
enrolledusercount?: number; // Number of enrolled users in this course.
|
|
completionhascriteria?: boolean; // If completion criteria is set.
|
|
completionusertracked?: boolean; // If the user is completion tracked.
|
|
progress?: number | null; // Progress percentage.
|
|
completed?: boolean; // @since 3.6. Whether the course is completed.
|
|
marker?: number; // @since 3.6. Course section marker.
|
|
lastaccess?: number; // @since 3.6. Last access to the course (timestamp).
|
|
isfavourite?: boolean; // If the user marked this course a favourite.
|
|
hidden?: boolean; // If the user hide the course from the dashboard.
|
|
overviewfiles?: CoreWSExternalFile[]; // @since 3.6.
|
|
showactivitydates?: boolean; // @since 3.11. Whether the activity dates are shown or not.
|
|
showcompletionconditions?: boolean; // @since 3.11. Whether the activity completion conditions are shown or not.
|
|
timemodified?: number; // @since 4.0. Last time course settings were updated (timestamp).
|
|
};
|
|
|
|
/**
|
|
* Basic course data received on search.
|
|
*/
|
|
export type CoreCourseBasicSearchedData = CoreCourseBasicData & {
|
|
categoryid: number; // Category id.
|
|
categoryname: string; // Category name.
|
|
sortorder?: number; // Sort order in the category.
|
|
summaryfiles?: CoreWSExternalFile[];
|
|
overviewfiles: CoreWSExternalFile[];
|
|
contacts: { // Contact users.
|
|
id: number; // Contact user id.
|
|
fullname: string; // Contact user fullname.
|
|
}[];
|
|
enrollmentmethods: string[]; // Enrollment methods list.
|
|
customfields?: CoreCourseCustomField[]; // Custom fields and associated values.
|
|
showactivitydates?: boolean; // @since 3.11. Whether the activity dates are shown or not.
|
|
showcompletionconditions?: boolean; // @since 3.11. Whether the activity completion conditions are shown or not.
|
|
};
|
|
|
|
export type CoreCourseSearchedData = CoreCourseBasicSearchedData & {
|
|
idnumber?: string; // Id number.
|
|
format?: string; // Course format: weeks, topics, social, site,..
|
|
showgrades?: number; // 1 if grades are shown, otherwise 0.
|
|
newsitems?: number; // Number of recent items appearing on the course page.
|
|
startdate?: number; // Timestamp when the course start.
|
|
enddate?: number; // Timestamp when the course end.
|
|
maxbytes?: number; // Largest size of file that can be uploaded into.
|
|
showreports?: number; // Are activity report shown (yes = 1, no =0).
|
|
visible?: number; // 1: available to student, 0:not available.
|
|
groupmode?: number; // No group, separate, visible.
|
|
groupmodeforce?: number; // 1: yes, 0: no.
|
|
defaultgroupingid?: number; // Default grouping id.
|
|
enablecompletion?: number; // Completion enabled? 1: yes 0: no.
|
|
completionnotify?: number; // 1: yes 0: no.
|
|
lang?: string; // Forced course language.
|
|
theme?: string; // Fame of the forced theme.
|
|
marker?: number; // Current course marker.
|
|
legacyfiles?: number; // If legacy files are enabled.
|
|
calendartype?: string; // Calendar type.
|
|
timecreated?: number; // Time when the course was created.
|
|
timemodified?: number; // Last time the course was updated.
|
|
requested?: number; // If is a requested course.
|
|
cacherev?: number; // Cache revision number.
|
|
filters?: { // Course filters.
|
|
filter: string; // Filter plugin name.
|
|
localstate: number; // Filter state: 1 for on, -1 for off, 0 if inherit.
|
|
inheritedstate: number; // 1 or 0 to use when localstate is set to inherit.
|
|
}[];
|
|
courseformatoptions?: CoreCourseFormatOption[]; // Additional options for particular course format.
|
|
};
|
|
|
|
/**
|
|
* Course to render as list item.
|
|
*/
|
|
export type CoreCourseListItem = ((CoreCourseSearchedData & CoreCourseWithImageAndColor) |
|
|
CoreCourseAnyCourseDataWithExtraInfoAndOptions) & {
|
|
isfavourite?: boolean; // If the user marked this course a favourite.
|
|
hidden?: boolean; // If the user hide the course from the dashboard.
|
|
completionusertracked?: boolean; // If the user is completion tracked.
|
|
progress?: number | null; // Progress percentage.
|
|
};
|
|
|
|
export type CoreCourseGetCoursesData = CoreEnrolledCourseBasicData & {
|
|
categoryid: number; // Category id.
|
|
categorysortorder?: number; // Sort order into the category.
|
|
newsitems?: number; // Number of recent items appearing on the course page.
|
|
/**
|
|
* Number of weeks/topics.
|
|
*
|
|
* @deprecated use courseformatoptions.
|
|
*/
|
|
numsections?: number;
|
|
maxbytes?: number; // Largest size of file that can be uploaded into the course.
|
|
showreports?: number; // Are activity report shown (yes = 1, no =0).
|
|
/**
|
|
* How the hidden sections in the course are displayed to students.
|
|
*
|
|
* @deprecated use courseformatoptions.
|
|
*/
|
|
hiddensections?: number;
|
|
groupmode?: number; // No group, separate, visible.
|
|
groupmodeforce?: number; // 1: yes, 0: no.
|
|
defaultgroupingid?: number; // Default grouping id.
|
|
timecreated?: number; // Timestamp when the course have been created.
|
|
timemodified?: number; // Timestamp when the course have been modified.
|
|
completionnotify?: number; // 1: yes 0: no.
|
|
forcetheme?: string; // Name of the force theme.
|
|
courseformatoptions?: CoreCourseFormatOption[]; // Additional options for particular course format.
|
|
customfields?: CoreCourseCustomField[]; // Custom fields and associated values.
|
|
showactivitydates?: boolean; // @since 3.11. Whether the activity dates are shown or not.
|
|
showcompletionconditions?: boolean; // @since 3.11. Whether the activity completion conditions are shown or not.
|
|
};
|
|
|
|
/**
|
|
* Course custom fields and associated values.
|
|
*/
|
|
export type CoreCourseCustomField = {
|
|
name: string; // The name of the custom field.
|
|
shortname: string; // The shortname of the custom field.
|
|
type: string; // The type of the custom field - text, checkbox...
|
|
valueraw: string; // The raw value of the custom field.
|
|
value: string; // The value of the custom field.
|
|
};
|
|
|
|
/**
|
|
* Additional options for particular course format.
|
|
*/
|
|
export type CoreCourseFormatOption = {
|
|
name: string; // Course format option name.
|
|
value: string; // Course format option value.
|
|
};
|
|
|
|
/**
|
|
* Indexed course format options.
|
|
*/
|
|
export type CoreCourseFormatOptionsIndexed = {
|
|
[name: string]: string;
|
|
};
|
|
|
|
/**
|
|
* Params of core_course_get_courses_by_field WS.
|
|
*/
|
|
type CoreCourseGetCoursesByFieldWSParams = {
|
|
/**
|
|
* The field to search can be left empty for all courses or:
|
|
* id: course id
|
|
* ids: comma separated course ids
|
|
* shortname: course short name
|
|
* idnumber: course id number
|
|
* category: category id the course belongs to.
|
|
*/
|
|
field?: string;
|
|
value?: string | number; // The value to match.
|
|
};
|
|
|
|
/**
|
|
* Data returned by core_course_get_courses_by_field WS.
|
|
*/
|
|
export type CoreCourseGetCoursesByFieldWSResponse = {
|
|
courses: CoreCourseSearchedData[];
|
|
warnings?: CoreWSExternalWarning[];
|
|
};
|
|
|
|
/**
|
|
* Params of core_course_search_courses WS.
|
|
*/
|
|
type CoreCourseSearchCoursesWSParams = {
|
|
criterianame: string; // Criteria name (search, modulelist (only admins), blocklist (only admins), tagid).
|
|
criteriavalue: string; // Criteria value.
|
|
page?: number; // Page number (0 based).
|
|
perpage?: number; // Items per page.
|
|
requiredcapabilities?: string[]; // Optional list of required capabilities (used to filter the list).
|
|
limittoenrolled?: boolean; // Limit to enrolled courses.
|
|
onlywithcompletion?: boolean; // Limit to courses where completion is enabled.
|
|
};
|
|
|
|
/**
|
|
* Data returned by core_course_search_courses WS.
|
|
*/
|
|
export type CoreCourseSearchCoursesWSResponse = {
|
|
total: number; // Total course count.
|
|
courses: CoreCourseBasicSearchedData[];
|
|
warnings?: CoreWSExternalWarning[];
|
|
};
|
|
|
|
/**
|
|
* Params of core_course_get_courses WS.
|
|
*/
|
|
type CoreCourseGetCoursesWSParams = {
|
|
options?: {
|
|
ids?: number[]; // List of course id. If empty return all courses except front page course.
|
|
}; // Options - operator OR is used.
|
|
};
|
|
|
|
/**
|
|
* Data returned by core_course_get_courses WS.
|
|
*/
|
|
export type CoreCourseGetCoursesWSResponse = CoreCourseGetCoursesData[];
|
|
|
|
/**
|
|
* Course data exported by course_summary_exporter;
|
|
*/
|
|
export type CoreCourseSummaryData = CoreCourseBasicData & { // Course.
|
|
idnumber: string; // Idnumber.
|
|
startdate: number; // Startdate.
|
|
enddate: number; // Enddate.
|
|
visible: boolean; // Visible.
|
|
showactivitydates: boolean; // Showactivitydates.
|
|
showcompletionconditions: boolean; // Showcompletionconditions.
|
|
fullnamedisplay: string; // Fullnamedisplay.
|
|
viewurl: string; // Viewurl.
|
|
courseimage: string; // Courseimage.
|
|
progress?: number; // Progress.
|
|
hasprogress: boolean; // Hasprogress.
|
|
isfavourite: boolean; // Isfavourite.
|
|
hidden: boolean; // Hidden.
|
|
timeaccess?: number; // Timeaccess.
|
|
showshortname: boolean; // Showshortname.
|
|
coursecategory: string; // Coursecategory.
|
|
};
|
|
|
|
/**
|
|
* Params of core_course_get_enrolled_courses_by_timeline_classification WS.
|
|
*/
|
|
type CoreCourseGetEnrolledCoursesByTimelineClassificationWSParams = {
|
|
classification: string; // Future, inprogress, or past.
|
|
limit?: number; // Result set limit.
|
|
offset?: number; // Result set offset.
|
|
sort?: string; // Sort string.
|
|
customfieldname?: string; // Used when classification = customfield.
|
|
customfieldvalue?: string; // Used when classification = customfield.
|
|
};
|
|
|
|
/**
|
|
* Data returned by core_course_get_enrolled_courses_by_timeline_classification WS.
|
|
*/
|
|
export type CoreCourseGetEnrolledCoursesByTimelineClassificationWSResponse = {
|
|
courses: CoreCourseSummaryData[];
|
|
nextoffset: number; // Offset for the next request.
|
|
};
|
|
|
|
/**
|
|
* Params of core_course_get_categories WS.
|
|
*/
|
|
type CoreCourseGetCategoriesWSParams = {
|
|
criteria?: { // Criteria.
|
|
/**
|
|
* The category column to search, expected keys (value format) are:
|
|
* "id" (int) the category id,
|
|
* "ids" (string) category ids separated by commas,
|
|
* "name" (string) the category name,
|
|
* "parent" (int) the parent category id,
|
|
* "idnumber" (string) category idnumber - user must have 'moodle/category:manage' to search on idnumber,
|
|
* "visible" (int) whether the returned categories must be visible or hidden.
|
|
* If the key is not passed, then the function return all categories that the user can see..
|
|
*/
|
|
key: string;
|
|
value: string | number; // The value to match.
|
|
}[];
|
|
addsubcategories?: boolean; // Return the sub categories infos (1 - default) otherwise only the category info (0).
|
|
};
|
|
|
|
/**
|
|
* Data returned by core_course_get_categories WS.
|
|
*/
|
|
export type CoreCourseGetCategoriesWSResponse = CoreCategoryData[];
|
|
|
|
/**
|
|
* Category data model.
|
|
*/
|
|
export type CoreCategoryData = {
|
|
id: number; // Category id.
|
|
name: string; // Category name.
|
|
idnumber?: string; // Category id number.
|
|
description: string; // Category description.
|
|
descriptionformat: number; // Description format (1 = HTML, 0 = MOODLE, 2 = PLAIN or 4 = MARKDOWN).
|
|
parent: number; // Parent category id.
|
|
sortorder: number; // Category sorting order.
|
|
coursecount: number; // Number of courses in this category.
|
|
visible?: number; // 1: available, 0:not available.
|
|
visibleold?: number; // 1: available, 0:not available.
|
|
timemodified?: number; // Timestamp.
|
|
depth: number; // Category depth.
|
|
path: string; // Category path.
|
|
theme?: string; // Category theme.
|
|
};
|
|
|
|
/**
|
|
* Params of core_course_get_user_navigation_options and core_course_get_user_administration_options WS.
|
|
*/
|
|
type CoreCourseGetUserAdminOrNavOptionsWSParams = {
|
|
courseids: number[];
|
|
};
|
|
|
|
/**
|
|
* Data returned by core_course_get_user_navigation_options and core_course_get_user_administration_options WS.
|
|
*/
|
|
export type CoreCourseGetUserAdminOrNavOptionsWSResponse = {
|
|
courses: CoreCourseUserAdminOrNavOption[];
|
|
warnings?: CoreWSExternalWarning[];
|
|
};
|
|
|
|
/**
|
|
* Admin or navigation option data.
|
|
*/
|
|
export type CoreCourseUserAdminOrNavOption = {
|
|
id: number; // Course id.
|
|
options: {
|
|
name: string; // Option name.
|
|
available: boolean; // Whether the option is available or not.
|
|
}[];
|
|
};
|
|
|
|
/**
|
|
* Indexed administration or navigation course options.
|
|
*/
|
|
export type CoreCourseUserAdminOrNavOptionCourseIndexed = {
|
|
[id: number]: CoreCourseUserAdminOrNavOptionIndexed;
|
|
};
|
|
|
|
/**
|
|
* Indexed administration or navigation options.
|
|
*/
|
|
export type CoreCourseUserAdminOrNavOptionIndexed = {
|
|
[name: string]: // Option name.
|
|
boolean; // Whether the option is available or not.
|
|
};
|
|
|
|
/**
|
|
* Params of core_enrol_get_course_enrolment_methods WS.
|
|
*/
|
|
type CoreEnrolGetCourseEnrolmentMethodsWSParams = {
|
|
courseid: number; // Course id.
|
|
};
|
|
|
|
/**
|
|
* Course enrolment method.
|
|
*/
|
|
export type CoreCourseEnrolmentMethod = {
|
|
id: number; // Id of course enrolment instance.
|
|
courseid: number; // Id of course.
|
|
type: string; // Type of enrolment plugin.
|
|
name: string; // Name of enrolment plugin.
|
|
status: string; // Status of enrolment plugin.
|
|
wsfunction?: string; // Webservice function to get more information.
|
|
};
|
|
|
|
/**
|
|
* Params of enrol_guest_get_instance_info WS.
|
|
*/
|
|
type EnrolGuestGetInstanceInfoWSParams = {
|
|
instanceid: number; // Instance id of guest enrolment plugin.
|
|
};
|
|
|
|
/**
|
|
* Data returned by enrol_guest_get_instance_info WS.
|
|
*/
|
|
export type EnrolGuestGetInstanceInfoWSResponse = {
|
|
instanceinfo: CoreCourseEnrolmentGuestMethod;
|
|
warnings?: CoreWSExternalWarning[];
|
|
};
|
|
|
|
/**
|
|
* Params of core_course_get_recent_courses WS.
|
|
*/
|
|
export type CoreCourseGetRecentCoursesWSParams = {
|
|
userid?: number; // Id of the user, default to current user.
|
|
limit?: number; // Result set limit.
|
|
offset?: number; // Result set offset.
|
|
sort?: string; // Sort string.
|
|
};
|
|
|
|
/**
|
|
* Options for getRecentCourses.
|
|
*/
|
|
export type CoreCourseGetRecentCoursesOptions = CoreSitesCommonWSOptions & {
|
|
userId?: number; // Id of the user, default to current user.
|
|
limit?: number; // Result set limit.
|
|
offset?: number; // Result set offset.
|
|
sort?: string; // Sort string.
|
|
};
|
|
|
|
/**
|
|
* Course guest enrolment method.
|
|
*/
|
|
export type CoreCourseEnrolmentGuestMethod = CoreCourseEnrolmentMethod & {
|
|
passwordrequired: boolean; // Is a password required?.
|
|
};
|
|
|
|
/**
|
|
* Params of enrol_self_enrol_user WS.
|
|
*/
|
|
type EnrolSelfEnrolUserWSParams = {
|
|
courseid: number; // Id of the course.
|
|
password?: string; // Enrolment key.
|
|
instanceid?: number; // Instance id of self enrolment plugin.
|
|
};
|
|
|
|
/**
|
|
* Params of core_course_set_favourite_courses WS.
|
|
*/
|
|
type CoreCourseSetFavouriteCoursesWSParams = {
|
|
courses: {
|
|
id: number; // Course ID.
|
|
favourite: boolean; // Favourite status.
|
|
}[];
|
|
};
|
|
|
|
/**
|
|
* Any of the possible course data.
|
|
*/
|
|
export type CoreCourseAnyCourseData = CoreEnrolledCourseData | CoreCourseSearchedData | CoreCourseGetCoursesData;
|
|
|
|
/**
|
|
* Course data with admin and navigation option availability.
|
|
*/
|
|
export type CoreCourseAnyCourseDataWithOptions = CoreCourseAnyCourseData & {
|
|
navOptions?: CoreCourseUserAdminOrNavOptionIndexed;
|
|
admOptions?: CoreCourseUserAdminOrNavOptionIndexed;
|
|
};
|