Vmeda.Online/src/core/courses/providers/courses.ts

1037 lines
39 KiB
TypeScript

// (C) Copyright 2015 Martin Dougiamas
//
// 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 { CoreLoggerProvider } from '@providers/logger';
import { CoreSitesProvider } from '@providers/sites';
import { CoreSite } from '@classes/site';
/**
* Service that provides some features regarding lists of courses and categories.
*/
@Injectable()
export class CoreCoursesProvider {
static SEARCH_PER_PAGE = 20;
static ENROL_INVALID_KEY = 'CoreCoursesEnrolInvalidKey';
static EVENT_MY_COURSES_UPDATED = 'courses_my_courses_updated';
static EVENT_MY_COURSES_REFRESHED = 'courses_my_courses_refreshed';
static EVENT_DASHBOARD_DOWNLOAD_ENABLED_CHANGED = 'dashboard_download_enabled_changed';
protected ROOT_CACHE_KEY = 'mmCourses:';
protected logger;
constructor(logger: CoreLoggerProvider, private sitesProvider: CoreSitesProvider) {
this.logger = logger.getInstance('CoreCoursesProvider');
}
/**
* Whether current site supports getting course options.
*
* @return {boolean} Whether current site supports getting course options.
*/
canGetAdminAndNavOptions(): boolean {
return this.sitesProvider.wsAvailableInCurrentSite('core_course_get_user_navigation_options') &&
this.sitesProvider.wsAvailableInCurrentSite('core_course_get_user_administration_options');
}
/**
* Get categories. They can be filtered by id.
*
* @param {number} categoryId Category ID to get.
* @param {boolean} [addSubcategories] If it should add subcategories to the list.
* @param {string} [siteId] Site to get the courses from. If not defined, use current site.
* @return {Promise<any[]>} Promise resolved with the categories.
*/
getCategories(categoryId: number, addSubcategories?: boolean, siteId?: string): Promise<any[]> {
return this.sitesProvider.getSite(siteId).then((site) => {
// Get parent when id is the root category.
const criteriaKey = categoryId == 0 ? 'parent' : 'id',
data = {
criteria: [
{ key: criteriaKey, value: categoryId }
],
addsubcategories: addSubcategories ? 1 : 0
},
preSets = {
cacheKey: this.getCategoriesCacheKey(categoryId, addSubcategories),
updateFrequency: CoreSite.FREQUENCY_RARELY
};
return site.read('core_course_get_categories', data, preSets);
});
}
/**
* Get cache key for get categories methods WS call.
*
* @param {number} categoryId Category ID to get.
* @param {boolean} [addSubcategories] If add subcategories to the list.
* @return {string} Cache key.
*/
protected getCategoriesCacheKey(categoryId: number, addSubcategories?: boolean): string {
return this.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 {number[]} courseIds Course IDs.
* @param {string} [siteId] Site Id. If not defined, use current site.
* @return {Promise} Promise resolved with the list of course IDs.
*/
protected getCourseIdsForAdminAndNavOptions(courseIds: number[], siteId?: string): Promise<number[]> {
return this.sitesProvider.getSite(siteId).then((site) => {
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.getUserCourses(true, siteId).then((courses) => {
const courseId = courseIds[0];
let useAllCourses = false;
if (courseId == siteHomeId) {
// It's site home, use all courses.
useAllCourses = true;
} else {
for (let i = 0; i < courses.length; i++) {
if (courses[i].id == courseId) {
useAllCourses = true;
break;
}
}
}
if (useAllCourses) {
// User is enrolled, retrieve all the courses.
courseIds = courses.map((course) => {
return course.id;
});
// Always add the site home ID.
courseIds.push(siteHomeId);
// Sort the course IDs.
courseIds.sort((a, b) => {
return b - a;
});
}
return courseIds;
}).catch(() => {
// Ignore errors.
return courseIds;
});
} else {
if (courseIds.length > 1 && courseIds.indexOf(siteHomeId) == -1) {
courseIds.push(siteHomeId);
}
// Sort the course IDs.
courseIds.sort((a, b) => {
return b - a;
});
return courseIds;
}
});
}
/**
* Check if download a whole course is disabled in a certain site.
*
* @param {string} [siteId] Site Id. If not defined, use current site.
* @return {Promise<boolean>} Promise resolved with true if disabled, rejected or resolved with false otherwise.
*/
isDownloadCourseDisabled(siteId?: string): Promise<boolean> {
return this.sitesProvider.getSite(siteId).then((site) => {
return this.isDownloadCoursesDisabledInSite(site);
});
}
/**
* Check if download a whole course is disabled in a certain site.
*
* @param {CoreSite} [site] Site. If not defined, use current site.
* @return {boolean} Whether it's disabled.
*/
isDownloadCourseDisabledInSite(site?: CoreSite): boolean {
site = site || this.sitesProvider.getCurrentSite();
return site.isFeatureDisabled('NoDelegate_CoreCourseDownload');
}
/**
* Check if download all courses is disabled in a certain site.
*
* @param {string} [siteId] Site Id. If not defined, use current site.
* @return {Promise<boolean>} Promise resolved with true if disabled, rejected or resolved with false otherwise.
*/
isDownloadCoursesDisabled(siteId?: string): Promise<boolean> {
return this.sitesProvider.getSite(siteId).then((site) => {
return this.isDownloadCoursesDisabledInSite(site);
});
}
/**
* Check if download all courses is disabled in a certain site.
*
* @param {CoreSite} [site] Site. If not defined, use current site.
* @return {boolean} Whether it's disabled.
*/
isDownloadCoursesDisabledInSite(site?: CoreSite): boolean {
site = site || this.sitesProvider.getCurrentSite();
return site.isFeatureDisabled('NoDelegate_CoreCoursesDownload');
}
/**
* Check if My Courses is disabled in a certain site.
*
* @param {string} [siteId] Site Id. If not defined, use current site.
* @return {Promise<boolean>} Promise resolved with true if disabled, rejected or resolved with false otherwise.
*/
isMyCoursesDisabled(siteId?: string): Promise<boolean> {
return this.sitesProvider.getSite(siteId).then((site) => {
return this.isMyCoursesDisabledInSite(site);
});
}
/**
* Check if My Courses is disabled in a certain site.
*
* @param {CoreSite} [site] Site. If not defined, use current site.
* @return {boolean} Whether it's disabled.
*/
isMyCoursesDisabledInSite(site?: CoreSite): boolean {
site = site || this.sitesProvider.getCurrentSite();
return site.isFeatureDisabled('CoreMainMenuDelegate_CoreCourses');
}
/**
* Check if Search Courses is disabled in a certain site.
*
* @param {string} [siteId] Site Id. If not defined, use current site.
* @return {Promise<boolean>} Promise resolved with true if disabled, rejected or resolved with false otherwise.
*/
isSearchCoursesDisabled(siteId?: string): Promise<boolean> {
return this.sitesProvider.getSite(siteId).then((site) => {
return this.isSearchCoursesDisabledInSite(site);
});
}
/**
* Check if Search Courses is disabled in a certain site.
*
* @param {CoreSite} [site] Site. If not defined, use current site.
* @return {boolean} Whether it's disabled.
*/
isSearchCoursesDisabledInSite(site?: CoreSite): boolean {
site = site || this.sitesProvider.getCurrentSite();
return site.isFeatureDisabled('CoreCourseOptionsDelegate_search');
}
/**
* Get course.
*
* @param {number} id ID of the course to get.
* @param {string} [siteId] Site to get the courses from. If not defined, use current site.
* @return {Promise<any>} Promise resolved with the course.
*/
getCourse(id: number, siteId?: string): Promise<any> {
return this.getCourses([id], siteId).then((courses) => {
if (courses && courses.length > 0) {
return courses[0];
}
return Promise.reject(null);
});
}
/**
* Get the enrolment methods from a course.
*
* @param {number} id ID of the course.
* @param {string} [siteId] Site ID. If not defined, use current site.
* @return {Promise<any[]} Promise resolved with the methods.
*/
getCourseEnrolmentMethods(id: number, siteId?: string): Promise<any[]> {
return this.sitesProvider.getSite(siteId).then((site) => {
const params = {
courseid: id
},
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 {number} id Course ID.
* @return {string} Cache key.
*/
protected getCourseEnrolmentMethodsCacheKey(id: number): string {
return this.ROOT_CACHE_KEY + 'enrolmentmethods:' + id;
}
/**
* Get info from a course guest enrolment method.
*
* @param {number} instanceId Guest instance ID.
* @param {string} [siteId] Site ID. If not defined, use current site.
* @return {Promise<any>} Promise resolved when the info is retrieved.
*/
getCourseGuestEnrolmentInfo(instanceId: number, siteId?: string): Promise<any> {
return this.sitesProvider.getSite(siteId).then((site) => {
const params = {
instanceid: instanceId
},
preSets = {
cacheKey: this.getCourseGuestEnrolmentInfoCacheKey(instanceId),
updateFrequency: CoreSite.FREQUENCY_RARELY
};
return site.read('enrol_guest_get_instance_info', params, preSets).then((response) => {
return response.instanceinfo;
});
});
}
/**
* Get cache key for get course guest enrolment methods WS call.
*
* @param {number} instanceId Guest instance ID.
* @return {string} Cache key.
*/
protected getCourseGuestEnrolmentInfoCacheKey(instanceId: number): string {
return this.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 {number[]} ids List of IDs of the courses to get.
* @param {string} [siteId] Site to get the courses from. If not defined, use current site.
* @return {Promise<any[]>} Promise resolved with the courses.
*/
getCourses(ids: number[], siteId?: string): Promise<any[]> {
if (!Array.isArray(ids)) {
return Promise.reject(null);
} else if (ids.length === 0) {
return Promise.resolve([]);
}
return this.sitesProvider.getSite(siteId).then((site) => {
const data = {
options: {
ids: ids
}
},
preSets = {
cacheKey: this.getCoursesCacheKey(ids),
updateFrequency: CoreSite.FREQUENCY_RARELY
};
return site.read('core_course_get_courses', data, preSets);
});
}
/**
* Get cache key for get courses WS call.
*
* @param {number[]} ids Courses IDs.
* @return {string} Cache key.
*/
protected getCoursesCacheKey(ids: number[]): string {
return this.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 {string} [field] The field to search.
* @param {any} [value] The value to match.
* @param {string} [siteId] Site ID. If not defined, use current site.
* @return {Promise<{field: string, value: any}>} Promise resolved with the field and value to use.
*/
protected fixCoursesByFieldParams(field?: string, value?: any, siteId?: string): Promise<{field: string, value: any}> {
if (field == 'id' || field == 'ids') {
const courseIds: any[] = String(value).split(',');
// Use the same optimization as in get admin and nav options. This will return the course IDs to use.
return this.getCourseIdsForAdminAndNavOptions(courseIds, siteId).then((courseIds) => {
if (courseIds.length > 1) {
return {field: 'ids', value: courseIds.join(',')};
} else {
return {field: 'id', value: Number(courseIds[0])};
}
});
} else {
// Nothing to do.
return Promise.resolve({field: field, value: value});
}
}
/**
* Get the first course returned by getCoursesByField.
*
* @param {string} [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 {any} [value] The value to match.
* @param {string} [siteId] Site ID. If not defined, use current site.
* @return {Promise<any>} Promise resolved with the first course.
* @since 3.2
*/
getCourseByField(field?: string, value?: any, siteId?: string): Promise<any> {
return this.getCoursesByField(field, value, siteId).then((courses) => {
if (courses && courses.length > 0) {
return courses[0];
}
return Promise.reject(null);
});
}
/**
* Get courses. They can be filtered by field.
*
* @param {string} [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 {any} [value] The value to match.
* @param {string} [siteId] Site ID. If not defined, use current site.
* @return {Promise<any[]>} Promise resolved with the courses.
* @since 3.2
*/
getCoursesByField(field?: string, value?: any, siteId?: string): Promise<any[]> {
siteId = siteId || this.sitesProvider.getCurrentSiteId();
const originalValue = value;
let hasChanged = false;
return this.fixCoursesByFieldParams(field, value, siteId).then((result) => {
hasChanged = result.field != field || result.value != value;
field = result.field;
value = result.value;
return this.sitesProvider.getSite(siteId);
}).then((site) => {
const data = {
field: field || '',
value: field ? value : ''
},
preSets = {
cacheKey: this.getCoursesByFieldCacheKey(field, value),
updateFrequency: CoreSite.FREQUENCY_RARELY
};
return site.read('core_course_get_courses_by_field', data, preSets).then((courses) => {
if (courses.courses) {
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(','),
finalCourses = [];
courses.courses.forEach((course) => {
const position = courseIds.indexOf(String(course.id));
if (position != -1) {
// Course is in the original list, take it.
finalCourses.push(course);
courseIds.splice(position, 1);
}
});
courses.courses = finalCourses;
}
// Courses will be sorted using sortorder if avalaible.
return courses.courses.sort((a, b) => {
if (typeof a.sortorder == 'undefined' && typeof b.sortorder == 'undefined') {
return b.id - a.id;
}
if (typeof a.sortorder == 'undefined') {
return 1;
}
if (typeof b.sortorder == 'undefined') {
return -1;
}
return a.sortorder - b.sortorder;
});
}
return Promise.reject(null);
});
});
}
/**
* Get cache key for get courses WS call.
*
* @param {string} [field] The field to search.
* @param {any} [value] The value to match.
* @return {string} Cache key.
*/
protected getCoursesByFieldCacheKey(field?: string, value?: any): string {
field = field || '';
value = field ? value : '';
return this.ROOT_CACHE_KEY + 'coursesbyfield:' + field + ':' + value;
}
/**
* Check if get courses by field WS is available in a certain site.
*
* @param {CoreSite} [site] Site to check.
* @return {boolean} Whether get courses by field is available.
* @since 3.2
*/
isGetCoursesByFieldAvailable(site?: CoreSite): boolean {
site = site || this.sitesProvider.getCurrentSite();
return site.wsAvailable('core_course_get_courses_by_field');
}
/**
* Check if get courses by field WS is available in a certain site, by site ID.
*
* @param {string} [siteId] Site ID. If not defined, current site.
* @return {Promise<boolean>} Promise resolved with boolean: whether get courses by field is available.
* @since 3.2
*/
isGetCoursesByFieldAvailableInSite(siteId?: string): Promise<boolean> {
return this.sitesProvider.getSite(siteId).then((site) => {
return this.isGetCoursesByFieldAvailable(site);
});
}
/**
* Get the navigation and administration options for the given courses.
*
* @param {number[]} courseIds IDs of courses to get.
* @param {string} [siteId] Site ID. If not defined, current site.
* @return {Promise<{navOptions: any, admOptions: any}>} Promise resolved with the options for each course.
*/
getCoursesAdminAndNavOptions(courseIds: number[], siteId?: string): Promise<{ navOptions: any, admOptions: any }> {
siteId = siteId || this.sitesProvider.getCurrentSiteId();
// Get the list of courseIds to use based on the param.
return this.getCourseIdsForAdminAndNavOptions(courseIds, siteId).then((courseIds) => {
const promises = [];
let navOptions,
admOptions;
// Get user navigation and administration options.
promises.push(this.getUserNavigationOptions(courseIds, siteId).catch(() => {
// Couldn't get it, return empty options.
return {};
}).then((options) => {
navOptions = options;
}));
promises.push(this.getUserAdministrationOptions(courseIds, siteId).catch(() => {
// Couldn't get it, return empty options.
return {};
}).then((options) => {
admOptions = options;
}));
return Promise.all(promises).then(() => {
return { navOptions: navOptions, admOptions: admOptions };
});
});
}
/**
* Get the common part of the cache keys for user administration options WS calls.
*
* @return {string} Cache key.
*/
protected getUserAdministrationOptionsCommonCacheKey(): string {
return this.ROOT_CACHE_KEY + 'administrationOptions:';
}
/**
* Get cache key for get user administration options WS call.
*
* @param {number[]} courseIds IDs of courses to get.
* @return {string} Cache key.
*/
protected getUserAdministrationOptionsCacheKey(courseIds: number[]): string {
return this.getUserAdministrationOptionsCommonCacheKey() + courseIds.join(',');
}
/**
* Get user administration options for a set of courses.
*
* @param {number[]} courseIds IDs of courses to get.
* @param {string} [siteId] Site ID. If not defined, current site.
* @return {Promise<any>} Promise resolved with administration options for each course.
*/
getUserAdministrationOptions(courseIds: number[], siteId?: string): Promise<any> {
if (!courseIds || courseIds.length == 0) {
return Promise.resolve({});
}
return this.sitesProvider.getSite(siteId).then((site) => {
const params = {
courseids: courseIds
},
preSets = {
cacheKey: this.getUserAdministrationOptionsCacheKey(courseIds),
updateFrequency: CoreSite.FREQUENCY_RARELY
};
return site.read('core_course_get_user_administration_options', params, preSets).then((response) => {
// Format returned data.
return this.formatUserAdminOrNavOptions(response.courses);
});
});
}
/**
* Get the common part of the cache keys for user navigation options WS calls.
*
* @param {number[]} courseIds IDs of courses to get.
* @return {string} Cache key.
*/
protected getUserNavigationOptionsCommonCacheKey(): string {
return this.ROOT_CACHE_KEY + 'navigationOptions:';
}
/**
* Get cache key for get user navigation options WS call.
*
* @return {string} Cache key.
*/
protected getUserNavigationOptionsCacheKey(courseIds: number[]): string {
return this.getUserNavigationOptionsCommonCacheKey() + courseIds.join(',');
}
/**
* Get user navigation options for a set of courses.
*
* @param {number[]} courseIds IDs of courses to get.
* @param {string} [siteId] Site ID. If not defined, current site.
* @return {Promise<any>} Promise resolved with navigation options for each course.
*/
getUserNavigationOptions(courseIds: number[], siteId?: string): Promise<any> {
if (!courseIds || courseIds.length == 0) {
return Promise.resolve({});
}
return this.sitesProvider.getSite(siteId).then((site) => {
const params = {
courseids: courseIds
},
preSets = {
cacheKey: this.getUserNavigationOptionsCacheKey(courseIds),
updateFrequency: CoreSite.FREQUENCY_RARELY
};
return site.read('core_course_get_user_navigation_options', params, preSets).then((response) => {
// Format returned data.
return this.formatUserAdminOrNavOptions(response.courses);
});
});
}
/**
* Format user navigation or administration options.
*
* @param {any[]} courses Navigation or administration options for each course.
* @return {any} Formatted options.
*/
protected formatUserAdminOrNavOptions(courses: any[]): any {
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 {number} id ID of the course to get.
* @param {boolean} [preferCache] True if shouldn't call WS if data is cached, false otherwise.
* @param {string} [siteId] Site to get the courses from. If not defined, use current site.
* @return {Promise<any>} Promise resolved with the course.
*/
getUserCourse(id: number, preferCache?: boolean, siteId?: string): Promise<any> {
if (!id) {
return Promise.reject(null);
}
return this.getUserCourses(preferCache, siteId).then((courses) => {
let course;
for (const i in courses) {
if (courses[i].id == id) {
course = courses[i];
break;
}
}
return course ? course : Promise.reject(null);
});
}
/**
* Get user courses.
*
* @param {boolean} [preferCache] True if shouldn't call WS if data is cached, false otherwise.
* @param {string} [siteId] Site to get the courses from. If not defined, use current site.
* @return {Promise<any[]>} Promise resolved with the courses.
*/
getUserCourses(preferCache?: boolean, siteId?: string): Promise<any[]> {
return this.sitesProvider.getSite(siteId).then((site) => {
const userId = site.getUserId(),
data: any = {
userid: userId
},
preSets = {
cacheKey: this.getUserCoursesCacheKey(),
getCacheUsingCacheKey: true,
omitExpires: !!preferCache,
updateFrequency: CoreSite.FREQUENCY_RARELY
};
if (site.isVersionGreaterEqualThan('3.7')) {
data.returnusercount = 0;
}
return site.read('core_enrol_get_users_courses', data, preSets);
});
}
/**
* Get cache key for get user courses WS call.
*
* @return {string} Cache key.
*/
protected getUserCoursesCacheKey(): string {
return this.ROOT_CACHE_KEY + 'usercourses';
}
/**
* Invalidates get categories WS call.
*
* @param {number} categoryId Category ID to get.
* @param {boolean} [addSubcategories] If it should add subcategories to the list.
* @param {string} [siteId] Site Id. If not defined, use current site.
* @return {Promise<any>} Promise resolved when the data is invalidated.
*/
invalidateCategories(categoryId: number, addSubcategories?: boolean, siteId?: string): Promise<any> {
return this.sitesProvider.getSite(siteId).then((site) => {
return site.invalidateWsCacheForKey(this.getCategoriesCacheKey(categoryId, addSubcategories));
});
}
/**
* Invalidates get course WS call.
*
* @param {number} id Course ID.
* @param {string} [siteId] Site Id. If not defined, use current site.
* @return {Promise<any>} Promise resolved when the data is invalidated.
*/
invalidateCourse(id: number, siteId?: string): Promise<any> {
return this.invalidateCourses([id], siteId);
}
/**
* Invalidates get course enrolment methods WS call.
*
* @param {number} id Course ID.
* @param {string} [siteId] Site Id. If not defined, use current site.
* @return {Promise<any>} Promise resolved when the data is invalidated.
*/
invalidateCourseEnrolmentMethods(id: number, siteId?: string): Promise<any> {
return this.sitesProvider.getSite(siteId).then((site) => {
return site.invalidateWsCacheForKey(this.getCourseEnrolmentMethodsCacheKey(id));
});
}
/**
* Invalidates get course guest enrolment info WS call.
*
* @param {number} instanceId Guest instance ID.
* @param {string} [siteId] Site Id. If not defined, use current site.
* @return {Promise<any>} Promise resolved when the data is invalidated.
*/
invalidateCourseGuestEnrolmentInfo(instanceId: number, siteId?: string): Promise<any> {
return this.sitesProvider.getSite(siteId).then((site) => {
return site.invalidateWsCacheForKey(this.getCourseGuestEnrolmentInfoCacheKey(instanceId));
});
}
/**
* Invalidates the navigation and administration options for the given courses.
*
* @param {number[]} courseIds IDs of courses to get.
* @param {string} [siteId] Site ID to invalidate. If not defined, use current site.
* @return {Promise<any>} Promise resolved when the data is invalidated.
*/
invalidateCoursesAdminAndNavOptions(courseIds: number[], siteId?: string): Promise<any> {
siteId = siteId || this.sitesProvider.getCurrentSiteId();
return this.getCourseIdsForAdminAndNavOptions(courseIds, siteId).then((ids) => {
const promises = [];
promises.push(this.invalidateUserAdministrationOptionsForCourses(ids, siteId));
promises.push(this.invalidateUserNavigationOptionsForCourses(ids, siteId));
return Promise.all(promises);
});
}
/**
* Invalidates get courses WS call.
*
* @param {number[]} ids Courses IDs.
* @param {string} [siteId] Site Id. If not defined, use current site.
* @return {Promise<any>} Promise resolved when the data is invalidated.
*/
invalidateCourses(ids: number[], siteId?: string): Promise<any> {
return this.sitesProvider.getSite(siteId).then((site) => {
return site.invalidateWsCacheForKey(this.getCoursesCacheKey(ids));
});
}
/**
* Invalidates get courses by field WS call.
*
* @param {string} [field] See getCoursesByField for info.
* @param {any} [value] The value to match.
* @param {string} [siteId] Site Id. If not defined, use current site.
* @return {Promise<any>} Promise resolved when the data is invalidated.
*/
invalidateCoursesByField(field?: string, value?: any, siteId?: string): Promise<any> {
siteId = siteId || this.sitesProvider.getCurrentSiteId();
return this.fixCoursesByFieldParams(field, value, siteId).then((result) => {
field = result.field;
value = result.value;
return this.sitesProvider.getSite(siteId);
}).then((site) => {
return site.invalidateWsCacheForKey(this.getCoursesByFieldCacheKey(field, value));
});
}
/**
* Invalidates all user administration options.
*
* @param {string} [siteId] Site ID to invalidate. If not defined, use current site.
* @return {Promise<any>} Promise resolved when the data is invalidated.
*/
invalidateUserAdministrationOptions(siteId?: string): Promise<any> {
return this.sitesProvider.getSite(siteId).then((site) => {
return site.invalidateWsCacheForKeyStartingWith(this.getUserAdministrationOptionsCommonCacheKey());
});
}
/**
* Invalidates user administration options for certain courses.
*
* @param {number[]} courseIds IDs of courses.
* @param {string} [siteId] Site ID to invalidate. If not defined, use current site.
* @return {Promise<any>} Promise resolved when the data is invalidated.
*/
invalidateUserAdministrationOptionsForCourses(courseIds: number[], siteId?: string): Promise<any> {
return this.sitesProvider.getSite(siteId).then((site) => {
return site.invalidateWsCacheForKey(this.getUserAdministrationOptionsCacheKey(courseIds));
});
}
/**
* Invalidates get user courses WS call.
*
* @param {string} [siteId] Site ID to invalidate. If not defined, use current site.
* @return {Promise<any>} Promise resolved when the data is invalidated.
*/
invalidateUserCourses(siteId?: string): Promise<any> {
return this.sitesProvider.getSite(siteId).then((site) => {
return site.invalidateWsCacheForKey(this.getUserCoursesCacheKey());
});
}
/**
* Invalidates all user navigation options.
*
* @param {string} [siteId] Site ID to invalidate. If not defined, use current site.
* @return {Promise<any>} Promise resolved when the data is invalidated.
*/
invalidateUserNavigationOptions(siteId?: string): Promise<any> {
return this.sitesProvider.getSite(siteId).then((site) => {
return site.invalidateWsCacheForKeyStartingWith(this.getUserNavigationOptionsCommonCacheKey());
});
}
/**
* Invalidates user navigation options for certain courses.
*
* @param {number[]} courseIds IDs of courses.
* @param {string} [siteId] Site ID to invalidate. If not defined, use current site.
* @return {Promise<any>} Promise resolved when the data is invalidated.
*/
invalidateUserNavigationOptionsForCourses(courseIds: number[], siteId?: string): Promise<any> {
return this.sitesProvider.getSite(siteId).then((site) => {
return site.invalidateWsCacheForKey(this.getUserNavigationOptionsCacheKey(courseIds));
});
}
/**
* Check if WS to retrieve guest enrolment data is available.
*
* @return {boolean} Whether guest WS is available.
*/
isGuestWSAvailable(): boolean {
const currentSite = this.sitesProvider.getCurrentSite();
return currentSite && currentSite.wsAvailable('enrol_guest_get_instance_info');
}
/**
* Search courses.
*
* @param {string} text Text to search.
* @param {number} [page=0] Page to get.
* @param {number} [perPage] Number of courses per page. Defaults to CoreCoursesProvider.SEARCH_PER_PAGE.
* @param {string} [siteId] Site ID. If not defined, use current site.
* @return {Promise<{total: number, courses: any[]}>} Promise resolved with the courses and the total of matches.
*/
search(text: string, page: number = 0, perPage?: number, siteId?: string): Promise<{ total: number, courses: any[] }> {
perPage = perPage || CoreCoursesProvider.SEARCH_PER_PAGE;
return this.sitesProvider.getSite(siteId).then((site) => {
const params = {
criterianame: 'search',
criteriavalue: text,
page: page,
perpage: perPage
},
preSets = {
getFromCache: false
};
return site.read('core_course_search_courses', params, preSets).then((response) => {
return { total: response.total, courses: response.courses };
});
});
}
/**
* Self enrol current user in a certain course.
*
* @param {number} courseId Course ID.
* @param {string} [password] Password to use.
* @param {number} [instanceId] Enrol instance ID.
* @param {string} [siteId] Site ID. If not defined, use current site.
* @return {Promise<any>} Promise resolved if the user is enrolled. If the password is invalid, the promise is rejected
* with an object with code = CoreCoursesProvider.ENROL_INVALID_KEY.
*/
selfEnrol(courseId: number, password: string = '', instanceId?: number, siteId?: string): Promise<any> {
return this.sitesProvider.getSite(siteId).then((site) => {
const params: any = {
courseid: courseId,
password: password
};
if (instanceId) {
params.instanceid = instanceId;
}
return site.write('enrol_self_enrol_user', params).then((response): any => {
if (response) {
if (response.status) {
return true;
} else if (response.warnings && response.warnings.length) {
let message;
response.warnings.forEach((warning) => {
// Invalid password warnings.
if (warning.warningcode == '2' || warning.warningcode == '3' || warning.warningcode == '4') {
message = warning.message;
}
});
if (message) {
return Promise.reject({ code: CoreCoursesProvider.ENROL_INVALID_KEY, message: message });
} else {
return Promise.reject(response.warnings[0]);
}
}
}
return Promise.reject(null);
});
});
}
/**
* Set favourite property on a course.
*
* @param {number} courseId Course ID.
* @param {boolean} favourite If favourite or unfavourite.
* @param {string} [siteId] Site ID. If not defined, use current site.
* @return {Promise<any>} Promise resolved when done.
*/
setFavouriteCourse(courseId: number, favourite: boolean, siteId?: string): Promise<any> {
return this.sitesProvider.getSite(siteId).then((site) => {
const params: any = {
courses: [
{
id: courseId,
favourite: favourite ? 1 : 0
}
]
};
return site.write('core_course_set_favourite_courses', params);
});
}
}