diff --git a/src/client/scripts/createaccount.js b/src/client/scripts/createaccount.js index ac6d47e23..0bf785c03 100644 --- a/src/client/scripts/createaccount.js +++ b/src/client/scripts/createaccount.js @@ -1,10 +1,13 @@ +// THIS LINE WILL BE INJECTED by HTMLScriptInjector! +// const reservedUsernames = [...]; + const element_usernameInput = document.getElementById('username'); const element_emailInput = document.getElementById('email'); const element_passwordInput = document.getElementById('password'); const element_submitButton = document.getElementById('submit'); -// This will be an object with 3 arrays: memberList, reservedUsernames, profainWords +// This will be an object with 1 array: profainWords let data; fetch('/createaccount/data') .then((response) => response.json()) @@ -26,7 +29,7 @@ element_usernameInput.addEventListener('input', (event) => { // When username fi const formatError = !onlyLettersAndNumbers(element_usernameInput.value); // If data is still uninitiated (late fetch call), just assume there's no error. const usernameReservedError = - data ? !lengthError && data.reservedUsernames.indexOf(element_usernameInput.value.toLowerCase()) !== -1 + data ? !lengthError && reservedUsernames.includes(element_usernameInput.value.toLowerCase()) : false; const profainError = data ? !lengthError && checkProfanity(element_usernameInput.value) diff --git a/src/server/controllers/createaccountController.js b/src/server/controllers/createaccountController.js index 647d2e56e..1174bcb65 100644 --- a/src/server/controllers/createaccountController.js +++ b/src/server/controllers/createaccountController.js @@ -157,7 +157,6 @@ async function generateAccount({ username, email, password, autoVerify }) { // into the createaccount html instead. function getRegisterData(req, res) { res.json({ - reservedUsernames, profainWords }); } diff --git a/src/server/routes/createaccount.js b/src/server/routes/createaccount.js index e81564e6c..5adad8404 100644 --- a/src/server/routes/createaccount.js +++ b/src/server/routes/createaccount.js @@ -6,8 +6,12 @@ const path = require('path'); const createaccountController = require('../controllers/createaccountController') const {getRegisterData, checkEmailAssociated, checkUsernameAssociated} = require('../controllers/createaccountController'); +const createAccountHTMLPath = path.join(__dirname, '..', '..', '..', 'dist', 'views', 'createaccount.html'); + + + router.get('/', (req, res) => { - res.sendFile(path.join(__dirname, '..', '..', '..', 'dist', 'views', 'createaccount.html')); + res.sendFile(createAccountHTMLPath); }) router.post('/', createaccountController.createNewMember); diff --git a/src/server/utility/HTMLScriptInjector.js b/src/server/utility/HTMLScriptInjector.js index 1d91587af..2482a55dd 100644 --- a/src/server/utility/HTMLScriptInjector.js +++ b/src/server/utility/HTMLScriptInjector.js @@ -14,6 +14,7 @@ const fs = require('fs'); const path = require('path'); const glob = require('glob'); +const { getReservedUsernames } = require('../controllers/createaccountController'); /** * A cache object that has file paths for the keys, and for the values- @@ -26,14 +27,13 @@ let htmlCache = {}; * a specified tag, then cache's that content into {@link htmlCache} * @param {string} htmlFilePath - The path of the html document in the project * @param {string} jsFilePath - The path of the javascript file containing the desired javascript code to inject. - * @param {string} injectAfterTag - The HTML tag after which the JavaScript code will be injected (typically the ``). * @param {Object} [stringInjection] - Optional argument: An object of the form {string: "htmlstring", injectafter: "tags"}. * The string will be insterted after the specified tags into the html doc */ -function prepareAndCacheHTML(htmlFilePath, jsFilePath, injectAfterTag, stringInjection = {}) { - injectScript(htmlFilePath, jsFilePath, injectAfterTag, stringInjection) +function prepareAndCacheHTML(htmlFilePath, jsFilePath, stringInjection = {}) { + injectScriptIntoHeadFromPaths(htmlFilePath, jsFilePath, stringInjection) .then(modifiedHTML => { - htmlCache[htmlFilePath] = modifiedHTML; + addHTMLToCache(htmlFilePath, modifiedHTML) }) .catch(error => console.error("Failed to inject script: ", error)); } @@ -41,14 +41,14 @@ function prepareAndCacheHTML(htmlFilePath, jsFilePath, injectAfterTag, stringInj /** * Injects a JavaScript file's content into an HTML file * after a specified tag, returning the new content. + * RECEIVES file paths, not raw data. * @param {string} htmlFilePath - The path of the html document in the project * @param {string} jsFilePath - The path of the javascript file containing the desired javascript code to inject. - * @param {string} injectAfterTag - The HTML tag after which the JavaScript code will be injected (typically the ``). * @param {Object} [stringInjection] - Optional argument: An object of the form {string: "htmlstring", injectafter: "tags"}. * The string will be insterted after the specified tags into the html doc * @returns {Promise} - A promise that resolves with the modified HTML content, or rejects with an error message. */ -function injectScript(htmlFilePath, jsFilePath, injectAfterTag, stringInjection = {}) { +function injectScriptIntoHeadFromPaths(htmlFilePath, jsFilePath, stringInjection = {}) { return new Promise((resolve, reject) => { // Read the JavaScript file fs.readFile(jsFilePath, 'utf8', (jsErr, jsData) => { @@ -56,17 +56,15 @@ function injectScript(htmlFilePath, jsFilePath, injectAfterTag, stringInjection reject("Error reading the JavaScript file: " + jsErr); return; } - // Create a script tag with the JavaScript content - const scriptTag = ``; - // Read the HTML file and inject the script tag fs.readFile(htmlFilePath, 'utf8', (htmlErr, htmlData) => { if (htmlErr) { reject("Error reading the HTML file: " + htmlErr); return; } - // Inject the script tag before the specified closing tag - let modifiedHTML = htmlData.replace(injectAfterTag, `${injectAfterTag}${scriptTag}`); + + let modifiedHTML = insertScriptInHead(htmlData, jsData) + // Inject the string of the optional argument "stringInjection" into the HTML file, if applicable if (Object.keys(stringInjection).length != 0){ modifiedHTML = modifiedHTML.replace(stringInjection.injectafter, `${stringInjection.injectafter}${stringInjection.string}`); @@ -77,6 +75,28 @@ function injectScript(htmlFilePath, jsFilePath, injectAfterTag, stringInjection }); } +/** + * Inserts the given javascript code into a script tag in the html header. + * Receives RAW, pre-read data. + * @param {string} html - The preloaded html file + * @param {string} js - The javascript code + */ +function insertScriptInHead(html, js) { + // Create a script tag with the JavaScript content + const scriptTag = ``; + // Inject the script tag before the specified closing tag + return html.replace('', `${scriptTag}`); +} + +/** + * Adds the modified html to the cache. + * @param {string} path - The path of the html (typically inside /dist) + * @param {string} contents - The modified contents of the html. + */ +function addHTMLToCache(path, contents) { + htmlCache[path] = contents; +} + /** * Sends our cached HTML file with injected code at the specified path, to the client. * If the HTML content is not ready or doesn't exist, an error message will be sent instead. @@ -104,7 +124,7 @@ function getCachedHTML(htmlFilePath) { // Inject the scripts we want... { // Prepare the injection of our (potentially minified) htmlscript.js script into play.html - const htmlFilePath = path.join(__dirname, '..', '..', "..", 'dist', 'views', 'play.html'); + const htmlFilePath = path.join(__dirname, '..', '..', '..', 'dist', 'views', 'play.html'); const jsFilePath = path.join(__dirname, '..', '..', '..', 'dist', 'scripts', 'game', 'htmlscript.js'); // Prepare the injection of references to all other game scripts into play.html @@ -122,7 +142,30 @@ function getCachedHTML(htmlFilePath) { } // Finally, perform the injection into play.html - prepareAndCacheHTML(htmlFilePath, jsFilePath, '', {string: HTML_callGame_JS_string, injectafter: injectafter_string}); + prepareAndCacheHTML(htmlFilePath, jsFilePath, {string: HTML_callGame_JS_string, injectafter: injectafter_string}); +} + +// Inject the reserved usernames into createaccount.html, then SAVE it in /dist! +// Does using synchronious read and write methods slow down startup? +{ + // Retrieve the reserved usernames + const reservedUsernames = getReservedUsernames(); + const reservedUsernamesJS = `const reservedUsernames = ${JSON.stringify(reservedUsernames)};` + + // Read the HTML file and inject the script tag + const createAccountScriptFilePath = path.join(__dirname, '..', '..', '..', 'dist', 'scripts', 'createaccount.js'); + let createAccountScript; + try { + createAccountScript = fs.readFileSync(createAccountScriptFilePath, 'utf8') + } catch (e) { + console.log("Error reading createaccount.js script in HTMLScriptInjector: " + e.stack); + return; + } + + const modifiedScript = `// Injected by HTMLScriptInjector\n${reservedUsernamesJS}\n\n${createAccountScript}`; + + // Write new script to /dist + fs.writeFileSync(createAccountScriptFilePath, modifiedScript); } module.exports = {