diff --git a/app.js b/app.js index ba938f8..220e887 100644 --- a/app.js +++ b/app.js @@ -3,7 +3,6 @@ const express = require('express'); const qr = require('qr-image'); const { - loadDatabase, searchDatabase, addMarkdown, addSimilarItems, @@ -11,21 +10,7 @@ const { const app = express(); -const allScans = []; - -function logScanned(uuid, fixture) { - // TRICK: fixture tells if the the uuid was found in database or not - if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(uuid)) { - return; - } - const now = new Date(); - if (!fixture) { - allScans.unshift({ time: now, status: 'missing', uuid }); - return; - } - allScans.map(item => item.status = (item.uuid === uuid) ? 'fixed' : item.status); - allScans.unshift({ time: now, fixture, uuid }); -} +const allScans = new Map(); app.set('view engine', 'ejs'); @@ -35,24 +20,43 @@ app.get(['/favicon.ico', '/robots.txt'], (req, res) => { res.sendStatus(204); }); + +function addRecentlyScanned(uuid, item, nbFound = 0) { + // TRICK: only record uuids + if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(uuid)) { + return; + } + const duplicatedItem = item; + duplicatedItem.time = new Date(); + duplicatedItem.duplicated = nbFound > 1; + duplicatedItem.link = item.cellRef; + if (nbFound === 0) { + duplicatedItem.fixture = ''; + duplicatedItem.uuid = uuid; + duplicatedItem.status = 'missing'; + } + allScans.set(uuid, duplicatedItem); +} + app.get('/search', (req, res) => { - loadDatabase((allItems) => { - res.render('search', { - matches: searchDatabase(req.query, allItems) - .sort((a, b) => (a.floor === b.floor ? 0 : +(a.floor > b.floor) || -1)), - }); - }); + searchDatabase(req.query, queryResult => res.render('search', { + matches: queryResult.sort((a, b) => (a.floor === b.floor ? 0 : +(a.floor > b.floor) || -1)), + })); }); app.get('/qrlist', (req, res) => { - loadDatabase((allItems) => { - const qrList = searchDatabase(req.query, allItems) - .filter(item => item.uuid !== '') + function renderQrList(qrList) { + const qrItems = qrList.filter(item => item.uuid !== '') .filter(item => item.uuid !== undefined) .sort((a, b) => (a.floor === b.floor ? 0 : +(a.floor > b.floor) || -1)); - qrList.forEach(item => item.qr = qr.imageSync('http://url.coderbunker.com/' + item.uuid, { type: 'svg' })); - res.render('qrList', { matches: qrList }); - }); + qrItems.forEach((item) => { + const itemWithQr = item; + itemWithQr.qr = qr.imageSync(item.uuid, { type: 'svg' }); + return itemWithQr; + }); + res.render('qrList', { matches: qrItems }); + } + searchDatabase(req.query, queryResult => renderQrList(queryResult)); }); app.get('/recent', (req, res) => { @@ -60,21 +64,26 @@ app.get('/recent', (req, res) => { }); app.get('/:uuid', (req, res) => { - loadDatabase((allItems) => { - const match = searchDatabase(req.params, allItems)[0]; - if (match.length === 0) { - logScanned(req.params.uuid); + function renderUuid(uuidsList) { + let uuids = uuidsList[0]; + if (uuidsList.length === 0) { + addRecentlyScanned(req.params.uuid, {}); res.status(404).render('notFound', { item: '', id: req.params.uuid, }); return; } - addMarkdown(match); - addSimilarItems(match, allItems); - logScanned(req.params.uuid, match.fixture); - res.render('item', match); - }); + if (uuidsList.length > 1) { + console.log(`Too much matches for uuid ${req.params.uuid} length = ${uuidsList.length}`); + } + // copying twice just to remove a lint warning (no-param-reassign): bad bad bad ! + uuids = addMarkdown(uuids); + uuids = addSimilarItems(uuids); + addRecentlyScanned(req.params.uuid, uuids, uuidsList.length); + res.render('item', uuids); + } + searchDatabase(req.params, queryResult => renderUuid(queryResult)); }); app.get('/', (req, res) => { diff --git a/googleSpreadsheet.js b/googleSpreadsheet.js index 1352d0a..60e4cd4 100644 --- a/googleSpreadsheet.js +++ b/googleSpreadsheet.js @@ -2,46 +2,66 @@ const google = require('googleapis'); const keys = require('./config/keys'); const marked = require('marked'); -function rowToObject(val, lab) { - const o = {}; - for (let i = 0; i < lab.length; i += 1) { - o[lab[i]] = val[i]; +const spreadsheetDataId = '1QHKa3vUpht7zRl_LEzl3BlUbolz3ZiL8yKHzdBL42dY'; +const spreadsheetLink = `https://docs.google.com/spreadsheets/d/${spreadsheetDataId}/edit`; +let loadedItems = []; + +// creates a dictionary mapping column names with the values +// ex: { floor : 402, business : coworking, etc..} +function spreadsheetValuesToObject(values, columns, index) { + const formatedRow = {}; + for (let i = 0; i < columns.length; i += 1) { + formatedRow[columns[i]] = values[i]; } - return o; + formatedRow.cellRef = `${spreadsheetLink}#gid=0&range=A${index}:T${index}`; + return formatedRow; } function loadDatabase(callback) { const sheets = google.sheets('v4'); sheets.spreadsheets.values.get({ auth: keys.apiKey, - spreadsheetId: '1QHKa3vUpht7zRl_LEzl3BlUbolz3ZiL8yKHzdBL42dY', + spreadsheetId: spreadsheetDataId, range: 'Agora inventory!A:Z', }, (err, response) => { if (err) { console.log(`The API returned an error: ${err}`); return; } - return callback(response.values.map(row => - rowToObject(row, response.values[0])).splice(1)); + const columns = response.values[0]; + let i = 0; + loadedItems = response.values.map((row) => { + i += 1; + return spreadsheetValuesToObject(row, columns, i); + }); + return callback(); }); } -function searchDatabase(query, rows) { - let matches = rows; +function searchDatabase(query, callback) { + if (loadedItems.length === 0) { + // if the database was not loaded load it then recall this function with the same parameters + // warning, this causes an infinite loop if the spreadsheet is empty or unreachable + loadDatabase(() => searchDatabase(query, callback)); + return; + } + let queryResult = loadedItems; Object.keys(query).map((key) => { - matches = matches.filter(item => item[key] === query[key]); + queryResult = loadedItems.filter(item => item[key] === query[key]); }); - return matches; + return callback(queryResult); } -function addSimilarItems(obj, allObj) { - obj.similarItems = searchDatabase({ fixture: obj.fixture }, allObj) +function addSimilarItems(items) { + const obj = items; + obj.similarItems = loadedItems.filter(item => item.fixture === obj.fixture) .filter(item => item.uuid !== obj.uuid) .splice(0, 3); return obj; } -function addMarkdown(obj) { +function addMarkdown(items) { + const obj = items; obj.HOWTO = marked(obj.HOWTO); obj.details = marked(obj.details); obj.Troubleshooting = marked(obj.Troubleshooting); @@ -49,7 +69,6 @@ function addMarkdown(obj) { } module.exports = { - loadDatabase, searchDatabase, addMarkdown, addSimilarItems, diff --git a/views/recent.ejs b/views/recent.ejs index 372cf57..3d415a0 100644 --- a/views/recent.ejs +++ b/views/recent.ejs @@ -1,26 +1,25 @@ <% include ./partials/header %> -
-

Recently scanned QR code

-
-
+ ??? + <% } %> + :
+ <%- item.uuid %> + <% if (!item.fixture) { %> + Missing Details! + <% } %> + <% if (item.duplicated) { %> + Duplicate UUID! + <% } %> + + <% } %> + + <% include ./partials/footer %>