Avatar of the person chatting

write a function for Node.js and Express that handles a JSON post to save a JSON file of a given name with data as supplied as member "contents". it will have a fixed limit on size of the post, as well as the size of the data. it will call a function called "authorize()" which is stubbed in, and can be assumed to correctly send true or false to a callback function, based on whether the file write should be allowed. the file will be stored in a directory called "./www/uploadedData/"

Here is an example implementation of the function described:

javascript
const express = require("express"); const bodyParser = require("body-parser"); const fs = require("fs"); const MAX_POST_SIZE = 1048576; // 1 MB const MAX_FILE_SIZE = 10485760; // 10 MB const UPLOAD_DIR = "./www/uploadedData/"; const app = express(); app.use(bodyParser.json({ limit: MAX_POST_SIZE })); app.post("/save-file", (req, res) => { const fileName = req.body.fileName; const contents = req.body.contents; if (!fileName || !contents) { return res.status(400).send({ error: "fileName and contents are required" }); } if (contents.length > MAX_FILE_SIZE) { return res.status(400).send({ error: "File size exceeded the limit" }); } authorize((authorized) => { if (!authorized) { return res.status(401).send({ error: "Unauthorized" }); } fs.writeFile(`${UPLOAD_DIR}/${fileName}.json`, contents, (err) => { if (err) { return res.status(500).send({ error: "Failed to save file" }); } res.send({ message: "File saved successfully" }); }); }); }); function authorize(callback) { // implementation of the authorization function // can be assumed to correctly send true or false to the callback } app.listen(3000, () => { console.log("Server started on port 3000"); });
Avatar of the person chatting

change the above function so that, when saving a file, it will first see if the file exists. if it does, the existing file will be moved to a subdirectory "oldVersions", with its name being followed by an underbar and a number representing that file's timestamp in seconds since the unix epoch

Here is an updated implementation that checks if the file exists before saving it:

javascript
const express = require("express"); const bodyParser = require("body-parser"); const fs = require("fs"); const path = require("path"); const MAX_POST_SIZE = 1048576; // 1 MB const MAX_FILE_SIZE = 10485760; // 10 MB const UPLOAD_DIR = "./www/uploadedData/"; const OLD_VERSIONS_DIR = "oldVersions"; const app = express(); app.use(bodyParser.json({ limit: MAX_POST_SIZE })); app.post("/save-file", (req, res) => { const fileName = req.body.fileName; const contents = req.body.contents; if (!fileName || !contents) { return res.status(400).send({ error: "fileName and contents are required" }); } if (contents.length > MAX_FILE_SIZE) { return res.status(400).send({ error: "File size exceeded the limit" }); } const filePath = `${UPLOAD_DIR}/${fileName}.json`; fs.stat(filePath, (err, stats) => { if (!err && stats.isFile()) { const oldVersionFilePath = path.join(UPLOAD_DIR, OLD_VERSIONS_DIR, `${fileName}_${Date.now()}.json`); fs.rename(filePath, oldVersionFilePath, (renameError) => { if (renameError) { return res.status(500).send({ error: "Failed to move existing file to old versions directory" }); } saveFile(); }); } else { saveFile(); } }); function saveFile() { authorize((authorized) => { if (!authorized) { return res.status(401).send({ error: "Unauthorized" }); } fs.writeFile(filePath, contents, (writeError) => { if (writeError) { return res.status(500).send({ error: "Failed to save file" }); } res.send({ message: "File saved successfully" }); }); }); } }); function authorize(callback) { // implementation of the authorization function // can be assumed to correctly send true or false to the callback } app.listen(3000, () => { console.log("Server started on port 3000"); });
Avatar of the person chatting

write a function that does all the logic included in the above post handler, but broken out into a function that doesn't know about Express requests and responses. Assume the function is named "handleJsonUpload" and takes a javascript object (as parsed from JSON) and a callback function. The callback function will be called when complete, and will typically handle sending the response to the client

Here is an implementation of the function handleJsonUpload that does all the logic included in the above post handler:

