From e0849668e3818e3018349baba2170c8535c95dad Mon Sep 17 00:00:00 2001 From: Dani Palou Date: Mon, 9 Dec 2019 15:34:08 +0100 Subject: [PATCH] MOBILE-2235 h5p: Support and use isEnabled function in file delegate --- .../folder/providers/pluginfile-handler.ts | 9 +++ .../mod/forum/providers/prefetch-handler.ts | 2 +- .../glossary/providers/prefetch-handler.ts | 2 +- .../mod/imscp/providers/pluginfile-handler.ts | 9 +++ .../mod/lesson/providers/prefetch-handler.ts | 3 +- .../mod/page/providers/pluginfile-handler.ts | 9 +++ .../mod/quiz/providers/prefetch-handler.ts | 2 +- .../resource/providers/pluginfile-handler.ts | 9 +++ .../mod/scorm/providers/pluginfile-handler.ts | 9 +++ src/classes/delegate.ts | 12 ++-- .../course/classes/module-prefetch-handler.ts | 4 +- src/core/course/providers/helper.ts | 6 +- src/core/h5p/providers/pluginfile-handler.ts | 11 ++- src/core/question/providers/helper.ts | 2 +- src/providers/filepool.ts | 53 +++++++++++++++ src/providers/plugin-file-delegate.ts | 67 +++++-------------- src/providers/utils/dom.ts | 17 +++-- upgrade.txt | 4 ++ 18 files changed, 160 insertions(+), 70 deletions(-) diff --git a/src/addon/mod/folder/providers/pluginfile-handler.ts b/src/addon/mod/folder/providers/pluginfile-handler.ts index cc4190e0b..35e816d94 100644 --- a/src/addon/mod/folder/providers/pluginfile-handler.ts +++ b/src/addon/mod/folder/providers/pluginfile-handler.ts @@ -47,4 +47,13 @@ export class AddonModFolderPluginFileHandler implements CorePluginFileHandler { // Component + Filearea + Revision return '/mod_folder/content/0/'; } + + /** + * Whether or not the handler is enabled on a site level. + * + * @return Whether or not the handler is enabled on a site level. + */ + isEnabled(): boolean | Promise { + return true; + } } diff --git a/src/addon/mod/forum/providers/prefetch-handler.ts b/src/addon/mod/forum/providers/prefetch-handler.ts index 2f1e05b5d..743d99b97 100644 --- a/src/addon/mod/forum/providers/prefetch-handler.ts +++ b/src/addon/mod/forum/providers/prefetch-handler.ts @@ -96,7 +96,7 @@ export class AddonModForumPrefetchHandler extends CoreCourseActivityPrefetchHand if (getInlineFiles && post.messageinlinefiles && post.messageinlinefiles.length) { files = files.concat(post.messageinlinefiles); } else if (post.message && !getInlineFiles) { - files = files.concat(this.domUtils.extractDownloadableFilesFromHtmlAsFakeFileObjects(post.message)); + files = files.concat(this.filepoolProvider.extractDownloadableFilesFromHtmlAsFakeFileObjects(post.message)); } }); diff --git a/src/addon/mod/glossary/providers/prefetch-handler.ts b/src/addon/mod/glossary/providers/prefetch-handler.ts index 34a94b142..590294ad7 100644 --- a/src/addon/mod/glossary/providers/prefetch-handler.ts +++ b/src/addon/mod/glossary/providers/prefetch-handler.ts @@ -93,7 +93,7 @@ export class AddonModGlossaryPrefetchHandler extends CoreCourseActivityPrefetchH if (getInlineFiles && entry.definitioninlinefiles && entry.definitioninlinefiles.length) { files = files.concat(entry.definitioninlinefiles); } else if (entry.definition && !getInlineFiles) { - files = files.concat(this.domUtils.extractDownloadableFilesFromHtmlAsFakeFileObjects(entry.definition)); + files = files.concat(this.filepoolProvider.extractDownloadableFilesFromHtmlAsFakeFileObjects(entry.definition)); } }); diff --git a/src/addon/mod/imscp/providers/pluginfile-handler.ts b/src/addon/mod/imscp/providers/pluginfile-handler.ts index d67c455a3..4d283a90e 100644 --- a/src/addon/mod/imscp/providers/pluginfile-handler.ts +++ b/src/addon/mod/imscp/providers/pluginfile-handler.ts @@ -54,4 +54,13 @@ export class AddonModImscpPluginFileHandler implements CorePluginFileHandler { // Component + Filearea + Revision return '/mod_imscp/' + args[2] + '/0/'; } + + /** + * Whether or not the handler is enabled on a site level. + * + * @return Whether or not the handler is enabled on a site level. + */ + isEnabled(): boolean | Promise { + return true; + } } diff --git a/src/addon/mod/lesson/providers/prefetch-handler.ts b/src/addon/mod/lesson/providers/prefetch-handler.ts index f0732535e..46ef36db2 100644 --- a/src/addon/mod/lesson/providers/prefetch-handler.ts +++ b/src/addon/mod/lesson/providers/prefetch-handler.ts @@ -419,7 +419,8 @@ export class AddonModLessonPrefetchHandler extends CoreCourseActivityPrefetchHan return; } answerPage.answerdata.answers.forEach((answer) => { - files.push(...this.domUtils.extractDownloadableFilesFromHtmlAsFakeFileObjects(answer[0])); + files.push(...this.filepoolProvider.extractDownloadableFilesFromHtmlAsFakeFileObjects( + answer[0])); }); }); diff --git a/src/addon/mod/page/providers/pluginfile-handler.ts b/src/addon/mod/page/providers/pluginfile-handler.ts index c17e6b626..1c93e3e21 100644 --- a/src/addon/mod/page/providers/pluginfile-handler.ts +++ b/src/addon/mod/page/providers/pluginfile-handler.ts @@ -47,4 +47,13 @@ export class AddonModPagePluginFileHandler implements CorePluginFileHandler { // Component + Filearea + Revision return '/mod_page/content/0/'; } + + /** + * Whether or not the handler is enabled on a site level. + * + * @return Whether or not the handler is enabled on a site level. + */ + isEnabled(): boolean | Promise { + return true; + } } diff --git a/src/addon/mod/quiz/providers/prefetch-handler.ts b/src/addon/mod/quiz/providers/prefetch-handler.ts index fdd66c7e5..0040dd8e8 100644 --- a/src/addon/mod/quiz/providers/prefetch-handler.ts +++ b/src/addon/mod/quiz/providers/prefetch-handler.ts @@ -126,7 +126,7 @@ export class AddonModQuizPrefetchHandler extends CoreCourseActivityPrefetchHandl files = files.concat(feedback.feedbackinlinefiles); } else if (feedback.feedbacktext && !getInlineFiles) { files = files.concat( - this.domUtils.extractDownloadableFilesFromHtmlAsFakeFileObjects(feedback.feedbacktext)); + this.filepoolProvider.extractDownloadableFilesFromHtmlAsFakeFileObjects(feedback.feedbacktext)); } })); } diff --git a/src/addon/mod/resource/providers/pluginfile-handler.ts b/src/addon/mod/resource/providers/pluginfile-handler.ts index b0b41368d..f9179a955 100644 --- a/src/addon/mod/resource/providers/pluginfile-handler.ts +++ b/src/addon/mod/resource/providers/pluginfile-handler.ts @@ -47,4 +47,13 @@ export class AddonModResourcePluginFileHandler implements CorePluginFileHandler // Component + Filearea + Revision return '/mod_resource/content/0/'; } + + /** + * Whether or not the handler is enabled on a site level. + * + * @return Whether or not the handler is enabled on a site level. + */ + isEnabled(): boolean | Promise { + return true; + } } diff --git a/src/addon/mod/scorm/providers/pluginfile-handler.ts b/src/addon/mod/scorm/providers/pluginfile-handler.ts index ccb1a3a6b..6cd13e393 100644 --- a/src/addon/mod/scorm/providers/pluginfile-handler.ts +++ b/src/addon/mod/scorm/providers/pluginfile-handler.ts @@ -47,4 +47,13 @@ export class AddonModScormPluginFileHandler implements CorePluginFileHandler { // Component + Filearea + Revision return '/mod_scorm/content/0/'; } + + /** + * Whether or not the handler is enabled on a site level. + * + * @return Whether or not the handler is enabled on a site level. + */ + isEnabled(): boolean | Promise { + return true; + } } diff --git a/src/classes/delegate.ts b/src/classes/delegate.ts index db31ff907..e342c1e62 100644 --- a/src/classes/delegate.ts +++ b/src/classes/delegate.ts @@ -237,14 +237,16 @@ export class CoreDelegate { * @return True when registered, false if already registered. */ registerHandler(handler: CoreDelegateHandler): boolean { - if (typeof this.handlers[handler[this.handlerNameProperty]] !== 'undefined') { + const key = handler[this.handlerNameProperty] || handler.name; + + if (typeof this.handlers[key] !== 'undefined') { this.logger.log(`Handler '${handler[this.handlerNameProperty]}' already registered`); return false; } this.logger.log(`Registered handler '${handler[this.handlerNameProperty]}'`); - this.handlers[handler[this.handlerNameProperty]] = handler; + this.handlers[key] = handler; return true; } @@ -282,10 +284,12 @@ export class CoreDelegate { }).then((enabled: boolean) => { // Check that site hasn't changed since the check started. if (this.sitesProvider.getCurrentSiteId() === siteId) { + const key = handler[this.handlerNameProperty] || handler.name; + if (enabled) { - this.enabledHandlers[handler[this.handlerNameProperty]] = handler; + this.enabledHandlers[key] = handler; } else { - delete this.enabledHandlers[handler[this.handlerNameProperty]]; + delete this.enabledHandlers[key]; } } }).finally(() => { diff --git a/src/core/course/classes/module-prefetch-handler.ts b/src/core/course/classes/module-prefetch-handler.ts index 0448dcd33..815cbf5c4 100644 --- a/src/core/course/classes/module-prefetch-handler.ts +++ b/src/core/course/classes/module-prefetch-handler.ts @@ -195,12 +195,12 @@ export class CoreCourseModulePrefetchHandlerBase implements CoreCourseModulePref if (typeof instance.introfiles != 'undefined') { return instance.introfiles; } else if (instance.intro) { - return this.domUtils.extractDownloadableFilesFromHtmlAsFakeFileObjects(instance.intro); + return this.filepoolProvider.extractDownloadableFilesFromHtmlAsFakeFileObjects(instance.intro); } } if (module.description) { - return this.domUtils.extractDownloadableFilesFromHtmlAsFakeFileObjects(module.description); + return this.filepoolProvider.extractDownloadableFilesFromHtmlAsFakeFileObjects(module.description); } return []; diff --git a/src/core/course/providers/helper.ts b/src/core/course/providers/helper.ts index 9cfb9385c..0501ba682 100644 --- a/src/core/course/providers/helper.ts +++ b/src/core/course/providers/helper.ts @@ -438,7 +438,7 @@ export class CoreCourseHelperProvider { sizePromise = this.prefetchDelegate.getDownloadSize(section.modules, courseId); // Check if the section has embedded files in the description. - haveEmbeddedFiles = this.domUtils.extractDownloadableFilesFromHtml(section.summary).length > 0; + haveEmbeddedFiles = this.filepoolProvider.extractDownloadableFilesFromHtml(section.summary).length > 0; } else { const promises = [], results = { @@ -454,7 +454,7 @@ export class CoreCourseHelperProvider { })); // Check if the section has embedded files in the description. - if (!haveEmbeddedFiles && this.domUtils.extractDownloadableFilesFromHtml(s.summary).length > 0) { + if (!haveEmbeddedFiles && this.filepoolProvider.extractDownloadableFilesFromHtml(s.summary).length > 0) { haveEmbeddedFiles = true; } } @@ -1449,7 +1449,7 @@ export class CoreCourseHelperProvider { })); // Download the files in the section description. - const introFiles = this.domUtils.extractDownloadableFilesFromHtmlAsFakeFileObjects(section.summary), + const introFiles = this.filepoolProvider.extractDownloadableFilesFromHtmlAsFakeFileObjects(section.summary), siteId = this.sitesProvider.getCurrentSiteId(); promises.push(this.filepoolProvider.addFilesToQueue(siteId, introFiles, CoreCourseProvider.COMPONENT, courseId) diff --git a/src/core/h5p/providers/pluginfile-handler.ts b/src/core/h5p/providers/pluginfile-handler.ts index a152945c0..13657fc2d 100644 --- a/src/core/h5p/providers/pluginfile-handler.ts +++ b/src/core/h5p/providers/pluginfile-handler.ts @@ -63,7 +63,7 @@ export class CoreH5PPluginFileHandler implements CorePluginFileHandler { /** * Given an HTML element, get the URLs of the files that should be downloaded and weren't treated by - * CoreDomUtilsProvider.extractDownloadableFilesFromHtml. + * CoreFilepoolProvider.extractDownloadableFilesFromHtml. * * @param container Container where to get the URLs from. * @return {string[]} List of URLs. @@ -103,6 +103,15 @@ export class CoreH5PPluginFileHandler implements CorePluginFileHandler { }); } + /** + * Whether or not the handler is enabled on a site level. + * + * @return Whether or not the handler is enabled on a site level. + */ + isEnabled(): boolean | Promise { + return this.h5pProvider.canGetTrustedH5PFileInSite(); + } + /** * Check whether the file should be treated by this handler. It is used in functions where the component isn't used. * diff --git a/src/core/question/providers/helper.ts b/src/core/question/providers/helper.ts index 4b7da5ea3..0cb77a0b0 100644 --- a/src/core/question/providers/helper.ts +++ b/src/core/question/providers/helper.ts @@ -516,7 +516,7 @@ export class CoreQuestionHelperProvider { */ prefetchQuestionFiles(question: any, component?: string, componentId?: string | number, siteId?: string, usageId?: number) : Promise { - const urls = this.domUtils.extractDownloadableFilesFromHtml(question.html); + const urls = this.filepoolProvider.extractDownloadableFilesFromHtml(question.html); if (!component) { component = CoreQuestionProvider.COMPONENT; diff --git a/src/providers/filepool.ts b/src/providers/filepool.ts index 07058ee71..9e8fa5790 100644 --- a/src/providers/filepool.ts +++ b/src/providers/filepool.ts @@ -1239,6 +1239,59 @@ export class CoreFilepoolProvider { } } + /** + * Extract the downloadable URLs from an HTML code. + * + * @param html HTML code. + * @return List of file urls. + */ + extractDownloadableFilesFromHtml(html: string): string[] { + let urls = [], + elements; + + const element = this.domUtils.convertToElement(html); + elements = element.querySelectorAll('a, img, audio, video, source, track'); + + for (let i = 0; i < elements.length; i++) { + const element = elements[i]; + let url = element.tagName === 'A' ? element.href : element.src; + + if (url && this.urlUtils.isDownloadableUrl(url) && urls.indexOf(url) == -1) { + urls.push(url); + } + + // Treat video poster. + if (element.tagName == 'VIDEO' && element.getAttribute('poster')) { + url = element.getAttribute('poster'); + if (url && this.urlUtils.isDownloadableUrl(url) && urls.indexOf(url) == -1) { + urls.push(url); + } + } + } + + // Now get other files from plugin file handlers. + urls = urls.concat(this.pluginFileDelegate.getDownloadableFilesFromHTML(element)); + + return urls; + } + + /** + * Extract the downloadable URLs from an HTML code and returns them in fake file objects. + * + * @param html HTML code. + * @return List of fake file objects with file URLs. + */ + extractDownloadableFilesFromHtmlAsFakeFileObjects(html: string): any[] { + const urls = this.extractDownloadableFilesFromHtml(html); + + // Convert them to fake file objects. + return urls.map((url) => { + return { + fileurl: url + }; + }); + } + /** * Fill Missing Extension In the File Object if needed. * This is to migrate from old versions. diff --git a/src/providers/plugin-file-delegate.ts b/src/providers/plugin-file-delegate.ts index f5582a28a..17354d4b5 100644 --- a/src/providers/plugin-file-delegate.ts +++ b/src/providers/plugin-file-delegate.ts @@ -13,18 +13,17 @@ // limitations under the License. import { Injectable } from '@angular/core'; +import { CoreEventsProvider } from './events'; import { CoreLoggerProvider } from './logger'; +import { CoreSitesProvider } from './sites'; import { CoreWSExternalFile } from '@providers/ws'; import { FileEntry } from '@ionic-native/file'; +import { CoreDelegate, CoreDelegateHandler } from '@classes/delegate'; /** * Interface that all plugin file handlers must implement. */ -export interface CorePluginFileHandler { - /** - * A name to identify the handler. - */ - name: string; +export interface CorePluginFileHandler extends CoreDelegateHandler { /** * The "component" of the handler. It should match the "component" of pluginfile URLs. @@ -69,7 +68,7 @@ export interface CorePluginFileHandler { /** * Given an HTML element, get the URLs of the files that should be downloaded and weren't treated by - * CoreDomUtilsProvider.extractDownloadableFilesFromHtml. + * CoreFilepoolProvider.extractDownloadableFilesFromHtml. * * @param container Container where to get the URLs from. * @return {string[]} List of URLs. @@ -108,12 +107,13 @@ export interface CorePluginFileHandler { * Delegate to register pluginfile information handlers. */ @Injectable() -export class CorePluginFileDelegate { - protected logger; - protected handlers: { [s: string]: CorePluginFileHandler } = {}; +export class CorePluginFileDelegate extends CoreDelegate { + protected handlerNameProperty = 'component'; - constructor(logger: CoreLoggerProvider) { - this.logger = logger.getInstance('CorePluginFileDelegate'); + constructor(loggerProvider: CoreLoggerProvider, + sitesProvider: CoreSitesProvider, + eventsProvider: CoreEventsProvider) { + super('CorePluginFileDelegate', loggerProvider, sitesProvider, eventsProvider); } /** @@ -167,18 +167,6 @@ export class CorePluginFileDelegate { return Promise.resolve(file); } - /** - * Get the handler for a certain pluginfile url. - * - * @param component Component of the plugin. - * @return Handler. Undefined if no handler found for the plugin. - */ - protected getPluginHandler(component: string): CorePluginFileHandler { - if (typeof this.handlers[component] != 'undefined') { - return this.handlers[component]; - } - } - /** * Get the RegExp of the component and filearea described in the URL. * @@ -187,7 +175,7 @@ export class CorePluginFileDelegate { */ getComponentRevisionRegExp(args: string[]): RegExp { // Get handler based on component (args[1]). - const handler = this.getPluginHandler(args[1]); + const handler = this.getHandler(args[1], true); if (handler && handler.getComponentRevisionRegExp) { return handler.getComponentRevisionRegExp(args); @@ -196,7 +184,7 @@ export class CorePluginFileDelegate { /** * Given an HTML element, get the URLs of the files that should be downloaded and weren't treated by - * CoreDomUtilsProvider.extractDownloadableFilesFromHtml. + * CoreFilepoolProvider.extractDownloadableFilesFromHtml. * * @param container Container where to get the URLs from. * @return List of URLs. @@ -204,8 +192,8 @@ export class CorePluginFileDelegate { getDownloadableFilesFromHTML(container: HTMLElement): string[] { let files = []; - for (const component in this.handlers) { - const handler = this.handlers[component]; + for (const component in this.enabledHandlers) { + const handler = this.enabledHandlers[component]; if (handler && handler.getDownloadableFilesFromHTML) { files = files.concat(handler.getDownloadableFilesFromHTML(container)); @@ -278,8 +266,8 @@ export class CorePluginFileDelegate { * @return Handler. */ protected getHandlerForFile(file: CoreWSExternalFile): CorePluginFileHandler { - for (const component in this.handlers) { - const handler = this.handlers[component]; + for (const component in this.enabledHandlers) { + const handler = this.enabledHandlers[component]; if (handler && handler.shouldHandleFile && handler.shouldHandleFile(file)) { return handler; @@ -287,25 +275,6 @@ export class CorePluginFileDelegate { } } - /** - * Register a handler. - * - * @param handler The handler to register. - * @return True if registered successfully, false otherwise. - */ - registerHandler(handler: CorePluginFileHandler): boolean { - if (typeof this.handlers[handler.component || handler.name] !== 'undefined') { - this.logger.log(`Handler '${handler.component}' already registered`); - - return false; - } - - this.logger.log(`Registered handler '${handler.component}'`); - this.handlers[handler.component || handler.name] = handler; - - return true; - } - /** * Removes the revision number from a file URL. * @@ -315,7 +284,7 @@ export class CorePluginFileDelegate { */ removeRevisionFromUrl(url: string, args: string[]): string { // Get handler based on component (args[1]). - const handler = this.getPluginHandler(args[1]); + const handler = this.getHandler(args[1], true); if (handler && handler.getComponentRevisionRegExp && handler.getComponentRevisionReplace) { const revisionRegex = handler.getComponentRevisionRegExp(args); diff --git a/src/providers/utils/dom.ts b/src/providers/utils/dom.ts index 564b889c2..6bc976dd6 100644 --- a/src/providers/utils/dom.ts +++ b/src/providers/utils/dom.ts @@ -22,7 +22,7 @@ import { TranslateService } from '@ngx-translate/core'; import { CoreTextUtilsProvider } from './text'; import { CoreAppProvider } from '../app'; import { CoreConfigProvider } from '../config'; -import { CorePluginFileDelegate } from '../plugin-file-delegate'; +import { CoreLoggerProvider } from '../logger'; import { CoreUrlUtilsProvider } from './url'; import { CoreFileProvider } from '@providers/file'; import { CoreConstants } from '@core/constants'; @@ -62,6 +62,7 @@ export class CoreDomUtilsProvider { protected lastInstanceId = 0; protected debugDisplay = false; // Whether to display debug messages. Store it in a variable to make it synchronous. protected displayedAlerts = {}; // To prevent duplicated alerts. + protected logger; constructor(private translate: TranslateService, private loadingCtrl: LoadingController, @@ -76,7 +77,9 @@ export class CoreDomUtilsProvider { private sanitizer: DomSanitizer, private popoverCtrl: PopoverController, private fileProvider: CoreFileProvider, - private pluginFileDelegate: CorePluginFileDelegate) { + loggerProvider: CoreLoggerProvider) { + + this.logger = loggerProvider.getInstance('CoreDomUtilsProvider'); // Check if debug messages should be displayed. configProvider.get(CoreConstants.SETTINGS_DEBUG_DISPLAY, false).then((debugDisplay) => { @@ -260,9 +263,13 @@ export class CoreDomUtilsProvider { * * @param html HTML code. * @return List of file urls. + * @deprecated since 3.8. Use CoreFilepoolProvider.extractDownloadableFilesFromHtml instead. */ extractDownloadableFilesFromHtml(html: string): string[] { - let urls = []; + this.logger.error('The function extractDownloadableFilesFromHtml has been moved to CoreFilepoolProvider.' + + ' Please use that function instead of this one.'); + + const urls = []; let elements; const element = this.convertToElement(html); @@ -285,9 +292,6 @@ export class CoreDomUtilsProvider { } } - // Now get other files from plugin file handlers. - urls = urls.concat(this.pluginFileDelegate.getDownloadableFilesFromHTML(element)); - return urls; } @@ -296,6 +300,7 @@ export class CoreDomUtilsProvider { * * @param html HTML code. * @return List of fake file objects with file URLs. + * @deprecated since 3.8. Use CoreFilepoolProvider.extractDownloadableFilesFromHtmlAsFakeFileObjects instead. */ extractDownloadableFilesFromHtmlAsFakeFileObjects(html: string): any[] { const urls = this.extractDownloadableFilesFromHtml(html); diff --git a/upgrade.txt b/upgrade.txt index 6599608e6..75333c0c4 100644 --- a/upgrade.txt +++ b/upgrade.txt @@ -1,6 +1,10 @@ This files describes API changes in the Moodle Mobile app, information provided here is intended especially for developers. +=== 3.8.0 === + +- CoreDomUtilsProvider.extractDownloadableFilesFromHtml and CoreDomUtilsProvider.extractDownloadableFilesFromHtmlAsFakeFileObjects have been deprecated. Please use CoreFilepoolProvider.extractDownloadableFilesFromHtml and CoreFilepoolProvider.extractDownloadableFilesFromHtmlAsFakeFileObjects. We had to move them to prevent a circular dependency. + === 3.7.1 === - CoreGroupsProvider.getActivityAllowedGroups and CoreGroupsProvider.getActivityAllowedGroupsIfEnabled now return the full response of core_group_get_activity_allowed_groups instead of just the groups.