From 2319cf807499b9585df5c85aa2fad1de69d825e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pau=20Ferrer=20Oca=C3=B1a?= Date: Thu, 25 Jan 2018 17:28:47 +0100 Subject: [PATCH] MOBILE-2317 core: Migrate delegates to CoreDelegate --- src/classes/delegate.ts | 38 +-- src/core/course/providers/format-delegate.ts | 166 +++--------- src/core/course/providers/module-delegate.ts | 167 ++---------- .../providers/module-prefetch-delegate.ts | 256 ++++++------------ src/core/courses/providers/delegate.ts | 218 ++++----------- src/core/fileuploader/providers/delegate.ts | 140 ++-------- src/core/user/providers/user-delegate.ts | 16 +- 7 files changed, 236 insertions(+), 765 deletions(-) diff --git a/src/classes/delegate.ts b/src/classes/delegate.ts index 6b34d75ca..780c6263d 100644 --- a/src/classes/delegate.ts +++ b/src/classes/delegate.ts @@ -19,7 +19,7 @@ import { CoreEventsProvider } from '../providers/events'; export interface CoreDelegateHandler { /** - * Name of the handler, or name and sub context (mmaMessages, mmaMessage:blockContact, ...). + * Name of the handler, or name and sub context (AddonMessages, AddonMessages:blockContact, ...). * @type {string} */ name: string; @@ -28,8 +28,8 @@ export interface CoreDelegateHandler { * Whether or not the handler is enabled on a site level. * @return {boolean|Promise} Whether or not the handler is enabled on a site level. */ - isEnabled(): boolean|Promise; -}; + isEnabled(): boolean | Promise; +} /** * Superclass to help creating delegates @@ -47,13 +47,13 @@ export class CoreDelegate { * List of registered handlers. * @type {any} */ - protected handlers: {[s: string]: CoreDelegateHandler} = {}; + protected handlers: { [s: string]: CoreDelegateHandler } = {}; /** * List of registered handlers enabled for the current site. * @type {any} */ - protected enabledHandlers: {[s: string]: CoreDelegateHandler} = {}; + protected enabledHandlers: { [s: string]: CoreDelegateHandler } = {}; /** * Default handler @@ -80,15 +80,19 @@ export class CoreDelegate { * @param {string} delegateName Delegate name used for logging purposes. * @param {CoreLoggerProvider} loggerProvider CoreLoggerProvider instance, cannot be directly injected. * @param {CoreSitesProvider} sitesProvider CoreSitesProvider instance, cannot be directly injected. + * @param {CoreEventsProvider} [eventsProvider] CoreEventsProvider instance, cannot be directly injected. + * If not set, no events will be fired. */ constructor(delegateName: string, protected loggerProvider: CoreLoggerProvider, protected sitesProvider: CoreSitesProvider, - protected eventsProvider: CoreEventsProvider) { + protected eventsProvider?: CoreEventsProvider) { this.logger = this.loggerProvider.getInstance(delegateName); - // Update handlers on this cases. - eventsProvider.on(CoreEventsProvider.LOGIN, this.updateHandlers.bind(this)); - eventsProvider.on(CoreEventsProvider.SITE_UPDATED, this.updateHandlers.bind(this)); - eventsProvider.on(CoreEventsProvider.REMOTE_ADDONS_LOADED, this.updateHandlers.bind(this)); + if (eventsProvider) { + // Update handlers on this cases. + eventsProvider.on(CoreEventsProvider.LOGIN, this.updateHandlers.bind(this)); + eventsProvider.on(CoreEventsProvider.SITE_UPDATED, this.updateHandlers.bind(this)); + eventsProvider.on(CoreEventsProvider.REMOTE_ADDONS_LOADED, this.updateHandlers.bind(this)); + } } /** @@ -100,7 +104,7 @@ export class CoreDelegate { * @param {any[]} params Parameters to pass to the function. * @return {any} Function returned value or default value. */ - protected executeFunctionOnEnabled(handlerName: string, fnName: string, params?: any[]) : any { + protected executeFunctionOnEnabled(handlerName: string, fnName: string, params?: any[]): any { return this.execute(this.enabledHandlers[handlerName], fnName, params); } @@ -113,7 +117,7 @@ export class CoreDelegate { * @param {any[]} params Parameters to pass to the function. * @return {any} Function returned value or default value. */ - protected executeFunction(handlerName: string, fnName: string, params?: any[]) : any { + protected executeFunction(handlerName: string, fnName: string, params?: any[]): any { return this.execute(this.handlers[handlerName], fnName, params); } @@ -126,7 +130,7 @@ export class CoreDelegate { * @param {any[]} params Parameters to pass to the function. * @return {any} Function returned value or default value. */ - private execute(handler: any, fnName: string, params?: any[]) : any { + private execute(handler: any, fnName: string, params?: any[]): any { if (handler && handler[fnName]) { return handler[fnName].apply(handler, params); } else if (this.defaultHandler && this.defaultHandler[fnName]) { @@ -163,7 +167,7 @@ export class CoreDelegate { * @param {number} time Time to check. * @return {boolean} Whether it's the last call. */ - isLastUpdateCall(time: number) : boolean { + isLastUpdateCall(time: number): boolean { if (!this.lastUpdateHandlersStart) { return true; } @@ -194,7 +198,7 @@ export class CoreDelegate { * @param {number} time Time this update process started. * @return {Promise} Resolved when done. */ - protected updateHandler(handler: CoreDelegateHandler, time: number) : Promise { + protected updateHandler(handler: CoreDelegateHandler, time: number): Promise { let promise, siteId = this.sitesProvider.getCurrentSiteId(), currentSite = this.sitesProvider.getCurrentSite(); @@ -230,7 +234,7 @@ export class CoreDelegate { * @param {any} site Site to check. * @return {boolean} Whether is enabled or disabled in site. */ - protected isFeatureDisabled(handler: CoreDelegateHandler, site: any) : boolean{ + protected isFeatureDisabled(handler: CoreDelegateHandler, site: any): boolean { return typeof this.featurePrefix != "undefined" && site.isFeatureDisabled(this.featurePrefix + handler.name); } @@ -239,7 +243,7 @@ export class CoreDelegate { * * @return {Promise} Resolved when done. */ - protected updateHandlers() : Promise { + protected updateHandlers(): Promise { let promises = [], now = Date.now(); diff --git a/src/core/course/providers/format-delegate.ts b/src/core/course/providers/format-delegate.ts index 36db3a662..d4d5d38fb 100644 --- a/src/core/course/providers/format-delegate.ts +++ b/src/core/course/providers/format-delegate.ts @@ -19,24 +19,12 @@ import { CoreLoggerProvider } from '../../../providers/logger'; import { CoreSitesProvider } from '../../../providers/sites'; import { CoreCourseProvider } from './course'; import { CoreCourseFormatDefaultHandler } from './default-format'; +import { CoreDelegate, CoreDelegateHandler } from '../../../classes/delegate'; /** * Interface that all course format handlers must implement. */ -export interface CoreCourseFormatHandler { - /** - * Name of the format. It should match the "format" returned in core_course_get_courses. - * @type {string} - */ - name: string; - - /** - * Whether or not the handler is enabled on a site level. - * - * @return {boolean|Promise} True or promise resolved with true if enabled. - */ - isEnabled(): boolean|Promise; - +export interface CoreCourseFormatHandler extends CoreDelegateHandler { /** * Get the title to use in course page. If not defined, course fullname. * This function will be called without sections first, and then call it again when the sections are retrieved. @@ -45,7 +33,7 @@ export interface CoreCourseFormatHandler { * @param {any[]} [sections] List of sections. * @return {string} Title. */ - getCourseTitle?(course: any, sections?: any[]) : string; + getCourseTitle?(course: any, sections?: any[]): string; /** * Whether it allows seeing all sections at the same time. Defaults to true. @@ -53,7 +41,7 @@ export interface CoreCourseFormatHandler { * @param {any} course The course to check. * @type {boolean} Whether it can view all sections. */ - canViewAllSections?(course: any) : boolean; + canViewAllSections?(course: any): boolean; /** * Whether the default section selector should be displayed. Defaults to true. @@ -61,7 +49,7 @@ export interface CoreCourseFormatHandler { * @param {any} course The course to check. * @type {boolean} Whether the default section selector should be displayed. */ - displaySectionSelector?(course: any) : boolean; + displaySectionSelector?(course: any): boolean; /** * Given a list of sections, get the "current" section that should be displayed first. Defaults to first section. @@ -71,7 +59,7 @@ export interface CoreCourseFormatHandler { * @return {any|Promise} Current section (or promise resolved with current section). If a promise is returned, it should * never fail. */ - getCurrentSection?(course: any, sections: any[]) : any|Promise; + getCurrentSection?(course: any, sections: any[]): any | Promise; /** * Open the page to display a course. If not defined, the page CoreCourseSectionPage will be opened. @@ -83,7 +71,7 @@ export interface CoreCourseFormatHandler { * @param {any} course The course to open. It should contain a "format" attribute. * @return {Promise} Promise resolved when done. */ - openCourse?(navCtrl: NavController, course: any) : Promise; + openCourse?(navCtrl: NavController, course: any): Promise; /** * Return the Component to use to display the course format instead of using the default one. @@ -93,7 +81,7 @@ export interface CoreCourseFormatHandler { * @param {any} course The course to render. * @return {any} The component to use, undefined if not found. */ - getCourseFormatComponent?(course: any) : any; + getCourseFormatComponent?(course: any): any; /** * Return the Component to use to display the course summary inside the default course format. @@ -135,26 +123,21 @@ export interface CoreCourseFormatHandler { * @param {any[]} sections List of sections. * @return {Promise} Promise resolved when the data is invalidated. */ - invalidateData?(course: any, sections: any[]) : Promise; -}; + invalidateData?(course: any, sections: any[]): Promise; +} /** * Service to interact with course formats. Provides the functions to register and interact with the addons. */ @Injectable() -export class CoreCourseFormatDelegate { - protected logger; - protected handlers: {[s: string]: CoreCourseFormatHandler} = {}; // All registered handlers. - protected enabledHandlers: {[s: string]: CoreCourseFormatHandler} = {}; // Handlers enabled for the current site. - protected lastUpdateHandlersStart: number; +export class CoreCourseFormatDelegate extends CoreDelegate { + protected handlers: { [s: string]: CoreCourseFormatHandler } = {}; // All registered handlers. + protected enabledHandlers: { [s: string]: CoreCourseFormatHandler } = {}; // Handlers enabled for the current site. + protected featurePrefix = 'CoreCourseFormatHandler_'; - constructor(logger: CoreLoggerProvider, private sitesProvider: CoreSitesProvider, eventsProvider: CoreEventsProvider, - private defaultHandler: CoreCourseFormatDefaultHandler) { - this.logger = logger.getInstance('CoreCoursesCourseFormatDelegate'); - - eventsProvider.on(CoreEventsProvider.LOGIN, this.updateHandlers.bind(this)); - eventsProvider.on(CoreEventsProvider.SITE_UPDATED, this.updateHandlers.bind(this)); - eventsProvider.on(CoreEventsProvider.REMOTE_ADDONS_LOADED, this.updateHandlers.bind(this)); + constructor(loggerProvider: CoreLoggerProvider, protected sitesProvider: CoreSitesProvider, eventsProvider: CoreEventsProvider, + protected defaultHandler: CoreCourseFormatDefaultHandler) { + super('CoreCoursesCourseFormatDelegate', loggerProvider, sitesProvider, eventsProvider); } /** @@ -163,7 +146,7 @@ export class CoreCourseFormatDelegate { * @param {any} course The course to check. * @return {boolean} Whether it allows seeing all sections at the same time. */ - canViewAllSections(course: any) : boolean { + canViewAllSections(course: any): boolean { return this.executeFunction(course.format, 'canViewAllSections', [course]); } @@ -173,7 +156,7 @@ export class CoreCourseFormatDelegate { * @param {any} course The course to check. * @return {boolean} Whether the section selector should be displayed. */ - displaySectionSelector(course: any) : boolean { + displaySectionSelector(course: any): boolean { return this.executeFunction(course.format, 'displaySectionSelector', [course]); } @@ -186,7 +169,7 @@ export class CoreCourseFormatDelegate { * @param {any[]} params Parameters to pass to the function. * @return {any} Function returned value or default value. */ - protected executeFunction(format: string, fnName: string, params?: any[]) : any { + protected executeFunction(format: string, fnName: string, params?: any[]): any { let handler = this.enabledHandlers[format]; if (handler && handler[fnName]) { return handler[fnName].apply(handler, params); @@ -201,7 +184,7 @@ export class CoreCourseFormatDelegate { * @param {any} course The course to render. * @return {any} The component to use, undefined if not found. */ - getAllSectionsComponent(course: any) : any { + getAllSectionsComponent(course: any): any { return this.executeFunction(course.format, 'getAllSectionsComponent', [course]); } @@ -211,7 +194,7 @@ export class CoreCourseFormatDelegate { * @param {any} course The course to render. * @return {any} The component to use, undefined if not found. */ - getCourseFormatComponent(course: any) : any { + getCourseFormatComponent(course: any): any { return this.executeFunction(course.format, 'getCourseFormatComponent', [course]); } @@ -221,7 +204,7 @@ export class CoreCourseFormatDelegate { * @param {any} course The course to render. * @return {any} The component to use, undefined if not found. */ - getCourseSummaryComponent(course: any) : any { + getCourseSummaryComponent(course: any): any { return this.executeFunction(course.format, 'getCourseSummaryComponent', [course]); } @@ -232,7 +215,7 @@ export class CoreCourseFormatDelegate { * @param {any[]} [sections] List of sections. * @return {string} Course title. */ - getCourseTitle(course: any, sections?: any[]) : string { + getCourseTitle(course: any, sections?: any[]): string { return this.executeFunction(course.format, 'getCourseTitle', [course, sections]); } @@ -243,13 +226,14 @@ export class CoreCourseFormatDelegate { * @param {any[]} sections List of sections. * @return {Promise} Promise resolved with current section. */ - getCurrentSection(course: any, sections: any[]) : Promise { + getCurrentSection(course: any, sections: any[]): Promise { // Convert the result to a Promise if it isn't. return Promise.resolve(this.executeFunction(course.format, 'getCurrentSection', [course, sections])).catch(() => { // This function should never fail. Just return the first section. if (sections[0].id != CoreCourseProvider.ALL_SECTIONS_ID) { return sections[0]; } + return sections[1]; }); } @@ -260,7 +244,7 @@ export class CoreCourseFormatDelegate { * @param {any} course The course to render. * @return {any} The component to use, undefined if not found. */ - getSectionSelectorComponent(course: any) : any { + getSectionSelectorComponent(course: any): any { return this.executeFunction(course.format, 'getSectionSelectorComponent', [course]); } @@ -271,7 +255,7 @@ export class CoreCourseFormatDelegate { * @param {any} course The course to render. * @return {any} The component to use, undefined if not found. */ - getSingleSectionComponent(course: any) : any { + getSingleSectionComponent(course: any): any { return this.executeFunction(course.format, 'getSingleSectionComponent', [course]); } @@ -282,24 +266,10 @@ export class CoreCourseFormatDelegate { * @param {any[]} sections List of sections. * @return {Promise} Promise resolved when the data is invalidated. */ - invalidateData(course: any, sections: any[]) : Promise { + invalidateData(course: any, sections: any[]): Promise { return this.executeFunction(course.format, 'invalidateData', [course, sections]); } - /** - * Check if a time belongs to the last update handlers call. - * This is to handle the cases where updateHandlers don't finish in the same order as they're called. - * - * @param {number} time Time to check. - * @return {boolean} Whether it's the last call. - */ - isLastUpdateCall(time: number) : boolean { - if (!this.lastUpdateHandlersStart) { - return true; - } - return time == this.lastUpdateHandlersStart; - } - /** * Open a course. * @@ -307,85 +277,11 @@ export class CoreCourseFormatDelegate { * @param {any} course The course to open. It should contain a "format" attribute. * @return {Promise} Promise resolved when done. */ - openCourse(navCtrl: NavController, course: any) : Promise { + openCourse(navCtrl: NavController, course: any): Promise { if (this.enabledHandlers[course.format] && this.enabledHandlers[course.format].openCourse) { return this.enabledHandlers[course.format].openCourse(navCtrl, course); } - return navCtrl.push('CoreCourseSectionPage', {course: course}); - } - /** - * Register a handler. - * - * @param {CoreCourseFormatHandler} handler The handler to register. - * @return {boolean} True if registered successfully, false otherwise. - */ - registerHandler(handler: CoreCourseFormatHandler) : boolean { - if (typeof this.handlers[handler.name] !== 'undefined') { - this.logger.log(`Addon '${handler.name}' already registered`); - return false; - } - this.logger.log(`Registered addon '${handler.name}'`); - this.handlers[handler.name] = handler; - return true; - } - - /** - * Update the handler for the current site. - * - * @param {CoreCourseFormatHandler} handler The handler to check. - * @param {number} time Time this update process started. - * @return {Promise} Resolved when done. - */ - protected updateHandler(handler: CoreCourseFormatHandler, time: number) : Promise { - let promise, - siteId = this.sitesProvider.getCurrentSiteId(), - currentSite = this.sitesProvider.getCurrentSite(); - - if (!this.sitesProvider.isLoggedIn()) { - promise = Promise.reject(null); - } else if (currentSite.isFeatureDisabled('CoreCourseFormatHandler_' + handler.name)) { - promise = Promise.resolve(false); - } else { - promise = Promise.resolve(handler.isEnabled()); - } - - // Checks if the handler is enabled. - return promise.catch(() => { - return false; - }).then((enabled: boolean) => { - // Verify that this call is the last one that was started. - // Check that site hasn't changed since the check started. - if (this.isLastUpdateCall(time) && this.sitesProvider.getCurrentSiteId() === siteId) { - if (enabled) { - this.enabledHandlers[handler.name] = handler; - } else { - delete this.enabledHandlers[handler.name]; - } - } - }); - } - - /** - * Update the handlers for the current site. - * - * @return {Promise} Resolved when done. - */ - protected updateHandlers() : Promise { - let promises = [], - now = Date.now(); - - this.logger.debug('Updating handlers for current site.'); - - this.lastUpdateHandlersStart = now; - - // Loop over all the handlers. - for (let name in this.handlers) { - promises.push(this.updateHandler(this.handlers[name], now)); - } - - return Promise.all(promises).catch(() => { - // Never reject. - }); + return navCtrl.push('CoreCourseSectionPage', { course: course }); } } diff --git a/src/core/course/providers/module-delegate.ts b/src/core/course/providers/module-delegate.ts index de195f394..ae2c952ea 100644 --- a/src/core/course/providers/module-delegate.ts +++ b/src/core/course/providers/module-delegate.ts @@ -19,30 +19,12 @@ import { CoreLoggerProvider } from '../../../providers/logger'; import { CoreSitesProvider } from '../../../providers/sites'; import { CoreCourseProvider } from './course'; import { CoreSite } from '../../../classes/site'; +import { CoreDelegate, CoreDelegateHandler } from '../../../classes/delegate'; /** * Interface that all course module handlers must implement. */ -export interface CoreCourseModuleHandler { - /** - * A name to identify the addon. - * @type {string} - */ - name: string; - - /** - * Name of the module. It should match the "modname" of the module returned in core_course_get_contents. - * @type {string} - */ - modname: string; - - /** - * Whether or not the handler is enabled on a site level. - * - * @return {boolean|Promise} True or promise resolved with true if enabled. - */ - isEnabled(): boolean|Promise; - +export interface CoreCourseModuleHandler extends CoreDelegateHandler { /** * Get the data required to display the module in the course contents view. * @@ -51,7 +33,7 @@ export interface CoreCourseModuleHandler { * @param {number} sectionId The section ID. * @return {CoreCourseModuleHandlerData} Data to render the module. */ - getData(module: any, courseId: number, sectionId: number) : CoreCourseModuleHandlerData; + getData(module: any, courseId: number, sectionId: number): CoreCourseModuleHandlerData; /** * Get the component to render the module. This is needed to support singleactivity course format. @@ -60,7 +42,7 @@ export interface CoreCourseModuleHandler { * @param {any} module The module object. * @return {any} The component to use, undefined if not found. */ - getMainComponent(course: any, module: any) : any; + getMainComponent(course: any, module: any): any; }; /** @@ -106,8 +88,8 @@ export interface CoreCourseModuleHandlerData { * @param {number} courseId The course ID. * @param {NavOptions} [options] Options for the navigation. */ - action?(event: Event, navCtrl: NavController, module: any, courseId: number, options?: NavOptions) : void; -}; + action?(event: Event, navCtrl: NavController, module: any, courseId: number, options?: NavOptions): void; +} /** * A button to display in a module item. @@ -151,26 +133,21 @@ export interface CoreCourseModuleHandlerButton { * @param {any} module The module object. * @param {number} courseId The course ID. */ - action(event: Event, navCtrl: NavController, module: any, courseId: number) : void; + action(event: Event, navCtrl: NavController, module: any, courseId: number): void; }; /** * Delegate to register module handlers. */ @Injectable() -export class CoreCourseModuleDelegate { - protected logger; - protected handlers: {[s: string]: CoreCourseModuleHandler} = {}; // All registered handlers. - protected enabledHandlers: {[s: string]: CoreCourseModuleHandler} = {}; // Handlers enabled for the current site. - protected lastUpdateHandlersStart: number; +export class CoreCourseModuleDelegate extends CoreDelegate { + protected handlers: { [s: string]: CoreCourseModuleHandler } = {}; // All registered handlers. + protected enabledHandlers: { [s: string]: CoreCourseModuleHandler } = {}; // Handlers enabled for the current site. + protected featurePrefix = '$mmCourseDelegate_'; - constructor(logger: CoreLoggerProvider, private sitesProvider: CoreSitesProvider, eventsProvider: CoreEventsProvider, - private courseProvider: CoreCourseProvider) { - this.logger = logger.getInstance('CoreCourseModuleDelegate'); - - eventsProvider.on(CoreEventsProvider.LOGIN, this.updateHandlers.bind(this)); - eventsProvider.on(CoreEventsProvider.SITE_UPDATED, this.updateHandlers.bind(this)); - eventsProvider.on(CoreEventsProvider.REMOTE_ADDONS_LOADED, this.updateHandlers.bind(this)); + constructor(loggerProvider: CoreLoggerProvider, protected sitesProvider: CoreSitesProvider, eventsProvider: CoreEventsProvider, + protected courseProvider: CoreCourseProvider) { + super('CoreCourseModuleDelegate', loggerProvider, sitesProvider, eventsProvider); } /** @@ -180,7 +157,7 @@ export class CoreCourseModuleDelegate { * @param {any} module The module object. * @return {any} The component to use, undefined if not found. */ - getMainComponent?(course: any, module: any) : any { + getMainComponent?(course: any, module: any): any { let handler = this.enabledHandlers[module.modname]; if (handler && handler.getMainComponent) { let component = handler.getMainComponent(course, module); @@ -199,7 +176,7 @@ export class CoreCourseModuleDelegate { * @param {number} sectionId The section ID. * @return {CoreCourseModuleHandlerData} Data to render the module. */ - getModuleDataFor(modname: string, module: any, courseId: number, sectionId: number) : CoreCourseModuleHandlerData { + getModuleDataFor(modname: string, module: any, courseId: number, sectionId: number): CoreCourseModuleHandlerData { if (typeof this.enabledHandlers[modname] != 'undefined') { return this.enabledHandlers[modname].getData(module, courseId, sectionId); } @@ -213,7 +190,7 @@ export class CoreCourseModuleDelegate { event.preventDefault(); event.stopPropagation(); - navCtrl.push('CoreCourseUnsupportedModulePage', {module: module}, options); + navCtrl.push('CoreCourseUnsupportedModulePage', { module: module }, options); } }; @@ -230,16 +207,6 @@ export class CoreCourseModuleDelegate { } return defaultData; - }; - - /** - * Check if a module has a registered handler (not necessarily enabled). - * - * @param {string} modname The name of the module type. - * @return {boolean} If the controller is installed or not. - */ - hasHandler(modname: string) : boolean { - return typeof this.handlers[modname] !== 'undefined'; } /** @@ -249,7 +216,7 @@ export class CoreCourseModuleDelegate { * @param {string} [siteId] Site ID. If not defined, current site. * @return {Promise} Promise resolved with boolean: whether module is disabled. */ - isModuleDisabled(modname: string, siteId?: string) : Promise { + isModuleDisabled(modname: string, siteId?: string): Promise { return this.sitesProvider.getSite(siteId).then((site) => { return this.isModuleDisabledInSite(modname, site); }); @@ -262,101 +229,13 @@ export class CoreCourseModuleDelegate { * @param {CoreSite} [site] Site. If not defined, use current site. * @return {boolean} Whether module is disabled. */ - isModuleDisabledInSite(modname: string, site?: CoreSite) : boolean { - site = site || this.sitesProvider.getCurrentSite(); - + isModuleDisabledInSite(modname: string, site?: CoreSite): boolean { if (typeof this.handlers[modname] != 'undefined') { - return site.isFeatureDisabled('$mmCourseDelegate_' + this.handlers[modname].name); + site = site || this.sitesProvider.getCurrentSite(); + + return this.isFeatureDisabled(this.handlers[modname], site); } + return false; } - - /** - * Check if a time belongs to the last update handlers call. - * This is to handle the cases where updateHandlers don't finish in the same order as they're called. - * - * @param {number} time Time to check. - * @return {boolean} Whether it's the last call. - */ - isLastUpdateCall(time: number) : boolean { - if (!this.lastUpdateHandlersStart) { - return true; - } - return time == this.lastUpdateHandlersStart; - } - - /** - * Register a handler. - * - * @param {CoreCourseModuleHandler} handler The handler to register. - * @return {boolean} True if registered successfully, false otherwise. - */ - registerHandler(handler: CoreCourseModuleHandler) : boolean { - if (typeof this.handlers[handler.modname] !== 'undefined') { - this.logger.log('There is an addon named \'' + this.handlers[handler.modname].name + - '\' already registered as handler for ' + handler.modname); - return false; - } - this.logger.log(`Registered addon '${handler.name}' for '${handler.modname}'`); - this.handlers[handler.modname] = handler; - return true; - } - - /** - * Update the handler for the current site. - * - * @param {CoreCourseModuleHandler} handler The handler to check. - * @param {number} time Time this update process started. - * @return {Promise} Resolved when done. - */ - protected updateHandler(handler: CoreCourseModuleHandler, time: number) : Promise { - let promise, - siteId = this.sitesProvider.getCurrentSiteId(), - currentSite = this.sitesProvider.getCurrentSite(); - - if (!this.sitesProvider.isLoggedIn()) { - promise = Promise.reject(null); - } else if (currentSite.isFeatureDisabled('$mmCourseDelegate_' + handler.name)) { - promise = Promise.resolve(false); - } else { - promise = Promise.resolve(handler.isEnabled()); - } - - // Checks if the handler is enabled. - return promise.catch(() => { - return false; - }).then((enabled: boolean) => { - // Verify that this call is the last one that was started. - if (this.isLastUpdateCall(time) && this.sitesProvider.getCurrentSiteId() === siteId) { - if (enabled) { - this.enabledHandlers[handler.modname] = handler; - } else { - delete this.enabledHandlers[handler.modname]; - } - } - }); - } - - /** - * Update the handlers for the current site. - * - * @return {Promise} Resolved when done. - */ - protected updateHandlers() : Promise { - let promises = [], - now = Date.now(); - - this.logger.debug('Updating handlers for current site.'); - - this.lastUpdateHandlersStart = now; - - // Loop over all the handlers. - for (let name in this.handlers) { - promises.push(this.updateHandler(this.handlers[name], now)); - } - - return Promise.all(promises).catch(() => { - // Never reject. - }); - } } diff --git a/src/core/course/providers/module-prefetch-delegate.ts b/src/core/course/providers/module-prefetch-delegate.ts index 39b492d7f..4b95c86b5 100644 --- a/src/core/course/providers/module-prefetch-delegate.ts +++ b/src/core/course/providers/module-prefetch-delegate.ts @@ -26,6 +26,7 @@ import { CoreSiteWSPreSets } from '../../../classes/site'; import { CoreConstants } from '../../constants'; import { Md5 } from 'ts-md5/dist/md5'; import { Subject, BehaviorSubject, Subscription } from 'rxjs'; +import { CoreDelegate, CoreDelegateHandler } from '../../../classes/delegate'; /** * Progress of downloading a list of modules. @@ -54,19 +55,7 @@ export type CoreCourseModulesProgressFunction = (data: CoreCourseModulesProgress /** * Interface that all course prefetch handlers must implement. */ -export interface CoreCourseModulePrefetchHandler { - /** - * A name to identify the addon. - * @type {string} - */ - name: string; - - /** - * Name of the module. It should match the "modname" of the module returned in core_course_get_contents. - * @type {string} - */ - modname: string; - +export interface CoreCourseModulePrefetchHandler extends CoreDelegateHandler { /** * The handler's component. * @type {string} @@ -80,13 +69,6 @@ export interface CoreCourseModulePrefetchHandler { */ updatesNames?: RegExp; - /** - * Whether or not the handler is enabled on a site level. - * - * @return {boolean|Promise} A boolean, or a promise resolved with a boolean, indicating if the handler is enabled. - */ - isEnabled() : boolean|Promise; - /** * Get the download size of a module. * @@ -96,7 +78,7 @@ export interface CoreCourseModulePrefetchHandler { * @return {Promise<{size: number, total: boolean}>} Promise resolved with the size and a boolean indicating if it was able * to calculate the total size. */ - getDownloadSize(module: any, courseId: number, single?: boolean) : Promise<{size: number, total: boolean}>; + getDownloadSize(module: any, courseId: number, single?: boolean): Promise<{ size: number, total: boolean }>; /** * Prefetch a module. @@ -117,7 +99,7 @@ export interface CoreCourseModulePrefetchHandler { * @param {number} courseId Course ID the module belongs to. * @return {boolean|Promise} Whether the module can use check_updates. The promise should never be rejected. */ - canUseCheckUpdates?(module: any, courseId: number) : boolean|Promise; + canUseCheckUpdates?(module: any, courseId: number): boolean | Promise; /** * Return the status to show based on current status. E.g. a module might want to show outdated instead of downloaded. @@ -128,7 +110,7 @@ export interface CoreCourseModulePrefetchHandler { * @param {boolean} canCheck Whether the site allows checking for updates. * @return {string} Status to display. */ - determineStatus?(module: any, status: string, canCheck: boolean) : string; + determineStatus?(module: any, status: string, canCheck: boolean): string; /** * Get the downloaded size of a module. If not defined, we'll use getFiles to calculate it (it can be slow). @@ -137,7 +119,7 @@ export interface CoreCourseModulePrefetchHandler { * @param {number} courseId Course ID the module belongs to. * @return {number|Promise} Size, or promise resolved with the size. */ - getDownloadedSize?(module: any, courseId: number) : number|Promise; + getDownloadedSize?(module: any, courseId: number): number | Promise; /** * Get the list of files of the module. If not defined, we'll assume they are in module.contents. @@ -146,7 +128,7 @@ export interface CoreCourseModulePrefetchHandler { * @param {number} courseId Course ID the module belongs to. * @return {any[]|Promise} List of files, or promise resolved with the files. */ - getFiles?(module: any, courseId: number) : any[]|Promise; + getFiles?(module: any, courseId: number): any[] | Promise; /** * Check if a certain module has updates based on the result of check updates. @@ -156,7 +138,7 @@ export interface CoreCourseModulePrefetchHandler { * @param {any[]} moduleUpdates List of updates for the module. * @return {boolean|Promise} Whether the module has updates. The promise should never be rejected. */ - hasUpdates?(module: any, courseId: number, moduleUpdates: any[]) : boolean|Promise; + hasUpdates?(module: any, courseId: number, moduleUpdates: any[]): boolean | Promise; /** * Invalidate WS calls needed to determine module status. It doesn't need to invalidate check updates. @@ -166,7 +148,7 @@ export interface CoreCourseModulePrefetchHandler { * @param {number} courseId Course ID the module belongs to. * @return {Promise} Promise resolved when invalidated. */ - invalidateModule?(module: any, courseId: number) : Promise; + invalidateModule?(module: any, courseId: number): Promise; /** * Check if a module can be downloaded. If the function is not defined, we assume that all modules are downloadable. @@ -175,7 +157,7 @@ export interface CoreCourseModulePrefetchHandler { * @param {number} courseId Course ID the module belongs to. * @return {boolean|Promise} Whether the module can be downloaded. The promise should never be rejected. */ - isDownloadable?(module: any, courseId: number) : boolean|Promise; + isDownloadable?(module: any, courseId: number): boolean | Promise; /** * Load module contents in module.contents if they aren't loaded already. This is meant for resources. @@ -184,7 +166,7 @@ export interface CoreCourseModulePrefetchHandler { * @param {number} courseId Course ID the module belongs to. * @return {Promise} Promise resolved when done. */ - loadContents?(module: any, courseId: number) : Promise; + loadContents?(module: any, courseId: number): Promise; /** * Remove module downloaded files. If not defined, we'll use getFiles to remove them (slow). @@ -193,14 +175,14 @@ export interface CoreCourseModulePrefetchHandler { * @param {number} courseId Course ID the module belongs to. * @return {Promise} Promise resolved when done. */ - removeFiles?(module: any, courseId: number) : Promise; -}; + removeFiles?(module: any, courseId: number): Promise; +} /** * Delegate to register module prefetch handlers. */ @Injectable() -export class CoreCourseModulePrefetchDelegate { +export class CoreCourseModulePrefetchDelegate extends CoreDelegate { // Variables for database. protected CHECK_UPDATES_TIMES_TABLE = 'check_updates_times'; protected checkUpdatesTableSchema = { @@ -217,31 +199,33 @@ export class CoreCourseModulePrefetchDelegate { notNull: true } ] - } + }; protected ROOT_CACHE_KEY = 'mmCourse:'; - protected logger; - protected handlers: {[s: string]: CoreCourseModulePrefetchHandler} = {}; // All registered handlers. - protected enabledHandlers: {[s: string]: CoreCourseModulePrefetchHandler} = {}; // Handlers enabled for the current site. + protected handlers: { [s: string]: CoreCourseModulePrefetchHandler } = {}; // All registered handlers. + protected enabledHandlers: { [s: string]: CoreCourseModulePrefetchHandler } = {}; // Handlers enabled for the current site. protected statusCache = new CoreCache(); - protected lastUpdateHandlersStart: number; // Promises for check updates, to prevent performing the same request twice at the same time. - protected courseUpdatesPromises: {[s: string]: {[s: string]: Promise}} = {}; + protected courseUpdatesPromises: { [s: string]: { [s: string]: Promise } } = {}; // Promises and observables for prefetching, to prevent downloading the same section twice at the same time // and notify the progress of the download. - protected prefetchData: {[s: string]: {[s: string]: { - promise: Promise, - observable: Subject, - subscriptions: Subscription[] - }}} = {}; + protected prefetchData: { + [s: string]: { + [s: string]: { + promise: Promise, + observable: Subject, + subscriptions: Subscription[] + } + } + } = {}; - constructor(logger: CoreLoggerProvider, private sitesProvider: CoreSitesProvider, private eventsProvider: CoreEventsProvider, - private courseProvider: CoreCourseProvider, private filepoolProvider: CoreFilepoolProvider, - private timeUtils: CoreTimeUtilsProvider, private utils: CoreUtilsProvider, private fileProvider: CoreFileProvider) { - this.logger = logger.getInstance('CoreCourseModulePrefetchDelegate'); + constructor(loggerProvider: CoreLoggerProvider, protected sitesProvider: CoreSitesProvider, protected eventsProvider: CoreEventsProvider, + private courseProvider: CoreCourseProvider, private filepoolProvider: CoreFilepoolProvider, + private timeUtils: CoreTimeUtilsProvider, private utils: CoreUtilsProvider, private fileProvider: CoreFileProvider) { + super('CoreCourseModulePrefetchDelegate', loggerProvider, sitesProvider); this.sitesProvider.createTableFromSchema(this.checkUpdatesTableSchema); } @@ -251,18 +235,18 @@ export class CoreCourseModulePrefetchDelegate { * * @return {boolean} True if can check updates, false otherwise. */ - canCheckUpdates() : boolean { + canCheckUpdates(): boolean { return this.sitesProvider.getCurrentSite().wsAvailable('core_course_check_updates'); } - /** + /** * Check if a certain module can use core_course_check_updates. * * @param {any} module Module. * @param {number} courseId Course ID the module belongs to. * @return {Promise} Promise resolved with boolean: whether the module can use check updates WS. */ - canModuleUseCheckUpdates(module: any, courseId: number) : Promise { + canModuleUseCheckUpdates(module: any, courseId: number): Promise { const handler = this.getPrefetchHandlerFor(module); if (!handler) { @@ -281,7 +265,7 @@ export class CoreCourseModulePrefetchDelegate { /** * Clear the status cache. */ - clearStatusCache() : void { + clearStatusCache(): void { this.statusCache.clear(); } @@ -292,11 +276,11 @@ export class CoreCourseModulePrefetchDelegate { * @param {number} courseId Course ID the modules belong to. * @return {Promise<{toCheck: any[], cannotUse: any[]}>} Promise resolved with the lists. */ - protected createToCheckList(modules: any[], courseId: number) : Promise<{toCheck: any[], cannotUse: any[]}> { + protected createToCheckList(modules: any[], courseId: number): Promise<{ toCheck: any[], cannotUse: any[] }> { let result = { - toCheck: [], - cannotUse: [] - }, + toCheck: [], + cannotUse: [] + }, promises = []; modules.forEach((module) => { @@ -309,7 +293,7 @@ export class CoreCourseModulePrefetchDelegate { result.toCheck.push({ contextlevel: 'module', id: module.id, - since: data.downloadTime || 0 + since: data.downloadTime || 0 }); } else { // Cannot use check updates, add it to the cannotUse array. @@ -340,7 +324,7 @@ export class CoreCourseModulePrefetchDelegate { * @param {boolean} [canCheck] True if updates can be checked using core_course_check_updates. * @return {string} Module status. */ - determineModuleStatus(module: any, status: string, canCheck?: boolean) : string { + determineModuleStatus(module: any, status: string, canCheck?: boolean): string { const handler = this.getPrefetchHandlerFor(module), siteId = this.sitesProvider.getCurrentSiteId(); @@ -368,7 +352,7 @@ export class CoreCourseModulePrefetchDelegate { * @return {Promise} Promise resolved with the updates. If a module is set to false, it means updates cannot be * checked for that module in the current site. */ - getCourseUpdates(modules: any[], courseId: number) : Promise { + getCourseUpdates(modules: any[], courseId: number): Promise { if (!this.canCheckUpdates()) { return Promise.reject(null); } @@ -400,9 +384,9 @@ export class CoreCourseModulePrefetchDelegate { // Get the site, maybe the user changed site. return this.sitesProvider.getSite(siteId).then((site) => { let params = { - courseid: courseId, - tocheck: data.toCheck - }, + courseid: courseId, + tocheck: data.toCheck + }, preSets: CoreSiteWSPreSets = { cacheKey: this.getCourseUpdatesCacheKey(courseId), emergencyCache: false, // If downloaded data has changed and offline, just fail. See MOBILE-2085. @@ -419,18 +403,18 @@ export class CoreCourseModulePrefetchDelegate { courseId: courseId, time: this.timeUtils.timestamp() }; - site.getDb().insertOrUpdateRecord(this.CHECK_UPDATES_TIMES_TABLE, entry, {courseId: courseId}); + site.getDb().insertOrUpdateRecord(this.CHECK_UPDATES_TIMES_TABLE, entry, { courseId: courseId }); return this.treatCheckUpdatesResult(data.toCheck, response, result); }).catch((error) => { // Cannot get updates. Get the cached entries but discard the modules with a download time higher // than the last execution of check updates. - return site.getDb().getRecord(this.CHECK_UPDATES_TIMES_TABLE, {courseId: courseId}).then((entry) => { + return site.getDb().getRecord(this.CHECK_UPDATES_TIMES_TABLE, { courseId: courseId }).then((entry) => { preSets.getCacheUsingCacheKey = true; preSets.omitExpires = true; return site.read('core_course_check_updates', params, preSets).then((response) => { - if (!response || typeof response.instances == 'undefined') { + if (!response || typeof response.instances == 'undefined') { return Promise.reject(error); } @@ -450,20 +434,19 @@ export class CoreCourseModulePrefetchDelegate { return this.courseUpdatesPromises[siteId][id]; } - /** * Check for updates in a course. * * @param {number} courseId Course ID the modules belong to. * @return {Promise} Promise resolved with the updates. */ - getCourseUpdatesByCourseId(courseId: number) : Promise { + getCourseUpdatesByCourseId(courseId: number): Promise { if (!this.canCheckUpdates()) { return Promise.reject(null); } // Get course sections and all their modules. - return this.courseProvider.getSections(courseId, false, true, {omitExpires: true}).then((sections) => { + return this.courseProvider.getSections(courseId, false, true, { omitExpires: true }).then((sections) => { return this.getCourseUpdates(this.courseProvider.getSectionsModules(sections), courseId); }); } @@ -474,7 +457,7 @@ export class CoreCourseModulePrefetchDelegate { * @param {number} courseId Course ID. * @return {string} Cache key. */ - protected getCourseUpdatesCacheKey(courseId: number) : string { + protected getCourseUpdatesCacheKey(courseId: number): string { return this.ROOT_CACHE_KEY + 'courseUpdates:' + courseId; } @@ -486,7 +469,7 @@ export class CoreCourseModulePrefetchDelegate { * @return {Promise<{size: number, total: boolean}>} Promise resolved with the size and a boolean indicating if it was able * to calculate the total size. */ - getDownloadSize(modules: any[], courseId: number) : Promise<{size: number, total: boolean}> { + getDownloadSize(modules: any[], courseId: number): Promise<{ size: number, total: boolean }> { // Get the status of each module. return this.getModulesStatus(modules, courseId).then((data) => { const downloadableModules = data[CoreConstants.NOT_DOWNLOADED].concat(data[CoreConstants.OUTDATED]), @@ -518,7 +501,7 @@ export class CoreCourseModulePrefetchDelegate { * @return {Promise<{size: number, total: boolean}>} Promise resolved with the size and a boolean indicating if it was able * to calculate the total size. */ - getModuleDownloadSize(module: any, courseId: number, single?: boolean) : Promise<{size: number, total: boolean}> { + getModuleDownloadSize(module: any, courseId: number, single?: boolean): Promise<{ size: number, total: boolean }> { let downloadSize, packageId, handler = this.getPrefetchHandlerFor(module); @@ -527,7 +510,7 @@ export class CoreCourseModulePrefetchDelegate { if (handler) { return this.isModuleDownloadable(module, courseId).then((downloadable) => { if (!downloadable) { - return {size: 0, total: true}; + return { size: 0, total: true }; } packageId = this.filepoolProvider.getPackageId(handler.component, module.id); @@ -548,7 +531,7 @@ export class CoreCourseModulePrefetchDelegate { }); } - return Promise.resolve({size: 0, total: false}); + return Promise.resolve({ size: 0, total: false }); } /** @@ -558,7 +541,7 @@ export class CoreCourseModulePrefetchDelegate { * @param {number} courseId Course ID the module belongs to. * @return {Promise} Promise resolved with the size. */ - getModuleDownloadedSize(module: any, courseId: number) : Promise { + getModuleDownloadedSize(module: any, courseId: number): Promise { let downloadedSize, packageId, promise, @@ -630,7 +613,7 @@ export class CoreCourseModulePrefetchDelegate { * @param {number} courseId Course ID the module belongs to. * @return {Promise} Promise resolved with the list of files. */ - getModuleFiles(module: any, courseId: number) : Promise { + getModuleFiles(module: any, courseId: number): Promise { const handler = this.getPrefetchHandlerFor(module); if (handler.getFiles) { @@ -657,7 +640,7 @@ export class CoreCourseModulePrefetchDelegate { * @param {number} [sectionId] ID of the section the module belongs to. * @return {Promise} Promise resolved with the status. */ - getModuleStatus(module: any, courseId: number, updates?: any, refresh?: boolean, sectionId?: number) : Promise { + getModuleStatus(module: any, courseId: number, updates?: any, refresh?: boolean, sectionId?: number): Promise { let handler = this.getPrefetchHandlerFor(module), siteId = this.sitesProvider.getCurrentSiteId(), canCheck = this.canCheckUpdates(); @@ -757,7 +740,7 @@ export class CoreCourseModulePrefetchDelegate { * - CoreConstants.DOWNLOADING (any[]) Modules with state DOWNLOADING. * - CoreConstants.OUTDATED (any[]) Modules with state OUTDATED. */ - getModulesStatus(modules: any[], courseId: number, sectionId?: number, refresh?: boolean) : any { + getModulesStatus(modules: any[], courseId: number, sectionId?: number, refresh?: boolean): any { let promises = [], status = CoreConstants.NOT_DOWNLOADABLE, result: any = { @@ -822,7 +805,7 @@ export class CoreCourseModulePrefetchDelegate { * @param {number} courseId Course ID the module belongs to. * @return {Promise<{status: string, downloadTime?: number}>} Promise resolved with the data. */ - protected getModuleStatusAndDownloadTime(module: any, courseId: number) : Promise<{status: string, downloadTime?: number}> { + protected getModuleStatusAndDownloadTime(module: any, courseId: number): Promise<{ status: string, downloadTime?: number }> { let handler = this.getPrefetchHandlerFor(module), siteId = this.sitesProvider.getCurrentSiteId(); @@ -839,7 +822,7 @@ export class CoreCourseModulePrefetchDelegate { } // Check if the module is downloadable. - return this.isModuleDownloadable(module, courseId).then((downloadable: boolean) : any => { + return this.isModuleDownloadable(module, courseId).then((downloadable: boolean): any => { if (!downloadable) { return { status: CoreConstants.NOT_DOWNLOADABLE @@ -868,7 +851,7 @@ export class CoreCourseModulePrefetchDelegate { * @param {any} module The module to work on. * @return {CoreCourseModulePrefetchHandler} Prefetch handler. */ - getPrefetchHandlerFor(module: any) : CoreCourseModulePrefetchHandler { + getPrefetchHandlerFor(module: any): CoreCourseModulePrefetchHandler { return this.enabledHandlers[module.modname]; } @@ -878,7 +861,7 @@ export class CoreCourseModulePrefetchDelegate { * @param {number} courseId Course ID. * @return {Promise} Promise resolved when data is invalidated. */ - invalidateCourseUpdates(courseId: number) : Promise { + invalidateCourseUpdates(courseId: number): Promise { return this.sitesProvider.getCurrentSite().invalidateWsCacheForKey(this.getCourseUpdatesCacheKey(courseId)); } @@ -889,7 +872,7 @@ export class CoreCourseModulePrefetchDelegate { * @param {number} courseId Course ID. * @return {Promise} Promise resolved when modules are invalidated. */ - invalidateModules(modules: any[], courseId: number) : Promise { + invalidateModules(modules: any[], courseId: number): Promise { let promises = []; modules.forEach((module) => { @@ -916,7 +899,7 @@ export class CoreCourseModulePrefetchDelegate { * * @param {any} module Module to be invalidated. */ - invalidateModuleStatusCache(module: any) : void { + invalidateModuleStatusCache(module: any): void { const handler = this.getPrefetchHandlerFor(module); if (handler) { this.statusCache.invalidate(this.filepoolProvider.getPackageId(handler.component, module.id)); @@ -929,25 +912,11 @@ export class CoreCourseModulePrefetchDelegate { * @param {string} id An ID to identify the download. * @return {boolean} True if it's being downloaded, false otherwise. */ - isBeingDownloaded(id: string) : boolean { + isBeingDownloaded(id: string): boolean { const siteId = this.sitesProvider.getCurrentSiteId(); return !!(this.prefetchData[siteId] && this.prefetchData[siteId][id]); } - /** - * Check if a time belongs to the last update handlers call. - * This is to handle the cases where updateHandlers don't finish in the same order as they're called. - * - * @param {number} time Time to check. - * @return {boolean} Whether it's the last call. - */ - isLastUpdateCall(time: number) : boolean { - if (!this.lastUpdateHandlersStart) { - return true; - } - return time == this.lastUpdateHandlersStart; - } - /** * Check if a module is downloadable. * @@ -955,7 +924,7 @@ export class CoreCourseModulePrefetchDelegate { * @param {Number} courseId Course ID the module belongs to. * @return {Promise} Promise resolved with true if downloadable, false otherwise. */ - isModuleDownloadable(module: any, courseId: number) : Promise { + isModuleDownloadable(module: any, courseId: number): Promise { let handler = this.getPrefetchHandlerFor(module); if (handler) { @@ -991,14 +960,14 @@ export class CoreCourseModulePrefetchDelegate { * @param {any} updates Result of getCourseUpdates. * @return {Promise} Promise resolved with boolean: whether the module has updates. */ - moduleHasUpdates(module: any, courseId: number, updates: any) : Promise { + moduleHasUpdates(module: any, courseId: number, updates: any): Promise { let handler = this.getPrefetchHandlerFor(module), moduleUpdates = updates[module.id]; if (handler && handler.hasUpdates) { // Handler implements its own function to check the updates, use it. return Promise.resolve(handler.hasUpdates(module, courseId, moduleUpdates)); - } else if (!moduleUpdates || !moduleUpdates.updates || !moduleUpdates.updates.length) { + } else if (!moduleUpdates || !moduleUpdates.updates || !moduleUpdates.updates.length) { // Module doesn't have any update. return Promise.resolve(false); } else if (handler && handler.updatesNames && handler.updatesNames.test) { @@ -1024,7 +993,7 @@ export class CoreCourseModulePrefetchDelegate { * @param {boolean} [single] True if we're downloading a single module, false if we're downloading a whole section. * @return {Promise} Promise resolved when finished. */ - prefetchModule(module: any, courseId: number, single?: boolean) : Promise { + prefetchModule(module: any, courseId: number, single?: boolean): Promise { const handler = this.getPrefetchHandlerFor(module); // Check if the module has a prefetch handler. @@ -1044,7 +1013,7 @@ export class CoreCourseModulePrefetchDelegate { * @param {CoreCourseModulesProgressFunction} [onProgress] Function to call everytime a module is downloaded. * @return {Promise} Promise resolved when all modules have been prefetched. */ - prefetchModules(id: string, modules: any[], courseId: number, onProgress?: CoreCourseModulesProgressFunction) : Promise { + prefetchModules(id: string, modules: any[], courseId: number, onProgress?: CoreCourseModulesProgressFunction): Promise { const siteId = this.sitesProvider.getCurrentSiteId(), currentData = this.prefetchData[siteId] && this.prefetchData[siteId][id]; @@ -1066,7 +1035,7 @@ export class CoreCourseModulePrefetchDelegate { // Initialize the prefetch data. const prefetchData = { - observable: new BehaviorSubject({count: count, total: total}), + observable: new BehaviorSubject({ count: count, total: total }), promise: undefined, subscriptions: [] }; @@ -1090,7 +1059,7 @@ export class CoreCourseModulePrefetchDelegate { // It's one of the modules we were expecting to download. moduleIds.splice(index, 1); count++; - prefetchData.observable.next({count: count, total: total}); + prefetchData.observable.next({ count: count, total: total }); } }); })); @@ -1115,23 +1084,6 @@ export class CoreCourseModulePrefetchDelegate { return prefetchData.promise; } - /** - * Register a handler. - * - * @param {CoreCourseModulePrefetchHandler} handler The handler to register. - * @return {boolean} True if registered successfully, false otherwise. - */ - registerHandler(handler: CoreCourseModulePrefetchHandler) : boolean { - if (typeof this.handlers[handler.modname] !== 'undefined') { - this.logger.log('There is an addon named \'' + this.handlers[handler.modname].name + - '\' already registered as a prefetch handler for ' + handler.modname); - return false; - } - this.logger.log(`Registered addon '${handler.name}' as a prefetch handler for '${handler.modname}'`); - this.handlers[handler.modname] = handler; - return true; - } - /** * Remove module Files from handler. * @@ -1139,7 +1091,7 @@ export class CoreCourseModulePrefetchDelegate { * @param {number} courseId Course ID the module belongs to. * @return {Promise} Promise resolved when done. */ - removeModuleFiles(module: any, courseId: number) : Promise { + removeModuleFiles(module: any, courseId: number): Promise { let handler = this.getPrefetchHandlerFor(module), siteId = this.sitesProvider.getCurrentSiteId(), promise; @@ -1176,7 +1128,7 @@ export class CoreCourseModulePrefetchDelegate { * @param {string} id An ID to identify the download. * @param {CoreCourseModulesProgressFunction} onProgress Function to call everytime a module is downloaded. */ - setOnProgress(id: string, onProgress: CoreCourseModulesProgressFunction) : void { + setOnProgress(id: string, onProgress: CoreCourseModulesProgressFunction): void { const siteId = this.sitesProvider.getCurrentSiteId(), currentData = this.prefetchData[siteId] && this.prefetchData[siteId][id]; @@ -1196,7 +1148,7 @@ export class CoreCourseModulePrefetchDelegate { * after this time will be ignored. * @return {any} Result. */ - protected treatCheckUpdatesResult(toCheckList: any[], response: any, result: any, previousTime?: number) : any { + protected treatCheckUpdatesResult(toCheckList: any[], response: any, result: any, previousTime?: number): any { // Format the response to index it by module ID. this.utils.arrayToObject(response.instances, 'id', result); @@ -1219,60 +1171,6 @@ export class CoreCourseModulePrefetchDelegate { return result; } - /** - * Update the enabled handlers for the current site. - * - * @param {CoreCourseModulePrefetchHandler} handler The handler to treat. - * @param {number} time Time this update process started. - * @return {Promise} Resolved when done. - */ - updateHandler(handler: CoreCourseModulePrefetchHandler, time: number) : Promise { - let promise, - siteId = this.sitesProvider.getCurrentSiteId(); - - if (!siteId) { - promise = Promise.reject(null); - } else { - promise = Promise.resolve(handler.isEnabled()); - } - - // Checks if the prefetch is enabled. - return promise.catch(() => { - return false; - }).then((enabled: boolean) => { - // Verify that this call is the last one that was started. - // Check that site hasn't changed since the check started. - if (this.isLastUpdateCall(time) && this.sitesProvider.getCurrentSiteId() == siteId) { - if (enabled) { - this.enabledHandlers[handler.modname] = handler; - } else { - delete this.enabledHandlers[handler.modname]; - } - } - }); - } - - /** - * Update the handlers for the current site. - * - * @return {Promise} Resolved when done. - */ - updateHandlers() : Promise { - const promises = [], - now = Date.now(); - - this.lastUpdateHandlersStart = now; - - // Loop over all the handlers. - for (let name in this.handlers) { - promises.push(this.updateHandler(this.handlers[name], now)); - } - - return Promise.all(promises).catch(() => { - // Never reject. - }); - } - /** * Update the status of a module in the "cache". * @@ -1282,7 +1180,7 @@ export class CoreCourseModulePrefetchDelegate { * @param {string|number} [componentId] An ID to use in conjunction with the component. * @param {number} [sectionId] Section ID of the module. */ - updateStatusCache(status: string, courseId: number, component: string, componentId?: string|number, sectionId?: number) : void { + updateStatusCache(status: string, courseId: number, component: string, componentId?: string | number, sectionId?: number): void { let notify, packageId = this.filepoolProvider.getPackageId(component, componentId), cachedStatus = this.statusCache.getValue(packageId, 'status', true); diff --git a/src/core/courses/providers/delegate.ts b/src/core/courses/providers/delegate.ts index 577047f8e..dd1c85667 100644 --- a/src/core/courses/providers/delegate.ts +++ b/src/core/courses/providers/delegate.ts @@ -13,6 +13,7 @@ // limitations under the License. import { Injectable } from '@angular/core'; +import { CoreDelegate, CoreDelegateHandler } from '../../../classes/delegate'; import { CoreEventsProvider } from '../../../providers/events'; import { CoreLoggerProvider } from '../../../providers/logger'; import { CoreSitesProvider } from '../../../providers/sites'; @@ -22,26 +23,13 @@ import { CoreCoursesProvider } from './courses'; /** * Interface that all courses handlers must implement. */ -export interface CoreCoursesHandler { - /** - * Name of the handler. - * @type {string} - */ - name: string; - +export interface CoreCoursesHandler extends CoreDelegateHandler { /** * The highest priority is displayed first. * @type {number} */ priority: number; - /** - * Whether or not the handler is enabled on a site level. - * - * @return {boolean|Promise} True or promise resolved with true if enabled. - */ - isEnabled(): boolean|Promise; - /** * Whether or not the handler is enabled for a certain course. * For perfomance reasons, do NOT call WebServices in here, call them in shouldDisplayForCourse. @@ -52,7 +40,7 @@ export interface CoreCoursesHandler { * @param {any} [admOptions] Course admin options for current user. See CoreCoursesProvider.getUserAdministrationOptions. * @return {boolean|Promise} True or promise resolved with true if enabled. */ - isEnabledForCourse(courseId: number, accessData: any, navOptions?: any, admOptions?: any) : boolean|Promise; + isEnabledForCourse(courseId: number, accessData: any, navOptions?: any, admOptions?: any): boolean | Promise; /** * Whether or not the handler should be displayed for a course. If not implemented, assume it's true. @@ -63,7 +51,7 @@ export interface CoreCoursesHandler { * @param {any} [admOptions] Course admin options for current user. See CoreCoursesProvider.getUserAdministrationOptions. * @return {boolean|Promise} True or promise resolved with true if enabled. */ - shouldDisplayForCourse(courseId: number, accessData: any, navOptions?: any, admOptions?: any) : boolean|Promise; + shouldDisplayForCourse(courseId: number, accessData: any, navOptions?: any, admOptions?: any): boolean | Promise; /** * Returns the data needed to render the handler. @@ -81,7 +69,7 @@ export interface CoreCoursesHandler { * @param {any} [admOptions] Course admin options for current user. See CoreCoursesProvider.getUserAdministrationOptions. * @return {Promise} Promise resolved when done. */ - invalidateEnabledForCourse?(courseId: number, navOptions?: any, admOptions?: any) : Promise; + invalidateEnabledForCourse?(courseId: number, navOptions?: any, admOptions?: any): Promise; /** * Called when a course is downloaded. It should prefetch all the data to be able to see the addon in offline. @@ -89,8 +77,8 @@ export interface CoreCoursesHandler { * @param {any} course The course. * @return {Promise} Promise resolved when done. */ - prefetch?(course: any) : Promise; -}; + prefetch?(course: any): Promise; +} /** * Data needed to render a course handler. It's returned by the handler. @@ -120,7 +108,7 @@ export interface CoreCoursesHandlerData { * @param {any} course The course. */ action(course: any): void; -}; +} /** * Data returned by the delegate for each handler. @@ -144,30 +132,30 @@ export interface CoreCoursesHandlerToDisplay { * @param {any} course The course. * @return {Promise} Promise resolved when done. */ - prefetch?(course: any) : Promise; -}; + prefetch?(course: any): Promise; +} /** * Service to interact with plugins to be shown in each course. */ @Injectable() -export class CoreCoursesDelegate { - protected logger; - protected handlers: {[s: string]: CoreCoursesHandler} = {}; // All registered handlers. - protected enabledHandlers: {[s: string]: CoreCoursesHandler} = {}; // Handlers enabled for the current site. - protected loaded: {[courseId: number]: boolean} = {}; - protected lastUpdateHandlersStart: number; +export class CoreCoursesDelegate extends CoreDelegate { + protected handlers: { [s: string]: CoreCoursesHandler } = {}; // All registered handlers. + protected enabledHandlers: { [s: string]: CoreCoursesHandler } = {}; // Handlers enabled for the current site. + protected loaded: { [courseId: number]: boolean } = {}; protected lastUpdateHandlersForCoursesStart: any = {}; - protected coursesHandlers: {[courseId: number]: { - access?: any, navOptions?: any, admOptions?: any, deferred?: PromiseDefer, enabledHandlers?: CoreCoursesHandler[]}} = {}; + protected coursesHandlers: { + [courseId: number]: { + access?: any, navOptions?: any, admOptions?: any, deferred?: PromiseDefer, enabledHandlers?: CoreCoursesHandler[] + } + } = {}; - constructor(logger: CoreLoggerProvider, private sitesProvider: CoreSitesProvider, private eventsProvider: CoreEventsProvider, - private coursesProvider: CoreCoursesProvider, private utils: CoreUtilsProvider) { - this.logger = logger.getInstance('CoreMainMenuDelegate'); + protected featurePrefix = '$mmCoursesDelegate_'; + + constructor(loggerProvider: CoreLoggerProvider, protected sitesProvider: CoreSitesProvider, private utils: CoreUtilsProvider, + protected eventsProvider: CoreEventsProvider, private coursesProvider: CoreCoursesProvider) { + super('CoreMainMenuDelegate', loggerProvider, sitesProvider, eventsProvider); - eventsProvider.on(CoreEventsProvider.LOGIN, this.updateHandlers.bind(this)); - eventsProvider.on(CoreEventsProvider.SITE_UPDATED, this.updateHandlers.bind(this)); - eventsProvider.on(CoreEventsProvider.REMOTE_ADDONS_LOADED, this.updateHandlers.bind(this)); eventsProvider.on(CoreEventsProvider.LOGOUT, () => { this.clearCoursesHandlers(); }); @@ -179,7 +167,7 @@ export class CoreCoursesDelegate { * @param {number} courseId The course ID to check. * @return {boolean} True if handlers are loaded, false otherwise. */ - areHandlersLoaded(courseId: number) : boolean { + areHandlersLoaded(courseId: number): boolean { return !!this.loaded[courseId]; } @@ -188,7 +176,7 @@ export class CoreCoursesDelegate { * * @param {number} [courseId] The course ID. If not defined, all handlers will be cleared. */ - protected clearCoursesHandlers(courseId?: number) : void { + protected clearCoursesHandlers(courseId?: number): void { if (courseId) { this.loaded[courseId] = false; delete this.coursesHandlers[courseId]; @@ -204,8 +192,8 @@ export class CoreCoursesDelegate { * @param {number} [courseId] The course ID. If not defined, all handlers will be cleared. * @return {Promise} Promise resolved when done. */ - clearAndInvalidateCoursesOptions(courseId?: number) : Promise { - var promises = []; + clearAndInvalidateCoursesOptions(courseId?: number): Promise { + let promises = []; this.eventsProvider.trigger(CoreCoursesProvider.EVENT_MY_COURSES_REFRESHED); @@ -240,14 +228,14 @@ export class CoreCoursesDelegate { * @return {Promise} Promise resolved with array of handlers. */ protected getHandlersForAccess(courseId: number, refresh: boolean, accessData: any, navOptions?: any, - admOptions?: any) : Promise { + admOptions?: any): Promise { // If the handlers aren't loaded, do not refresh. if (!this.loaded[courseId]) { refresh = false; } - if (refresh || !this.coursesHandlers[courseId] || this.coursesHandlers[courseId].access.type != accessData.type) { + if (refresh || !this.coursesHandlers[courseId] || this.coursesHandlers[courseId].access.type != accessData.type) { if (!this.coursesHandlers[courseId]) { this.coursesHandlers[courseId] = {}; } @@ -274,8 +262,8 @@ export class CoreCoursesDelegate { * @param {any} [admOptions] Course admin options for current user. See CoreCoursesProvider.getUserAdministrationOptions. * @return {Promise} Promise resolved with array of handlers. */ - getHandlersToDisplay(course: any, refresh?: boolean, isGuest?: boolean, navOptions?: any, admOptions?: any) : - Promise { + getHandlersToDisplay(course: any, refresh?: boolean, isGuest?: boolean, navOptions?: any, admOptions?: any): + Promise { course.id = parseInt(course.id, 10); let accessData = { @@ -300,7 +288,7 @@ export class CoreCoursesDelegate { this.coursesHandlers[course.id].enabledHandlers.forEach((handler) => { if (handler.shouldDisplayForCourse) { promise = Promise.resolve(handler.shouldDisplayForCourse( - course.id, accessData, course.navOptions, course.admOptions)); + course.id, accessData, course.navOptions, course.admOptions)); } else { // Not implemented, assume it should be displayed. promise = Promise.resolve(true); @@ -335,7 +323,7 @@ export class CoreCoursesDelegate { * @param {boolean} [refresh] True if it should refresh the list. * @return {Promise} Promise resolved with boolean: true if it has handlers, false otherwise. */ - hasHandlersForCourse(course: any, refresh?: boolean) : Promise { + hasHandlersForCourse(course: any, refresh?: boolean): Promise { // Load course options if missing. return this.loadCourseOptions(course, refresh).then(() => { return this.hasHandlersForDefault(course.id, refresh, course.navOptions, course.admOptions); @@ -351,7 +339,7 @@ export class CoreCoursesDelegate { * @param {any} [admOptions] Course admin options for current user. See CoreCoursesProvider.getUserAdministrationOptions. * @return {Promise} Promise resolved with boolean: true if it has handlers, false otherwise. */ - hasHandlersForDefault(courseId: number, refresh?: boolean, navOptions?: any, admOptions?: any) : Promise { + hasHandlersForDefault(courseId: number, refresh?: boolean, navOptions?: any, admOptions?: any): Promise { // Default access. let accessData = { type: CoreCoursesProvider.ACCESS_DEFAULT @@ -370,7 +358,7 @@ export class CoreCoursesDelegate { * @param {any} [admOptions] Course admin options for current user. See CoreCoursesProvider.getUserAdministrationOptions. * @return {Promise} Promise resolved with boolean: true if it has handlers, false otherwise. */ - hasHandlersForGuest(courseId: number, refresh?: boolean, navOptions?: any, admOptions?: any) : Promise { + hasHandlersForGuest(courseId: number, refresh?: boolean, navOptions?: any, admOptions?: any): Promise { // Guest access. var accessData = { type: CoreCoursesProvider.ACCESS_GUEST @@ -386,7 +374,7 @@ export class CoreCoursesDelegate { * @param {number} courseId Course ID. * @return {Promise} Promise resolved when done. */ - invalidateCourseHandlers(courseId: number) : Promise { + invalidateCourseHandlers(courseId: number): Promise { let promises = [], courseData = this.coursesHandlers[courseId]; @@ -397,27 +385,13 @@ export class CoreCoursesDelegate { courseData.enabledHandlers.forEach((handler) => { if (handler && handler.invalidateEnabledForCourse) { promises.push(Promise.resolve( - handler.invalidateEnabledForCourse(courseId, courseData.navOptions, courseData.admOptions))); + handler.invalidateEnabledForCourse(courseId, courseData.navOptions, courseData.admOptions))); } }); return this.utils.allPromises(promises); } - /** - * Check if a time belongs to the last update handlers call. - * This is to handle the cases where updateHandlers don't finish in the same order as they're called. - * - * @param {number} time Time to check. - * @return {boolean} Whether it's the last call. - */ - isLastUpdateCall(time: number) : boolean { - if (!this.lastUpdateHandlersStart) { - return true; - } - return time == this.lastUpdateHandlersStart; - } - /** * Check if a time belongs to the last update handlers for course call. * This is to handle the cases where updateHandlersForCourse don't finish in the same order as they're called. @@ -426,7 +400,7 @@ export class CoreCoursesDelegate { * @param {number} time Time to check. * @return {boolean} Whether it's the last call. */ - isLastUpdateCourseCall(courseId: number, time: number) : boolean { + isLastUpdateCourseCall(courseId: number, time: number): boolean { if (!this.lastUpdateHandlersForCoursesStart[courseId]) { return true; } @@ -440,7 +414,7 @@ export class CoreCoursesDelegate { * @param {boolean} [refresh] True if it should refresh the list. * @return {Promise} Promise resolved when done. */ - protected loadCourseOptions(course: any, refresh?: boolean) : Promise { + protected loadCourseOptions(course: any, refresh?: boolean): Promise { if (typeof course.navOptions == 'undefined' || typeof course.admOptions == 'undefined' || refresh) { return this.coursesProvider.getCoursesOptions([course.id]).then((options) => { course.navOptions = options.navOptions[course.id]; @@ -451,92 +425,14 @@ export class CoreCoursesDelegate { } } - /** - * Register a handler. - * - * @param {CoreCoursesHandler} handler The handler to register. - * @return {boolean} True if registered successfully, false otherwise. - */ - registerHandler(handler: CoreCoursesHandler) : boolean { - if (typeof this.handlers[handler.name] !== 'undefined') { - this.logger.log(`Addon '${handler.name}' already registered`); - return false; - } - this.logger.log(`Registered addon '${handler.name}'`); - this.handlers[handler.name] = handler; - return true; - } - - /** - * Update the handler for the current site. - * - * @param {CoreInitHandler} handler The handler to check. - * @param {number} time Time this update process started. - * @return {Promise} Resolved when done. - */ - protected updateHandler(handler: CoreCoursesHandler, time: number) : Promise { - let promise, - siteId = this.sitesProvider.getCurrentSiteId(), - currentSite = this.sitesProvider.getCurrentSite(); - - if (!this.sitesProvider.isLoggedIn()) { - promise = Promise.reject(null); - } else if (currentSite.isFeatureDisabled('$mmCoursesDelegate_' + handler.name)) { - promise = Promise.resolve(false); - } else { - promise = Promise.resolve(handler.isEnabled()); - } - - // Checks if the handler is enabled. - return promise.catch(() => { - return false; - }).then((enabled: boolean) => { - // Verify that this call is the last one that was started. - // Check that site hasn't changed since the check started. - if (this.isLastUpdateCall(time) && this.sitesProvider.getCurrentSiteId() === siteId) { - if (enabled) { - this.enabledHandlers[handler.name] = handler; - } else { - delete this.enabledHandlers[handler.name]; - } + updateData(siteId?: string) { + if (this.sitesProvider.getCurrentSiteId() === siteId) { + // Update handlers for all courses. + for (let courseId in this.coursesHandlers) { + let handler = this.coursesHandlers[courseId]; + this.updateHandlersForCourse(parseInt(courseId, 10), handler.access, handler.navOptions, handler.admOptions); } - }); - } - - /** - * Update the handlers for the current site. - * - * @return {Promise} Resolved when done. - */ - protected updateHandlers() : Promise { - let promises = [], - siteId = this.sitesProvider.getCurrentSiteId(), - now = Date.now(); - - this.logger.debug('Updating handlers for current site.'); - - this.lastUpdateHandlersStart = now; - - // Loop over all the handlers. - for (let name in this.handlers) { - promises.push(this.updateHandler(this.handlers[name], now)); } - - return Promise.all(promises).then(() => { - return true; - }, () => { - // Never reject. - return true; - }).then(() => { - // Verify that this call is the last one that was started. - if (this.isLastUpdateCall(now) && this.sitesProvider.getCurrentSiteId() === siteId) { - // Update handlers for all courses. - for (let courseId in this.coursesHandlers) { - let handler = this.coursesHandlers[courseId]; - this.updateHandlersForCourse(parseInt(courseId, 10), handler.access, handler.navOptions, handler.admOptions); - } - } - }); } /** @@ -549,7 +445,7 @@ export class CoreCoursesDelegate { * @return {Promise} Resolved when updated. * @protected */ - updateHandlersForCourse(courseId: number, accessData: any, navOptions?: any, admOptions?: any) : Promise { + updateHandlersForCourse(courseId: number, accessData: any, navOptions?: any, admOptions?: any): Promise { let promises = [], enabledForCourse = [], siteId = this.sitesProvider.getCurrentSiteId(), @@ -562,15 +458,15 @@ export class CoreCoursesDelegate { // Checks if the handler is enabled for the user. promises.push(Promise.resolve(handler.isEnabledForCourse(courseId, accessData, navOptions, admOptions)) - .then(function(enabled) { - if (enabled) { - enabledForCourse.push(handler); - } else { - return Promise.reject(null); - } - }).catch(() => { - // Nothing to do here, it is not enabled for this user. - })); + .then(function(enabled) { + if (enabled) { + enabledForCourse.push(handler); + } else { + return Promise.reject(null); + } + }).catch(() => { + // Nothing to do here, it is not enabled for this user. + })); } return Promise.all(promises).then(() => { @@ -590,5 +486,5 @@ export class CoreCoursesDelegate { this.coursesHandlers[courseId].deferred.resolve(); } }); - }; + } } diff --git a/src/core/fileuploader/providers/delegate.ts b/src/core/fileuploader/providers/delegate.ts index 30ee687d7..30f9aa1b2 100644 --- a/src/core/fileuploader/providers/delegate.ts +++ b/src/core/fileuploader/providers/delegate.ts @@ -16,45 +16,33 @@ import { Injectable } from '@angular/core'; import { CoreEventsProvider } from '../../../providers/events'; import { CoreLoggerProvider } from '../../../providers/logger'; import { CoreSitesProvider } from '../../../providers/sites'; +import { CoreDelegate, CoreDelegateHandler } from '../../../classes/delegate'; /** * Interface that all handlers must implement. */ -export interface CoreFileUploaderHandler { - /** - * A name to identify the addon. - * @type {string} - */ - name: string; - +export interface CoreFileUploaderHandler extends CoreDelegateHandler { /** * Handler's priority. The highest priority, the highest position. * @type {string} */ priority?: number; - /** - * Whether or not the handler is enabled on a site level. - * - * @return {boolean|Promise} True or promise resolved with true if enabled. - */ - isEnabled(): boolean|Promise; - /** * Given a list of mimetypes, return the ones that are supported by the handler. * * @param {string[]} [mimetypes] List of mimetypes. * @return {string[]} Supported mimetypes. */ - getSupportedMimetypes(mimetypes: string[]) : string[]; + getSupportedMimetypes(mimetypes: string[]): string[]; /** * Get the data to display the handler. * * @return {CoreFileUploaderHandlerData} Data. */ - getData() : CoreFileUploaderHandlerData; -}; + getData(): CoreFileUploaderHandlerData; +} /** * Data needed to render the handler in the file picker. It must be returned by the handler. @@ -88,7 +76,7 @@ export interface CoreFileUploaderHandlerData { * @return {Promise} Promise resolved with the result of picking/uploading the file. */ action?(maxSize?: number, upload?: boolean, allowOffline?: boolean, mimetypes?: string[]) - : Promise; + : Promise; /** * Function called after the handler is rendered. @@ -98,8 +86,8 @@ export interface CoreFileUploaderHandlerData { * @param {boolean} [allowOffline] True to allow selecting in offline, false to require connection. * @param {string[]} [mimetypes] List of supported mimetypes. If undefined, all mimetypes supported. */ - afterRender?(maxSize: number, upload: boolean, allowOffline: boolean, mimetypes: string[]) : void; -}; + afterRender?(maxSize: number, upload: boolean, allowOffline: boolean, mimetypes: string[]): void; +} /** * The result of clicking a handler. @@ -134,7 +122,7 @@ export interface CoreFileUploaderHandlerResult { * @type {any} */ result?: any; -}; +} /** * Data returned by the delegate for each handler. @@ -146,37 +134,32 @@ export interface CoreFileUploaderHandlerDataToReturn extends CoreFileUploaderHan */ priority?: number; - /** * Supported mimetypes. * @type {string[]} */ mimetypes?: string[]; -}; +} /** * Delegate to register handlers to be shown in the file picker. */ @Injectable() -export class CoreFileUploaderDelegate { - protected logger; - protected handlers: {[s: string]: CoreFileUploaderHandler} = {}; // All registered handlers. - protected enabledHandlers: {[s: string]: CoreFileUploaderHandler} = {}; // Handlers enabled for the current site. - protected lastUpdateHandlersStart: number; +export class CoreFileUploaderDelegate extends CoreDelegate { + protected handlers: { [s: string]: CoreFileUploaderHandler } = {}; // All registered handlers. + protected enabledHandlers: { [s: string]: CoreFileUploaderHandler } = {}; // Handlers enabled for the current site. - constructor(logger: CoreLoggerProvider, private sitesProvider: CoreSitesProvider, eventsProvider: CoreEventsProvider) { - this.logger = logger.getInstance('CoreFileUploaderDelegate'); + constructor(loggerProvider: CoreLoggerProvider, protected sitesProvider: CoreSitesProvider, + protected eventsProvider: CoreEventsProvider) { + super('CoreFileUploaderDelegate', loggerProvider, sitesProvider, eventsProvider); - eventsProvider.on(CoreEventsProvider.LOGIN, this.updateHandlers.bind(this)); - eventsProvider.on(CoreEventsProvider.SITE_UPDATED, this.updateHandlers.bind(this)); - eventsProvider.on(CoreEventsProvider.REMOTE_ADDONS_LOADED, this.updateHandlers.bind(this)); eventsProvider.on(CoreEventsProvider.LOGOUT, this.clearSiteHandlers.bind(this)); } /** * Clear current site handlers. Reserved for core use. */ - protected clearSiteHandlers() : void { + protected clearSiteHandlers(): void { this.enabledHandlers = {}; } @@ -186,7 +169,7 @@ export class CoreFileUploaderDelegate { * @param {string[]} [mimetypes] List of supported mimetypes. If undefined, all mimetypes supported. * @return {CoreFileUploaderHandlerDataToReturn[]} List of handlers data. */ - getHandlers(mimetypes: string[]) : CoreFileUploaderHandlerDataToReturn[] { + getHandlers(mimetypes: string[]): CoreFileUploaderHandlerDataToReturn[] { let handlers = []; for (let name in this.enabledHandlers) { @@ -207,7 +190,7 @@ export class CoreFileUploaderDelegate { } } - let data : CoreFileUploaderHandlerDataToReturn = handler.getData(); + let data: CoreFileUploaderHandlerDataToReturn = handler.getData(); data.priority = handler.priority; data.mimetypes = supportedMimetypes; handlers.push(data); @@ -215,89 +198,4 @@ export class CoreFileUploaderDelegate { return handlers; } - - /** - * Check if a time belongs to the last update handlers call. - * This is to handle the cases where updateHandlers don't finish in the same order as they're called. - * - * @param {number} time Time to check. - * @return {boolean} Whether it's the last call. - */ - isLastUpdateCall(time: number) : boolean { - if (!this.lastUpdateHandlersStart) { - return true; - } - return time == this.lastUpdateHandlersStart; - } - - /** - * Register a handler. - * - * @param {CoreFileUploaderHandler} handler The handler to register. - * @return {boolean} True if registered successfully, false otherwise. - */ - registerHandler(handler: CoreFileUploaderHandler) : boolean { - if (typeof this.handlers[handler.name] !== 'undefined') { - this.logger.log(`Addon '${handler.name}' already registered`); - return false; - } - this.logger.log(`Registered addon '${handler.name}'`); - this.handlers[handler.name] = handler; - return true; - } - - /** - * Update the handler for the current site. - * - * @param {CoreFileUploaderHandler} handler The handler to check. - * @param {number} time Time this update process started. - * @return {Promise} Resolved when done. - */ - protected updateHandler(handler: CoreFileUploaderHandler, time: number) : Promise { - let promise, - siteId = this.sitesProvider.getCurrentSiteId(); - - if (!this.sitesProvider.isLoggedIn()) { - promise = Promise.reject(null); - } else { - promise = Promise.resolve(handler.isEnabled()); - } - - // Checks if the handler is enabled. - return promise.catch(() => { - return false; - }).then((enabled: boolean) => { - // Verify that this call is the last one that was started. - if (this.isLastUpdateCall(time) && this.sitesProvider.getCurrentSiteId() === siteId) { - if (enabled) { - this.enabledHandlers[handler.name] = handler; - } else { - delete this.enabledHandlers[handler.name]; - } - } - }); - } - - /** - * Update the handlers for the current site. - * - * @return {Promise} Resolved when done. - */ - protected updateHandlers() : Promise { - let promises = [], - now = Date.now(); - - this.logger.debug('Updating handlers for current site.'); - - this.lastUpdateHandlersStart = now; - - // Loop over all the handlers. - for (let name in this.handlers) { - promises.push(this.updateHandler(this.handlers[name], now)); - } - - return Promise.all(promises).catch(() => { - // Never reject. - }); - } } diff --git a/src/core/user/providers/user-delegate.ts b/src/core/user/providers/user-delegate.ts index 97a50f6eb..c6769b824 100644 --- a/src/core/user/providers/user-delegate.ts +++ b/src/core/user/providers/user-delegate.ts @@ -19,7 +19,7 @@ import { CoreLoggerProvider } from '../../../providers/logger'; import { CoreSitesProvider } from '../../../providers/sites'; import { CoreEventsProvider } from '../../../providers/events'; -export interface CoreUserProfileHandler extends CoreDelegateHandler { +export interface CoreUserProfileHandler extends CoreDelegateHandler { /** * The highest priority is displayed first. * @type {number} @@ -44,7 +44,7 @@ export interface CoreUserProfileHandler extends CoreDelegateHandler { * @param {any} [admOptions] Admin options for the course. * @return {boolean|Promise} Whether or not the handler is enabled for a user. */ - isEnabledForUser(user: any, courseId: number, navOptions?: any, admOptions?: any): boolean|Promise; + isEnabledForUser(user: any, courseId: number, navOptions?: any, admOptions?: any): boolean | Promise; /** * Returns the data needed to render the handler. @@ -53,7 +53,7 @@ export interface CoreUserProfileHandler extends CoreDelegateHandler { * @return {CoreUserProfileHandlerData} Data to be shown. */ getDisplayData(user: any, courseId: number): CoreUserProfileHandlerData; -}; +} export interface CoreUserProfileHandlerData { /** @@ -94,7 +94,7 @@ export interface CoreUserProfileHandlerData { * @return {any} Action to be done. */ action?($event: any, user: any, courseId: number): any; -}; +} /** * Service to interact with plugins to be shown in user profile. Provides functions to register a plugin @@ -119,12 +119,12 @@ export class CoreUserDelegate extends CoreDelegate { */ public static TYPE_ACTION = 'action'; - protected handlers: {[s: string]: CoreUserProfileHandler} = {}; - protected enabledHandlers: {[s: string]: CoreUserProfileHandler} = {}; + protected handlers: { [s: string]: CoreUserProfileHandler } = {}; + protected enabledHandlers: { [s: string]: CoreUserProfileHandler } = {}; protected featurePrefix = '$mmUserDelegate_'; constructor(protected loggerProvider: CoreLoggerProvider, protected sitesProvider: CoreSitesProvider, - private coursesProvider: CoreCoursesProvider, protected eventsProvider: CoreEventsProvider) { + private coursesProvider: CoreCoursesProvider, protected eventsProvider: CoreEventsProvider) { super('CoreUserDelegate', loggerProvider, sitesProvider, eventsProvider); } @@ -168,7 +168,7 @@ export class CoreUserDelegate extends CoreDelegate { }).catch(() => { // Nothing to do here, it is not enabled for this user. }); - promises.push(promise); + promises.push(promise); } return Promise.all(promises).then(() => {