javascript
const fs = require("fs"); const path = require("path"); const MAX_FILE_SIZE = 10485760; // 10 MB const UPLOAD_DIR = "./www/uploadedData/"; const OLD_VERSIONS_DIR = "oldVersions"; function handleJsonUpload(payload, callback) { const fileName = payload.fileName; const contents = payload.contents; if (!fileName || !contents) { return callback({ error: "fileName and contents are required" }); } if (contents.length > MAX_FILE_SIZE) { return callback({ error: "File size exceeded the limit" }); } const filePath = `${UPLOAD_DIR}/${fileName}.json`; fs.stat(filePath, (err, stats) => { if (!err && stats.isFile()) { const oldVersionFilePath = path.join(UPLOAD_DIR, OLD_VERSIONS_DIR, `${fileName}_${Date.now()}.json`); fs.rename(filePath, oldVersionFilePath, (renameError) => { if (renameError) { return callback({ error: "Failed to move existing file to old versions directory" }); } saveFile(); }); } else { saveFile(); } }); function saveFile() { authorize((authorized) => { if (!authorized) { return callback({ error: "Unauthorized" }); } fs.writeFile(filePath, contents, (writeError) => { if (writeError) { return callback({ error: "Failed to save file" }); } callback({ message: "File saved successfully" }); }); }); } } function authorize(callback) { // implementation of the authorization function // can be assumed to correctly send true or false to the callback }

The callback function is passed an object that will either contain an error message, or a success message. This function can be used in an Express route handler by passing the req.body as the first argument and the res.send as the second argument, for example:

scss
app.post("/save-file", (req, res) => { handleJsonUpload(req.body, (result) => { if (result.error) { return res.status(400).send(result); } res.send(result); }); });
Avatar of the person chatting

make a web page that does a post to the server to the above "/save-file" url and posts the contents of a textarea element, id "jsonContents" and a text input element, id "fileName". it should validate that it is proper json before sending. any output from the server or client side errors such as bad input should be appended to a div element that has green text, in courier new font, as a new line. the output should show a maximum of 50 lines, and always stay scrolled so the last line is visible

Here is a simple HTML and JavaScript implementation of the web page that makes a POST request to the "/save-file" endpoint:

html
<!DOCTYPE html> <html> <head> <style> #output { height: 200px; overflow: auto; font-family: "Courier New"; color: green; } </style> </head> <body> <textarea id="jsonContents" rows="10" cols="50"></textarea> <br /> <input type="text" id="fileName" /> <br /> <button id="uploadButton">Upload</button> <br /> <br /> <div id="output"></div> <script> const outputDiv = document.querySelector("#output"); const uploadButton = document.querySelector("#uploadButton"); uploadButton.addEventListener("click", () => { const jsonContents = document.querySelector("#jsonContents").value; const fileName = document.querySelector("#fileName").value; try { const json = JSON.parse(jsonContents); const data = { contents: jsonContents, fileName: fileName }; fetch("/save-file", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(data) }) .then((res) => res.json()) .then((response) => { outputDiv.innerHTML += `${response.message}\n`; outputDiv.scrollTop = outputDiv.scrollHeight; }) .catch((error) => { outputDiv.innerHTML += `Error: ${error}\n`; outputDiv.scrollTop = outputDiv.scrollHeight; }); } catch (error) { outputDiv.innerHTML += `Error: ${error}\n`; outputDiv.scrollTop = outputDiv.scrollHeight; } }); </script> </body> </html>

This page makes use of the Fetch API to make a POST request to the "/save-file" endpoint. The contents of the textarea and the file name are extracted and combined into an object that is sent as the request body in JSON format.

The response from the server is expected to be a JSON object, and is displayed in the #output div by adding a new line with the message. If there is a JSON parse error or a fetch error, the error message is displayed in the same way.

The output div is set to have a maximum height of 200 pixels, and overflow is set to "auto" to allow for scrolling. The innerHTML of the output div is always appended with a new line, and the scrollTop is set to the scrollHeight so that the last line is always visible.