From c70b8f938ababf03bb8f46db8d5d03547ea45e61 Mon Sep 17 00:00:00 2001 From: Oliver Date: Sat, 7 Feb 2026 00:32:47 -0700 Subject: [PATCH] Initial framework to make URL DB imports work --- langs/en-ca.json | 3 +- module/api.mjs | 2 ++ module/utils/imports.mjs | 70 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 module/utils/imports.mjs diff --git a/langs/en-ca.json b/langs/en-ca.json index b3fff92..c177655 100644 --- a/langs/en-ca.json +++ b/langs/en-ca.json @@ -73,7 +73,8 @@ "error": { "db-out-of-date": "Database out of date, please try again.", "document-ID-404": "Cannot find {dbType} with ID: {id}", - "no-upload-permission": "Cannot save due to missing the \"Upload Files\" permission." + "no-upload-permission": "Cannot save due to missing the \"Upload Files\" permission.", + "invalid-import-type": "Invalid import type: {type}" } } } diff --git a/module/api.mjs b/module/api.mjs index f74de0f..72ddd09 100644 --- a/module/api.mjs +++ b/module/api.mjs @@ -6,6 +6,7 @@ import { ImageApp } from "./apps/ImageApp.mjs"; // Utils import { convertToWebp, getFileSize, hashFile, lastModifiedAt } from "./utils/fs.mjs"; +import { importFromURL } from "./utils/imports.mjs"; export const api = foundry.utils.deepFreeze({ Apps: { @@ -21,5 +22,6 @@ export const api = foundry.utils.deepFreeze({ lastModifiedAt, getFileSize, }, + importFromURL, }, }); diff --git a/module/utils/imports.mjs b/module/utils/imports.mjs new file mode 100644 index 0000000..38e2a99 --- /dev/null +++ b/module/utils/imports.mjs @@ -0,0 +1,70 @@ +import { getFile } from "./fs.mjs"; + +const { Dialog } = foundry.applications.api; +const { fetchJsonWithTimeout, mergeObject } = foundry.utils; + +const TRUSTED_DOMAINS = new Set([ + `git.varify.ca`, + `cdn.varify.ca`, + window.location.host, +]); + +/** + * Imports an existing JSON DB into the module's current database. + * + * @param {string} url The URL pointing to a raw JSON file + * @param {`keep`|`replace`|`merge`} type The type of import that should be performed + */ +export async function importFromURL(url, type) { + + if (![`keep`, `replace`, `merge`].includes(type)) { + ui.notifications.error(_loc(`IT.notifs.error.invalid-import-type`, { type })); + return false; + }; + + const domain = new URL(url); + if (!TRUSTED_DOMAINS.has(domain.host)) { + const confirmed = await Dialog.confirm({ + content: `An import is trying to happen from:
${url}
Do you trust this website?`, + rejectClose: false, + }); + if (!confirmed) { + return false; + }; + }; + + let data; + try { + data = await fetchJsonWithTimeout(url); + } catch (err) { + throw err; + }; + + const images = await getFile(`storage/db/images.json`); + const artists = await getFile(`storage/db/artists.json`); + + switch (type) { + case `keep`: { + importKeepExisting(data, images, artists); + break; + }; + case `replace`: { + importReplaceExisting(data, images, artists); + break; + }; + case `merge`: { + await importMerge(data, images, artists); + break; + }; + }; + + return true; +}; + +async function importKeepExisting(data, imageDB, artistDB) {}; + +async function importReplaceExisting(data, imageDB, artistDB) {}; + +async function importMerge(data, imageDB, artistDB) { + throw `Merge-based importing is not implemented yet`; +};