MOBILE-3432 files: File type exclusion list for mobile

main
Tien Nguyen Phuc 2020-08-13 17:50:27 +07:00 committed by Dani Palou
parent 59d4e189c8
commit b8daa1dc1b
6 changed files with 81 additions and 3 deletions

View File

@ -1373,6 +1373,7 @@
"core.cannotconnecttrouble": "local_moodlemobileapp", "core.cannotconnecttrouble": "local_moodlemobileapp",
"core.cannotconnectverify": "local_moodlemobileapp", "core.cannotconnectverify": "local_moodlemobileapp",
"core.cannotdownloadfiles": "local_moodlemobileapp", "core.cannotdownloadfiles": "local_moodlemobileapp",
"core.cannotopeninapp": "moodle",
"core.captureaudio": "local_moodlemobileapp", "core.captureaudio": "local_moodlemobileapp",
"core.capturedimage": "local_moodlemobileapp", "core.capturedimage": "local_moodlemobileapp",
"core.captureimage": "local_moodlemobileapp", "core.captureimage": "local_moodlemobileapp",
@ -1916,6 +1917,7 @@
"core.offline": "message", "core.offline": "message",
"core.ok": "moodle", "core.ok": "moodle",
"core.online": "message", "core.online": "message",
"core.openfile": "moodle",
"core.openfullimage": "local_moodlemobileapp", "core.openfullimage": "local_moodlemobileapp",
"core.openinbrowser": "local_moodlemobileapp", "core.openinbrowser": "local_moodlemobileapp",
"core.openmodinbrowser": "local_moodlemobileapp", "core.openmodinbrowser": "local_moodlemobileapp",

View File

@ -183,7 +183,19 @@ export class AddonModResourceHelperProvider {
* @param courseId Course Id, used for completion purposes. * @param courseId Course Id, used for completion purposes.
* @return Resolved when done. * @return Resolved when done.
*/ */
openModuleFile(module: any, courseId: number): Promise<any> { async openModuleFile(module: any, courseId: number): Promise<any> {
// 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(); const modal = this.domUtils.showModalLoading();
// Download and open the file from the resource contents. // Download and open the file from the resource contents.

View File

@ -1373,6 +1373,7 @@
"core.cannotconnecttrouble": "We're having trouble connecting to your site.", "core.cannotconnecttrouble": "We're having trouble connecting to your site.",
"core.cannotconnectverify": "<strong>Please check the address is correct.</strong>", "core.cannotconnectverify": "<strong>Please check the address is correct.</strong>",
"core.cannotdownloadfiles": "File downloading is disabled. Please contact your site administrator.", "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.captureaudio": "Record audio",
"core.capturedimage": "Taken picture.", "core.capturedimage": "Taken picture.",
"core.captureimage": "Take picture", "core.captureimage": "Take picture",
@ -1916,6 +1917,7 @@
"core.offline": "Offline", "core.offline": "Offline",
"core.ok": "OK", "core.ok": "OK",
"core.online": "Online", "core.online": "Online",
"core.openfile": "Open file",
"core.openfullimage": "Click here to display the full size image", "core.openfullimage": "Click here to display the full size image",
"core.openinbrowser": "Open in browser", "core.openinbrowser": "Open in browser",
"core.openmodinbrowser": "Open {{$a}} in browser", "core.openmodinbrowser": "Open {{$a}} in browser",

View File

@ -148,7 +148,7 @@ export class CoreFileComponent implements OnInit, OnDestroy {
* @param e Click event. * @param e Click event.
* @param openAfterDownload Whether the file should be opened after download. * @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<void> {
e && e.preventDefault(); e && e.preventDefault();
e && e.stopPropagation(); e && e.stopPropagation();
@ -156,6 +156,13 @@ export class CoreFileComponent implements OnInit, OnDestroy {
return; 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) { if (!this.canDownload || !this.state || this.state == CoreConstants.NOT_DOWNLOADABLE) {
// File cannot be downloaded, just open it. // File cannot be downloaded, just open it.
if (this.file.toURL) { if (this.file.toURL) {

View File

@ -16,6 +16,7 @@
"cannotconnecttrouble": "We're having trouble connecting to your site.", "cannotconnecttrouble": "We're having trouble connecting to your site.",
"cannotconnectverify": "<strong>Please check the address is correct.</strong>", "cannotconnectverify": "<strong>Please check the address is correct.</strong>",
"cannotdownloadfiles": "File downloading is disabled. Please contact your site administrator.", "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", "captureaudio": "Record audio",
"capturedimage": "Taken picture.", "capturedimage": "Taken picture.",
"captureimage": "Take picture", "captureimage": "Take picture",
@ -200,6 +201,7 @@
"offline": "Offline", "offline": "Offline",
"ok": "OK", "ok": "OK",
"online": "Online", "online": "Online",
"openfile": "Open file",
"openfullimage": "Click here to display the full size image", "openfullimage": "Click here to display the full size image",
"openinbrowser": "Open in browser", "openinbrowser": "Open in browser",
"openmodinbrowser": "Open {{$a}} in browser", "openmodinbrowser": "Open {{$a}} in browser",

View File

@ -15,6 +15,7 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { CoreAppProvider } from './app'; import { CoreAppProvider } from './app';
import { CoreDomUtilsProvider } from '@providers/utils/dom';
import { CoreFileProvider } from './file'; import { CoreFileProvider } from './file';
import { CoreFilepoolProvider } from './filepool'; import { CoreFilepoolProvider } from './filepool';
import { CoreSitesProvider } from './sites'; import { CoreSitesProvider } from './sites';
@ -30,7 +31,8 @@ import { makeSingleton } from '@singletons/core.singletons';
@Injectable() @Injectable()
export class CoreFileHelperProvider { export class CoreFileHelperProvider {
constructor(protected fileProvider: CoreFileProvider, constructor(protected domUtils: CoreDomUtilsProvider,
protected fileProvider: CoreFileProvider,
protected filepoolProvider: CoreFilepoolProvider, protected filepoolProvider: CoreFilepoolProvider,
protected sitesProvider: CoreSitesProvider, protected sitesProvider: CoreSitesProvider,
protected appProvider: CoreAppProvider, protected appProvider: CoreAppProvider,
@ -339,6 +341,57 @@ export class CoreFileHelperProvider {
throw new Error('Couldn\'t determine file size: ' + file.fileurl); 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<boolean> {
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) {} export class CoreFileHelper extends makeSingleton(CoreFileHelperProvider) {}