From 234c34f78057546eeb63451967e661958d295a9c Mon Sep 17 00:00:00 2001 From: Ben <36240171+benkyd@users.noreply.github.com> Date: Tue, 19 Apr 2022 21:42:34 +0100 Subject: [PATCH] smaller images Former-commit-id: dde678d5fa343d18dcf0c82ef7a07936c676bfea --- client/public/about/index.html | 1 + client/public/basket/index.html | 39 +++ client/public/components/basket-popout.mjs | 228 ++++++++++++++++++ client/public/components/basket.mjs | 205 +--------------- client/public/components/product-listing.mjs | 2 +- .../public/components/templates/navbar.html | 2 +- .../components/templates/notificationbar.html | 2 +- client/public/featured/index.html | 1 + client/public/index.html | 1 + client/public/product/index.html | 1 + client/public/search/index.html | 1 + db/image-smallinator.js | 50 ++++ package-lock.json | 13 +- package.json | 3 +- src/controllers/controller-master.js | 5 +- src/first-time-run.js | 26 +- src/routes/content-delivery.js | 0 17 files changed, 358 insertions(+), 222 deletions(-) create mode 100644 client/public/basket/index.html create mode 100644 client/public/components/basket-popout.mjs create mode 100644 db/image-smallinator.js delete mode 100644 src/routes/content-delivery.js diff --git a/client/public/about/index.html b/client/public/about/index.html index 0ec73a7..7ea7a90 100644 --- a/client/public/about/index.html +++ b/client/public/about/index.html @@ -23,6 +23,7 @@ + diff --git a/client/public/basket/index.html b/client/public/basket/index.html new file mode 100644 index 0000000..94d0e8d --- /dev/null +++ b/client/public/basket/index.html @@ -0,0 +1,39 @@ + + + LegoLog! + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/client/public/components/basket-popout.mjs b/client/public/components/basket-popout.mjs new file mode 100644 index 0000000..8b4b493 --- /dev/null +++ b/client/public/components/basket-popout.mjs @@ -0,0 +1,228 @@ +import { RegisterComponent, Component } from './components.mjs'; + +// Basket is stored locally only and is not persisted to the server. +// It is used to store the current basket and is used to calculate the total price of the basket. +// It is also used to store the current user's basket. +// The structure of the basket is in local storage and is as follows: +// { +// "basket": { +// "items": { +// "item1~modifier": { quantity, type }, +// "item2": { quantity, type }, +// ... +// }, +// "total": total +// }, +// } + +let basketCallback = null; + + +// TODO: Does the localstorage have a problem with mutual exclusion? +// TODO: Should the basket be persisted to the server? +export function AddProductToBasket(product, type, amount, brickModifier = 'none') { + if (localStorage.getItem('basket') === null || !localStorage.getItem('basket')) { + localStorage.setItem('basket', JSON.stringify({ + items: {}, + total: 0, + })); + } + + const basket = JSON.parse(localStorage.getItem('basket')); + + if (type === 'brick') { + product += '~' + brickModifier; + } + + if (basket.items[product]) { + basket.items[product].quantity += amount; + } else { + basket.items[product] = { + quantity: amount, + type, + }; + } + + basket.total += amount; + + localStorage.setItem('basket', JSON.stringify(basket)); + + if (basketCallback) { + basketCallback(); + } +} + +export function RemoveProductFromBasket(product, type, amount, brickModifier = 'none') { + if (localStorage.getItem('basket') === null || !localStorage.getItem('basket')) { + return; + } + const basket = JSON.parse(localStorage.getItem('basket')); + + if (type === 'brick') { + product += '~' + brickModifier; + } + + if (basket.items[product] > amount) { + basket.items[product] -= amount; + } else { + delete basket.items[product]; + } + + basket.total -= amount; + + localStorage.setItem('basket', JSON.stringify(basket)); + + if (basketCallback) { + basketCallback(); + } +} + + +class BasketPopout extends Component { + static __IDENTIFY() { return 'basket-popout'; } + + constructor() { + super(BasketPopout); + } + + OnLocalBasketUpdate() { + const basket = localStorage.getItem('basket'); + + if (basket) { + try { + const basketJSON = JSON.parse(basket); + this.setState({ + items: basketJSON.items, + total: basketJSON.total, + }); + } catch (e) { + console.log(e); + } + } else { + this.setState({ + items: {}, + total: 0, + }); + } + } + + OnMount() { + this.OnLocalBasketUpdate(Object.bind(this)); + + basketCallback = this.OnLocalBasketUpdate.bind(this); + } + + Render() { + return { + template: /* html */` + +
+ + {this.state.total} +
+ + +
+ `, + style: ` + #basket-wrapper { + flex-basis: 4%; + } + + .basket { + display: flex; + justify-content: space-between; + padding-bottom: 2px; + } + + .basket:hover { + opacity: 0.5; + } + + #basket-icon { + padding-top: 2px; + cursor: pointer; + } + + #basket-count { + padding-top: 9px; + font-size: 1em; + font-weight: 100; + cursor: pointer; + } + + .popup { + display: none; + } + + .show { + display: flex; + } + + #basket-popup { + position: absolute; + background-color: #AB8FFF; + right: 0; + width: 200px; + height: 200px; + flex-direction: column; + justify-content: center; + align-items: center; + z-index: 100; + } + `, + }; + } + + OnRender() { + // set up basket + const basketToggler = this.root.querySelector('.basket'); + + basketToggler.addEventListener('click', () => { + const popup = this.root.querySelector('.popup'); + popup.classList.toggle('show'); + + popup.addEventListener('click', (e) => { + if (e.target.classList.contains('popup-close')) { + popup.classList.remove('show'); + } + }); + + // allow "click off to close" + // document.addEventListener('click', (e) => { + // if (!popup.contains(e.target)) { + // popup.classList.remove('show'); + // } + // }); + }); + } +} + +RegisterComponent(BasketPopout); diff --git a/client/public/components/basket.mjs b/client/public/components/basket.mjs index 82db116..6d7ff3c 100644 --- a/client/public/components/basket.mjs +++ b/client/public/components/basket.mjs @@ -1,83 +1,5 @@ import { RegisterComponent, Component } from './components.mjs'; -// Basket is stored locally only and is not persisted to the server. -// It is used to store the current basket and is used to calculate the total price of the basket. -// It is also used to store the current user's basket. -// The structure of the basket is in local storage and is as follows: -// { -// "basket": { -// "items": { -// "item1~modifier": { quantity, type }, -// "item2": { quantity, type }, -// ... -// }, -// "total": total -// }, -// } - -let basketCallback = null; - - -// TODO: Does the localstorage have a problem with mutual exclusion? -// TODO: Should the basket be persisted to the server? -export function AddProductToBasket(product, type, amount, brickModifier = 'none') { - if (localStorage.getItem('basket') === null || !localStorage.getItem('basket')) { - localStorage.setItem('basket', JSON.stringify({ - items: {}, - total: 0, - })); - } - - const basket = JSON.parse(localStorage.getItem('basket')); - - if (type === 'brick') { - product += '~' + brickModifier; - } - - if (basket.items[product]) { - basket.items[product].quantity += amount; - } else { - basket.items[product] = { - quantity: amount, - type, - }; - } - - basket.total += amount; - - localStorage.setItem('basket', JSON.stringify(basket)); - - if (basketCallback) { - basketCallback(); - } -} - -export function RemoveProductFromBasket(product, type, amount, brickModifier = 'none') { - if (localStorage.getItem('basket') === null || !localStorage.getItem('basket')) { - return; - } - const basket = JSON.parse(localStorage.getItem('basket')); - - if (type === 'brick') { - product += '~' + brickModifier; - } - - if (basket.items[product] > amount) { - basket.items[product] -= amount; - } else { - delete basket.items[product]; - } - - basket.total -= amount; - - localStorage.setItem('basket', JSON.stringify(basket)); - - if (basketCallback) { - basketCallback(); - } -} - - class Basket extends Component { static __IDENTIFY() { return 'basket'; } @@ -85,133 +7,30 @@ class Basket extends Component { super(Basket); } - OnLocalBasketUpdate() { - const basket = localStorage.getItem('basket'); - - if (basket) { - try { - const basketJSON = JSON.parse(basket); - this.setState({ - items: basketJSON.items, - total: basketJSON.total, - }); - } catch (e) { - console.log(e); - } - } else { - this.setState({ - items: {}, - total: 0, - }); - } - } - - OnMount() { - this.OnLocalBasketUpdate(Object.bind(this)); - - basketCallback = this.OnLocalBasketUpdate.bind(this); - } - Render() { return { template: /* html */` - -
- - {this.state.total} -
- - \ No newline at end of file diff --git a/client/public/components/templates/notificationbar.html b/client/public/components/templates/notificationbar.html index 5635b17..2fe5f1a 100644 --- a/client/public/components/templates/notificationbar.html +++ b/client/public/components/templates/notificationbar.html @@ -1,4 +1,4 @@ -
+n
{this.state.timePretty} - {this.state.title}
diff --git a/client/public/featured/index.html b/client/public/featured/index.html index 3b53e9a..32fa39c 100644 --- a/client/public/featured/index.html +++ b/client/public/featured/index.html @@ -23,6 +23,7 @@ + diff --git a/client/public/index.html b/client/public/index.html index 5815c6d..43a982f 100644 --- a/client/public/index.html +++ b/client/public/index.html @@ -23,6 +23,7 @@ + diff --git a/client/public/product/index.html b/client/public/product/index.html index 3866364..f1625b0 100644 --- a/client/public/product/index.html +++ b/client/public/product/index.html @@ -19,6 +19,7 @@ + diff --git a/client/public/search/index.html b/client/public/search/index.html index 1f1745f..a104595 100644 --- a/client/public/search/index.html +++ b/client/public/search/index.html @@ -23,6 +23,7 @@ + diff --git a/db/image-smallinator.js b/db/image-smallinator.js new file mode 100644 index 0000000..25b4cf0 --- /dev/null +++ b/db/image-smallinator.js @@ -0,0 +1,50 @@ +const fs = require('fs'); +const sharp = require('sharp'); + +// itterate over every single png file in img recursively +const dir = './db/img'; +const replaceDir = './db/image'; + +// https://stackoverflow.com/questions/5827612/node-js-fs-readdir-recursive-directory-search +const { promisify } = require('util'); +const { resolve } = require('path'); +const readdir = promisify(fs.readdir); +const stat = promisify(fs.stat); + +async function getFiles(dir) { + const subdirs = await readdir(dir); + const files = await Promise.all(subdirs.map(async (subdir) => { + const res = resolve(dir, subdir); + return (await stat(res)).isDirectory() ? getFiles(res) : res; + })); + return files.reduce((a, f) => a.concat(f), []); +} + +function itterate(files) { + for (let i = 0; i < files.length; i++) { + const file = files[i]; + + // if file is a png, compress using sharp + if (file.endsWith('.png')) { + console.log(`Compressing ${file}`); + const fileName = file.split('img').pop(); + sharp(file) + .withMetadata() + .png({ + quality: 50, + compression: 6, + }) + .toFile(`${replaceDir}/${fileName}`, (err) => { + if (err) { + console.log(err); + return; + } + console.log(`Compressed ${file}`); + }); + } + } +} + +getFiles(dir) + .then(files => itterate(files)) + .catch(e => console.error(e)); diff --git a/package-lock.json b/package-lock.json index bbefec1..f45b08c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -25,7 +25,8 @@ "pg": "^8.7.3", "pg-format": "^1.0.4", "pg-native": "^3.0.0", - "sharp": "^0.30.3" + "sharp": "^0.30.3", + "sql-escape": "^1.0.1" }, "devDependencies": { "eslint": "^8.9.0", @@ -8722,6 +8723,11 @@ "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" }, + "node_modules/sql-escape": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sql-escape/-/sql-escape-1.0.1.tgz", + "integrity": "sha1-96BQdDxPL5G8SqhVLtEO0cIoTi8=" + }, "node_modules/stack-utils": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.5.tgz", @@ -15854,6 +15860,11 @@ "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" }, + "sql-escape": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sql-escape/-/sql-escape-1.0.1.tgz", + "integrity": "sha1-96BQdDxPL5G8SqhVLtEO0cIoTi8=" + }, "stack-utils": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.5.tgz", diff --git a/package.json b/package.json index ce5aba1..97d1e99 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,8 @@ "pg": "^8.7.3", "pg-format": "^1.0.4", "pg-native": "^3.0.0", - "sharp": "^0.30.3" + "sharp": "^0.30.3", + "sql-escape": "^1.0.1" }, "devDependencies": { "eslint": "^8.9.0", diff --git a/src/controllers/controller-master.js b/src/controllers/controller-master.js index f2b4e02..3d9aaff 100644 --- a/src/controllers/controller-master.js +++ b/src/controllers/controller-master.js @@ -1,3 +1,4 @@ +const escape = require('sql-escape'); // http://stackoverflow.com/questions/11919065/sort-an-array-by-the-levenshtein-distance-with-best-performance-in-javascript function LevenshteinDistance(s, t) { @@ -50,8 +51,10 @@ function LevenshteinDistance(s, t) { return d[n][m]; } +// TODO: get this working properly + function SanatiseQuery(query) { - return query.replace(/[^a-zA-Z0-9 ]/g, '').toLowerCase(); + return escape(query).toLowerCase().replace(/[()*]/g, ''); } module.exports = { diff --git a/src/first-time-run.js b/src/first-time-run.js index 5b3717f..e52fd16 100644 --- a/src/first-time-run.js +++ b/src/first-time-run.js @@ -3,9 +3,6 @@ const Logger = require('./logger.js'); const Config = require('./config.js'); const Database = require('./database/database.js'); -const decompress = require('decompress'); -const decompressTargz = require('decompress-targz'); - const fs = require('fs'); console.log('LegoLog Setting Up:tm:'); @@ -18,28 +15,14 @@ async function main() { logToConsole: process.env.LOG_CONSOLE, logFile: process.env.LOG_FILE, }); - - Logger.Info('DECOMPRESSING - DO NOT CLOSE, THIS MAY TAKE A WHILE...'); - Logger.Info('DECOMPRESSING - DO NOT CLOSE, THIS MAY TAKE A WHILE...'); - // connect to database await Database.Connect(); - // unzip images ASYNC - decompress('db/img.tar.gz', 'db/', { - plugins: [ - decompressTargz(), - ], - }).then(() => { - console.log('Files decompressed'); - }); - - const tableQuery = fs.readFileSync('./db/schema.sql').toString(); /* eslint-disable-next-line */ await new Promise(async (resolve, reject) => { // run setup script to create schema - await db.query(tableQuery, [], (err, res) => { + await Database.query(tableQuery, [], (err, res) => { if (err) { Logger.Error(err); resolve(); @@ -56,7 +39,7 @@ async function main() { const dump = fs.readFileSync('./db/dump.sql').toString(); /* eslint-disable-next-line */ await new Promise(async (resolve, reject) => { - await db.query(dump, [], (err, res) => { + await Database.query(dump, [], (err, res) => { if (err) { Logger.Error(err); resolve(); @@ -69,10 +52,7 @@ async function main() { }); }); - await db.destroy(); - - Logger.Info('DECOMPRESSING - DO NOT CLOSE, THIS MAY TAKE A WHILE...'); - Logger.Info('DECOMPRESSING - DO NOT CLOSE, THIS MAY TAKE A WHILE...'); + await Database.destroy(); } main(); diff --git a/src/routes/content-delivery.js b/src/routes/content-delivery.js deleted file mode 100644 index e69de29..0000000