diff --git a/app.js b/app.js index ba938f8..1c0d904 100644 --- a/app.js +++ b/app.js @@ -1,6 +1,5 @@ const express = require('express'); -const qr = require('qr-image'); const { loadDatabase, @@ -11,20 +10,26 @@ const { const app = express(); -const allScans = []; +const allScans = new Map(); -function logScanned(uuid, fixture) { - // TRICK: fixture tells if the the uuid was found in database or not +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 now = new Date(); - if (!fixture) { - allScans.unshift({ time: now, status: 'missing', 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.map(item => item.status = (item.uuid === uuid) ? 'fixed' : item.status); - allScans.unshift({ time: now, fixture, uuid }); + + allScans.set(uuid, duplicatedItem); } app.set('view engine', 'ejs'); @@ -38,19 +43,17 @@ app.get(['/favicon.ico', '/robots.txt'], (req, res) => { 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)), + matches: searchDatabase(req.query, allItems).sortByFloor(), }); }); }); app.get('/qrlist', (req, res) => { loadDatabase((allItems) => { - const qrList = searchDatabase(req.query, allItems) - .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' })); + let qrList = searchDatabase(req.query, allItems); + qrList = qrList.sortByFloor(); + qrList = qrList.filterEmptyUuid(); + qrList.forEach(item => item.addQrImg()); res.render('qrList', { matches: qrList }); }); }); @@ -61,19 +64,22 @@ 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); + const matches = searchDatabase(req.params, allItems); + if (matches.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 (matches.length > 1) { + console.log(`Too much matches for uuid ${req.params.uuid} length = ${matches.length}`); + } + addRecentlyScanned(req.params.uuid, matches[0], matches.length); + addMarkdown(matches[0]); + addSimilarItems(matches[0], allItems); + res.render('item', matches[0]); }); }); diff --git a/googleSpreadsheet.js b/googleSpreadsheet.js index 1352d0a..f83fa88 100644 --- a/googleSpreadsheet.js +++ b/googleSpreadsheet.js @@ -1,28 +1,46 @@ const google = require('googleapis'); const keys = require('./config/keys'); const marked = require('marked'); +const qr = require('qr-image'); -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`; + +// 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.addQrImg = function addQrImg() { + if (/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(this.uuid)) { + this.qr = qr.imageSync(this.uuid, { type: 'svg' }); + } + }; + 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]; + // map function transforms a list into another list using the given lambda function + let i = 0; + const formatedRows = response.values.map((row) => { + i += 1; + return spreadsheetValuesToObject(row, columns, i); + }); + return callback(formatedRows); }); } @@ -31,17 +49,25 @@ function searchDatabase(query, rows) { Object.keys(query).map((key) => { matches = matches.filter(item => item[key] === query[key]); }); + matches.filterEmptyUuid = function filterEmptyUuid() { + return this.filter(item => item.uuid !== '').filter(item => item.uuid !== undefined); + }; + matches.sortByFloor = function sortByFloor() { + return this.sort((a, b) => (a.floor === b.floor ? 0 : +(a.floor > b.floor) || -1)); + }; return matches; } -function addSimilarItems(obj, allObj) { +function addSimilarItems(refItem, allObj) { + const obj = refItem; obj.similarItems = searchDatabase({ fixture: obj.fixture }, allObj) .filter(item => item.uuid !== obj.uuid) .splice(0, 3); return obj; } -function addMarkdown(obj) { +function addMarkdown(refItem) { + const obj = refItem; obj.HOWTO = marked(obj.HOWTO); obj.details = marked(obj.details); obj.Troubleshooting = marked(obj.Troubleshooting); 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 %>