From b8daa1dc1be3b8b5eb0f4e2c4a0fb4097c3ee0a1 Mon Sep 17 00:00:00 2001 From: Tien Nguyen Phuc Date: Thu, 13 Aug 2020 17:50:27 +0700 Subject: [PATCH] MOBILE-3432 files: File type exclusion list for mobile --- scripts/langindex.json | 2 + src/addon/mod/resource/providers/helper.ts | 14 +++++- src/assets/lang/en.json | 2 + src/components/file/file.ts | 9 +++- src/lang/en.json | 2 + src/providers/file-helper.ts | 55 +++++++++++++++++++++- 6 files changed, 81 insertions(+), 3 deletions(-) diff --git a/scripts/langindex.json b/scripts/langindex.json index df9739345..a3738eb16 100644 --- a/scripts/langindex.json +++ b/scripts/langindex.json @@ -1373,6 +1373,7 @@ "core.cannotconnecttrouble": "local_moodlemobileapp", "core.cannotconnectverify": "local_moodlemobileapp", "core.cannotdownloadfiles": "local_moodlemobileapp", + "core.cannotopeninapp": "moodle", "core.captureaudio": "local_moodlemobileapp", "core.capturedimage": "local_moodlemobileapp", "core.captureimage": "local_moodlemobileapp", @@ -1916,6 +1917,7 @@ "core.offline": "message", "core.ok": "moodle", "core.online": "message", + "core.openfile": "moodle", "core.openfullimage": "local_moodlemobileapp", "core.openinbrowser": "local_moodlemobileapp", "core.openmodinbrowser": "local_moodlemobileapp", diff --git a/src/addon/mod/resource/providers/helper.ts b/src/addon/mod/resource/providers/helper.ts index 62a00e511..8f43d77ee 100644 --- a/src/addon/mod/resource/providers/helper.ts +++ b/src/addon/mod/resource/providers/helper.ts @@ -183,7 +183,19 @@ export class AddonModResourceHelperProvider { * @param courseId Course Id, used for completion purposes. * @return Resolved when done. */ - openModuleFile(module: any, courseId: number): Promise { + async openModuleFile(module: any, courseId: number): Promise { + // Check whether the file type excluded to open in app. + if (!module.contents.length) { + await this.courseProvider.loadModuleContents(module, courseId); + } + + if (!this.fileHelper.isOpenableInApp(module.contents[0])) { + const confirmed = await this.fileHelper.showConfirmOpenUnsupportedFile(); + if (!confirmed) { + return; + } + } + const modal = this.domUtils.showModalLoading(); // Download and open the file from the resource contents. diff --git a/src/assets/lang/en.json b/src/assets/lang/en.json index 6d3fd2ffe..699eea430 100644 --- a/src/assets/lang/en.json +++ b/src/assets/lang/en.json @@ -1373,6 +1373,7 @@ "core.cannotconnecttrouble": "We're having trouble connecting to your site.", "core.cannotconnectverify": "Please check the address is correct.", "core.cannotdownloadfiles": "File downloading is disabled. Please contact your site administrator.", + "core.cannotopeninapp": "This file may not work as expected on this device. Would you like to open it anyway?", "core.captureaudio": "Record audio", "core.capturedimage": "Taken picture.", "core.captureimage": "Take picture", @@ -1916,6 +1917,7 @@ "core.offline": "Offline", "core.ok": "OK", "core.online": "Online", + "core.openfile": "Open file", "core.openfullimage": "Click here to display the full size image", "core.openinbrowser": "Open in browser", "core.openmodinbrowser": "Open {{$a}} in browser", diff --git a/src/components/file/file.ts b/src/components/file/file.ts index 5df003e25..d920b54f9 100644 --- a/src/components/file/file.ts +++ b/src/components/file/file.ts @@ -148,7 +148,7 @@ export class CoreFileComponent implements OnInit, OnDestroy { * @param e Click event. * @param openAfterDownload Whether the file should be opened after download. */ - download(e?: Event, openAfterDownload: boolean = false): void { + async download(e?: Event, openAfterDownload: boolean = false): Promise { e && e.preventDefault(); e && e.stopPropagation(); @@ -156,6 +156,13 @@ export class CoreFileComponent implements OnInit, OnDestroy { return; } + if (!this.fileHelper.isOpenableInApp(this.file)) { + const confirmed = await this.fileHelper.showConfirmOpenUnsupportedFile(); + if (!confirmed) { + return; + } + } + if (!this.canDownload || !this.state || this.state == CoreConstants.NOT_DOWNLOADABLE) { // File cannot be downloaded, just open it. if (this.file.toURL) { diff --git a/src/lang/en.json b/src/lang/en.json index 40da0174b..97fcaba84 100644 --- a/src/lang/en.json +++ b/src/lang/en.json @@ -16,6 +16,7 @@ "cannotconnecttrouble": "We're having trouble connecting to your site.", "cannotconnectverify": "Please check the address is correct.", "cannotdownloadfiles": "File downloading is disabled. Please contact your site administrator.", + "cannotopeninapp": "This file may not work as expected on this device. Would you like to open it anyway?", "captureaudio": "Record audio", "capturedimage": "Taken picture.", "captureimage": "Take picture", @@ -200,6 +201,7 @@ "offline": "Offline", "ok": "OK", "online": "Online", + "openfile": "Open file", "openfullimage": "Click here to display the full size image", "openinbrowser": "Open in browser", "openmodinbrowser": "Open {{$a}} in browser", diff --git a/src/providers/file-helper.ts b/src/providers/file-helper.ts index 9a9ab8eaf..11e0e6345 100644 --- a/src/providers/file-helper.ts +++ b/src/providers/file-helper.ts @@ -15,6 +15,7 @@ import { Injectable } from '@angular/core'; import { TranslateService } from '@ngx-translate/core'; import { CoreAppProvider } from './app'; +import { CoreDomUtilsProvider } from '@providers/utils/dom'; import { CoreFileProvider } from './file'; import { CoreFilepoolProvider } from './filepool'; import { CoreSitesProvider } from './sites'; @@ -30,7 +31,8 @@ import { makeSingleton } from '@singletons/core.singletons'; @Injectable() export class CoreFileHelperProvider { - constructor(protected fileProvider: CoreFileProvider, + constructor(protected domUtils: CoreDomUtilsProvider, + protected fileProvider: CoreFileProvider, protected filepoolProvider: CoreFilepoolProvider, protected sitesProvider: CoreSitesProvider, protected appProvider: CoreAppProvider, @@ -339,6 +341,57 @@ export class CoreFileHelperProvider { throw new Error('Couldn\'t determine file size: ' + file.fileurl); } + + /** + * Is the file openable in app. + * + * @param file The file to check. + * @return bool. + */ + isOpenableInApp(file: any): boolean { + const re = /(?:\.([^.]+))?$/; + + const ext = re.exec(file.filename)[1]; + + return !this.isFileTypeExcludedInApp(ext); + } + + /** + * Is the file openable in app. + * + * @param file The file to check. + * @return bool. + */ + async showConfirmOpenUnsupportedFile(): Promise { + try { + await this.domUtils.showConfirm(this.translate.instant('core.cannotopeninapp'), undefined, + this.translate.instant('core.openfile')); + + return true; + } + catch (e) { + return false; + } + } + + /** + * Is the file type excluded to open in app. + * + * @param file The file to check. + * @return bool. + */ + isFileTypeExcludedInApp(fileType: string): boolean { + const currentSite = this.sitesProvider.getCurrentSite(); + const fileTypeExcludeList = currentSite && currentSite.getStoredConfig('tool_mobile_filetypeexclusionlist'); + + if (!fileTypeExcludeList) { + return false; + } + + const regEx = new RegExp('(,|^)' + fileType + '(,|$)', 'g'); + + return !!fileTypeExcludeList.match(regEx); + } } export class CoreFileHelper extends makeSingleton(CoreFileHelperProvider) {}