diff --git a/index.js b/index.js index edadbb1..3166a00 100644 --- a/index.js +++ b/index.js @@ -11,6 +11,8 @@ const passport = require('passport') const fetch = require('node-fetch') const express = require('express') +_CC._ = require('lodash') + const config = require('./config') _CC.config = config diff --git a/package.json b/package.json index 80f301f..b3a1082 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,7 @@ "express-session": "^1.17.2", "get-product-name": "1", "jsdom": "^17.0.0", + "lodash": "^4.17.20", "marked": "^3.0.3", "memdown": "^6.0.0", "mkdirp": "^1.0.4", diff --git a/routes/adminSettings/index.js b/routes/adminSettings/index.js index 8901263..f2bcbc0 100644 --- a/routes/adminSettings/index.js +++ b/routes/adminSettings/index.js @@ -11,7 +11,7 @@ const SECRET_TOKEN_LIFETIME = 24 * // hours 7 // days -module.exports = (db) => { +module.exports = ({ db, ensurePfp }) => { const router = express.Router() router.get('/', verifyAuth(), (req, res) => { @@ -25,15 +25,16 @@ module.exports = (db) => { router.post('/add', verifyAuth(), async (req, res) => { if (!req.user.admin) return res.redirect('/') + const username = req.body.newUserUsername.trim() await db.put({ - _id: req.body.newUserUsername.trim(), + _id: username, admin: false, wishlist: [], signupToken: nanoid(SECRET_TOKEN_LENGTH), expiry: new Date().getTime() + SECRET_TOKEN_LIFETIME - }) + await ensurePfp(username) res.redirect(`/admin-settings/edit/${req.body.newUserUsername.trim()}`) }) diff --git a/routes/index.js b/routes/index.js index 7a34263..9f6d1d2 100644 --- a/routes/index.js +++ b/routes/index.js @@ -1,8 +1,24 @@ const publicRoute = require('../middlewares/publicRoute') const express = require('express') const path = require('path') +const fs = require('fs/promises') module.exports = ({ db, config }) => { + async function ensurePfp (username) { + const user = await db.get(username) + console.log(user) + if (user.pfp) return + + const { rows } = await db.allDocs({ include_docs: true }) + + const unfilteredPool = await fs.readdir('static/img/default-pfps') + const filteredPool = unfilteredPool.filter(file => !rows.find(row => row.doc.pfp === `${_CC.config.base}img/default-pfps/${file}`)) + const pool = filteredPool.length ? filteredPool : unfilteredPool + + user.pfp = `${_CC.config.base}img/default-pfps/${_CC._.sample(pool)}` + await db.put(user) + } + const router = express.Router() router.use('/', express.static(path.join(__dirname, '../static'))) @@ -26,7 +42,7 @@ module.exports = ({ db, config }) => { router.use('/setup', require('./setup')(db)) - router.use('/login', require('./login')()) + router.use('/login', require('./login')({ ensurePfp })) router.use('/logout', require('./logout')()) router.use('/resetpw', require('./resetpw')(db)) router.use('/confirm-account', require('./confirm-account')(db)) @@ -34,9 +50,9 @@ module.exports = ({ db, config }) => { router.use('/wishlist', require('./wishlist')(db)) router.use('/supported-sites', require('./supported-sites')()) - router.use('/profile', require('./profile')(db)) + router.use('/profile', require('./profile')({ db, ensurePfp })) - router.use('/admin-settings', require('./adminSettings')(db)) + router.use('/admin-settings', require('./adminSettings')({ db, ensurePfp })) router.use('/manifest.json', require('./manifest.json')({ config })) diff --git a/routes/profile/index.js b/routes/profile/index.js index 277a697..4f8d0b7 100644 --- a/routes/profile/index.js +++ b/routes/profile/index.js @@ -2,10 +2,20 @@ const verifyAuth = require('../../middlewares/verifyAuth') const bcrypt = require('bcrypt-nodejs') const express = require('express') -module.exports = (db) => { +module.exports = ({ db, ensurePfp }) => { const router = express.Router() - router.get('/', verifyAuth(), (req, res) => res.render('profile', { title: `Profile Settings - ${req.user._id}` })) + router.get('/', verifyAuth(), async (req, res) => { + await ensurePfp(req.user._id) + res.render('profile', { title: `Profile Settings - ${req.user._id}` }) + }) + router.post('/pfp', verifyAuth(), async (req, res) => { + req.user.pfp = req.body.image + await db.put(req.user) + if (!req.user.pfp) await ensurePfp(req.user._id) + req.flash('success', 'Saved profile picture!') + res.redirect(`${_CC.config.base}profile`) + }) router.post('/', verifyAuth(), (req, res) => { if (req.body.oldPassword && req.body.newPassword) { bcrypt.compare(req.body.oldPassword, req.user.password, (err, correct) => { diff --git a/static/img/default-pfps/1.jpg b/static/img/default-pfps/1.jpg new file mode 100644 index 0000000..52394a7 Binary files /dev/null and b/static/img/default-pfps/1.jpg differ diff --git a/static/img/default-pfps/10.jpg b/static/img/default-pfps/10.jpg new file mode 100644 index 0000000..40ff79a Binary files /dev/null and b/static/img/default-pfps/10.jpg differ diff --git a/static/img/default-pfps/2.jpg b/static/img/default-pfps/2.jpg new file mode 100644 index 0000000..39fda64 Binary files /dev/null and b/static/img/default-pfps/2.jpg differ diff --git a/static/img/default-pfps/3.jpg b/static/img/default-pfps/3.jpg new file mode 100644 index 0000000..edcbbbb Binary files /dev/null and b/static/img/default-pfps/3.jpg differ diff --git a/static/img/default-pfps/4.png b/static/img/default-pfps/4.png new file mode 100644 index 0000000..14988a4 Binary files /dev/null and b/static/img/default-pfps/4.png differ diff --git a/static/img/default-pfps/5.png b/static/img/default-pfps/5.png new file mode 100644 index 0000000..5d87b16 Binary files /dev/null and b/static/img/default-pfps/5.png differ diff --git a/static/img/default-pfps/6.jpg b/static/img/default-pfps/6.jpg new file mode 100644 index 0000000..c6175fb Binary files /dev/null and b/static/img/default-pfps/6.jpg differ diff --git a/static/img/default-pfps/7.jpg b/static/img/default-pfps/7.jpg new file mode 100644 index 0000000..40dbc92 Binary files /dev/null and b/static/img/default-pfps/7.jpg differ diff --git a/static/img/default-pfps/8.jpg b/static/img/default-pfps/8.jpg new file mode 100644 index 0000000..b42a2d7 Binary files /dev/null and b/static/img/default-pfps/8.jpg differ diff --git a/static/img/default-pfps/9.jpg b/static/img/default-pfps/9.jpg new file mode 100644 index 0000000..338de15 Binary files /dev/null and b/static/img/default-pfps/9.jpg differ diff --git a/views/profile-password.pug b/views/profile-password.pug new file mode 100644 index 0000000..bc64df4 --- /dev/null +++ b/views/profile-password.pug @@ -0,0 +1,20 @@ +extends layout.pug + +block content + form(method='POST') + .field + label.label Old Password (Required if changing password) + .control.has-icons-left + input.input(type='password', name='oldPassword', placeholder='pa$$word!') + span.icon.is-small.is-left + i.fas.fa-lock + .field + label.label New Password (Leave blank if not changing password) + .control.has-icons-left + input.input(type='password', name='newPassword', placeholder='pa$$word!') + span.icon.is-small.is-left + i.fas.fa-lock + .field + .control + input.button.is-primary(type='submit' value='Save') + diff --git a/views/profile.pug b/views/profile.pug index bc64df4..94f2a77 100644 --- a/views/profile.pug +++ b/views/profile.pug @@ -1,20 +1,31 @@ extends layout.pug block content - form(method='POST') - .field - label.label Old Password (Required if changing password) - .control.has-icons-left - input.input(type='password', name='oldPassword', placeholder='pa$$word!') - span.icon.is-small.is-left - i.fas.fa-lock - .field - label.label New Password (Leave blank if not changing password) - .control.has-icons-left - input.input(type='password', name='newPassword', placeholder='pa$$word!') - span.icon.is-small.is-left - i.fas.fa-lock - .field - .control - input.button.is-primary(type='submit' value='Save') - + h2 Profile + div(style='margin-top: 1em;') + .columns(style='margin-top: 1em;') + .column.is-narrow + .box + .columns + .column + figure.image.is-square(style='display: inline-block; width: 90%;') + img.is-rounded(src=req.user.pfp, style='object-fit: cover;') + .column.is-narrow + .column + span.is-size-3= req.user._id + br + br + form(action=`${_CC.config.base}profile/pfp`, method='POST') + label.label Image URL + .field.has-addons + .control + input.input(name='image', value=req.user.pfp) + .control + button.button.is-primary(type='submit') + span.icon + i.fas.fa-save + h2 Security + a.button.is-primary(href=`${_CC.config.base}profile/password`) + span.icon + i.fas.fa-shield-alt + span Change Password diff --git a/views/wishlists.pug b/views/wishlists.pug index ba96ad1..bae2129 100644 --- a/views/wishlists.pug +++ b/views/wishlists.pug @@ -6,14 +6,24 @@ block content li a(href=`${_CC.config.base}wishlist/${req.user._id}`) .box - span=req.user._id - span : ???/??? - progress.progress(value=1, max=1) + .columns + .column.is-1(style='overflow: hidden;') + figure.image.is-square.is-fullwidth.is-marginless(style='display: inline-block;') + img.is-rounded.is-fullwidth(src=req.user.pfp, style='object-fit: cover;') + .column + span=req.user._id + span : ???/??? + progress.progress(value=1, max=1) each user in users if req.user._id !== user.id li a(href=`${_CC.config.base}wishlist/${user.id}`) .box - span= user.id - span : #{totals(user.doc.wishlist).pledged}/#{user.doc.wishlist.length} - progress.progress.is-info(value=totals(user.doc.wishlist).pledged, max=user.doc.wishlist.length) \ No newline at end of file + .columns + .column.is-1(style='overflow: hidden;') + figure.image.is-square.is-fullwidth.is-marginless(style='display: inline-block;') + img.is-rounded.is-fullwidth(src=user.doc.pfp, style='object-fit: cover;') + .column + span= user.id + span : #{totals(user.doc.wishlist).pledged}/#{user.doc.wishlist.length} + progress.progress.is-info(value=totals(user.doc.wishlist).pledged, max=user.doc.wishlist.length) \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 3fd0c0e..d28fb60 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2700,7 +2700,7 @@ "resolved" "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz" "version" "4.4.2" -"lodash@^4.15.0", "lodash@^4.17.19": +"lodash@^4.15.0", "lodash@^4.17.19", "lodash@^4.17.20": "integrity" "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==" "resolved" "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz" "version" "4.17.20"