add eslint, fix bugs found

This commit is contained in:
Wingy 2020-11-08 16:54:08 -05:00
parent fc2c3a7114
commit 12558d3384
28 changed files with 1774 additions and 745 deletions

2
.eslintignore Normal file
View file

@ -0,0 +1,2 @@
static/libraries
patched-express-response.js

18
.eslintrc.js Normal file
View file

@ -0,0 +1,18 @@
module.exports = {
env: {
commonjs: true,
es2021: true,
node: true
},
extends: [
'standard'
],
parserOptions: {
ecmaVersion: 12
},
globals: {
_CC: 'readonly'
},
rules: {
}
}

View file

@ -1,6 +1,6 @@
require('dotenv').config(); require('dotenv').config()
const yesNo = require('yes-no'); const yesNo = require('yes-no')
module.exports = { module.exports = {
dbPrefix: process.env.DB_PREFIX || 'dbs/', dbPrefix: process.env.DB_PREFIX || 'dbs/',
@ -16,4 +16,4 @@ module.exports = {
wishlist: require('./wishlist'), wishlist: require('./wishlist'),
base: (process.env.ROOT_PATH || '/').endsWith('/') ? (process.env.ROOT_PATH || '/') : `${process.env.ROOT_PATH}/`, base: (process.env.ROOT_PATH || '/').endsWith('/') ? (process.env.ROOT_PATH || '/') : `${process.env.ROOT_PATH}/`,
trustProxy: process.env.TRUST_PROXY === 'true' ? true : process.env.TRUST_PROXY || 'loopback' trustProxy: process.env.TRUST_PROXY === 'true' ? true : process.env.TRUST_PROXY || 'loopback'
}; }

View file

@ -1,13 +1,13 @@
const { nanoid } = require('nanoid') const { nanoid } = require('nanoid')
const path = require('path'); const path = require('path')
const fs = require('fs'); const fs = require('fs')
const secretFilePath = path.join((process.env.SECRET_DIRNAME ? process.env.SECRET_DIRNAME : __dirname), 'secret.txt'); const secretFilePath = path.join((process.env.SECRET_DIRNAME ? process.env.SECRET_DIRNAME : __dirname), 'secret.txt')
try { try {
module.exports = fs.readFileSync(secretFilePath).toString(); module.exports = fs.readFileSync(secretFilePath).toString()
} catch (_) { } catch (_) {
const secret = nanoid(128); const secret = nanoid(128)
fs.writeFileSync(secretFilePath, secret); fs.writeFileSync(secretFilePath, secret)
module.exports = secret; module.exports = secret
} }

View file

@ -1,14 +1,13 @@
global._CC = { require } global._CC = { require }
const PouchSession = require('session-pouchdb-store'); const PouchSession = require('session-pouchdb-store')
const LocalStrategy = require('passport-local').Strategy; const LocalStrategy = require('passport-local').Strategy
const session = require('express-session'); const session = require('express-session')
const bcrypt = require('bcrypt-nodejs'); const bcrypt = require('bcrypt-nodejs')
const flash = require('connect-flash'); const flash = require('connect-flash')
const passport = require('passport'); const passport = require('passport')
const express = require('express'); const express = require('express')
const level = require('level');
const config = require('./config'); const config = require('./config')
_CC.config = config _CC.config = config
if (!config.dbPrefix.startsWith('http')) { if (!config.dbPrefix.startsWith('http')) {
@ -16,44 +15,43 @@ if (!config.dbPrefix.startsWith('http')) {
mkdirp(config.dbPrefix) mkdirp(config.dbPrefix)
} }
const PouchDB = require('pouchdb').defaults({ prefix: config.dbPrefix }); const PouchDB = require('pouchdb').defaults({ prefix: config.dbPrefix })
const logger = require('./logger'); const logger = require('./logger')
const app = express(); const app = express()
app.set('base', config.base) app.set('base', config.base)
app.set('trust proxy', config.trustProxy) app.set('trust proxy', config.trustProxy)
const db = new PouchDB('users'); const db = new PouchDB('users')
passport.use('local', new LocalStrategy( passport.use('local', new LocalStrategy(
(username, password, done) => { (username, password, done) => {
username = username.trim(); username = username.trim()
db.get(username) db.get(username)
.then(doc => { .then(doc => {
bcrypt.compare(password, doc.password, (err, correct) => { bcrypt.compare(password, doc.password, (err, correct) => {
if (err) return done(err); if (err) return done(err)
if (!correct) return done(null, false, { message: 'Incorrect password' }); if (!correct) return done(null, false, { message: 'Incorrect password' })
if (correct) return done(null, doc); if (correct) return done(null, doc)
}); })
}) })
.catch(err => { .catch(err => {
if (err.message === 'missing') return done(null, false, { message: 'Incorrect username.' }); if (err.message === 'missing') return done(null, false, { message: 'Incorrect username.' })
return done(err); return done(err)
}); })
} }
)); ))
passport.serializeUser((user, callback) => callback(null, user._id)); passport.serializeUser((user, callback) => callback(null, user._id))
passport.deserializeUser((user, callback) => { passport.deserializeUser((user, callback) => {
db.get(user) db.get(user)
.then(dbUser => callback(null, dbUser)) .then(dbUser => callback(null, dbUser))
.catch(() => callback(null, null)); .catch(() => callback(null, null))
}); })
app.use(require('body-parser').urlencoded({ extended: true }))
app.use(require('body-parser').urlencoded({ extended: true }));
app.use(session({ app.use(session({
secret: config.secret, secret: config.secret,
resave: false, resave: false,
@ -63,26 +61,26 @@ app.use(session({
maxAge: config.sessionMaxAge maxAge: config.sessionMaxAge
}, },
name: 'christmas_community.connect.sid' name: 'christmas_community.connect.sid'
})); }))
app.use(flash()); app.use(flash())
app.use(passport.initialize()); app.use(passport.initialize())
app.use(passport.session()); app.use(passport.session())
app.use(require('./middlewares/locals')); app.use(require('./middlewares/locals'))
app.use((req, res, next) => { app.use((req, res, next) => {
logger.log('express', `${req.ip} - ${req.method} ${req.originalUrl}`); logger.log('express', `${req.ip} - ${req.method} ${req.originalUrl}`)
next(); next()
}); })
app.set('view engine', 'pug'); app.set('view engine', 'pug')
app.use(config.base, require('./routes')({ db, config })); app.use(config.base, require('./routes')({ db, config }))
app.listen(config.port, () => logger.success('express', `Express server started on port ${config.port}!`)) app.listen(config.port, () => logger.success('express', `Express server started on port ${config.port}!`))
;(() => { ;(() => {
if (!config.dbExposePort) return if (!config.dbExposePort) return
const dbExposeApp = express() const dbExposeApp = express()
dbExposeApp.use('/', require('express-pouchdb')(PouchDB, { inMemoryConfig: true })); dbExposeApp.use('/', require('express-pouchdb')(PouchDB, { inMemoryConfig: true }))
dbExposeApp.listen(config.dbExposePort, () => logger.success('db expose', `DB has been exposed on port ${config.dbExposePort}`)) dbExposeApp.listen(config.dbExposePort, () => logger.success('db expose', `DB has been exposed on port ${config.dbExposePort}`))
})() })()

View file

@ -1,12 +1,9 @@
const chalk = require('chalk'); const chalk = require('chalk')
const config = require('./config'); const colors = { log: 'blue', success: 'green', error: 'red', warn: 'yellow' }
const colors = {log: 'blue', success: 'green', error: 'red', warn: 'yellow'};
// rewrite to use Object.keys() Object.keys(colors).forEach(
for (let property in colors) { method => // eslint-disable-line no-return-assign
if (colors.hasOwnProperty(property)) { module.exports[method] =
module.exports[property] = (type, msg) => { (type, msg) =>
console.log(chalk.keyword(colors[property])(`[ ${type.toUpperCase()} ] ${msg}`)); console.log(chalk.keyword(colors[method])(`[ ${type.toUpperCase()} ] ${msg}`))
}; )
}
}

View file

@ -3,14 +3,14 @@ const { spawn } = require('child_process')
const PACKAGENAME = 'get-product-name' const PACKAGENAME = 'get-product-name'
async function isOutdated() { async function isOutdated () {
const command = `npm outdated ${PACKAGENAME} --json` const command = `npm outdated ${PACKAGENAME} --json`
const npm = await exec(command) const npm = await exec(command)
const data = JSON.parse(npm.stdout) const data = JSON.parse(npm.stdout)
return data[PACKAGENAME]?.current !== data[PACKAGENAME]?.wanted return data[PACKAGENAME]?.current !== data[PACKAGENAME]?.wanted
} }
async function updateGPD() { async function updateGPD () {
// https://blog.cloud66.com/using-node-with-docker/ // https://blog.cloud66.com/using-node-with-docker/
const command = `mv ./node_modules ./node_modules.tmp && mv ./node_modules.tmp ./node_modules && npm update ${PACKAGENAME}` const command = `mv ./node_modules ./node_modules.tmp && mv ./node_modules.tmp ./node_modules && npm update ${PACKAGENAME}`
await exec(command) await exec(command)
@ -18,15 +18,15 @@ async function updateGPD() {
;(async () => { ;(async () => {
let cc = null let cc = null
function spawnCC() { function spawnCC () {
cc = spawn('node', [ 'index.js' ], { env: process.env }) cc = spawn('node', ['index.js'], { env: process.env })
cc.on('exit', spawnCC) cc.on('exit', spawnCC)
cc.stdout.pipe(process.stdout) cc.stdout.pipe(process.stdout)
cc.stderr.pipe(process.stderr) cc.stderr.pipe(process.stderr)
} }
if (process.env.UPDATE_GPD !== 'false') { if (process.env.UPDATE_GPD !== 'false') {
async function update() { async function update () {
if (await isOutdated()) { if (await isOutdated()) {
try { try {
await updateGPD() await updateGPD()

View file

@ -1,6 +1,6 @@
const config = require('../config'); const config = require('../config')
module.exports = (req, res, next) => { module.exports = (req, res, next) => {
res.locals.config = config; res.locals.config = config
res.locals.req = req; res.locals.req = req
next(); next()
}; }

View file

@ -1,7 +1,7 @@
const config = require('../config'); const config = require('../config')
module.exports = options => { module.exports = options => {
return (req, res, next) => { return (req, res, next) => {
options = options ? options : {}; options = options || {}
let authed = false let authed = false
try { try {
authed = req.isAuthenticated() authed = req.isAuthenticated()
@ -10,5 +10,5 @@ module.exports = options => {
} }
if (authed) return next() if (authed) return next()
res.redirect(options.failureRedirect || config.defaultFailureRedirect) res.redirect(options.failureRedirect || config.defaultFailureRedirect)
}; }
} }

View file

@ -36,5 +36,12 @@
"session-pouchdb-store": "^0.4.1", "session-pouchdb-store": "^0.4.1",
"u64": "^1.0.1", "u64": "^1.0.1",
"yes-no": "^0.0.1" "yes-no": "^0.0.1"
},
"devDependencies": {
"eslint": "^7.13.0",
"eslint-config-standard": "^16.0.1",
"eslint-plugin-import": "^2.22.1",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-promise": "^4.2.1"
} }
} }

File diff suppressed because it is too large Load diff

View file

@ -1,31 +1,30 @@
const verifyAuth = require('../../middlewares/verifyAuth'); const verifyAuth = require('../../middlewares/verifyAuth')
const bcrypt = require('bcrypt-nodejs'); const express = require('express')
const express = require('express');
const { nanoid } = require('nanoid') const { nanoid } = require('nanoid')
const SECRET_TOKEN_LENGTH = 32 const SECRET_TOKEN_LENGTH = 32
const SECRET_TOKEN_LIFETIME = const SECRET_TOKEN_LIFETIME =
// One week, approximately. Doesn't need to be perfect. // One week, approximately. Doesn't need to be perfect.
1000 // milliseconds 1000 * // milliseconds
* 60 // seconds 60 * // seconds
* 60 // minutes 60 * // minutes
* 24 // hours 24 * // hours
* 07 // days 7 // days
module.exports = (db) => { module.exports = (db) => {
const router = express.Router(); const router = express.Router()
router.get('/', verifyAuth(), (req, res) => { router.get('/', verifyAuth(), (req, res) => {
if (!req.user.admin) return res.redirect('/'); if (!req.user.admin) return res.redirect('/')
db.allDocs({ include_docs: true }) db.allDocs({ include_docs: true })
.then(docs => { .then(docs => {
res.render('adminSettings', { title: 'Admin Settings', users: docs.rows }) res.render('adminSettings', { title: 'Admin Settings', users: docs.rows })
}) })
.catch(err => { throw err; }); .catch(err => { throw err })
}); })
router.post('/add', verifyAuth(), async (req, res) => { router.post('/add', verifyAuth(), async (req, res) => {
if (!req.user.admin) return res.redirect('/'); if (!req.user.admin) return res.redirect('/')
await db.put({ await db.put({
_id: req.body.newUserUsername.trim(), _id: req.body.newUserUsername.trim(),
admin: false, admin: false,
@ -34,43 +33,43 @@ module.exports = (db) => {
signupToken: nanoid(SECRET_TOKEN_LENGTH), signupToken: nanoid(SECRET_TOKEN_LENGTH),
expiry: new Date().getTime() + SECRET_TOKEN_LIFETIME expiry: new Date().getTime() + SECRET_TOKEN_LIFETIME
}); })
res.redirect(`/admin-settings/edit/${req.body.newUserUsername.trim()}`) res.redirect(`/admin-settings/edit/${req.body.newUserUsername.trim()}`)
}); })
router.get('/edit/:userToEdit', verifyAuth(), async (req, res) => { router.get('/edit/:userToEdit', verifyAuth(), async (req, res) => {
if (!req.user.admin) return res.redirect('/'); if (!req.user.admin) return res.redirect('/')
const doc = await db.get(req.params.userToEdit) const doc = await db.get(req.params.userToEdit)
delete doc.password delete doc.password
res.render('admin-user-edit', { user: doc }); res.render('admin-user-edit', { user: doc })
}); })
router.post('/edit/refresh-signup-token/:userToEdit', verifyAuth(), async (req, res) => { router.post('/edit/refresh-signup-token/:userToEdit', verifyAuth(), async (req, res) => {
if (!req.user.admin) return res.redirect('/'); if (!req.user.admin) return res.redirect('/')
const doc = await db.get(req.params.userToEdit) const doc = await db.get(req.params.userToEdit)
doc.signupToken = nanoid(SECRET_TOKEN_LENGTH) doc.signupToken = nanoid(SECRET_TOKEN_LENGTH)
doc.expiry = new Date().getTime() + SECRET_TOKEN_LIFETIME doc.expiry = new Date().getTime() + SECRET_TOKEN_LIFETIME
await db.put(doc) await db.put(doc)
return res.redirect(`/admin-settings/edit/${req.params.userToEdit}`) return res.redirect(`/admin-settings/edit/${req.params.userToEdit}`)
}); })
router.post('/edit/resetpw/:userToEdit', verifyAuth(), async (req, res) => { router.post('/edit/resetpw/:userToEdit', verifyAuth(), async (req, res) => {
if (!req.user.admin) return res.redirect('/'); if (!req.user.admin) return res.redirect('/')
const doc = await db.get(req.params.userToEdit) const doc = await db.get(req.params.userToEdit)
doc.pwToken = nanoid(SECRET_TOKEN_LENGTH) doc.pwToken = nanoid(SECRET_TOKEN_LENGTH)
doc.pwExpiry = new Date().getTime() + SECRET_TOKEN_LIFETIME doc.pwExpiry = new Date().getTime() + SECRET_TOKEN_LIFETIME
await db.put(doc) await db.put(doc)
return res.redirect(`/admin-settings/edit/${req.params.userToEdit}`) return res.redirect(`/admin-settings/edit/${req.params.userToEdit}`)
}); })
router.post('/edit/cancelresetpw/:userToEdit', verifyAuth(), async (req, res) => { router.post('/edit/cancelresetpw/:userToEdit', verifyAuth(), async (req, res) => {
if (!req.user.admin) return res.redirect('/'); if (!req.user.admin) return res.redirect('/')
const doc = await db.get(req.params.userToEdit) const doc = await db.get(req.params.userToEdit)
delete doc.pwToken delete doc.pwToken
delete doc.pwExpiry delete doc.pwExpiry
await db.put(doc) await db.put(doc)
return res.redirect(`/admin-settings/edit/${req.params.userToEdit}`) return res.redirect(`/admin-settings/edit/${req.params.userToEdit}`)
}); })
router.post('/edit/rename/:userToRename', verifyAuth(), async (req, res) => { router.post('/edit/rename/:userToRename', verifyAuth(), async (req, res) => {
if (!req.user.admin && req.user._id !== req.params.userToRename) return res.redirect('/') if (!req.user.admin && req.user._id !== req.params.userToRename) return res.redirect('/')
@ -119,7 +118,7 @@ module.exports = (db) => {
}) })
router.post('/edit/impersonate/:userToEdit', verifyAuth(), async (req, res) => { router.post('/edit/impersonate/:userToEdit', verifyAuth(), async (req, res) => {
if (!req.user.admin) return res.redirect('/'); if (!req.user.admin) return res.redirect('/')
req.login({ _id: req.params.userToEdit }, err => { req.login({ _id: req.params.userToEdit }, err => {
if (err) { if (err) {
req.flash('error', err.message) req.flash('error', err.message)
@ -128,29 +127,29 @@ module.exports = (db) => {
req.flash('success', `You are now ${req.params.userToEdit}.`) req.flash('success', `You are now ${req.params.userToEdit}.`)
res.redirect('/') res.redirect('/')
}) })
}); })
router.post('/edit/remove/:userToRemove', verifyAuth(), async (req, res) => { router.post('/edit/remove/:userToRemove', verifyAuth(), async (req, res) => {
if (!req.user.admin) return res.redirect('/'); if (!req.user.admin) return res.redirect('/')
const doc = await db.get(req.params.userToRemove); const doc = await db.get(req.params.userToRemove)
if (doc.admin) { if (doc.admin) {
req.flash('error', 'Failed to remove: user is admin.'); req.flash('error', 'Failed to remove: user is admin.')
return res.redirect('/admin-settings'); return res.redirect('/admin-settings')
} }
await db.remove(doc); await db.remove(doc)
const docs = await db.allDocs({ include_docs: true }); const { rows } = await db.allDocs({ include_docs: true })
for (let i = 0; i < docs.length; i++) { for (let i = 0; i < rows.length; i++) {
for (let j = 0; j < docs[i].doc.wishlist.length; j++) { for (let j = 0; j < rows[i].doc.wishlist.length; j++) {
if (docs[i].doc.wishlist[j].pledgedBy === req.params.userToRemove) { if (rows[i].doc.wishlist[j].pledgedBy === req.params.userToRemove) {
docs[i].doc.wishlist[j].pledgedBy === undefined; rows[i].doc.wishlist[j].pledgedBy = undefined
if (docs[i].doc.wishlist[j].addedBy === req.params.userToRemove) await db.remove(doc); if (rows[i].doc.wishlist[j].addedBy === req.params.userToRemove) rows[i].doc.wishlist.splice(j, 1)
else await db.put(docs[i].doc); await db.put(rows[i].doc)
} }
} }
} }
req.flash('success', `Successfully removed user ${req.params.userToRemove}`); req.flash('success', `Successfully removed user ${req.params.userToRemove}`)
res.redirect('/admin-settings') res.redirect('/admin-settings')
}); })
return router; return router
}; }

View file

@ -1,9 +1,8 @@
const verifyAuth = require('../../middlewares/verifyAuth'); const verifyAuth = require('../../middlewares/verifyAuth')
const express = require('express'); const express = require('express')
const path = require('path');
module.exports = ({ db, config }) => { module.exports = ({ db, config }) => {
const router = express.Router(); const router = express.Router()
router.use(verifyAuth()) router.use(verifyAuth())
@ -13,7 +12,7 @@ module.exports = ({ db, config }) => {
}) })
}) })
router.use('/wishlist', require('./wishlist')({ db })); router.use('/wishlist', require('./wishlist')({ db }))
return router; return router
} }

View file

@ -1,8 +1,6 @@
const verifyAuth = require('../../../middlewares/verifyAuth')
const express = require('express') const express = require('express')
const path = require('path')
module.exports = ({ db, config }) => { module.exports = ({ db }) => {
const router = express.Router() const router = express.Router()
router.get('/', (req, res) => { router.get('/', (req, res) => {
@ -19,12 +17,12 @@ module.exports = ({ db, config }) => {
if (req.params.direction === 'up') wishlist.reverse() if (req.params.direction === 'up') wishlist.reverse()
let moveFromIndex let moveFromIndex
wishlist.forEach(wish => { wishlist.forEach(wish => {
if (wish.id === req.params.id) return moveFromIndex = wishlist.indexOf(wish) if (wish.id === req.params.id) moveFromIndex = wishlist.indexOf(wish)
}) })
const moveToIndex = wishlist.findIndex(wish => { const moveToIndex = wishlist.findIndex(wish => {
return ( wishlist.indexOf(wish) > moveFromIndex && wish.addedBy === req.user._id ) return (wishlist.indexOf(wish) > moveFromIndex && wish.addedBy === req.user._id)
}) })
if (moveToIndex < 0 || moveToIndex > wishlist.length) return res.send({ error: 'Invalid move '}) if (moveToIndex < 0 || moveToIndex > wishlist.length) return res.send({ error: 'Invalid move ' })
const original = wishlist[moveToIndex] const original = wishlist[moveToIndex]
wishlist[moveToIndex] = wishlist[moveFromIndex] wishlist[moveToIndex] = wishlist[moveFromIndex]
wishlist[moveFromIndex] = original wishlist[moveFromIndex] = original

View file

@ -1,8 +1,8 @@
const bcrypt = require('bcrypt-nodejs'); const bcrypt = require('bcrypt-nodejs')
const express = require('express'); const express = require('express')
module.exports = (db) => { module.exports = (db) => {
const router = express.Router(); const router = express.Router()
router.get('/:code', async (req, res) => { router.get('/:code', async (req, res) => {
const row = (await db.allDocs({ include_docs: true })) const row = (await db.allDocs({ include_docs: true }))
@ -10,7 +10,7 @@ module.exports = (db) => {
.find(({ doc }) => doc.signupToken === req.params.code) .find(({ doc }) => doc.signupToken === req.params.code)
res.render('confirm-account', { doc: row ? row.doc : undefined }) res.render('confirm-account', { doc: row ? row.doc : undefined })
}); })
router.post('/:code', async (req, res) => { router.post('/:code', async (req, res) => {
const { doc } = (await db.allDocs({ include_docs: true })) const { doc } = (await db.allDocs({ include_docs: true }))
@ -20,7 +20,7 @@ module.exports = (db) => {
if (doc.expiry < new Date().getTime()) return res.redirect(`/confirm-account/${req.params.code}`) if (doc.expiry < new Date().getTime()) return res.redirect(`/confirm-account/${req.params.code}`)
bcrypt.hash(req.body.password, null, null, async (err, passwordHash) => { bcrypt.hash(req.body.password, null, null, async (err, passwordHash) => {
if (err) throw err; if (err) throw err
doc.password = passwordHash doc.password = passwordHash
delete doc.signupToken delete doc.signupToken
@ -34,11 +34,11 @@ module.exports = (db) => {
req.flash('error', err.message) req.flash('error', err.message)
return res.redirect('/') return res.redirect('/')
} }
req.flash('success', `Welcome to ${_CC.config.siteTitle}!`); req.flash('success', `Welcome to ${_CC.config.siteTitle}!`)
res.redirect('/'); res.redirect('/')
}) })
}); })
}); })
return router; return router
}; }

View file

@ -1,44 +1,44 @@
const verifyAuth = require('../middlewares/verifyAuth'); const verifyAuth = require('../middlewares/verifyAuth')
const express = require('express'); const express = require('express')
const path = require('path'); const path = require('path')
module.exports = ({ db, config }) => { module.exports = ({ db, config }) => {
const router = express.Router(); const router = express.Router()
router.use('/', express.static(path.join(__dirname, '../static'))); router.use('/', express.static(path.join(__dirname, '../static')))
router.get('/', router.get('/',
async (req, res, next) => { async (req, res, next) => {
dbInfo = await db.info(); const dbInfo = await db.info()
if (dbInfo.doc_count === 0) { if (dbInfo.doc_count === 0) {
res.redirect('/setup'); res.redirect('/setup')
} else { } else {
next(); next()
} }
}, },
verifyAuth(), verifyAuth(),
(req, res) => { (req, res) => {
res.redirect('/wishlist'); res.redirect('/wishlist')
} }
); )
router.use('/api', require('./api')({ db })) router.use('/api', require('./api')({ db }))
router.use('/setup', require('./setup')(db)); router.use('/setup', require('./setup')(db))
router.use('/login', require('./login')()); router.use('/login', require('./login')())
router.use('/logout', require('./logout')()); router.use('/logout', require('./logout')())
router.use('/resetpw', require('./resetpw')(db)); router.use('/resetpw', require('./resetpw')(db))
router.use('/confirm-account', require('./confirm-account')(db)); router.use('/confirm-account', require('./confirm-account')(db))
router.use('/wishlist', require('./wishlist')(db)); router.use('/wishlist', require('./wishlist')(db))
router.use('/supported-sites', require('./supported-sites')()) router.use('/supported-sites', require('./supported-sites')())
router.use('/profile', require('./profile')(db)); router.use('/profile', require('./profile')(db))
router.use('/admin-settings', require('./adminSettings')(db)); router.use('/admin-settings', require('./adminSettings')(db))
router.use('/manifest.json', require('./manifest.json')({ config })) router.use('/manifest.json', require('./manifest.json')({ config }))
return router; return router
} }

View file

@ -1,29 +1,29 @@
const passport = require('passport'); const passport = require('passport')
const express = require('express'); const express = require('express')
module.exports = () => { module.exports = () => {
const router = express.Router(); const router = express.Router()
router.get('/', router.get('/',
(req, res) => { (req, res) => {
if (req.isAuthenticated()) { if (req.isAuthenticated()) {
res.redirect('/'); res.redirect('/')
} else { } else {
res.render('login'); res.render('login')
} }
} }
); )
router.post( router.post(
'/', '/',
(req, res, next) => { (req, res, next) => {
next(); next()
}, },
passport.authenticate('local', { passport.authenticate('local', {
successRedirect: '/', successRedirect: '/',
failureRedirect: '/login', failureRedirect: '/login',
failureFlash: 'Invalid username or password' failureFlash: 'Invalid username or password'
}) })
); )
return router; return router
}; }

View file

@ -1,14 +1,14 @@
const verifyAuth = require('../../middlewares/verifyAuth'); const verifyAuth = require('../../middlewares/verifyAuth')
const express = require('express'); const express = require('express')
module.exports = () => { module.exports = () => {
const router = express.Router(); const router = express.Router()
router.get('/', verifyAuth(), (req, res) => res.render('logout')); router.get('/', verifyAuth(), (req, res) => res.render('logout'))
router.post('/', (req, res) => { router.post('/', (req, res) => {
req.logout(); req.logout()
res.redirect('/'); res.redirect('/')
}); })
return router; return router
}; }

View file

@ -1,7 +1,7 @@
const express = require('express'); const express = require('express')
module.exports = ({ config }) => { module.exports = ({ config }) => {
const router = express.Router(); const router = express.Router()
router.get('/', (req, res) => { router.get('/', (req, res) => {
res.send({ res.send({
@ -19,7 +19,7 @@ module.exports = ({ config }) => {
} }
] ]
}) })
}); })
return router; return router
}; }

View file

@ -1,39 +1,39 @@
const verifyAuth = require('../../middlewares/verifyAuth'); const verifyAuth = require('../../middlewares/verifyAuth')
const bcrypt = require('bcrypt-nodejs'); const bcrypt = require('bcrypt-nodejs')
const express = require('express'); const express = require('express')
module.exports = (db) => { module.exports = (db) => {
const router = express.Router(); const router = express.Router()
router.get('/', verifyAuth(), (req, res) => res.render('profile', { title: `Profile Settings - ${req.user._id}`})); router.get('/', verifyAuth(), (req, res) => res.render('profile', { title: `Profile Settings - ${req.user._id}` }))
router.post('/', verifyAuth(), (req, res) => { router.post('/', verifyAuth(), (req, res) => {
if (req.body.oldPassword && req.body.newPassword) { if (req.body.oldPassword && req.body.newPassword) {
bcrypt.compare(req.body.oldPassword, req.user.password, (err, correct) => { bcrypt.compare(req.body.oldPassword, req.user.password, (err, correct) => {
if (err) throw err; if (err) throw err
if (correct) { if (correct) {
bcrypt.hash(req.body.newPassword, null, null, (err, hash) => { bcrypt.hash(req.body.newPassword, null, null, (err, hash) => {
if (err) throw err; if (err) throw err
db.get(req.user._id) db.get(req.user._id)
.then(doc => { .then(doc => {
doc.password = hash; doc.password = hash
db.put(doc) db.put(doc)
.then(() => { .then(() => {
req.flash('success', 'Changes saved successfully!'); req.flash('success', 'Changes saved successfully!')
res.redirect('/profile'); res.redirect('/profile')
}) })
.catch(err => { throw err; }); .catch(err => { throw err })
}) })
.catch(err => { throw err; }); .catch(err => { throw err })
}); })
} else { } else {
req.flash('error', 'Incorrect old password'); req.flash('error', 'Incorrect old password')
res.redirect('/profile'); res.redirect('/profile')
} }
}); })
} else { } else {
res.redirect('/profile'); res.redirect('/profile')
} }
}); })
return router; return router
}; }

View file

@ -1,17 +1,16 @@
const bcrypt = require('bcrypt-nodejs'); const bcrypt = require('bcrypt-nodejs')
const express = require('express'); const express = require('express')
module.exports = (db) => { module.exports = (db) => {
const router = express.Router(); const router = express.Router()
router.get('/:code', async (req, res) => { router.get('/:code', async (req, res) => {
const row = (await db.allDocs({ include_docs: true })) const row = (await db.allDocs({ include_docs: true }))
.rows .rows
.find(({ doc }) => doc.pwToken === req.params.code) .find(({ doc }) => doc.pwToken === req.params.code)
res.render('resetpw', { doc: row ? row.doc : undefined }) res.render('resetpw', { doc: row ? row.doc : undefined })
}); })
router.post('/:code', async (req, res) => { router.post('/:code', async (req, res) => {
const { doc } = (await db.allDocs({ include_docs: true })) const { doc } = (await db.allDocs({ include_docs: true }))
@ -21,7 +20,7 @@ module.exports = (db) => {
if (doc.expiry < new Date().getTime()) return res.redirect(`/resetpw/${req.params.code}`) if (doc.expiry < new Date().getTime()) return res.redirect(`/resetpw/${req.params.code}`)
bcrypt.hash(req.body.password, null, null, async (err, passwordHash) => { bcrypt.hash(req.body.password, null, null, async (err, passwordHash) => {
if (err) throw err; if (err) throw err
doc.password = passwordHash doc.password = passwordHash
delete doc.pwToken delete doc.pwToken
@ -35,11 +34,11 @@ module.exports = (db) => {
req.flash('error', err.message) req.flash('error', err.message)
return res.redirect('/') return res.redirect('/')
} }
req.flash('success', `Welcome to ${_CC.config.siteTitle}!`); req.flash('success', `Welcome to ${_CC.config.siteTitle}!`)
res.redirect('/'); res.redirect('/')
}) })
}); })
}); })
return router; return router
}; }

View file

@ -1,39 +1,39 @@
const bcrypt = require('bcrypt-nodejs') const bcrypt = require('bcrypt-nodejs')
const express = require('express'); const express = require('express')
module.exports = (db) => { module.exports = (db) => {
const router = express.Router(); const router = express.Router()
router.get('/', router.get('/',
async (req, res) => { async (req, res) => {
const dbInfo = await db.info(); const dbInfo = await db.info()
if (dbInfo.doc_count === 0) { if (dbInfo.doc_count === 0) {
res.render('setup', { title: 'Setup' }); res.render('setup', { title: 'Setup' })
} else { } else {
res.redirect('/'); res.redirect('/')
} }
} }
); )
router.post('/', router.post('/',
async (req, res) => { async (req, res) => {
const dbInfo = await db.info(); const dbInfo = await db.info()
if (dbInfo.doc_count === 0) { if (dbInfo.doc_count === 0) {
bcrypt.hash(req.body.adminPassword, null, null, (err, adminPasswordHash) => { bcrypt.hash(req.body.adminPassword, null, null, (err, adminPasswordHash) => {
if (err) throw err; if (err) throw err
db.put({ db.put({
_id: req.body.adminUsername.trim(), _id: req.body.adminUsername.trim(),
password: adminPasswordHash, password: adminPasswordHash,
admin: true, admin: true,
wishlist: [] wishlist: []
}) })
res.redirect('/'); res.redirect('/')
}); })
} else { } else {
res.redirect('/'); res.redirect('/')
} }
} }
); )
return router; return router
} }

View file

@ -1,18 +1,18 @@
const verifyAuth = require('../../middlewares/verifyAuth'); const verifyAuth = require('../../middlewares/verifyAuth')
const getProductName = require('get-product-name'); const getProductName = require('get-product-name')
const express = require('express'); const express = require('express')
const config = require('../../config'); const config = require('../../config')
const u64 = require('u64') const u64 = require('u64')
const totals = wishlist => { const totals = wishlist => {
let unpledged = 0; let unpledged = 0
let pledged = 0; let pledged = 0
wishlist.forEach(wishItem => { wishlist.forEach(wishItem => {
if (wishItem.pledgedBy) pledged += 1; if (wishItem.pledgedBy) pledged += 1
else unpledged += 1; else unpledged += 1
}); })
return { unpledged, pledged }; return { unpledged, pledged }
}; }
const ValidURL = (string) => { // Ty SO const ValidURL = (string) => { // Ty SO
try { try {
@ -20,40 +20,40 @@ const ValidURL = (string) => { // Ty SO
if (process.env.SMILE !== 'false') { if (process.env.SMILE !== 'false') {
if (url.hostname === 'www.amazon.com') url.hostname = 'smile.amazon.com' if (url.hostname === 'www.amazon.com') url.hostname = 'smile.amazon.com'
} }
if (url) return url; if (url) return url
} catch (_) { } catch (_) {
return false; return false
} }
} }
module.exports = (db) => { module.exports = (db) => {
const router = express.Router(); const router = express.Router()
router.get('/', verifyAuth(), async (req, res) => { router.get('/', verifyAuth(), async (req, res) => {
const docs = await db.allDocs({ include_docs: true }) const docs = await db.allDocs({ include_docs: true })
if (process.env.SINGLE_LIST === 'true') { if (process.env.SINGLE_LIST === 'true') {
for (row of docs.rows) { for (const row of docs.rows) {
if (row.doc.admin) return res.redirect(`/wishlist/${row.doc._id}`) if (row.doc.admin) return res.redirect(`/wishlist/${row.doc._id}`)
} }
} }
res.render('wishlists', { title: 'Wishlists', users: docs.rows, totals}) res.render('wishlists', { title: 'Wishlists', users: docs.rows, totals })
}); })
router.get('/:user', verifyAuth(), async (req, res) => { router.get('/:user', verifyAuth(), async (req, res) => {
try { try {
const dbUser = await db.get(req.params.user); const dbUser = await db.get(req.params.user)
if (process.env.SINGLE_LIST === 'true') { if (process.env.SINGLE_LIST === 'true') {
if (!dbUser.admin) { if (!dbUser.admin) {
const docs = await db.allDocs({ include_docs: true }) const docs = await db.allDocs({ include_docs: true })
for (row of docs.rows) { for (const row of docs.rows) {
if (row.doc.admin) return res.redirect(`/wishlist/${row.doc._id}`) if (row.doc.admin) return res.redirect(`/wishlist/${row.doc._id}`)
} }
} }
} }
const firstCanSee = dbUser.wishlist.findIndex(element => (element.addedBy === req.params.user)); const firstCanSee = dbUser.wishlist.findIndex(element => (element.addedBy === req.params.user))
const wishlistReverse = [...dbUser.wishlist].reverse(); const wishlistReverse = [...dbUser.wishlist].reverse()
const lastCanSeeValue = wishlistReverse.find(element => (element.addedBy === req.params.user)); const lastCanSeeValue = wishlistReverse.find(element => (element.addedBy === req.params.user))
const lastCanSee = dbUser.wishlist.indexOf(lastCanSeeValue); const lastCanSee = dbUser.wishlist.indexOf(lastCanSeeValue)
res.render('wishlist', { res.render('wishlist', {
title: `Wishlist - ${dbUser._id}`, title: `Wishlist - ${dbUser._id}`,
wishlist: [ wishlist: [
@ -62,40 +62,40 @@ module.exports = (db) => {
], ],
firstCanSee, firstCanSee,
lastCanSee lastCanSee
}); })
} catch (error) { } catch (error) {
req.flash('error', error); req.flash('error', error)
return res.redirect('/wishlist'); return res.redirect('/wishlist')
} }
}); })
router.post('/:user', verifyAuth(), async (req, res) => { router.post('/:user', verifyAuth(), async (req, res) => {
if (!req.body.itemUrlOrName) { if (!req.body.itemUrlOrName) {
req.flash('error', 'Item URL or Name is required') req.flash('error', 'Item URL or Name is required')
return res.redirect(`/wishlist/${req.params.user}`) return res.redirect(`/wishlist/${req.params.user}`)
} }
const potentialUrl = req.body.itemUrlOrName.split(' ').pop(); const potentialUrl = req.body.itemUrlOrName.split(' ').pop()
const url = ValidURL(potentialUrl); const url = ValidURL(potentialUrl)
const item = {}; const item = {}
let productData; let productData
try { try {
if (url) productData = await getProductName(url, config.proxyServer); if (url) productData = await getProductName(url, config.proxyServer)
} catch (err) { } catch (err) {
req.flash('error', err.toString()); req.flash('error', err.toString())
} }
item.name = (productData ? productData.name : ''); item.name = (productData ? productData.name : '')
item.price = productData?.price item.price = productData?.price
item.image = productData?.image item.image = productData?.image
item.addedBy = req.user._id; item.addedBy = req.user._id
item.pledgedBy = (req.user._id === req.params.user ? undefined : req.user._id); item.pledgedBy = (req.user._id === req.params.user ? undefined : req.user._id)
item.note = req.body.note; item.note = req.body.note
if (url) item.url = url; if (url) item.url = url
if (!url) item.name = req.body.itemUrlOrName if (!url) item.name = req.body.itemUrlOrName
item.id = u64.encode(new Date().getTime().toString()); item.id = u64.encode(new Date().getTime().toString())
const doc = await db.get(req.params.user); const doc = await db.get(req.params.user)
doc.wishlist.push(item); doc.wishlist.push(item)
try { try {
await db.put(doc); await db.put(doc)
} catch { } catch {
req.flash('error', 'Items are being added too quickly. Please try again.') req.flash('error', 'Items are being added too quickly. Please try again.')
return res.redirect(`/wishlist/${req.params.user}`) return res.redirect(`/wishlist/${req.params.user}`)
@ -104,134 +104,134 @@ module.exports = (db) => {
'success', 'success',
( (
req.user._id === req.params.user req.user._id === req.params.user
? 'Added item to wishlist' ? 'Added item to wishlist'
: `Pleged item for ${req.params.user}` : `Pleged item for ${req.params.user}`
) )
); )
res.redirect(`/wishlist/${req.params.user}`); res.redirect(`/wishlist/${req.params.user}`)
}); })
router.post('/:user/pledge/:itemId', verifyAuth(), async (req, res) => { router.post('/:user/pledge/:itemId', verifyAuth(), async (req, res) => {
const docs = await db.allDocs({ include_docs: true }); const docs = await db.allDocs({ include_docs: true })
for (let i = 0; i < docs.rows.length; i++) { for (let i = 0; i < docs.rows.length; i++) {
for (let j = 0; j < docs.rows[i].doc.wishlist.length; j++) { for (let j = 0; j < docs.rows[i].doc.wishlist.length; j++) {
if (docs.rows[i].doc.wishlist[j].id === req.params.itemId) { if (docs.rows[i].doc.wishlist[j].id === req.params.itemId) {
if (docs.rows[i].doc.wishlist[j].pledgedBy !== undefined) { if (docs.rows[i].doc.wishlist[j].pledgedBy !== undefined) {
req.flash('error', 'Item already pledged for'); req.flash('error', 'Item already pledged for')
return res.redirect(`/wishlist/${req.params.user}`); return res.redirect(`/wishlist/${req.params.user}`)
} }
docs.rows[i].doc.wishlist[j].pledgedBy = req.user._id; docs.rows[i].doc.wishlist[j].pledgedBy = req.user._id
await db.put(docs.rows[i].doc); await db.put(docs.rows[i].doc)
req.flash('success', 'Successfully pledged for item!'); req.flash('success', 'Successfully pledged for item!')
return res.redirect(`/wishlist/${req.params.user}`); return res.redirect(`/wishlist/${req.params.user}`)
} }
} }
} }
}); })
router.post('/:user/unpledge/:itemId', verifyAuth(), async (req, res) => { router.post('/:user/unpledge/:itemId', verifyAuth(), async (req, res) => {
const docs = await db.allDocs({ include_docs: true }); const docs = await db.allDocs({ include_docs: true })
for (let i = 0; i < docs.rows.length; i++) { for (let i = 0; i < docs.rows.length; i++) {
for (let j = 0; j < docs.rows[i].doc.wishlist.length; j++) { for (let j = 0; j < docs.rows[i].doc.wishlist.length; j++) {
if (docs.rows[i].doc.wishlist[j].id === req.params.itemId) { if (docs.rows[i].doc.wishlist[j].id === req.params.itemId) {
if (docs.rows[i].doc.wishlist[j].pledgedBy !== req.user._id) { if (docs.rows[i].doc.wishlist[j].pledgedBy !== req.user._id) {
req.flash('error', 'You did not pledge for this'); req.flash('error', 'You did not pledge for this')
return res.redirect(`/wishlist/${req.params.user}`); return res.redirect(`/wishlist/${req.params.user}`)
} }
docs.rows[i].doc.wishlist[j].pledgedBy = undefined; docs.rows[i].doc.wishlist[j].pledgedBy = undefined
if (docs.rows[i].doc.wishlist[j].addedBy === req.user._id) docs.rows[i].doc.wishlist.splice(j, 1); if (docs.rows[i].doc.wishlist[j].addedBy === req.user._id) docs.rows[i].doc.wishlist.splice(j, 1)
await db.put(docs.rows[i].doc); await db.put(docs.rows[i].doc)
req.flash('success', 'Successfully unpledged for item'); req.flash('success', 'Successfully unpledged for item')
return res.redirect(`/wishlist/${req.params.user}`); return res.redirect(`/wishlist/${req.params.user}`)
} }
} }
} }
req.flash('error', 'Failed to find item'); req.flash('error', 'Failed to find item')
return res.redirect(`/wishlist/${req.params.user}`); return res.redirect(`/wishlist/${req.params.user}`)
}); })
router.post('/:user/remove/:itemId', verifyAuth(), async (req, res) => { router.post('/:user/remove/:itemId', verifyAuth(), async (req, res) => {
if (req.user._id !== req.params.user) { if (req.user._id !== req.params.user) {
req.flash('error', 'Not correct user'); req.flash('error', 'Not correct user')
return res.redirect(`/wishlist/${req.params.user}`); return res.redirect(`/wishlist/${req.params.user}`)
} }
const doc = await db.get(req.user._id); const doc = await db.get(req.user._id)
for (let i = 0; i < doc.wishlist.length; i++) { for (let i = 0; i < doc.wishlist.length; i++) {
if (doc.wishlist[i].id === req.params.itemId) { if (doc.wishlist[i].id === req.params.itemId) {
doc.wishlist.splice(i, 1); doc.wishlist.splice(i, 1)
await db.put(doc); await db.put(doc)
req.flash('success', 'Successfully removed from wishlist'); req.flash('success', 'Successfully removed from wishlist')
return res.redirect(`/wishlist/${req.params.user}`); return res.redirect(`/wishlist/${req.params.user}`)
} }
} }
req.flash('error', 'Failed to find item'); req.flash('error', 'Failed to find item')
return res.redirect(`/wishlist/${req.params.user}`); return res.redirect(`/wishlist/${req.params.user}`)
}); })
router.post('/:user/move/:direction/:itemId', verifyAuth(), async (req, res) => { router.post('/:user/move/:direction/:itemId', verifyAuth(), async (req, res) => {
if (req.user._id !== req.params.user) { if (req.user._id !== req.params.user) {
req.flash('error', 'Not correct user'); req.flash('error', 'Not correct user')
return res.redirect(`/wishlist/${req.params.user}`); return res.redirect(`/wishlist/${req.params.user}`)
} }
const doc = await db.get(req.user._id); const doc = await db.get(req.user._id)
const wishlist = doc.wishlist; const wishlist = doc.wishlist
if (req.params.direction === 'up') wishlist.reverse(); if (req.params.direction === 'up') wishlist.reverse()
let moveFromIndex; let moveFromIndex
wishlist.forEach(wish => { wishlist.forEach(wish => {
if (wish.id === req.params.itemId) return moveFromIndex = wishlist.indexOf(wish); if (wish.id === req.params.itemId) moveFromIndex = wishlist.indexOf(wish)
}); })
const moveToIndex = wishlist.findIndex(wish => ( wishlist.indexOf(wish) > moveFromIndex && wish.addedBy === req.user._id )); const moveToIndex = wishlist.findIndex(wish => (wishlist.indexOf(wish) > moveFromIndex && wish.addedBy === req.user._id))
if (moveToIndex < 0 || moveToIndex > wishlist.length) { if (moveToIndex < 0 || moveToIndex > wishlist.length) {
req.flash('error', 'Invalid move'); req.flash('error', 'Invalid move')
return res.redirect(`/wishlist/${req.params.user}`); return res.redirect(`/wishlist/${req.params.user}`)
} }
[ wishlist[moveFromIndex], wishlist[moveToIndex] ] = [ wishlist[moveToIndex], wishlist[moveFromIndex] ]; [wishlist[moveFromIndex], wishlist[moveToIndex]] = [wishlist[moveToIndex], wishlist[moveFromIndex]]
if (req.params.direction === 'up') wishlist.reverse(); if (req.params.direction === 'up') wishlist.reverse()
doc.wishlist = wishlist; doc.wishlist = wishlist
await db.put(doc); await db.put(doc)
req.flash('success', 'Successfully moved item!'); req.flash('success', 'Successfully moved item!')
return res.redirect(`/wishlist/${req.params.user}`); return res.redirect(`/wishlist/${req.params.user}`)
}); })
router.get('/:user/note/:id', verifyAuth(), async (req, res) => { router.get('/:user/note/:id', verifyAuth(), async (req, res) => {
const doc = await db.get(req.params.user); const doc = await db.get(req.params.user)
const item = doc.wishlist.find(item => item.id === req.params.id) const item = doc.wishlist.find(item => item.id === req.params.id)
res.render('note', { item }); res.render('note', { item })
}); })
router.post('/:user/note/:id', verifyAuth(), async (req, res) => { router.post('/:user/note/:id', verifyAuth(), async (req, res) => {
const doc = await db.get(req.params.user); const doc = await db.get(req.params.user)
const wishlist = doc.wishlist; const wishlist = doc.wishlist
for (let i=0; i < wishlist.length; i++) { for (let i = 0; i < wishlist.length; i++) {
wishlistItem = wishlist[i]; const wishlistItem = wishlist[i]
if (wishlistItem.id !== req.params.id) continue; if (wishlistItem.id !== req.params.id) continue
if (req.user._id !== req.params.user && req.user._id !== wishlistItem.addedBy) { if (req.user._id !== req.params.user && req.user._id !== wishlistItem.addedBy) {
req.flash('error', 'Invalid user'); req.flash('error', 'Invalid user')
return res.redirect(`/wishlist/${req.params.user}`); return res.redirect(`/wishlist/${req.params.user}`)
} }
for (const type of [ for (const type of [
'name', 'note', 'url', 'price', 'image' 'name', 'note', 'url', 'price', 'image'
]) { ]) {
if (!req.body.hasOwnProperty(type)) { if (!Object.prototype.hasOwnProperty.call(req.body, type)) {
req.flash('error', `Missing property ${type}`) req.flash('error', `Missing property ${type}`)
return res.redirect(`/wishlist/${req.params.user}/note/${req.params.id}`) return res.redirect(`/wishlist/${req.params.user}/note/${req.params.id}`)
} }
wishlistItem[type] = req.body[type] wishlistItem[type] = req.body[type]
} }
wishlist[i] = wishlistItem; wishlist[i] = wishlistItem
} }
doc.wishlist = wishlist; doc.wishlist = wishlist
await db.put(doc); await db.put(doc)
req.flash('success', `Successfully saved note!`); req.flash('success', 'Successfully saved note!')
return res.redirect(`/wishlist/${req.params.user}`); return res.redirect(`/wishlist/${req.params.user}`)
}); })
router.post('/:user/refresh/:id', verifyAuth(), async (req, res) => { router.post('/:user/refresh/:id', verifyAuth(), async (req, res) => {
const doc = await db.get(req.params.user); const doc = await db.get(req.params.user)
const wishlist = doc.wishlist; const wishlist = doc.wishlist
for (let i=0; i < wishlist.length; i++) { for (let i = 0; i < wishlist.length; i++) {
wishlistItem = wishlist[i]; const wishlistItem = wishlist[i]
if (wishlistItem.id !== req.params.id) continue; if (wishlistItem.id !== req.params.id) continue
if (req.user._id !== req.params.user && req.user._id !== wishlistItem.addedBy) { if (req.user._id !== req.params.user && req.user._id !== wishlistItem.addedBy) {
req.flash('error', 'Invalid user'); req.flash('error', 'Invalid user')
return res.redirect(`/wishlist/${req.params.user}`); return res.redirect(`/wishlist/${req.params.user}`)
} }
if (!wishlistItem.url) { if (!wishlistItem.url) {
@ -240,38 +240,39 @@ module.exports = (db) => {
} }
const productData = await getProductName(wishlistItem.url) const productData = await getProductName(wishlistItem.url)
for (field of [ 'name', 'price', 'image' ]) { for (const field of ['name', 'price', 'image']) {
if (productData[field]) wishlistItem[field] = productData[field] if (productData[field]) wishlistItem[field] = productData[field]
} }
wishlist[i] = wishlistItem; wishlist[i] = wishlistItem
} }
doc.wishlist = wishlist; doc.wishlist = wishlist
await db.put(doc); await db.put(doc)
req.flash('success', `Successfully refreshed data!`); req.flash('success', 'Successfully refreshed data!')
return res.redirect(`/wishlist/${req.params.user}/note/${req.params.id}`); return res.redirect(`/wishlist/${req.params.user}/note/${req.params.id}`)
}); })
router.post('/:user/note/remove/:id', verifyAuth(), async (req, res) => { router.post('/:user/note/remove/:id', verifyAuth(), async (req, res) => {
const doc = await db.get(req.params.user); const doc = await db.get(req.params.user)
const wishlist = doc.wishlist; const wishlist = doc.wishlist
for (let i=0; i < wishlist.length; i++) { for (let i = 0; i < wishlist.length; i++) {
wishlistItem = wishlist[i]; const wishlistItem = wishlist[i]
if (wishlistItem.id !== req.params.id) continue; if (wishlistItem.id !== req.params.id) continue
if (req.user._id !== req.params.user && req.user._id !== wishlistItem.addedBy) { if (req.user._id !== req.params.user && req.user._id !== wishlistItem.addedBy) {
req.flash('error', 'Invalid user'); req.flash('error', 'Invalid user')
return res.redirect(`/wishlist/${req.params.user}`); return res.redirect(`/wishlist/${req.params.user}`)
} }
if (wishlistItem.note) { if (wishlistItem.note) {
wishlistItem.note = undefined; wishlistItem.note = undefined
wishlist[i] = wishlistItem; wishlist[i] = wishlistItem
} else { } else {
req.flash('error', 'Has no note'); req.flash('error', 'Has no note')
return res.redirect(`/wishlist/${req.params.user}`); } return res.redirect(`/wishlist/${req.params.user}`)
}
} }
doc.wishlist = wishlist; doc.wishlist = wishlist
await db.put(doc); await db.put(doc)
req.flash('success', 'Successfully removed note'); req.flash('success', 'Successfully removed note')
return res.redirect(`/wishlist/${req.params.user}`); return res.redirect(`/wishlist/${req.params.user}`)
}) })
return router; return router
}; }

View file

@ -1,8 +1,8 @@
window.onload = () => { window.onload = () => {
const burger = document.getElementById('navBarBurger'); const burger = document.getElementById('navBarBurger')
const navBarMenu = document.getElementById('navBarMenu'); const navBarMenu = document.getElementById('navBarMenu')
burger.addEventListener('click', () => { burger.addEventListener('click', () => {
burger.classList.toggle('is-active'); burger.classList.toggle('is-active')
navBarMenu.classList.toggle('is-active'); navBarMenu.classList.toggle('is-active')
}); })
}; }

View file

@ -1,12 +1,13 @@
function animateCSS(node, animationName) { /* eslint-env browser */
function animateCSS (node, animationName) {
return new Promise(resolve => { return new Promise(resolve => {
node.classList.add('animated', animationName) node.classList.add('animated', animationName)
function handleAnimationEnd() { function handleAnimationEnd () {
node.classList.remove('animated', animationName) node.classList.remove('animated', animationName)
node.removeEventListener('animationend', handleAnimationEnd) node.removeEventListener('animationend', handleAnimationEnd)
resolve() resolve()
} }
node.addEventListener('animationend', handleAnimationEnd) node.addEventListener('animationend', handleAnimationEnd)
@ -15,16 +16,14 @@ function animateCSS(node, animationName) {
// These move function are stolen from // These move function are stolen from
// https://stackoverflow.com/a/34914096 // https://stackoverflow.com/a/34914096
function moveUp(element) { function moveUp (element) {
if(element.previousElementSibling) if (element.previousElementSibling) { element.parentNode.insertBefore(element, element.previousElementSibling) }
element.parentNode.insertBefore(element, element.previousElementSibling);
} }
function moveDown(element) { function moveDown (element) {
if(element.nextElementSibling) if (element.nextElementSibling) { element.parentNode.insertBefore(element.nextElementSibling, element) }
element.parentNode.insertBefore(element.nextElementSibling, element);
} }
function listen(element, upOrDown) { function listen (element, upOrDown) {
element.addEventListener('submit', async event => { element.addEventListener('submit', async event => {
try { try {
event.preventDefault() event.preventDefault()
@ -66,8 +65,8 @@ function listen(element, upOrDown) {
return false return false
} catch (error) { } catch (error) {
alert(error.message) alert(error.message)
throw error
location.reload() location.reload()
throw error // probably useless but just in case reload doesn't do anything
} }
}) })
} }

1048
yarn.lock

File diff suppressed because it is too large Load diff