diff --git a/src/core/h5p/providers/h5p.ts b/src/core/h5p/providers/h5p.ts index dde10e3d3..6dc9f3814 100644 --- a/src/core/h5p/providers/h5p.ts +++ b/src/core/h5p/providers/h5p.ts @@ -617,6 +617,27 @@ export class CoreH5PProvider { }); } + /** + * Delete all package content data. + * + * @param fileUrl File URL. + * @param siteId Site ID. If not defined, current site. + * @return Promise resolved when done. + */ + deleteContentByUrl(fileUrl: string, siteId?: string): Promise { + siteId = siteId || this.sitesProvider.getCurrentSiteId(); + + return this.getContentDataByUrl(fileUrl, siteId).then((data) => { + const promises = []; + + promises.push(this.deleteContentData(data.id, siteId)); + + promises.push(this.deleteContentFolder(data.foldername, siteId)); + + return this.utils.allPromises(promises); + }); + } + /** * Delete content data from DB. * @@ -638,6 +659,17 @@ export class CoreH5PProvider { return Promise.all(promises); } + /** + * Deletes a content folder from the file system. + * + * @param folderName Folder name of the content. + * @param siteId Site ID. If not defined, current site. + * @return Promise resolved when done. + */ + deleteContentFolder(folderName: string, siteId?: string): Promise { + return this.fileProvider.removeDir(this.getContentFolderPath(folderName, siteId)); + } + /** * Delete content indexes from filesystem. * @@ -1160,9 +1192,13 @@ export class CoreH5PProvider { return this.sitesProvider.getSite(siteId).then((site) => { const db = site.getDb(); + // Try to use the folder name, it should be more reliable than the URL. return this.getContentFolderNameByUrl(fileUrl, site.getId()).then((folderName) => { return db.getRecord(this.CONTENT_TABLE, {foldername: folderName}); + }, () => { + // Cannot get folder name, the h5p file was probably deleted. Just use the URL. + return db.getRecord(this.CONTENT_TABLE, {fileurl: fileUrl}); }); }); } diff --git a/src/core/h5p/providers/pluginfile-handler.ts b/src/core/h5p/providers/pluginfile-handler.ts index fed35e88e..71b82053d 100644 --- a/src/core/h5p/providers/pluginfile-handler.ts +++ b/src/core/h5p/providers/pluginfile-handler.ts @@ -48,6 +48,19 @@ export class CoreH5PPluginFileHandler implements CorePluginFileHandler { return this.h5pProvider.getTrustedH5PFile(file.fileurl, {}, false, siteId); } + /** + * React to a file being deleted. + * + * @param fileUrl The file URL used to download the file. + * @param path The path of the deleted file. + * @param siteId Site ID. If not defined, current site. + * @return Promise resolved when done. + */ + fileDeleted(fileUrl: string, path: string, siteId?: string): Promise { + // If an h5p file is deleted, remove the contents folder. + return this.h5pProvider.deleteContentByUrl(fileUrl, siteId); + } + /** * Given an HTML element, get the URLs of the files that should be downloaded and weren't treated by * CoreDomUtilsProvider.extractDownloadableFilesFromHtml. diff --git a/src/providers/filepool.ts b/src/providers/filepool.ts index ddea2ddbb..5ad03bead 100644 --- a/src/providers/filepool.ts +++ b/src/providers/filepool.ts @@ -2646,7 +2646,22 @@ export class CoreFilepoolProvider { protected removeFileById(siteId: string, fileId: string): Promise { return this.sitesProvider.getSiteDb(siteId).then((db) => { // Get the path to the file first since it relies on the file object stored in the pool. - return Promise.resolve(this.getFilePath(siteId, fileId)).then((path) => { + // Don't use getFilePath to prevent performing 2 DB requests. + let path = this.getFilepoolFolderPath(siteId) + '/' + fileId, + fileUrl; + + return this.hasFileInPool(siteId, fileId).then((entry) => { + fileUrl = entry.url; + + if (entry.extension) { + path += '.' + entry.extension; + } + + return path; + }).catch(() => { + // If file not found, use the path without extension. + return path; + }).then((path) => { const promises = []; // Remove entry from filepool store. @@ -2668,6 +2683,10 @@ export class CoreFilepoolProvider { return Promise.all(promises).then(() => { this.notifyFileDeleted(siteId, fileId); + + return this.pluginFileDelegate.fileDeleted(fileUrl, path, siteId).catch((error) => { + // Ignore errors. + }); }); }); }); diff --git a/src/providers/plugin-file-delegate.ts b/src/providers/plugin-file-delegate.ts index 6ff96e5c3..01aea603e 100644 --- a/src/providers/plugin-file-delegate.ts +++ b/src/providers/plugin-file-delegate.ts @@ -57,6 +57,16 @@ export interface CorePluginFileHandler { */ canDownloadFile?(file: CoreWSExternalFile, siteId?: string): Promise; + /** + * React to a file being deleted. + * + * @param fileUrl The file URL used to download the file. + * @param path The path of the deleted file. + * @param siteId Site ID. If not defined, current site. + * @return Promise resolved when done. + */ + fileDeleted?(fileUrl: string, path: string, siteId?: string): Promise; + /** * Given an HTML element, get the URLs of the files that should be downloaded and weren't treated by * CoreDomUtilsProvider.extractDownloadableFilesFromHtml. @@ -139,6 +149,24 @@ export class CorePluginFileDelegate { return Promise.resolve(file); } + /** + * React to a file being deleted. + * + * @param fileUrl The file URL used to download the file. + * @param path The path of the deleted file. + * @param siteId Site ID. If not defined, current site. + * @return Promise resolved when done. + */ + fileDeleted(fileUrl: string, path: string, siteId?: string): Promise { + const handler = this.getHandlerForFile({fileurl: fileUrl}); + + if (handler && handler.fileDeleted) { + return handler.fileDeleted(fileUrl, path, siteId); + } + + return Promise.resolve(); + } + /** * Get the handler for a certain pluginfile url. * @@ -310,7 +338,7 @@ export class CorePluginFileDelegate { treatDownloadedFile(fileUrl: string, file: FileEntry, siteId?: string): Promise { const handler = this.getHandlerForFile({fileurl: fileUrl}); - if (handler && handler.getFileSize) { + if (handler && handler.treatDownloadedFile) { return handler.treatDownloadedFile(fileUrl, file, siteId); }