From 6c01e6eaaf7a73b3519058d2fb0606c5d690e53e Mon Sep 17 00:00:00 2001 From: Jakub Kuczys <me@jacken.men> Date: Tue, 21 Mar 2023 14:39:54 +0100 Subject: [PATCH] Accept `.blob` files when importing Actual export (#785) I'm not sure if this is something you want but it was a simple change so I figured I might as well contribute it. This PR allows the user to upload `.blob` files that they may have gotten from server's `user-files/` folder. This can be useful if the user didn't export the file but has server backups. --------- Co-authored-by: Jed Fox <git@jedfox.com> --- packages/loot-core/src/server/cloud-storage.js | 9 +++++++-- packages/loot-core/src/server/main.js | 16 ++++++++++++---- packages/loot-core/src/shared/errors.js | 1 + .../src/components/manager/ImportActual.js | 8 +++++++- upcoming-release-notes/785.md | 6 ++++++ 5 files changed, 33 insertions(+), 7 deletions(-) create mode 100644 upcoming-release-notes/785.md diff --git a/packages/loot-core/src/server/cloud-storage.js b/packages/loot-core/src/server/cloud-storage.js index fd5a9a5cd..d37d97530 100644 --- a/packages/loot-core/src/server/cloud-storage.js +++ b/packages/loot-core/src/server/cloud-storage.js @@ -161,8 +161,13 @@ export async function exportBuffer() { } export async function importBuffer(fileData, buffer) { - let zipped = new AdmZip(buffer); - let entries = zipped.getEntries(); + let zipped, entries; + try { + zipped = new AdmZip(buffer); + entries = zipped.getEntries(); + } catch (err) { + throw FileDownloadError('not-zip-file'); + } let dbEntry = entries.find(e => e.entryName.includes('db.sqlite')); let metaEntry = entries.find(e => e.entryName.includes('metadata.json')); diff --git a/packages/loot-core/src/server/main.js b/packages/loot-core/src/server/main.js index d81348c10..eed06087f 100644 --- a/packages/loot-core/src/server/main.js +++ b/packages/loot-core/src/server/main.js @@ -2108,10 +2108,18 @@ handlers['import-budget'] = async function ({ filepath, type }) { // duplicate some of the workflow await handlers['close-budget'](); - let { id } = await cloudStorage.importBuffer( - { cloudFileId: null, groupId: null }, - buffer, - ); + let id; + try { + ({ id } = await cloudStorage.importBuffer( + { cloudFileId: null, groupId: null }, + buffer, + )); + } catch (e) { + if (e.type === 'FileDownloadError') { + return { error: e.reason }; + } + throw e; + } // We never want to load cached data from imported files, so // delete the cache diff --git a/packages/loot-core/src/shared/errors.js b/packages/loot-core/src/shared/errors.js index 3b20c0519..fc0a8cd19 100644 --- a/packages/loot-core/src/shared/errors.js +++ b/packages/loot-core/src/shared/errors.js @@ -28,6 +28,7 @@ export function getDownloadError({ reason, meta, fileName }) { case 'network': case 'download-failure': return 'Downloading the file failed. Check your network connection.'; + case 'not-zip-file': case 'invalid-zip-file': case 'invalid-meta-file': return 'Downloaded file is invalid, sorry! Contact help@actualbudget.com for support.'; diff --git a/packages/loot-design/src/components/manager/ImportActual.js b/packages/loot-design/src/components/manager/ImportActual.js index f541b061f..50cb6da77 100644 --- a/packages/loot-design/src/components/manager/ImportActual.js +++ b/packages/loot-design/src/components/manager/ImportActual.js @@ -12,6 +12,12 @@ function getErrorMessage(error) { return 'Unable to parse file. Please select a JSON file exported from nYNAB.'; case 'not-ynab5': return 'This file is not valid. Please select a JSON file exported from nYNAB.'; + case 'not-zip-file': + return 'This file is not valid. Please select an unencrypted archive of Actual data.'; + case 'invalid-zip-file': + return 'This archive is not a valid Actual export file.'; + case 'invalid-metadata-file': + return 'The metadata file in the given archive is corrupted.'; default: return 'An unknown error occurred while importing. Sorry! We have been notified of this issue.'; } @@ -25,7 +31,7 @@ function Import({ modalProps, availableImports }) { async function onImport() { const res = await window.Actual.openFileDialog({ properties: ['openFile'], - filters: [{ name: 'actual', extensions: ['zip'] }], + filters: [{ name: 'actual', extensions: ['zip', 'blob'] }], }); if (res) { setImporting(true); diff --git a/upcoming-release-notes/785.md b/upcoming-release-notes/785.md new file mode 100644 index 000000000..534b88ee0 --- /dev/null +++ b/upcoming-release-notes/785.md @@ -0,0 +1,6 @@ +--- +category: Enhancements +authors: [Jackenmen] +--- + +Allow importing `.blob` files from actual-server -- GitLab