From b0367a43203d1a0be017225461ce6be141b55feb Mon Sep 17 00:00:00 2001 From: Raunak Raj <71929976+bajrangCoder@users.noreply.github.com> Date: Mon, 4 Nov 2024 21:59:58 +0530 Subject: [PATCH] feat: backup plugins --- src/lang/en-us.json | 2 +- src/settings/backupRestore.js | 58 +++++++++++++++++++++++++++++++++-- 2 files changed, 57 insertions(+), 3 deletions(-) diff --git a/src/lang/en-us.json b/src/lang/en-us.json index 0a06f9fcd..6dcdedcf3 100644 --- a/src/lang/en-us.json +++ b/src/lang/en-us.json @@ -269,7 +269,7 @@ "server port": "Server port", "preview settings": "Preview settings", "preview settings note": "If preview port and server port are different, app will not start server and it will instead open https://: in browser or in-app browser. This is useful when you are running a server somewhere else.", - "backup/restore note": "It will only backup your settings, custom theme and key bindings. It will not backup your FTP/SFTP.", + "backup/restore note": "It will only backup your settings, custom theme, installed plugins and key bindings. It will not backup your FTP/SFTP or App state.", "host": "Host", "retry ftp/sftp when fail": "Retry ftp/sftp when fail", "more": "More", diff --git a/src/settings/backupRestore.js b/src/settings/backupRestore.js index 4f0212fa7..1e28f466c 100644 --- a/src/settings/backupRestore.js +++ b/src/settings/backupRestore.js @@ -1,10 +1,13 @@ import settingsPage from "components/settingsPage"; +import toast from "components/toast"; import alert from "dialogs/alert"; import fsOperation from "fileSystem"; +import constants from "lib/constants"; import appSettings from "lib/settings"; import FileBrowser from "pages/fileBrowser"; import Uri from "utils/Uri"; import Url from "utils/Url"; +import helpers from "utils/helpers"; function backupRestore() { const title = @@ -46,6 +49,9 @@ function backupRestore() { try { const settings = appSettings.value; const keyBindings = await fsOperation(KEYBINDING_FILE).readFile("json"); + const installedPlugins = ( + await fsOperation(window.PLUGIN_DIR).lsDir() + ).map((plugin) => plugin.name); const { url } = await FileBrowser("folder", strings["select folder"]); @@ -68,6 +74,7 @@ function backupRestore() { const backupString = JSON.stringify({ settings, keyBindings, + installedPlugins, }); await backupFileFS.writeFile(backupString); @@ -104,14 +111,61 @@ backupRestore.restore = async function (url) { backup = JSON.parse(backup); } catch (error) { alert(strings.error.toUpperCase(), strings["invalid backup file"]); + return; } try { const text = JSON.stringify(backup.keyBindings, undefined, 2); await fsOperation(window.KEYBINDING_FILE).writeFile(text); - } catch (error) {} + } catch (error) { + console.error("Error restoring key bindings:", error); + } + + const { settings, installedPlugins } = backup; + + const { default: installPlugin } = await import("lib/installPlugin"); + + // Restore plugins + if (Array.isArray(installedPlugins)) { + for (const id of installedPlugins) { + try { + if (!id) continue; + const pluginUrl = Url.join(constants.API_BASE, `plugin/${id}`); + const remotePlugin = await fsOperation(pluginUrl) + .readFile("json") + .catch(() => null); + + if (remotePlugin) { + let purchaseToken = null; + if (Number.parseFloat(remotePlugin.price) > 0) { + try { + const [product] = await helpers.promisify(iap.getProducts, [ + remotePlugin.sku, + ]); + if (product) { + async function getPurchase(sku) { + const purchases = await helpers.promisify(iap.getPurchases); + const purchase = purchases.find((p) => + p.productIds.includes(sku), + ); + return purchase; + } + const purchase = await getPurchase(product.productId); + purchaseToken = purchase?.purchaseToken; + } + } catch (error) { + helpers.error(error); + } + } + toast("Restoring plugins", 3000); + await installPlugin(id, remotePlugin.name, purchaseToken); + } + } catch (error) { + console.error(`Error restoring plugin ${id}:`, error); + } + } + } - const { settings } = backup; await appSettings.update(settings); location.reload(); } catch (err) {