From f9265169fd80f8952ff3d97fa6aa7bceff5ea0a0 Mon Sep 17 00:00:00 2001 From: Jeremy Ruston Date: Fri, 23 Feb 2024 09:27:53 +0000 Subject: [PATCH] Commands to load and save tiddlers, bags and recipes as a JSON archive @linonetwo the resulting archive should be suitable for storing in git --- .../modules/command-mws-load.js | 72 ++++++++++--------- .../modules/command-mws-save.js | 62 ++++++++++++++++ 2 files changed, 101 insertions(+), 33 deletions(-) create mode 100644 plugins/tiddlywiki/multiwikiserver/modules/command-mws-save.js diff --git a/plugins/tiddlywiki/multiwikiserver/modules/command-mws-load.js b/plugins/tiddlywiki/multiwikiserver/modules/command-mws-load.js index 9a305914d..277828f03 100644 --- a/plugins/tiddlywiki/multiwikiserver/modules/command-mws-load.js +++ b/plugins/tiddlywiki/multiwikiserver/modules/command-mws-load.js @@ -3,7 +3,7 @@ title: $:/plugins/tiddlywiki/multiwikiserver/mws-load.js type: application/javascript module-type: command -Command to load tiddlers from a file or directory +Command to load tiddlers from a directory \*/ (function(){ @@ -39,47 +39,53 @@ function loadBackupArchive(archivePath) { path = require("path"); // Iterate the bags const bagNames = fs.readdirSync(path.resolve(archivePath,"bags")).filter(filename => filename !== ".DS_Store"); - for(const bagName of bagNames) { + for(const bagFilename of bagNames) { + const bagName = decodeURIComponent(bagFilename); console.log(`Reading bag ${bagName}`); - $tw.mws.store.createBag(decodeURIComponent(bagName),"No description for " + bagName); - // Read the metadata - const jsonInfo = JSON.parse(fs.readFileSync(path.resolve(archivePath,"bags",bagName,"meta/info.json"),"utf8")); - if(fs.existsSync(path.resolve(archivePath,"bags",bagName,"tiddlers"))) { - // Read each tiddler - const tiddlerFilenames = fs.readdirSync(path.resolve(archivePath,"bags",bagName,"tiddlers")).filter(filename => filename !== ".DS_Store"); + const bagInfo = JSON.parse(fs.readFileSync(path.resolve(archivePath,"bags",bagFilename,"meta.json"),"utf8")); + $tw.mws.store.createBag(bagName,bagInfo.description,bagInfo.accesscontrol); + if(fs.existsSync(path.resolve(archivePath,"bags",bagFilename,"tiddlers"))) { + const tiddlerFilenames = fs.readdirSync(path.resolve(archivePath,"bags",bagFilename,"tiddlers")); for(const tiddlerFilename of tiddlerFilenames) { - const tiddlerPath = path.resolve(archivePath,"bags",bagName,"tiddlers",tiddlerFilename), - jsonTiddler = fs.readFileSync(tiddlerPath,"utf8"), - tiddler = JSON.parse(jsonTiddler); - if(tiddler) { - var sanitisedFields = Object.create(null); - for(const fieldName in tiddler) { - const fieldValue = tiddler[fieldName]; - let sanitisedValue = ""; - if(typeof fieldValue === "string") { - sanitisedValue = fieldValue; - } else if($tw.utils.isDate(fieldValue)) { - sanitisedValue = $tw.utils.stringifyDate(fieldValue); - } else if($tw.utils.isArray(fieldValue)) { - sanitisedValue = $tw.utils.stringifyList(fieldValue); - } - sanitisedFields[fieldName] = sanitisedValue; + if(tiddlerFilename.endsWith(".json")) { + const tiddlerPath = path.resolve(archivePath,"bags",bagFilename,"tiddlers",tiddlerFilename), + jsonTiddler = fs.readFileSync(tiddlerPath,"utf8"), + tiddler = sanitiseTiddler(JSON.parse(jsonTiddler)); + if(tiddler && tiddler.title) { + $tw.mws.store.saveBagTiddler(tiddler,bagName); + } else { + console.log(`Malformed JSON tiddler in file ${tiddlerPath}`); } - if(sanitisedFields.title) { - $tw.mws.store.saveBagTiddler(sanitisedFields,decodeURIComponent(bagName)); - } - } else { - console.log(`Malformed JSON tiddler in file ${tiddlerPath}`); } } } } // Iterate the recipes - const recipeNames = fs.readdirSync(path.resolve(archivePath,"recipes")).filter(filename => filename !== ".DS_Store"); - for(const recipeName of recipeNames) { - const jsonInfo = JSON.parse(fs.readFileSync(path.resolve(archivePath,"recipes",recipeName,"info.json"),"utf8")); - $tw.mws.store.createRecipe(decodeURIComponent(recipeName),jsonInfo.recipe.map(recipeLine => recipeLine[0]),"No description for " + recipeName); + const recipeNames = fs.readdirSync(path.resolve(archivePath,"recipes")); + for(const recipeFilename of recipeNames) { + if(recipeFilename.endsWith(".json")) { + const recipeName = decodeURIComponent(recipeFilename.substring(0,recipeFilename.length - ".json".length)); + const jsonInfo = JSON.parse(fs.readFileSync(path.resolve(archivePath,"recipes",recipeFilename),"utf8")); + $tw.mws.store.createRecipe(recipeName,jsonInfo.bag_names,jsonInfo.description,jsonInfo.accesscontrol); + } } +}; + +function sanitiseTiddler(tiddler) { + var sanitisedFields = Object.create(null); + for(const fieldName in tiddler) { + const fieldValue = tiddler[fieldName]; + let sanitisedValue = ""; + if(typeof fieldValue === "string") { + sanitisedValue = fieldValue; + } else if($tw.utils.isDate(fieldValue)) { + sanitisedValue = $tw.utils.stringifyDate(fieldValue); + } else if($tw.utils.isArray(fieldValue)) { + sanitisedValue = $tw.utils.stringifyList(fieldValue); + } + sanitisedFields[fieldName] = sanitisedValue; + } + return sanitisedFields; } exports.Command = Command; diff --git a/plugins/tiddlywiki/multiwikiserver/modules/command-mws-save.js b/plugins/tiddlywiki/multiwikiserver/modules/command-mws-save.js new file mode 100644 index 000000000..c5f957f5a --- /dev/null +++ b/plugins/tiddlywiki/multiwikiserver/modules/command-mws-save.js @@ -0,0 +1,62 @@ +/*\ +title: $:/plugins/tiddlywiki/multiwikiserver/mws-save.js +type: application/javascript +module-type: command + +Command to save tiddlers to a directory + +\*/ +(function(){ + +/*jslint node: true, browser: true */ +/*global $tw: false */ +"use strict"; + +exports.info = { + name: "mws-save", + synchronous: true +}; + +var Command = function(params,commander,callback) { + this.params = params; + this.commander = commander; + this.callback = callback; +}; + +Command.prototype.execute = function() { + var self = this; + // Check parameters + if(this.params.length < 1) { + return "Missing directory path"; + } + var archivePath = this.params[0]; + saveArchive(archivePath); + return null; +}; + +function saveArchive(archivePath) { + const fs = require("fs"), + path = require("path"); + function saveJsonFile(filename,json) { + const filepath = path.resolve(archivePath,filename); + console.log(filepath); + $tw.utils.createFileDirectories(filepath); + fs.writeFileSync(filepath,JSON.stringify(json,null,4)); + } + for(const recipeInfo of $tw.mws.store.listRecipes()) { + console.log(`Recipe ${recipeInfo.recipe_name}`); + saveJsonFile(`recipes/${encodeURIComponent(recipeInfo.recipe_name)}.json`,recipeInfo); + } + for(const bagInfo of $tw.mws.store.listBags()) { + console.log(`Bag ${bagInfo.bag_name}`); + saveJsonFile(`bags/${encodeURIComponent(bagInfo.bag_name)}/meta.json`,bagInfo); + for(const title of $tw.mws.store.getBagTiddlers(bagInfo.bag_name)) { + const tiddlerInfo = $tw.mws.store.getBagTiddler(title,bagInfo.bag_name); + saveJsonFile(`bags/${encodeURIComponent(bagInfo.bag_name)}/tiddlers/${encodeURIComponent(title)}.json`,tiddlerInfo.tiddler); + } + } +} + +exports.Command = Command; + +})();