From d5e12fb1367bfc88c32985d19fc8e57f7e89f7c4 Mon Sep 17 00:00:00 2001 From: Dani Palou Date: Mon, 25 Nov 2019 15:05:49 +0100 Subject: [PATCH] MOBILE-2235 h5p: Delete index files when updating libs --- .../h5p/components/h5p-player/h5p-player.ts | 19 +++- src/core/h5p/providers/h5p.ts | 87 ++++++++++++++++--- src/core/h5p/providers/pluginfile-handler.ts | 1 + src/providers/plugin-file-delegate.ts | 1 + 4 files changed, 92 insertions(+), 16 deletions(-) diff --git a/src/core/h5p/components/h5p-player/h5p-player.ts b/src/core/h5p/components/h5p-player/h5p-player.ts index ccc5b5325..b4058b4dd 100644 --- a/src/core/h5p/components/h5p-player/h5p-player.ts +++ b/src/core/h5p/components/h5p-player/h5p-player.ts @@ -15,6 +15,7 @@ import { Component, Input, ElementRef, OnInit, OnDestroy, OnChanges, SimpleChange } from '@angular/core'; import { CoreAppProvider } from '@providers/app'; import { CoreEventsProvider } from '@providers/events'; +import { CoreFileProvider } from '@providers/file'; import { CoreFilepoolProvider } from '@providers/filepool'; import { CoreLoggerProvider } from '@providers/logger'; import { CoreSitesProvider } from '@providers/sites'; @@ -62,7 +63,8 @@ export class CoreH5PPlayerComponent implements OnInit, OnChanges, OnDestroy { protected eventsProvider: CoreEventsProvider, protected appProvider: CoreAppProvider, protected domUtils: CoreDomUtilsProvider, - protected pluginFileDelegate: CorePluginFileDelegate) { + protected pluginFileDelegate: CorePluginFileDelegate, + protected fileProvider: CoreFileProvider) { this.logger = loggerProvider.getInstance('CoreH5PPlayerComponent'); this.siteId = sitesProvider.getCurrentSiteId(); @@ -103,8 +105,19 @@ export class CoreH5PPlayerComponent implements OnInit, OnChanges, OnDestroy { if (this.canDownload && (this.state == CoreConstants.DOWNLOADED || this.state == CoreConstants.OUTDATED)) { // Package is downloaded, use the local URL. - promise = this.h5pProvider.getContentIndexFileUrl(this.urlParams.url).catch((error) => { - // It seems there was something wrong when creating the index file. Delete the package? + promise = this.h5pProvider.getContentIndexFileUrl(this.urlParams.url, this.siteId).catch(() => { + + // Index file doesn't exist, probably deleted because a lib was updated. Try to create it again. + return this.filepoolProvider.getInternalUrlByUrl(this.siteId, this.urlParams.url).then((path) => { + return this.fileProvider.getFile(path); + }).then((file) => { + return this.h5pProvider.extractH5PFile(this.urlParams.url, file, this.siteId); + }).then(() => { + // File treated. Try to get the index file URL again. + return this.h5pProvider.getContentIndexFileUrl(this.urlParams.url, this.siteId); + }); + }).catch((error) => { + // Still failing. Delete the H5P package? this.logger.error('Error loading downloaded index:', error, this.src); }); } else { diff --git a/src/core/h5p/providers/h5p.ts b/src/core/h5p/providers/h5p.ts index d92f398a7..dde10e3d3 100644 --- a/src/core/h5p/providers/h5p.ts +++ b/src/core/h5p/providers/h5p.ts @@ -25,6 +25,7 @@ import { CoreMimetypeUtilsProvider } from '@providers/utils/mimetype'; import { CoreUrlUtilsProvider } from '@providers/utils/url'; import { CoreUtilsProvider } from '@providers/utils/utils'; import { CoreH5PUtilsProvider } from './utils'; +import { FileEntry } from '@ionic-native/file'; /** * Service to provide H5P functionalities. @@ -279,6 +280,11 @@ export class CoreH5PProvider { name: 'hash', type: 'TEXT', notNull: true + }, + { + name: 'foldername', + type: 'TEXT', + notNull: true } ] } @@ -566,7 +572,8 @@ export class CoreH5PProvider { db.deleteRecords(this.CONTENT_TABLE), db.deleteRecords(this.LIBRARIES_TABLE), db.deleteRecords(this.LIBRARY_DEPENDENCIES_TABLE), - db.deleteRecords(this.CONTENTS_LIBRARIES_TABLE) + db.deleteRecords(this.CONTENTS_LIBRARIES_TABLE), + db.deleteRecords(this.LIBRARIES_CACHEDASSETS_TABLE) ]); }); } @@ -575,15 +582,13 @@ export class CoreH5PProvider { * Delete cached assets from DB and filesystem. * * @param libraryId Library identifier. - * @param folderName Name of the folder of the H5P package. * @param siteId Site ID. If not defined, current site. * @return Promise resolved when done. */ - protected deleteCachedAssets(libraryId: number, folderName: string, siteId?: string): Promise { + protected deleteCachedAssets(libraryId: number, siteId?: string): Promise { return this.sitesProvider.getSite(siteId).then((site) => { - const db = site.getDb(), - cachedAssetsFolder = this.getCachedAssetsFolderPath(folderName, site.getId()); + const db = site.getDb(); // Get all the hashes that use this library. return db.getRecords(this.LIBRARIES_CACHEDASSETS_TABLE, {libraryid: libraryId}).then((entries) => { @@ -594,6 +599,8 @@ export class CoreH5PProvider { entries.forEach((entry) => { hashes.push(entry.hash); + const cachedAssetsFolder = this.getCachedAssetsFolderPath(entry.foldername, site.getId()); + ['js', 'css'].forEach((type) => { const path = this.textUtils.concatenatePaths(cachedAssetsFolder, entry.hash + '.' + type); @@ -603,11 +610,6 @@ export class CoreH5PProvider { }); }); - // Also, delete the index.html file. - promises.push(this.fileProvider.removeFile(this.getContentIndexPath(folderName, site.getId())).catch(() => { - // Ignore errors. - })); - return Promise.all(promises).then(() => { return db.deleteRecordsList(this.LIBRARIES_CACHEDASSETS_TABLE, 'hash', hashes); }); @@ -636,6 +638,45 @@ export class CoreH5PProvider { return Promise.all(promises); } + /** + * Delete content indexes from filesystem. + * + * @param libraryId Library identifier. + * @param siteId Site ID. If not defined, current site. + * @return Promise resolved when done. + */ + protected deleteContentIndexesForLibrary(libraryId: number, siteId?: string): Promise { + + return this.sitesProvider.getSite(siteId).then((site) => { + const db = site.getDb(); + + // Get the folder names of all the packages that use this library. + const query = 'SELECT DISTINCT hc.foldername ' + + 'FROM ' + this.CONTENTS_LIBRARIES_TABLE + ' hcl ' + + 'JOIN ' + this.CONTENT_TABLE + ' hc ON hcl.h5pid = hc.id ' + + 'WHERE hcl.libraryid = ?', + queryArgs = []; + + queryArgs.push(libraryId); + + return db.execute(query, queryArgs).then((result) => { + const promises = []; + + for (let i = 0; i < result.rows.length; i++) { + const entry = result.rows.item(i); + + // Delete the index.html file. + promises.push(this.fileProvider.removeFile(this.getContentIndexPath(entry.foldername, site.getId())) + .catch(() => { + // Ignore errors. + })); + } + + return Promise.all(promises); + }); + }); + } + /** * Delete library data from DB. * @@ -1796,6 +1837,27 @@ export class CoreH5PProvider { }); } + /** + * Performs actions required when a library has been installed. + * + * @param libraryId ID of library that was installed. + * @param siteId Site ID. + * @return Promise resolved when done. + */ + protected libraryInstalled(libraryId: number, siteId: string): Promise { + const promises = []; + + // Remove all indexes of contents that use this library. + promises.push(this.deleteContentIndexesForLibrary(libraryId, siteId)); + + if (this.aggregateAssets) { + // Remove cached assets that use this library. + promises.push(this.deleteCachedAssets(libraryId, siteId)); + } + + return this.utils.allPromises(promises); + } + /** * Writes library data as string on the form {machineName} {majorVersion}.{minorVersion}. * @@ -2198,9 +2260,8 @@ export class CoreH5PProvider { }); }); }).then(() => { - // Remove cached assets that use this library. - if (this.aggregateAssets && typeof libraryData.libraryId != 'undefined') { - return this.deleteCachedAssets(libraryData.libraryId, folderName, siteId); + if (typeof libraryData.libraryId != 'undefined') { + return this.libraryInstalled(libraryData.libraryId, siteId); } }); })); diff --git a/src/core/h5p/providers/pluginfile-handler.ts b/src/core/h5p/providers/pluginfile-handler.ts index a7787a3f0..fed35e88e 100644 --- a/src/core/h5p/providers/pluginfile-handler.ts +++ b/src/core/h5p/providers/pluginfile-handler.ts @@ -21,6 +21,7 @@ import { CoreUrlUtilsProvider } from '@providers/utils/url'; import { CoreUtilsProvider } from '@providers/utils/utils'; import { CoreH5PProvider } from './h5p'; import { CoreWSExternalFile } from '@providers/ws'; +import { FileEntry } from '@ionic-native/file'; /** * Handler to treat H5P files. diff --git a/src/providers/plugin-file-delegate.ts b/src/providers/plugin-file-delegate.ts index b1c33e1f0..6ff96e5c3 100644 --- a/src/providers/plugin-file-delegate.ts +++ b/src/providers/plugin-file-delegate.ts @@ -15,6 +15,7 @@ import { Injectable } from '@angular/core'; import { CoreLoggerProvider } from './logger'; import { CoreWSExternalFile } from '@providers/ws'; +import { FileEntry } from '@ionic-native/file'; /** * Interface that all plugin file handlers must implement.