diff --git a/src/core/features/h5p/classes/file-storage.ts b/src/core/features/h5p/classes/file-storage.ts index 9b949b889..50d1c93ea 100644 --- a/src/core/features/h5p/classes/file-storage.ts +++ b/src/core/features/h5p/classes/file-storage.ts @@ -449,4 +449,43 @@ export class CoreH5PFileStorage { } } + /** + * Check that library is fully saved to the file system. + * + * @param libraryData Library data. + * @param siteId Site ID. If not defined, current site. + * @returns Promise resolved with true if all library files are present. + */ + async checkLibrary(libraryData: CoreH5PLibraryBeingSaved, siteId?: string): Promise { + const getFileNames = async (baseDir: string, dirName = ''): Promise => { + const entries = await CoreFile.getDirectoryContents( baseDir + dirName); + const fileNames: string[] = []; + + for (const entry of entries) { + const name = dirName + '/' + entry.name; + if (entry.isDirectory) { + fileNames.push(...(await getFileNames(baseDir, name))); + } else { + fileNames.push(name); + } + } + + return fileNames; + }; + + if (!libraryData.uploadDirectory) { + return true; + } + + siteId = siteId || CoreSites.getCurrentSiteId(); + const folderPath = this.getLibraryFolderPath(libraryData, siteId); + + const [sourceFiles, destFiles] = await Promise.all([ + getFileNames(libraryData.uploadDirectory), + getFileNames(folderPath).catch(() => ([])).then(files => new Set(files)), + ]); + + return sourceFiles.every(name => destFiles.has(name)); + } + } diff --git a/src/core/features/h5p/classes/storage.ts b/src/core/features/h5p/classes/storage.ts index 4d4a3d892..9f6bcdcc6 100644 --- a/src/core/features/h5p/classes/storage.ts +++ b/src/core/features/h5p/classes/storage.ts @@ -65,7 +65,9 @@ export class CoreH5PStorage { const newerPatchVersion = existingLibrary.patchversion < libraryData.patchVersion; - if (!newerPatchVersion) { + // Make sure the library is fully saved to the file system if it is present in the DB. + // Some files might be missing if a previous library update was interrupted. + if (!newerPatchVersion && await this.h5pCore.h5pFS.checkLibrary(libraryData, siteId)) { // Same or older version, no need to save. libraryData.saveDependencies = false; @@ -79,21 +81,12 @@ export class CoreH5PStorage { libraryData.metadataSettings = libraryData.metadataSettings ? CoreH5PMetadata.boolifyAndEncodeSettings(libraryData.metadataSettings) : undefined; + // Save the library files before saving to DB, in case the app is closed while copying the files. + await this.h5pCore.h5pFS.saveLibrary(libraryData, siteId); + // Save the library data in DB. await this.h5pFramework.saveLibraryData(libraryData, siteId); - // Now save it in FS. - try { - await this.h5pCore.h5pFS.saveLibrary(libraryData, siteId); - } catch (error) { - if (libraryData.libraryId) { - // An error occurred, delete the DB data because the lib FS data has been deleted. - await this.h5pFramework.deleteLibrary(libraryData.libraryId, siteId); - } - - throw error; - } - if (libraryData.libraryId !== undefined) { const promises: Promise[] = []; @@ -196,21 +189,15 @@ export class CoreH5PStorage { content.params = JSON.stringify(data.contentJsonData); - // Save the content data in DB. - await this.h5pCore.saveContent(content, folderName, fileUrl, siteId); - // Save the content files in their right place in FS. const destFolder = CorePath.concatenatePaths(CoreFileProvider.TMPFOLDER, 'h5p/' + folderName); const contentPath = CorePath.concatenatePaths(destFolder, 'content'); - try { - await this.h5pCore.h5pFS.saveContent(contentPath, folderName, siteId); - } catch (error) { - // An error occurred, delete the DB data because the content files have been deleted. - await this.h5pFramework.deleteContentData(content.id!, siteId); + // Save the content files before saving to DB, in case the app is closed while copying the files. + await this.h5pCore.h5pFS.saveContent(contentPath, folderName, siteId); - throw error; - } + // Save the content data in DB. + await this.h5pCore.saveContent(content, folderName, fileUrl, siteId); } return content;