localization support
This commit is contained in:
parent
f99d6f88c3
commit
d91128274b
29 changed files with 396 additions and 194 deletions
|
@ -91,6 +91,8 @@ BULMASWATCH=default
|
||||||
UPDATE_CHECK=true
|
UPDATE_CHECK=true
|
||||||
# Set to false to disable the profile pictures feature
|
# Set to false to disable the profile pictures feature
|
||||||
PFP=true
|
PFP=true
|
||||||
|
# Language of the interface, options listed in `languages` directory
|
||||||
|
LANGUAGE=en-US
|
||||||
|
|
||||||
## Wishlist Settings
|
## Wishlist Settings
|
||||||
# Set to true to not allow users to have their own lists. You may want this for a birthday or wedding.
|
# Set to true to not allow users to have their own lists. You may want this for a birthday or wedding.
|
||||||
|
|
|
@ -14,5 +14,6 @@ module.exports = {
|
||||||
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',
|
||||||
bulmaswatch: (process.env.BULMASWATCH || 'default').toLowerCase(),
|
bulmaswatch: (process.env.BULMASWATCH || 'default').toLowerCase(),
|
||||||
pfp: process.env.PFP !== 'false'
|
pfp: process.env.PFP !== 'false',
|
||||||
|
language: process.env.LANGUAGE?.toLowerCase() || 'en-us'
|
||||||
}
|
}
|
||||||
|
|
24
index.js
24
index.js
|
@ -12,10 +12,34 @@ const fetch = require('node-fetch')
|
||||||
const express = require('express')
|
const express = require('express')
|
||||||
|
|
||||||
_CC._ = require('lodash')
|
_CC._ = require('lodash')
|
||||||
|
_CC.moment = require('moment/min/moment-with-locales')
|
||||||
|
|
||||||
const config = require('./config')
|
const config = require('./config')
|
||||||
_CC.config = config
|
_CC.config = config
|
||||||
|
|
||||||
|
;(() => {
|
||||||
|
let language
|
||||||
|
try {
|
||||||
|
language = require(`./languages/${config.language}`)
|
||||||
|
} catch (error) {
|
||||||
|
if (error.message.startsWith('Cannot find module')) console.error(`Language ${config.language} is not supported. If you know this language and would like to translate Christmas Community, please ask for help doing so here: https://github.com/Wingysam/Christmas-Community/issues/new`)
|
||||||
|
else console.error(`Failed to load language ${config.language} because of ${error}`)
|
||||||
|
process.exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_CC.moment.locale(language.momentLocale) !== language.momentLocale) {
|
||||||
|
console.error(`${_CC.moment.locale()} Failed to load language ${config.language}, moment locale missing. Valid locales: ${_CC.moment.locales().join(', ')}`)
|
||||||
|
process.exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
_CC.lang = (key, ...args) => {
|
||||||
|
const lang = language.strings[key]
|
||||||
|
if (!lang) return language.strings._NOT_LOCALIZED(key)
|
||||||
|
if (typeof lang === 'function') return lang(...args)
|
||||||
|
return lang
|
||||||
|
}
|
||||||
|
})()
|
||||||
|
|
||||||
if (!config.dbPrefix.startsWith('http')) {
|
if (!config.dbPrefix.startsWith('http')) {
|
||||||
const mkdirp = require('mkdirp').sync
|
const mkdirp = require('mkdirp').sync
|
||||||
mkdirp(config.dbPrefix)
|
mkdirp(config.dbPrefix)
|
||||||
|
|
181
languages/en-us.js
Normal file
181
languages/en-us.js
Normal file
|
@ -0,0 +1,181 @@
|
||||||
|
module.exports.momentLocale = 'en'
|
||||||
|
|
||||||
|
module.exports.strings = {
|
||||||
|
_NOT_LOCALIZED: key => `${key} hasn't been translated to English yet.`,
|
||||||
|
ADMIN_CLEAR_WISHLISTS_BUTTON: 'Clear all wishlists',
|
||||||
|
ADMIN_CLEAR_WISHLISTS_DESCRIPTION: 'This will instantly <b>irreversibly delete all wishlists!</b> Consider making a backup of the database before using this.',
|
||||||
|
ADMIN_CLEAR_WISHLISTS_HEADER: 'Wishlist Deletion',
|
||||||
|
ADMIN_SETTINGS_CLEARDB_BUTTON: 'Clear Wishlists',
|
||||||
|
ADMIN_SETTINGS_CLEARDB_DESCRIPTION: '<b>Warning</b>: These options <b>destroy data</b>! You may want to back up the database before using these options.',
|
||||||
|
ADMIN_SETTINGS_CLEARDB_HEADER: 'Data Destruction',
|
||||||
|
ADMIN_SETTINGS_CLEARDB_SUCCESS: 'Cleared all wishlists.',
|
||||||
|
ADMIN_SETTINGS_HEADER: 'Admin Settings',
|
||||||
|
ADMIN_SETTINGS_USERS_ADD_BUTTON: 'Add User',
|
||||||
|
ADMIN_SETTINGS_USERS_ADD_HEADER: 'Add user',
|
||||||
|
ADMIN_SETTINGS_USERS_ADD_PLACEHOLDER: 'john',
|
||||||
|
ADMIN_SETTINGS_USERS_ADD_USERNAME: 'Username',
|
||||||
|
ADMIN_SETTINGS_USERS_EDIT_DELETE_FAIL_ADMIN: 'Failed to remove: user is admin.',
|
||||||
|
ADMIN_SETTINGS_USERS_EDIT_DELETE_SUCCESS: name => `Successfully removed user ${name}`,
|
||||||
|
ADMIN_SETTINGS_USERS_EDIT_DEMOTE_NOT_ADMIN: 'user is not an admin',
|
||||||
|
ADMIN_SETTINGS_USERS_EDIT_DEMOTE_SELF: 'You cannot demote yourself.',
|
||||||
|
ADMIN_SETTINGS_USERS_EDIT_DEMOTE_SUCCESS: name => `${name} is no longer an admin.`,
|
||||||
|
ADMIN_SETTINGS_USERS_EDIT_IMPERSONATE_SUCCESS: name => `You are now ${name}.`,
|
||||||
|
ADMIN_SETTINGS_USERS_EDIT_NO_USERNAME_PROVIDED: 'No username provided',
|
||||||
|
ADMIN_SETTINGS_USERS_EDIT_PROMOTE_ALREADY_ADMIN: 'user is already admin',
|
||||||
|
ADMIN_SETTINGS_USERS_EDIT_PROMOTE_DEMOTE_NOT_FOUND: 'User not found.',
|
||||||
|
ADMIN_SETTINGS_USERS_EDIT_PROMOTE_SUCCESS: name => `${name} is now an admin.`,
|
||||||
|
ADMIN_SETTINGS_USERS_EDIT_RENAMED_USER: 'Renamed user!',
|
||||||
|
ADMIN_SETTINGS_USERS_EDIT_SAME_NAME: 'Username is same as new username.',
|
||||||
|
ADMIN_SETTINGS_USERS_EDIT: 'Edit',
|
||||||
|
ADMIN_SETTINGS_USERS_HEADER: 'Users',
|
||||||
|
ADMIN_SETTINGS_VERSION_INFO: 'Version Info',
|
||||||
|
ADMIN_USER_EDIT_ACCOUNT_UNCONFIRMED: "This account hasn't been confirmed.",
|
||||||
|
ADMIN_USER_EDIT_ADMIN_ISADMIN: name => `${name} is an admin.`,
|
||||||
|
ADMIN_USER_EDIT_ADMIN_NOTADMIN: name => `${name} is not an admin.`,
|
||||||
|
ADMIN_USER_EDIT_ADMIN: 'Admin',
|
||||||
|
ADMIN_USER_EDIT_CHANGE_NAME: 'Change Name',
|
||||||
|
ADMIN_USER_EDIT_CHANGE_USERNAME: 'Change Username',
|
||||||
|
ADMIN_USER_EDIT_CONFIRMATION_LINK: 'Confirmation Link',
|
||||||
|
ADMIN_USER_EDIT_DELETE_ADMIN: 'User is admin',
|
||||||
|
ADMIN_USER_EDIT_DELETE_HEADER: 'Irreversible Deletion',
|
||||||
|
ADMIN_USER_EDIT_DELETE_USER: name => `Remove user ${name}`,
|
||||||
|
ADMIN_USER_EDIT_DEMOTE_SELF: 'You cannot demote yourself',
|
||||||
|
ADMIN_USER_EDIT_DEMOTE: name => `Demote ${name}`,
|
||||||
|
ADMIN_USER_EDIT_EDITING_USER: name => `Editing user "${name}"`,
|
||||||
|
ADMIN_USER_EDIT_GENERATE_NEW_LINK: 'Generate New Link',
|
||||||
|
ADMIN_USER_EDIT_IMPERSONATE_BUTTON: name => `Log in as ${name}`,
|
||||||
|
ADMIN_USER_EDIT_IMPERSONATE_HEADER: 'Impersonate',
|
||||||
|
ADMIN_USER_EDIT_LINK_EXPIRY_FUTURE: fromNow => `The following link expires ${fromNow}`, // fromNow is localized by moment
|
||||||
|
ADMIN_USER_EDIT_LINK_EXPIRY_PAST: fromNow => `The following link expired ${fromNow}`,
|
||||||
|
ADMIN_USER_EDIT_PROMOTE: name => `Promote ${name}`,
|
||||||
|
ADMIN_USER_EDIT_RESET_PASSWORD_HASLINK_EXPIRY_FUTURE: fromNow => `It expires ${fromNow}`,
|
||||||
|
ADMIN_USER_EDIT_RESET_PASSWORD_HASLINK_EXPIRY_PAST: fromNow => `It expired ${fromNow}`,
|
||||||
|
ADMIN_USER_EDIT_RESET_PASSWORD_HASLINK: 'There is a reset password link for this user.',
|
||||||
|
ADMIN_USER_EDIT_RESET_PASSWORD_HEADER: 'Reset Password',
|
||||||
|
ADMIN_USER_EDIT_RESET_PASSWORD_LINK_CANCEL: 'Cancel Password Reset Link',
|
||||||
|
ADMIN_USER_EDIT_RESET_PASSWORD_LINK_CREATE: 'Create Password Reset Link',
|
||||||
|
ADMIN_USER_EDIT_RESET_PASSWORD_LINK_REFRESH: 'Refresh Password Reset Link',
|
||||||
|
ADMIN_USER_EDIT_USERNAME: 'Username',
|
||||||
|
BACK_BUTTON: 'Back',
|
||||||
|
CONFIRM_ACCOUNT_EXPIRED: 'Your confirmation link has expired. Please ask for a new one.',
|
||||||
|
CONFIRM_ACCOUNT_HEADER_INVALID: `${_CC.config.siteTitle} | Confirmation Link Invalid`,
|
||||||
|
CONFIRM_ACCOUNT_HEADER_VALID: `${_CC.config.siteTitle} | Confirm Account`,
|
||||||
|
CONFIRM_ACCOUNT_INVALID: "This confirmation link isn't valid, perhaps the account was deleted or some characters at the end got cut off?",
|
||||||
|
CONFIRM_ACCOUNT_SET_PW_BUTTON: `Join ${_CC.config.siteTitle}`,
|
||||||
|
CONFIRM_ACCOUNT_SET_PW_PLACEHOLDER: 'pa$$word!',
|
||||||
|
CONFIRM_ACCOUNT_SET_PW_TEXT: name => `Hello ${name}! Please set your password here.`,
|
||||||
|
CONFIRM_ACCOUNT_SUCCESS: `Welcome to ${_CC.config.siteTitle}!`,
|
||||||
|
LOGIN_BUTTON: 'Log In',
|
||||||
|
LOGIN_PASSWORD_PLACEHOLDER: 'pa$$word!',
|
||||||
|
LOGIN_PASSWORD: 'Password',
|
||||||
|
LOGIN_USERNAME_PLACEHOLDER: 'john',
|
||||||
|
LOGIN_USERNAME: 'Username',
|
||||||
|
LOGOUT_BUTTON: 'Log Out',
|
||||||
|
NAVBAR_ADMIN: 'Admin Settings',
|
||||||
|
NAVBAR_LOGIN: 'Log In',
|
||||||
|
NAVBAR_LOGOUT: 'Log Out',
|
||||||
|
NAVBAR_PROFILE: 'Profile',
|
||||||
|
NAVBAR_WISHLIST: 'My Wishlist',
|
||||||
|
NOTE_BACK: name => `Back to ${name}'s wishlist`,
|
||||||
|
NOTE_GET_PRODUCT_DATA: 'Get Product Data',
|
||||||
|
NOTE_GUARD: 'Invalid user',
|
||||||
|
NOTE_IMAGE_URL: 'Image URL',
|
||||||
|
NOTE_MISSING_PROP: prop => `Missing property ${prop}`, // not really possible to localize this unfortunately
|
||||||
|
NOTE_NAME: 'Name',
|
||||||
|
NOTE_NOTE: 'Note',
|
||||||
|
NOTE_PRICE: 'Price',
|
||||||
|
NOTE_REFRESH_DATA: 'Refresh Data',
|
||||||
|
NOTE_REMOVE_GUARD: 'Invalid user',
|
||||||
|
NOTE_REMOVE_MISSING: 'Has no note',
|
||||||
|
NOTE_REMOVE_SUCCESS: 'Successfully removed note',
|
||||||
|
NOTE_SAVE_BUTTON: 'Save Item',
|
||||||
|
NOTE_SUCCESS: 'Successfully saved!',
|
||||||
|
NOTE_URL: 'URL',
|
||||||
|
PROFILE_HEADER: 'Profile',
|
||||||
|
PROFILE_PASSWORD_BUTTON: 'Save',
|
||||||
|
PROFILE_PASSWORD_NEW: 'New Password',
|
||||||
|
PROFILE_PASSWORD_OLD_MISMATCH: 'Incorrect old password',
|
||||||
|
PROFILE_PASSWORD_OLD: 'Old Password',
|
||||||
|
PROFILE_PASSWORD_PLACEHOLDER: 'pa$$word!',
|
||||||
|
PROFILE_PASSWORD_REQUIRED_NEW: 'New Password is required',
|
||||||
|
PROFILE_PASSWORD_REQUIRED_OLD: 'Old Password is required',
|
||||||
|
PROFILE_PASSWORD_SUCCESS: 'Changed saved successfully!',
|
||||||
|
PROFILE_PASSWORD_TITLE: name => `Profile Settings - Password - ${name}`,
|
||||||
|
PROFILE_PFP_IMAGE_URL: 'Image URL',
|
||||||
|
PROFILE_SAVE_PFP_DISABLED: 'Profile pictures are disabled.',
|
||||||
|
PROFILE_SAVE_PFP_SUCCESS: 'Saved profile picture!',
|
||||||
|
PROFILE_SECURITY_CHANGE_PASSWORD: 'Change Password',
|
||||||
|
PROFILE_SECURITY: 'Security',
|
||||||
|
PROFILE_TITLE: name => `Profile Settings - ${name}`,
|
||||||
|
RESET_PASSWORD_BUTTON: 'Reset Password',
|
||||||
|
RESET_PASSWORD_GREETING_EXPIRED: 'Your reset link has expired. Please ask for a new one.',
|
||||||
|
RESET_PASSWORD_GREETING_INVALID: "This reset link isn't valid, perhaps the link was canceled or some characters at the end got cut off?",
|
||||||
|
RESET_PASSWORD_GREETING_VALID: name => `Hello ${name}! Please set your password here.`,
|
||||||
|
RESET_PASSWORD_HEADER_INVALID: `${_CC.config.siteTitle} | Reset Link Invalid`,
|
||||||
|
RESET_PASSWORD_HEADER_VALID: `${_CC.config.siteTitle} | Reset Password`,
|
||||||
|
RESET_PASSWORD_PASSWORD_PLACEHOLDER: 'pa$$word!',
|
||||||
|
RESET_PASSWORD_PASSWORD: 'Password',
|
||||||
|
RESET_PASSWORD_SUCCESS: 'Password reset successfully!',
|
||||||
|
SETUP_ADMIN_USER: 'Admin User',
|
||||||
|
SETUP_BUTTON: 'Set up!',
|
||||||
|
SETUP_HEADER: 'Setup',
|
||||||
|
SETUP_PASSWORD_PLACEHOLDER: 'pa$$word!',
|
||||||
|
SETUP_PASSWORD: 'Password',
|
||||||
|
SETUP_USERNAME_PLACEHOLDER: 'john',
|
||||||
|
SETUP_USERNAME: 'Username',
|
||||||
|
SUPPORTED_SITES_HEADER: 'Supported Sites',
|
||||||
|
SUPPORTED_SITES_TEXT: 'Is a site missing or broken? Open an issue <a href="https://gitlab.com/wingysam/get-product-name/-/issues/new">here</a>! :)',
|
||||||
|
UPDATE_NOTICE: (current, latest) => `
|
||||||
|
<span class="has-text-danger is-size-4 has-text-weight-bold">
|
||||||
|
Christmas Community is out of date. There may be new features or bug fixes. Consider updating! :)
|
||||||
|
</span>
|
||||||
|
<br>
|
||||||
|
<span>(you can turn this off with <code>UPDATE_CHECK=false</code>)</span>
|
||||||
|
<br><br>
|
||||||
|
<span>Current: ${current}</span>
|
||||||
|
<br>
|
||||||
|
<span>Latest: ${latest}</span>
|
||||||
|
<span class="has-text-info" style="float: right;">This message is only visible to admins</span>`,
|
||||||
|
WISHLIST_ADD: 'Add item to wishlist',
|
||||||
|
WISHLIST_ADDED_BY_USER: addedBy => `Added by: ${addedBy}`,
|
||||||
|
WISHLIST_ADDED_BY: 'Added By',
|
||||||
|
WISHLIST_CONFLICT: 'Items are being added too quickly. Please try again.',
|
||||||
|
WISHLIST_DELETE: 'Delete',
|
||||||
|
WISHLIST_EDIT_ITEM: 'Edit Item',
|
||||||
|
WISHLIST_IMAGE: 'Image',
|
||||||
|
WISHLIST_MOVE_DOWN: 'Move Down',
|
||||||
|
WISHLIST_MOVE_GUARD: 'Not correct user',
|
||||||
|
WISHLIST_MOVE_INVALID: 'Invalid move',
|
||||||
|
WISHLIST_MOVE_ITEM_DOWN: 'Move Item Down',
|
||||||
|
WISHLIST_MOVE_ITEM_TOP: 'Move Item Top',
|
||||||
|
WISHLIST_MOVE_ITEM_UP: 'Move Item Up',
|
||||||
|
WISHLIST_MOVE_SUCCESS: 'Successfully moved item!',
|
||||||
|
WISHLIST_MOVE_TOP: 'Move Top',
|
||||||
|
WISHLIST_MOVE_UP: 'Move Up',
|
||||||
|
WISHLIST_NAME: 'Name',
|
||||||
|
WISHLIST_NOTE: 'Note',
|
||||||
|
WISHLIST_OPTIONAL: 'Optional',
|
||||||
|
WISHLIST_PLEDGE_DUPLICATE: 'Item already pledged for',
|
||||||
|
WISHLIST_PLEDGE_ITEM: 'Pledge item',
|
||||||
|
WISHLIST_PLEDGE_SUCCESS: 'Successfully pledged for item!',
|
||||||
|
WISHLIST_PLEDGE: 'Pledge',
|
||||||
|
WISHLIST_PLEDGED: pledgedBy => `Pledged for by ${pledgedBy}`,
|
||||||
|
WISHLIST_PRICE: 'Price',
|
||||||
|
WISHLIST_REFRESH_GUARD: 'Invalid user',
|
||||||
|
WISHLIST_REFRESH_NO_URL: 'Item has no URL.',
|
||||||
|
WISHLIST_REFRESH_SUCCESS: 'Successfully refreshed data!',
|
||||||
|
WISHLIST_REMOVE_GUARD: 'Not correct user',
|
||||||
|
WISHLIST_REMOVE_MISSING: 'Failed to find item',
|
||||||
|
WISHLIST_REMOVE_SUCCESS: 'Successfully removed from wishlist',
|
||||||
|
WISHLIST_TITLE: name => `${_CC.config.siteTitle} - Wishlist - ${name}`,
|
||||||
|
WISHLIST_UNPLEDGE_GUARD: 'You did not pledge for this', // should never happen unless someone makes their own http requests
|
||||||
|
WISHLIST_UNPLEDGE_MISSING: 'Failed to find item',
|
||||||
|
WISHLIST_UNPLEDGE_SUCCESS: 'Successfully unpledged for item!',
|
||||||
|
WISHLIST_UNPLEDGE: 'Unpledge',
|
||||||
|
WISHLIST_URL_LABEL: 'Item URL or Name (<a href="/supported-sites">Supported Sites</a>)',
|
||||||
|
WISHLIST_URL_PLACEHOLDER: 'https://www.amazon.com/dp/B00ZV9RDKK',
|
||||||
|
WISHLIST_URL_REQUIRED: 'Item URL or Name is required',
|
||||||
|
WISHLISTS_COUNTS_SELF: name => `${name}: ???/???`,
|
||||||
|
WISHLISTS_COUNTS: (name, pledged, total) => `${name}: ${pledged}/${total}`,
|
||||||
|
WISHLISTS_TITLE: `${_CC.config.siteTitle} - Wishlists`
|
||||||
|
}
|
|
@ -1,6 +1,8 @@
|
||||||
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
|
||||||
|
res.locals.lang = _CC.lang
|
||||||
next()
|
next()
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@ module.exports = ({ db, ensurePfp }) => {
|
||||||
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: _CC.lang('ADMIN_SETTINGS_HEADER'), users: docs.rows })
|
||||||
})
|
})
|
||||||
.catch(err => { throw err })
|
.catch(err => { throw err })
|
||||||
})
|
})
|
||||||
|
@ -75,11 +75,11 @@ module.exports = ({ db, ensurePfp }) => {
|
||||||
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('/')
|
||||||
if (!req.body.newUsername) {
|
if (!req.body.newUsername) {
|
||||||
req.flash('error', 'No username provided')
|
req.flash('error', _CC.lang('ADMIN_SETTINGS_USERS_EDIT_NO_USERNAME_PROVIDED'))
|
||||||
return res.redirect(`/admin-settings/edit/${req.params.userToRename}`)
|
return res.redirect(`/admin-settings/edit/${req.params.userToRename}`)
|
||||||
}
|
}
|
||||||
if (req.body.newUsername === req.params.userToRename) {
|
if (req.body.newUsername === req.params.userToRename) {
|
||||||
req.flash('error', 'Username is same as new username.')
|
req.flash('error', _CC.lang('ADMIN_SETTINGS_USERS_EDIT_SAME_NAME'))
|
||||||
return res.redirect(`/admin-settings/edit/${req.params.userToRename}`)
|
return res.redirect(`/admin-settings/edit/${req.params.userToRename}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -105,7 +105,7 @@ module.exports = ({ db, ensurePfp }) => {
|
||||||
await db.bulkDocs(usersBulk)
|
await db.bulkDocs(usersBulk)
|
||||||
await db.remove(await db.get(oldName))
|
await db.remove(await db.get(oldName))
|
||||||
|
|
||||||
await req.flash('success', 'Renamed user!')
|
req.flash('success', _CC.lang('ADMIN_SETTINGS_USERS_EDIT_RENAMED_USER'))
|
||||||
return res.redirect(`/wishlist/${newName}`)
|
return res.redirect(`/wishlist/${newName}`)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error, error.stack)
|
console.log(error, error.stack)
|
||||||
|
@ -125,7 +125,7 @@ module.exports = ({ db, ensurePfp }) => {
|
||||||
req.flash('error', err.message)
|
req.flash('error', err.message)
|
||||||
return res.redirect(`/admin-settings/edit/${req.params.userToEdit}`)
|
return res.redirect(`/admin-settings/edit/${req.params.userToEdit}`)
|
||||||
}
|
}
|
||||||
req.flash('success', `You are now ${req.params.userToEdit}.`)
|
req.flash('success', _CC.lang('ADMIN_SETTINGS_USERS_EDIT_IMPERSONATE_SUCCESS', req.params.userToEdit))
|
||||||
res.redirect('/')
|
res.redirect('/')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -134,43 +134,43 @@ module.exports = ({ db, ensurePfp }) => {
|
||||||
if (!req.user.admin) return res.redirect('/')
|
if (!req.user.admin) return res.redirect('/')
|
||||||
const user = await db.get(req.params.userToPromote)
|
const user = await db.get(req.params.userToPromote)
|
||||||
if (!user) {
|
if (!user) {
|
||||||
req.flash('error', 'User not found.')
|
req.flash('error', _CC.lang('ADMIN_SETTINGS_USERS_EDIT_PROMOTE_DEMOTE_NOT_FOUND'))
|
||||||
return res.redirect(`/admin-settings/edit/${req.params.userToPromote}`)
|
return res.redirect(`/admin-settings/edit/${req.params.userToPromote}`)
|
||||||
}
|
}
|
||||||
if (user.admin) {
|
if (user.admin) {
|
||||||
req.flash('error', 'user is already admin')
|
req.flash('error', _CC.lang('ADMIN_SETTINGS_USERS_EDIT_PROMOTE_ALREADY_ADMIN'))
|
||||||
return res.redirect(`/admin-settings/edit/${req.params.userToPromote}`)
|
return res.redirect(`/admin-settings/edit/${req.params.userToPromote}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
user.admin = true
|
user.admin = true
|
||||||
await db.put(user)
|
await db.put(user)
|
||||||
|
|
||||||
req.flash('success', `${user._id} is now an admin.`)
|
req.flash('success', _CC.lang('ADMIN_SETTINGS_USERS_EDIT_PROMOTE_SUCCESS', user._id))
|
||||||
return res.redirect(`/admin-settings/edit/${req.params.userToPromote}`)
|
return res.redirect(`/admin-settings/edit/${req.params.userToPromote}`)
|
||||||
})
|
})
|
||||||
|
|
||||||
router.post('/edit/demote/:userToDemote', verifyAuth(), async (req, res) => {
|
router.post('/edit/demote/:userToDemote', verifyAuth(), async (req, res) => {
|
||||||
if (!req.user.admin) return res.redirect('/')
|
if (!req.user.admin) return res.redirect('/')
|
||||||
if (req.user._id === req.params.userToDemote) {
|
if (req.user._id === req.params.userToDemote) {
|
||||||
req.flash('error', 'You cannot demote yourself.')
|
req.flash('error', _CC.lang('ADMIN_SETTINGS_USERS_EDIT_DEMOTE_SELF'))
|
||||||
return res.redirect(`/admin-settings/edit/${req.params.userToDemote}`)
|
return res.redirect(`/admin-settings/edit/${req.params.userToDemote}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
const user = await db.get(req.params.userToDemote)
|
const user = await db.get(req.params.userToDemote)
|
||||||
|
|
||||||
if (!user) {
|
if (!user) {
|
||||||
req.flash('error', 'User not found.')
|
req.flash('error', _CC.lang('ADMIN_SETTINGS_USERS_EDIT_PROMOTE_DEMOTE_NOT_FOUND'))
|
||||||
return res.redirect(`/admin-settings/edit/${req.params.userToDemote}`)
|
return res.redirect(`/admin-settings/edit/${req.params.userToDemote}`)
|
||||||
}
|
}
|
||||||
if (!user.admin) {
|
if (!user.admin) {
|
||||||
req.flash('error', 'user is not an admin')
|
req.flash('error', _CC.lang('ADMIN_SETTINGS_USERS_EDIT_DEMOTE_NOT_ADMIN'))
|
||||||
return res.redirect(`/admin-settings/edit/${req.params.userToDemote}`)
|
return res.redirect(`/admin-settings/edit/${req.params.userToDemote}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
user.admin = false
|
user.admin = false
|
||||||
await db.put(user)
|
await db.put(user)
|
||||||
|
|
||||||
req.flash('success', `${user._id} is no longer an admin.`)
|
req.flash('success', _CC.lang('ADMIN_SETTINGS_USERS_EDIT_DEMOTE_SUCCESS', user._id))
|
||||||
return res.redirect(`/admin-settings/edit/${req.params.userToDemote}`)
|
return res.redirect(`/admin-settings/edit/${req.params.userToDemote}`)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -178,7 +178,7 @@ module.exports = ({ db, ensurePfp }) => {
|
||||||
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', _CC.lang('ADMIN_SETTINGS_USERS_EDIT_DELETE_FAIL_ADMIN'))
|
||||||
return res.redirect('/admin-settings')
|
return res.redirect('/admin-settings')
|
||||||
}
|
}
|
||||||
await db.remove(doc)
|
await db.remove(doc)
|
||||||
|
@ -192,7 +192,7 @@ module.exports = ({ db, ensurePfp }) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
req.flash('success', `Successfully removed user ${req.params.userToRemove}`)
|
req.flash('success', _CC.lang('ADMIN_SETTINGS_USERS_EDIT_DELETE_SUCCESS', req.params.userToRemove))
|
||||||
res.redirect('/admin-settings')
|
res.redirect('/admin-settings')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -208,7 +208,7 @@ module.exports = ({ db, ensurePfp }) => {
|
||||||
row.doc.wishlist = []
|
row.doc.wishlist = []
|
||||||
await db.put(row.doc)
|
await db.put(row.doc)
|
||||||
}
|
}
|
||||||
req.flash('success', 'Cleared all wishlists.')
|
req.flash('success', _CC.lang('ADMIN_SETTINGS_CLEARDB_SUCCESS'))
|
||||||
res.redirect('/admin-settings')
|
res.redirect('/admin-settings')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,7 @@ 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', _CC.lang('CONFIRM_ACCOUNT_SUCCESS'))
|
||||||
res.redirect('/')
|
res.redirect('/')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -7,7 +7,7 @@ module.exports = ({ db, config, ensurePfp }) => {
|
||||||
|
|
||||||
router.get('/', verifyAuth(), async (req, res) => {
|
router.get('/', verifyAuth(), async (req, res) => {
|
||||||
await ensurePfp(req.user._id)
|
await ensurePfp(req.user._id)
|
||||||
res.render('profile', { title: `Profile Settings - ${req.user._id}` })
|
res.render('profile', { title: _CC.lang('PROFILE_TITLE', req.user._id) })
|
||||||
})
|
})
|
||||||
|
|
||||||
router.post('/pfp', verifyAuth(), async (req, res) => {
|
router.post('/pfp', verifyAuth(), async (req, res) => {
|
||||||
|
@ -15,24 +15,24 @@ module.exports = ({ db, config, ensurePfp }) => {
|
||||||
req.user.pfp = req.body.image
|
req.user.pfp = req.body.image
|
||||||
await db.put(req.user)
|
await db.put(req.user)
|
||||||
if (!req.user.pfp) await ensurePfp(req.user._id)
|
if (!req.user.pfp) await ensurePfp(req.user._id)
|
||||||
req.flash('success', 'Saved profile picture!')
|
req.flash('success', _CC.lang('PROFILE_SAVE_PFP_SUCCESS'))
|
||||||
} else {
|
} else {
|
||||||
req.flash('error', 'Profile pictures are disabled.')
|
req.flash('error', _CC.lang('PROFILE_SAVE_PFP_DISABLED'))
|
||||||
}
|
}
|
||||||
res.redirect(`${_CC.config.base}profile`)
|
res.redirect(`${_CC.config.base}profile`)
|
||||||
})
|
})
|
||||||
|
|
||||||
router.get('/password', verifyAuth(), async (req, res) => {
|
router.get('/password', verifyAuth(), async (req, res) => {
|
||||||
await ensurePfp(req.user._id)
|
await ensurePfp(req.user._id)
|
||||||
res.render('profile-password', { title: `Profile Settings - Password - ${req.user._id}` })
|
res.render('profile-password', { title: _CC.lang('PROFILE_PASSWORD_TITLE', req.user._id) })
|
||||||
})
|
})
|
||||||
router.post('/password', verifyAuth(), (req, res) => {
|
router.post('/password', verifyAuth(), (req, res) => {
|
||||||
if (!req.body.oldPassword) {
|
if (!req.body.oldPassword) {
|
||||||
req.flash('error', 'Old Password is required')
|
req.flash('error', _CC.lang('PROFILE_PASSWORD_REQUIRED_OLD'))
|
||||||
return res.redirect('/profile/password')
|
return res.redirect('/profile/password')
|
||||||
}
|
}
|
||||||
if (!req.body.newPassword) {
|
if (!req.body.newPassword) {
|
||||||
req.flash('error', 'New Password is required')
|
req.flash('error', _CC.lang('PROFILE_PASSWORD_REQUIRED_NEW'))
|
||||||
return res.redirect('/profile/password')
|
return res.redirect('/profile/password')
|
||||||
}
|
}
|
||||||
bcrypt.compare(req.body.oldPassword, req.user.password, (err, correct) => {
|
bcrypt.compare(req.body.oldPassword, req.user.password, (err, correct) => {
|
||||||
|
@ -45,7 +45,7 @@ module.exports = ({ db, config, ensurePfp }) => {
|
||||||
doc.password = hash
|
doc.password = hash
|
||||||
db.put(doc)
|
db.put(doc)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
req.flash('success', 'Changes saved successfully!')
|
req.flash('success', _CC.lang('PROFILE_PASSWORD_SUCCESS'))
|
||||||
res.redirect('/profile/password')
|
res.redirect('/profile/password')
|
||||||
})
|
})
|
||||||
.catch(err => { throw err })
|
.catch(err => { throw err })
|
||||||
|
@ -53,7 +53,7 @@ module.exports = ({ db, config, ensurePfp }) => {
|
||||||
.catch(err => { throw err })
|
.catch(err => { throw err })
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
req.flash('error', 'Incorrect old password')
|
req.flash('error', _CC.lang('PROFILE_PASSWORD_OLD_MISMATCH'))
|
||||||
res.redirect('/profile/password')
|
res.redirect('/profile/password')
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -34,7 +34,7 @@ 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', _CC.lang('RESET_PASSWORD_SUCCESS'))
|
||||||
res.redirect('/')
|
res.redirect('/')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -8,7 +8,7 @@ module.exports = (db) => {
|
||||||
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: _CC.lang('SETUP_HEADER') })
|
||||||
} else {
|
} else {
|
||||||
res.redirect('/')
|
res.redirect('/')
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ module.exports = () => {
|
||||||
const router = express.Router()
|
const router = express.Router()
|
||||||
|
|
||||||
router.get('/', async (req, res) => {
|
router.get('/', async (req, res) => {
|
||||||
res.render('supported-sites', { title: 'Supported Sites' })
|
res.render('supported-sites', { title: _CC.lang('SUPPORTED_SITES_HEADER') })
|
||||||
})
|
})
|
||||||
|
|
||||||
return router
|
return router
|
||||||
|
|
|
@ -44,7 +44,7 @@ module.exports = (db) => {
|
||||||
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: _CC.lang('WISHLISTS_TITLE'), users: docs.rows, totals })
|
||||||
})
|
})
|
||||||
|
|
||||||
router.get('/:user', publicRoute(), async (req, res) => {
|
router.get('/:user', publicRoute(), async (req, res) => {
|
||||||
|
@ -66,7 +66,8 @@ module.exports = (db) => {
|
||||||
if (global._CC.config.wishlist.note.markdown) item.note = DOMPurify.sanitize(marked(item.note))
|
if (global._CC.config.wishlist.note.markdown) item.note = DOMPurify.sanitize(marked(item.note))
|
||||||
}
|
}
|
||||||
res.render('wishlist', {
|
res.render('wishlist', {
|
||||||
title: `Wishlist - ${dbUser._id}`,
|
title: _CC.lang('WISHLIST_TITLE', dbUser._id),
|
||||||
|
name: dbUser._id,
|
||||||
wishlist: [
|
wishlist: [
|
||||||
...dbUser.wishlist.filter(item => item.addedBy === req.params.user),
|
...dbUser.wishlist.filter(item => item.addedBy === req.params.user),
|
||||||
...dbUser.wishlist.filter(item => item.addedBy !== req.params.user)
|
...dbUser.wishlist.filter(item => item.addedBy !== req.params.user)
|
||||||
|
@ -82,7 +83,7 @@ module.exports = (db) => {
|
||||||
|
|
||||||
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', _CC.lang('WISHLIST_URL_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()
|
||||||
|
@ -108,7 +109,7 @@ module.exports = (db) => {
|
||||||
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', _CC.lang('WISHLIST_CONFLICT'))
|
||||||
return res.redirect(`/wishlist/${req.params.user}`)
|
return res.redirect(`/wishlist/${req.params.user}`)
|
||||||
}
|
}
|
||||||
req.flash(
|
req.flash(
|
||||||
|
@ -128,12 +129,12 @@ module.exports = (db) => {
|
||||||
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', _CC.lang('WISHLIST_PLEDGE_DUPLICATE'))
|
||||||
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', _CC.lang('WISHLIST_PLEDGE_SUCCESS'))
|
||||||
return res.redirect(`/wishlist/${req.params.user}`)
|
return res.redirect(`/wishlist/${req.params.user}`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -145,24 +146,24 @@ module.exports = (db) => {
|
||||||
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', _CC.lang('WISHLIST_UNPLEDGE_GUARD'))
|
||||||
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', _CC.lang('WISHLIST_UNPLEDGE_SUCCESS'))
|
||||||
return res.redirect(`/wishlist/${req.params.user}`)
|
return res.redirect(`/wishlist/${req.params.user}`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
req.flash('error', 'Failed to find item')
|
req.flash('error', _CC.lang('WISHLIST_UNPLEDGE_MISSING'))
|
||||||
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', _CC.lang('WISHLIST_REMOVE_GUARD'))
|
||||||
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)
|
||||||
|
@ -170,17 +171,17 @@ module.exports = (db) => {
|
||||||
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', _CC.lang('WISHLIST_REMOVE_SUCCESS'))
|
||||||
return res.redirect(`/wishlist/${req.params.user}`)
|
return res.redirect(`/wishlist/${req.params.user}`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
req.flash('error', 'Failed to find item')
|
req.flash('error', _CC.lang('WISHLIST_REMOVE_MISSING'))
|
||||||
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', _CC.lang('WISHLIST_MOVE_GUARD'))
|
||||||
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)
|
||||||
|
@ -197,7 +198,7 @@ module.exports = (db) => {
|
||||||
})
|
})
|
||||||
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', _CC.lang('WISHLIST_MOVE_INVALID'))
|
||||||
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]]
|
||||||
|
@ -206,7 +207,7 @@ module.exports = (db) => {
|
||||||
|
|
||||||
doc.wishlist = wishlist
|
doc.wishlist = wishlist
|
||||||
await db.put(doc)
|
await db.put(doc)
|
||||||
req.flash('success', 'Successfully moved item!')
|
req.flash('success', _CC.lang('WISHLIST_MOVE_SUCCESS'))
|
||||||
return res.redirect(`/wishlist/${req.params.user}`)
|
return res.redirect(`/wishlist/${req.params.user}`)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -222,14 +223,14 @@ module.exports = (db) => {
|
||||||
const 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', _CC.lang('NOTE_GUARD'))
|
||||||
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 (!Object.prototype.hasOwnProperty.call(req.body, type)) {
|
if (!Object.prototype.hasOwnProperty.call(req.body, type)) {
|
||||||
req.flash('error', `Missing property ${type}`)
|
req.flash('error', _CC.lang('NOTE_MISSING_PROP', 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]
|
||||||
|
@ -238,7 +239,7 @@ module.exports = (db) => {
|
||||||
}
|
}
|
||||||
doc.wishlist = wishlist
|
doc.wishlist = wishlist
|
||||||
await db.put(doc)
|
await db.put(doc)
|
||||||
req.flash('success', 'Successfully saved note!')
|
req.flash('success', _CC.lang('NOTE_SUCCESS'))
|
||||||
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) => {
|
||||||
|
@ -248,12 +249,12 @@ module.exports = (db) => {
|
||||||
const 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', _CC.lang('WISHLIST_REFRESH_GUARD'))
|
||||||
return res.redirect(`/wishlist/${req.params.user}`)
|
return res.redirect(`/wishlist/${req.params.user}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!wishlistItem.url) {
|
if (!wishlistItem.url) {
|
||||||
req.flash('error', 'Item has no URL.')
|
req.flash('error', _CC.lang('WISHLIST_REFRESH_NO_URL'))
|
||||||
return res.redirect(`/wishlist/${req.params.user}/note/${req.params.id}`)
|
return res.redirect(`/wishlist/${req.params.user}/note/${req.params.id}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -266,7 +267,7 @@ module.exports = (db) => {
|
||||||
}
|
}
|
||||||
doc.wishlist = wishlist
|
doc.wishlist = wishlist
|
||||||
await db.put(doc)
|
await db.put(doc)
|
||||||
req.flash('success', 'Successfully refreshed data!')
|
req.flash('success', _CC.lang('WISHLIST_REFRESH_SUCCESS'))
|
||||||
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) => {
|
||||||
|
@ -276,20 +277,20 @@ module.exports = (db) => {
|
||||||
const 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', _CC.lang('NOTE_REMOVE_GUARD'))
|
||||||
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', _CC.lang('NOTE_REMOVE_MISSING'))
|
||||||
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', _CC.lang('NOTE_REMOVE_SUCCESS'))
|
||||||
return res.redirect(`/wishlist/${req.params.user}`)
|
return res.redirect(`/wishlist/${req.params.user}`)
|
||||||
})
|
})
|
||||||
return router
|
return router
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
extends layout.pug
|
extends layout.pug
|
||||||
|
|
||||||
block content
|
block content
|
||||||
h2 Wishlist Deletion
|
h2= lang('ADMIN_CLEAR_WISHLISTS_HEADER')
|
||||||
p This will instantly <b>irreversibly delete all wishlists!</b> Consider making a backup of the database before using this.
|
p!= lang('ADMIN_CLEAR_WISHLISTS_DESCRIPTION')
|
||||||
form(method='POST', action=`${_CC.config.base}admin-settings/clear-wishlists`)
|
form(method='POST', action=`${_CC.config.base}admin-settings/clear-wishlists`)
|
||||||
.field
|
.field
|
||||||
.control
|
.control
|
||||||
input.button.is-danger(type='submit' value=`Clear all wishlists`)
|
input.button.is-danger(type='submit' value=lang('ADMIN_CLEAR_WISHLISTS_BUTTON'))
|
|
@ -4,7 +4,7 @@ block title
|
||||||
h1(style="margin-bottom: 0;")
|
h1(style="margin-bottom: 0;")
|
||||||
a(href='..') <
|
a(href='..') <
|
||||||
| #{config.siteTitle}
|
| #{config.siteTitle}
|
||||||
p Editing user "#{user._id}"
|
p= lang('ADMIN_USER_EDIT_EDITING_USER', user._id)
|
||||||
|
|
||||||
block content
|
block content
|
||||||
.columns
|
.columns
|
||||||
|
@ -14,94 +14,94 @@ block content
|
||||||
.box(style='overflow: hidden;')
|
.box(style='overflow: hidden;')
|
||||||
.columns(style='margin-bottom: 0;')
|
.columns(style='margin-bottom: 0;')
|
||||||
.column.is-narrow(style='padding-bottom: 0;')
|
.column.is-narrow(style='padding-bottom: 0;')
|
||||||
h2 Confirmation Link
|
h2= lang('ADMIN_USER_EDIT_CONFIRMATION_LINK')
|
||||||
.column(style='padding-bottom: 0;')
|
.column(style='padding-bottom: 0;')
|
||||||
p
|
p
|
||||||
span This account hasn't been confirmed.
|
span= lang('ADMIN_USER_EDIT_ACCOUNT_UNCONFIRMED')
|
||||||
br
|
br
|
||||||
if user.expiry > new Date().getTime()
|
if user.expiry > new Date().getTime()
|
||||||
span= `The following link expires ${_CC.require('moment')(user.expiry).fromNow()}`
|
span= lang('ADMIN_USER_EDIT_LINK_EXPIRY_FUTURE', _CC.moment(user.expiry).fromNow())
|
||||||
else
|
else
|
||||||
span.has-text-weight-bold(style='color: red;')= `The following link expired ${_CC.require('moment')(user.expiry).fromNow()}`
|
span.has-text-weight-bold(style='color: red;')= lang('ADMIN_USER_EDIT_LINK_EXPIRY_PAST', _CC.moment(user.expiry).fromNow())
|
||||||
h3(style='margin-bottom: 0; margin-top: 0;')
|
h3(style='margin-bottom: 0; margin-top: 0;')
|
||||||
.level
|
.level
|
||||||
.level-left
|
.level-left
|
||||||
.level-item
|
.level-item
|
||||||
form(method='POST', action=`${_CC.config.base}admin-settings/edit/refresh-signup-token/${user._id}`)
|
form(method='POST', action=`${_CC.config.base}admin-settings/edit/refresh-signup-token/${user._id}`)
|
||||||
input.button.is-rounded(type='submit', value='Generate New Link')
|
input.button.is-rounded(type='submit', value=lang('ADMIN_USER_EDIT_GENERATE_NEW_LINK'))
|
||||||
.level-item
|
.level-item
|
||||||
a(href=signupLink, style='font-family: monospaced; word-break: break-all;')= signupLink
|
a(href=signupLink, style='font-family: monospaced; word-break: break-all;')= signupLink
|
||||||
.columns
|
.columns
|
||||||
.column.is-narrow
|
.column.is-narrow
|
||||||
h2 Change Name
|
h2= lang('ADMIN_USER_EDIT_CHANGE_NAME')
|
||||||
form(action=`${_CC.config.base}admin-settings/edit/rename/${user._id}`, method='POST')
|
form(action=`${_CC.config.base}admin-settings/edit/rename/${user._id}`, method='POST')
|
||||||
.field
|
.field
|
||||||
label.label Username
|
label.label= lang('ADMIN_USER_EDIT_USERNAME')
|
||||||
.control.has-icons-left
|
.control.has-icons-left
|
||||||
input.input(type='text', name='newUsername', placeholder=user._id, value=user._id)
|
input.input(type='text', name='newUsername', placeholder=user._id, value=user._id)
|
||||||
span.icon.is-small.is-left
|
span.icon.is-small.is-left
|
||||||
i.fas.fa-user
|
i.fas.fa-user
|
||||||
.field
|
.field
|
||||||
.control
|
.control
|
||||||
input.button.is-primary(type='submit' value='Change Username')
|
input.button.is-primary(type='submit' value=lang('ADMIN_USER_EDIT_CHANGE_USERNAME'))
|
||||||
.column.is-narrow
|
.column.is-narrow
|
||||||
h2 Admin
|
h2= lang('ADMIN_USER_EDIT_ADMIN')
|
||||||
//- Yes, ternary exists, but I think the code is cleaner with a more "naive" style :)
|
//- Yes, ternary exists, but I think the code is cleaner with a more "naive" style :)
|
||||||
//- p.is-marginless #{user._id} is #{user.admin ? '' : 'not '}an admin.
|
//- p.is-marginless #{user._id} is #{user.admin ? '' : 'not '}an admin.
|
||||||
//- vs.
|
//- vs.
|
||||||
if user.admin
|
if user.admin
|
||||||
p.is-marginless #{user._id} is an admin.
|
p.is-marginless= lang('ADMIN_USER_EDIT_ADMIN_ISADMIN', user._id)
|
||||||
form(action=`${_CC.config.base}admin-settings/edit/demote/${user._id}`, method='POST')
|
form(action=`${_CC.config.base}admin-settings/edit/demote/${user._id}`, method='POST')
|
||||||
.field
|
.field
|
||||||
.control
|
.control
|
||||||
if user._id === req.user._id
|
if user._id === req.user._id
|
||||||
input.input.button(disabled, type='submit', value=`You cannot demote yourself`, style='margin-top: 1em;')
|
input.input.button(disabled, type='submit', value=lang('ADMIN_USER_EDIT_DEMOTE_SELF'), style='margin-top: 1em;')
|
||||||
else
|
else
|
||||||
input.input.button(type='submit', value=`Demote ${user._id}`, style='margin-top: 1em;')
|
input.input.button(type='submit', value=lang('ADMIN_USER_EDIT_DEMOTE', user._id), style='margin-top: 1em;')
|
||||||
else
|
else
|
||||||
p.is-marginless #{user._id} is not an admin.
|
p.is-marginless= lang('ADMIN_USER_EDIT_ADMIN_NOTADMIN', user._id)
|
||||||
form(action=`${_CC.config.base}admin-settings/edit/promote/${user._id}`, method='POST')
|
form(action=`${_CC.config.base}admin-settings/edit/promote/${user._id}`, method='POST')
|
||||||
.field
|
.field
|
||||||
.control
|
.control
|
||||||
input.input.button(type='submit', value=`Promote ${user._id}`, style='margin-top: 1em;')
|
input.input.button(type='submit', value=lang('ADMIN_USER_EDIT_PROMOTE', user._id), style='margin-top: 1em;')
|
||||||
if user._id !== req.user._id
|
if user._id !== req.user._id
|
||||||
.column.is-narrow
|
.column.is-narrow
|
||||||
h2 Impersonate
|
h2= lang('ADMIN_USER_EDIT_IMPERSONATE_HEADER')
|
||||||
form(action=`${_CC.config.base}admin-settings/edit/impersonate/${user._id}`, method='POST')
|
form(action=`${_CC.config.base}admin-settings/edit/impersonate/${user._id}`, method='POST')
|
||||||
.field
|
.field
|
||||||
.control
|
.control
|
||||||
input.input.button.is-warning(type='submit', value=`Log in as ${user._id}`, style='margin-top: 1em;')
|
input.input.button.is-warning(type='submit', value=lang('ADMIN_USER_EDIT_IMPERSONATE_BUTTON', user._id), style='margin-top: 1em;')
|
||||||
h2(style='margin-bottom: 1em;') Reset Password
|
h2(style='margin-bottom: 1em;')= lang('ADMIN_USER_EDIT_RESET_PASSWORD_HEADER')
|
||||||
if user.pwToken
|
if user.pwToken
|
||||||
- const resetLink = `${_CC.config.base}resetpw/${user.pwToken}`
|
- const resetLink = `${_CC.config.base}resetpw/${user.pwToken}`
|
||||||
p There is a reset password link for this user.
|
p= lang('ADMIN_USER_EDIT_RESET_PASSWORD_HASLINK')
|
||||||
if user.pwExpiry > new Date().getTime()
|
if user.pwExpiry > new Date().getTime()
|
||||||
span It expires #{_CC.require('moment')(user.pwExpiry).fromNow()}
|
span= lang('ADMIN_USER_EDIT_RESET_PASSWORD_HASLINK_EXPIRY_FUTURE', _CC.moment(user.pwExpiry).fromNow())
|
||||||
else
|
else
|
||||||
span.has-text-weight-bold.has-text-danger It expired #{_CC.require('moment')(user.pwExpiry).fromNow()}
|
span.has-text-weight-bold.has-text-danger= lang('ADMIN_USER_EDIT_RESET_PASSWORD_HASLINK_EXPIRY_PAST', _CC.moment(user.pwExpiry).fromNow())
|
||||||
a(href=resetLink)= resetLink
|
a(href=resetLink)= resetLink
|
||||||
.columns
|
.columns
|
||||||
.column.is-narrow
|
.column.is-narrow
|
||||||
form(method='POST', action=`${_CC.config.base}admin-settings/edit/resetpw/${user._id}`)
|
form(method='POST', action=`${_CC.config.base}admin-settings/edit/resetpw/${user._id}`)
|
||||||
.field
|
.field
|
||||||
.control
|
.control
|
||||||
input.button.is-primary(type='submit' value='Refresh Password Reset Link')
|
input.button.is-primary(type='submit' value=lang('ADMIN_USER_EDIT_RESET_PASSWORD_LINK_REFRESH'))
|
||||||
.column.is-narrow
|
.column.is-narrow
|
||||||
form(method='POST', action=`${_CC.config.base}admin-settings/edit/cancelresetpw/${user._id}`)
|
form(method='POST', action=`${_CC.config.base}admin-settings/edit/cancelresetpw/${user._id}`)
|
||||||
.field
|
.field
|
||||||
.control
|
.control
|
||||||
input.button.is-info(type='submit' value='Cancel Password Reset Link')
|
input.button.is-info(type='submit' value=lang('ADMIN_USER_EDIT_RESET_PASSWORD_LINK_CANCEL'))
|
||||||
else
|
else
|
||||||
form(method='POST', action=`${_CC.config.base}admin-settings/edit/resetpw/${user._id}`)
|
form(method='POST', action=`${_CC.config.base}admin-settings/edit/resetpw/${user._id}`)
|
||||||
.field
|
.field
|
||||||
.control
|
.control
|
||||||
input.button.is-danger(type='submit' value='Create Password Reset Link')
|
input.button.is-danger(type='submit' value=lang('ADMIN_USER_EDIT_RESET_PASSWORD_LINK_CREATE'))
|
||||||
.column.is-narrow
|
.column.is-narrow
|
||||||
h2 Irreversible Deletion
|
h2= lang('ADMIN_USER_EDIT_DELETE_HEADER')
|
||||||
form(method='POST', action=`${_CC.config.base}admin-settings/edit/remove/${user._id}`)
|
form(method='POST', action=`${_CC.config.base}admin-settings/edit/remove/${user._id}`)
|
||||||
.field
|
.field
|
||||||
.control
|
.control
|
||||||
if user.admin
|
if user.admin
|
||||||
input.button.is-danger(disabled, type='submit' value=`User is admin`)
|
input.button.is-danger(disabled, type='submit' value=lang('ADMIN_USER_EDIT_DELETE_ADMIN'))
|
||||||
else
|
else
|
||||||
input.button.is-danger(type='submit' value=`Remove user ${user._id}`)
|
input.button.is-danger(type='submit' value=lang('ADMIN_USER_EDIT_DELETE_USER', user._id))
|
|
@ -1,30 +1,30 @@
|
||||||
extends layout.pug
|
extends layout.pug
|
||||||
|
|
||||||
block content
|
block content
|
||||||
h2 Users
|
h2= lang('ADMIN_SETTINGS_USERS_HEADER')
|
||||||
each user in users
|
each user in users
|
||||||
span.is-size-6.inline= user.id
|
span.is-size-6.inline= user.id
|
||||||
a(href=`${_CC.config.base}admin-settings/edit/${user.id}`)
|
a(href=`${_CC.config.base}admin-settings/edit/${user.id}`)
|
||||||
span.is-size-7.icon.has-text-info
|
span.is-size-7.icon.has-text-info
|
||||||
i.fas.fa-edit
|
i.fas.fa-edit
|
||||||
span.is-sr-only
|
span.is-sr-only
|
||||||
| Edit
|
= lang('ADMIN_SETTINGS_USERS_EDIT')
|
||||||
br
|
br
|
||||||
h3 Add user
|
h3= lang('ADMIN_SETTINGS_USERS_ADD_HEADER')
|
||||||
form(action=`${_CC.config.base}admin-settings/add`, method='POST')
|
form(action=`${_CC.config.base}admin-settings/add`, method='POST')
|
||||||
.field
|
.field
|
||||||
label.label Username
|
label.label= lang('ADMIN_SETTINGS_USERS_ADD_USERNAME')
|
||||||
.control.has-icons-left
|
.control.has-icons-left
|
||||||
input.input(type='text', name='newUserUsername', placeholder='john')
|
input.input(type='text', name='newUserUsername', placeholder=lang('ADMIN_SETTINGS_USERS_ADD_PLACEHOLDER'))
|
||||||
span.icon.is-small.is-left
|
span.icon.is-small.is-left
|
||||||
i.fas.fa-user
|
i.fas.fa-user
|
||||||
.field
|
.field
|
||||||
.control
|
.control
|
||||||
input.button.is-primary(type='submit' value='Add User')
|
input.button.is-primary(type='submit' value=lang('ADMIN_SETTINGS_USERS_ADD_BUTTON'))
|
||||||
h3 Data Destruction
|
h3= lang('ADMIN_SETTINGS_CLEARDB_HEADER')
|
||||||
p <b>Warning</b>: These options <b>destroy data</b>! You may want to back up the database before using these options.
|
p!= lang('ADMIN_SETTINGS_CLEARDB_DESCRIPTION')
|
||||||
a.button.is-danger(href=`${_CC.config.base}admin-settings/clear-wishlists`) Clear Wishlists
|
a.button.is-danger(href=`${_CC.config.base}admin-settings/clear-wishlists`)= lang('ADMIN_SETTINGS_CLEARDB_BUTTON')
|
||||||
h3 Version Info
|
h3= lang('ADMIN_SETTINGS_VERSION_INFO')
|
||||||
p Christmas Community: v#{_CC.package.version}
|
p Christmas Community: v#{_CC.package.version}
|
||||||
p Get Product Data: v#{_CC.require('get-product-name/package.json').version}
|
p Get Product Data: v#{_CC.require('get-product-name/package.json').version}
|
||||||
p Node: #{process.version}
|
p Node: #{process.version}
|
||||||
|
|
|
@ -9,26 +9,26 @@ mixin icon(c, text)
|
||||||
|
|
||||||
block title
|
block title
|
||||||
if doc
|
if doc
|
||||||
h1 #{config.siteTitle} | Confirm Account
|
h1= lang('CONFIRM_ACCOUNT_HEADER_VALID')
|
||||||
else
|
else
|
||||||
h1 #{config.siteTitle} | Confirmation Link Invalid
|
h1= lang('CONFIRM_ACCOUNT_HEADER_INVALID')
|
||||||
|
|
||||||
block content
|
block content
|
||||||
if doc
|
if doc
|
||||||
if doc.expiry > new Date().getTime()
|
if doc.expiry > new Date().getTime()
|
||||||
+icon('fas fa-smile-beam', `Hello ${doc._id}! Please set your password here.`)
|
+icon('fas fa-smile-beam', lang('CONFIRM_ACCOUNT_SET_PW_TEXT', doc._id))
|
||||||
form(method='POST')
|
form(method='POST')
|
||||||
.field
|
.field
|
||||||
label.label Password
|
label.label Password
|
||||||
.control.has-icons-left
|
.control.has-icons-left
|
||||||
input.input(type='password', name='password', placeholder='pa$$word!')
|
input.input(type='password', name='password', placeholder=lang('CONFIRM_ACCOUNT_SET_PW_PLACEHOLDER'))
|
||||||
span.icon.is-small.is-left
|
span.icon.is-small.is-left
|
||||||
i.fas.fa-lock
|
i.fas.fa-lock
|
||||||
.field
|
.field
|
||||||
.control
|
.control
|
||||||
input.button.is-primary(type='submit' value=`Join ${_CC.config.siteTitle}`)
|
input.button.is-primary(type='submit' value=lang('CONFIRM_ACCOUNT_SET_PW_BUTTON'))
|
||||||
else
|
else
|
||||||
+icon('fas fa-frown-open', 'Your confirmation link has expired. Please ask for a new one.')
|
+icon('fas fa-frown-open', lang('CONFIRM_ACCOUNT_EXPIRED'))
|
||||||
else
|
else
|
||||||
+icon('fas fa-frown-open', "This confirmation link isn't valid, perhaps the account was deleted or some characters at the end got cut off?")
|
+icon('fas fa-frown-open', lang('CONFIRM_ACCOUNT_INVALID'))
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@ mixin navBarLink(href, title)
|
||||||
a.is-active.navbar-item(href=href)= title
|
a.is-active.navbar-item(href=href)= title
|
||||||
else
|
else
|
||||||
a.navbar-item(href=href)= title
|
a.navbar-item(href=href)= title
|
||||||
|
|
||||||
nav.navbar.is-fixed-top(role='navigation', aria-label='main navigation',style='box-shadow: 0px 0px 7px rgb(14, 15, 17);')
|
nav.navbar.is-fixed-top(role='navigation', aria-label='main navigation',style='box-shadow: 0px 0px 7px rgb(14, 15, 17);')
|
||||||
.navbar-brand
|
.navbar-brand
|
||||||
if _CC.config.base === req.path
|
if _CC.config.base === req.path
|
||||||
|
@ -22,17 +23,17 @@ nav.navbar.is-fixed-top(role='navigation', aria-label='main navigation',style='b
|
||||||
if req.isAuthenticated()
|
if req.isAuthenticated()
|
||||||
if req.user._id === 'Unknown'
|
if req.user._id === 'Unknown'
|
||||||
.navbar-item
|
.navbar-item
|
||||||
a.button.is-primary(href='/login') Log In
|
a.button.is-primary(href='/login')= lang('NAVBAR_')
|
||||||
else
|
else
|
||||||
.navbar-item.has-dropdown.is-hoverable
|
.navbar-item.has-dropdown.is-hoverable
|
||||||
a.navbar-link= req.user._id
|
a.navbar-link= req.user._id
|
||||||
.navbar-dropdown
|
.navbar-dropdown
|
||||||
+navBarLink(`${_CC.config.base}wishlist/${req.user._id}`, 'My Wishlist')
|
+navBarLink(`${_CC.config.base}wishlist/${req.user._id}`, lang('NAVBAR_WISHLIST'))
|
||||||
+navBarLink(`${_CC.config.base}profile`, 'Profile')
|
+navBarLink(`${_CC.config.base}profile`, lang('NAVBAR_PROFILE'))
|
||||||
if req.user.admin
|
if req.user.admin
|
||||||
+navBarLink(`${_CC.config.base}admin-settings`, 'Admin settings')
|
+navBarLink(`${_CC.config.base}admin-settings`, lang('NAVBAR_ADMIN'))
|
||||||
hr.navbar-divider
|
hr.navbar-divider
|
||||||
.navbar-item
|
.navbar-item
|
||||||
form#logoutForm(action=`${_CC.config.base}logout`, method='POST')
|
form#logoutForm(action=`${_CC.config.base}logout`, method='POST')
|
||||||
button.button.is-warning(type='submit') Log Out
|
button.button.is-warning(type='submit')= lang('NAVBAR_LOGOUT')
|
||||||
script(src=`${_CC.config.base}js/nav.js`)
|
script(src=`${_CC.config.base}js/nav.js`)
|
||||||
|
|
|
@ -2,13 +2,4 @@ if req.user && req.user.admin && _CC.updateNotice
|
||||||
.columns
|
.columns
|
||||||
.column
|
.column
|
||||||
.column.is-narrow
|
.column.is-narrow
|
||||||
.box
|
.box!= lang('UPDATE_NOTICE', _CC.updateNotice.current, _CC.updateNotice.latest)
|
||||||
span.has-text-danger.is-size-4.has-text-weight-bold Christmas Community is out of date. There may be new features or bug fixes. Consider updating! :)
|
|
||||||
br
|
|
||||||
span (you can turn this off with <code>UPDATE_CHECK=false</code>)
|
|
||||||
br
|
|
||||||
br
|
|
||||||
span Current: #{_CC.updateNotice.current}
|
|
||||||
br
|
|
||||||
span Latest: #{_CC.updateNotice.latest}
|
|
||||||
span.has-text-info(style='float: right;') This message is only visible to admins
|
|
|
@ -36,7 +36,7 @@ html(lang='en')
|
||||||
div.container.is-marginless.fullwidth
|
div.container.is-marginless.fullwidth
|
||||||
block title
|
block title
|
||||||
if title
|
if title
|
||||||
h1= config.siteTitle + ' - ' + title
|
h1= title
|
||||||
else if title !== false
|
else if title !== false
|
||||||
h1 #{config.siteTitle}
|
h1 #{config.siteTitle}
|
||||||
include includes/messages.pug
|
include includes/messages.pug
|
||||||
|
|
|
@ -3,18 +3,18 @@ extends layout.pug
|
||||||
block content
|
block content
|
||||||
form(method='POST')
|
form(method='POST')
|
||||||
.field
|
.field
|
||||||
label.label Username
|
label.label= lang('LOGIN_USERNAME')
|
||||||
.control.has-icons-left
|
.control.has-icons-left
|
||||||
input.input(type='text', name='username', placeholder='john')
|
input.input(type='text', name='username', placeholder=lang('LOGIN_USERNAME_PLACEHOLDER'))
|
||||||
span.icon.is-small.is-left
|
span.icon.is-small.is-left
|
||||||
i.fas.fa-user
|
i.fas.fa-user
|
||||||
.field
|
.field
|
||||||
label.label Password
|
label.label= lang('LOGIN_PASSWORD')
|
||||||
.control.has-icons-left
|
.control.has-icons-left
|
||||||
input.input(type='password', name='password', placeholder='pa$$word!')
|
input.input(type='password', name='password', placeholder=lang('LOGIN_PASSWORD_PLACEHOLDER'))
|
||||||
span.icon.is-small.is-left
|
span.icon.is-small.is-left
|
||||||
i.fas.fa-lock
|
i.fas.fa-lock
|
||||||
.field
|
.field
|
||||||
.control
|
.control
|
||||||
input.button.is-primary(type='submit' value='Log In')
|
input.button.is-primary(type='submit' value=lang('LOGIN_BUTTON'))
|
||||||
|
|
||||||
|
|
|
@ -4,4 +4,4 @@ block content
|
||||||
form(method='POST')
|
form(method='POST')
|
||||||
.field
|
.field
|
||||||
.control
|
.control
|
||||||
input.button.is-primary(type='submit' value='Log Out')
|
input.button.is-primary(type='submit' value=lang('LOGOUT_BUTTON'))
|
|
@ -1,40 +1,40 @@
|
||||||
extends layout.pug
|
extends layout.pug
|
||||||
|
|
||||||
block content
|
block content
|
||||||
a(href='..') <i class="fas fa-arrow-left"></i> Back to #{req.params.user}'s wishlist
|
a(href='..') <i class="fas fa-arrow-left"></i> #{lang('NOTE_BACK', req.params.user)}
|
||||||
form(id='refreshform', method='POST', action=`${_CC.config.base}wishlist/${req.params.user}/refresh/${req.params.id}`)
|
form(id='refreshform', method='POST', action=`${_CC.config.base}wishlist/${req.params.user}/refresh/${req.params.id}`)
|
||||||
form.inline(method='POST', action=`${_CC.config.base}wishlist/${req.params.user}/note/${req.params.id}`)
|
form.inline(method='POST', action=`${_CC.config.base}wishlist/${req.params.user}/note/${req.params.id}`)
|
||||||
.columns
|
.columns
|
||||||
.column
|
.column
|
||||||
.field
|
.field
|
||||||
label.label Name
|
label.label= lang('NOTE_NAME')
|
||||||
.control
|
.control
|
||||||
input.input(name='name', value=item.name)
|
input.input(name='name', value=item.name)
|
||||||
.column
|
.column
|
||||||
.field
|
.field
|
||||||
label.label URL
|
label.label= lang('NOTE_URL')
|
||||||
.control
|
.control
|
||||||
input.input(name='url', value=item.url)
|
input.input(name='url', value=item.url)
|
||||||
.column
|
.column
|
||||||
.field
|
.field
|
||||||
label.label Price
|
label.label= lang('NOTE_PRICE')
|
||||||
.control
|
.control
|
||||||
input.input(name='price', value=item.price)
|
input.input(name='price', value=item.price)
|
||||||
.column
|
.column
|
||||||
.field
|
.field
|
||||||
label.label Image URL
|
label.label= lang('NOTE_IMAGE_URL')
|
||||||
.control
|
.control
|
||||||
input.input(name='image', value=item.image)
|
input.input(name='image', value=item.image)
|
||||||
.column.is-narrow
|
.column.is-narrow
|
||||||
.field
|
.field
|
||||||
label.label Get Product Data
|
label.label= lang('NOTE_GET_PRODUCT_DATA')
|
||||||
input.is-ghost.button(type='submit', value='Refresh Data' style='width: 100%;', form='refreshform')
|
input.is-ghost.button(type='submit', value=lang('NOTE_REFRESH_DATA') style='width: 100%;', form='refreshform')
|
||||||
.field
|
.field
|
||||||
label.label Note
|
label.label= lang('NOTE_NOTE')
|
||||||
.control
|
.control
|
||||||
textarea.textarea(
|
textarea.textarea(
|
||||||
name='note'
|
name='note'
|
||||||
)= item.note
|
)= item.note
|
||||||
.field.inline
|
.field.inline
|
||||||
.control.inline
|
.control.inline
|
||||||
input.button.is-primary(type='submit' value='Save Item')
|
input.button.is-primary(type='submit' value=lang('NOTE_SAVE_BUTTON'))
|
|
@ -1,21 +1,21 @@
|
||||||
extends layout.pug
|
extends layout.pug
|
||||||
|
|
||||||
block content
|
block content
|
||||||
a.button(href=`${_CC.config.base}profile`) Back
|
a.button(href=`${_CC.config.base}profile`)= lang('BACK_BUTTON')
|
||||||
form(method='POST')
|
form(method='POST')
|
||||||
.field
|
.field
|
||||||
label.label Old Password (Required if changing password)
|
label.label= lang('PROFILE_PASSWORD_OLD')
|
||||||
.control.has-icons-left
|
.control.has-icons-left
|
||||||
input.input(type='password', name='oldPassword', placeholder='pa$$word!')
|
input.input(type='password', name='oldPassword', placeholder=lang('PROFILE_PASSWORD_PLACEHOLDER'))
|
||||||
span.icon.is-small.is-left
|
span.icon.is-small.is-left
|
||||||
i.fas.fa-lock
|
i.fas.fa-lock
|
||||||
.field
|
.field
|
||||||
label.label New Password (Leave blank if not changing password)
|
label.label= lang('PROFILE_PASSWORD_NEW')
|
||||||
.control.has-icons-left
|
.control.has-icons-left
|
||||||
input.input(type='password', name='newPassword', placeholder='pa$$word!')
|
input.input(type='password', name='newPassword', placeholder=lang('PROFILE_PASSWORD_PLACEHOLDER'))
|
||||||
span.icon.is-small.is-left
|
span.icon.is-small.is-left
|
||||||
i.fas.fa-lock
|
i.fas.fa-lock
|
||||||
.field
|
.field
|
||||||
.control
|
.control
|
||||||
input.button.is-primary(type='submit' value='Save')
|
input.button.is-primary(type='submit' value=lang('PROFILE_PASSWORD_BUTTON'))
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@ extends layout.pug
|
||||||
|
|
||||||
block content
|
block content
|
||||||
if config.pfp
|
if config.pfp
|
||||||
h2 Profile
|
h2= lang('PROFILE_HEADER')
|
||||||
div(style='margin-top: 1em;')
|
div(style='margin-top: 1em;')
|
||||||
.columns(style='margin-top: 1em;')
|
.columns(style='margin-top: 1em;')
|
||||||
.column.is-narrow
|
.column.is-narrow
|
||||||
|
@ -17,7 +17,7 @@ block content
|
||||||
br
|
br
|
||||||
br
|
br
|
||||||
form(action=`${_CC.config.base}profile/pfp`, method='POST')
|
form(action=`${_CC.config.base}profile/pfp`, method='POST')
|
||||||
label.label Image URL
|
label.label= lang('PROFILE_PFP_IMAGE_URL')
|
||||||
.field.has-addons
|
.field.has-addons
|
||||||
.control
|
.control
|
||||||
input.input(name='image', value=req.user.pfp)
|
input.input(name='image', value=req.user.pfp)
|
||||||
|
@ -25,8 +25,8 @@ block content
|
||||||
button.button.is-primary(type='submit')
|
button.button.is-primary(type='submit')
|
||||||
span.icon
|
span.icon
|
||||||
i.fas.fa-save
|
i.fas.fa-save
|
||||||
h2 Security
|
h2= lang('PROFILE_SECURITY')
|
||||||
a.button.is-primary(href=`${_CC.config.base}profile/password`)
|
a.button.is-primary(href=`${_CC.config.base}profile/password`)
|
||||||
span.icon
|
span.icon
|
||||||
i.fas.fa-shield-alt
|
i.fas.fa-shield-alt
|
||||||
span Change Password
|
span= lang('PROFILE_SECURITY_CHANGE_PASSWORD')
|
||||||
|
|
|
@ -9,26 +9,26 @@ mixin icon(c, text)
|
||||||
|
|
||||||
block title
|
block title
|
||||||
if doc
|
if doc
|
||||||
h1 #{config.siteTitle} | Reset Password
|
h1= lang('RESET_PASSWORD_HEADER_VALID')
|
||||||
else
|
else
|
||||||
h1 #{config.siteTitle} | Reset Link Invalid
|
h1= lang('RESET_PASSWORD_HEADER_INVALID')
|
||||||
|
|
||||||
block content
|
block content
|
||||||
if doc
|
if doc
|
||||||
if doc.pwExpiry > new Date().getTime()
|
if doc.pwExpiry > new Date().getTime()
|
||||||
+icon('fas fa-smile-beam', `Hello ${doc._id}! Please set your password here.`)
|
+icon('fas fa-smile-beam', lang('RESET_PASSWORD_GREETING_VALID', doc._id))
|
||||||
form(method='POST')
|
form(method='POST')
|
||||||
.field
|
.field
|
||||||
label.label Password
|
label.label= lang('RESET_PASSWORD_PASSWORD')
|
||||||
.control.has-icons-left
|
.control.has-icons-left
|
||||||
input.input(type='password', name='password', placeholder='pa$$word!')
|
input.input(type='password', name='password', placeholder=lang('RESET_PASSWORD_PASSWORD_PLACEHOLDER'))
|
||||||
span.icon.is-small.is-left
|
span.icon.is-small.is-left
|
||||||
i.fas.fa-lock
|
i.fas.fa-lock
|
||||||
.field
|
.field
|
||||||
.control
|
.control
|
||||||
input.button.is-primary(type='submit' value=`Reset Password`)
|
input.button.is-primary(type='submit' value=`Reset Password`)
|
||||||
else
|
else
|
||||||
+icon('fas fa-frown-open', 'Your reset link has expired. Please ask for a new one.')
|
+icon('fas fa-frown-open', lang('RESET_PASSWORD_GREETING_EXPIRED'))
|
||||||
else
|
else
|
||||||
+icon('fas fa-frown-open', "This reset link isn't valid, perhaps the link was canceled or some characters at the end got cut off?")
|
+icon('fas fa-frown-open', lang('RESET_PASSWORD_INVALID'))
|
||||||
|
|
||||||
|
|
|
@ -1,20 +1,20 @@
|
||||||
extends layout.pug
|
extends layout.pug
|
||||||
|
|
||||||
block content
|
block content
|
||||||
h2 Admin User
|
h2= lang('SETUP_ADMIN_USER')
|
||||||
form(action=`${_CC.config.base}setup`, method='POST')
|
form(action=`${_CC.config.base}setup`, method='POST')
|
||||||
.field
|
.field
|
||||||
label.label Username
|
label.label= lang('SETUP_USERNAME')
|
||||||
.control.has-icons-left
|
.control.has-icons-left
|
||||||
input.input(type='text', name='adminUsername', placeholder='john')
|
input.input(type='text', name='adminUsername', placeholder=lang('SETUP_USERNAME_PLACEHOLDER'))
|
||||||
span.icon.is-small.is-left
|
span.icon.is-small.is-left
|
||||||
i.fas.fa-user
|
i.fas.fa-user
|
||||||
.field
|
.field
|
||||||
label.label Password
|
label.label= lang('SETUP_PASSWORD')
|
||||||
.control.has-icons-left
|
.control.has-icons-left
|
||||||
input.input(type='password', name='adminPassword', placeholder='pa$$word!')
|
input.input(type='password', name='adminPassword', placeholder=lang('SETUP_PASSWORD_PLACEHOLDER'))
|
||||||
span.icon.is-small.is-left
|
span.icon.is-small.is-left
|
||||||
i.fas.fa-lock
|
i.fas.fa-lock
|
||||||
.field
|
.field
|
||||||
.control
|
.control
|
||||||
input.button.is-primary(type='submit' value='Set up!')
|
input.button.is-primary(type='submit' value=lang('SETUP_BUTTON'))
|
|
@ -3,8 +3,8 @@ extends layout.pug
|
||||||
block content
|
block content
|
||||||
if req.headers.referer
|
if req.headers.referer
|
||||||
span.is-size-3(style='margin-top: 0; padding-top: 0;')
|
span.is-size-3(style='margin-top: 0; padding-top: 0;')
|
||||||
a(href=req.headers.referer) < Back
|
a(href=req.headers.referer) < #{lang('BACK_BUTTON')}
|
||||||
ul
|
ul
|
||||||
for site of _CC.require('get-product-name').sites
|
for site of _CC.require('get-product-name').sites
|
||||||
li= site.name
|
li= site.name
|
||||||
p Is a site missing or broken? Open an issue <a href="https://gitlab.com/wingysam/get-product-name/-/issues/new">here</a>! :)
|
p!= lang('SUPPORTED_SITES_TEXT')
|
|
@ -9,7 +9,7 @@ block title
|
||||||
span.icon
|
span.icon
|
||||||
i.fas.fa-sync-alt
|
i.fas.fa-sync-alt
|
||||||
.level-item
|
.level-item
|
||||||
span #{config.siteTitle} - #{title}
|
span= lang('WISHLIST_TITLE', name)
|
||||||
|
|
||||||
block content
|
block content
|
||||||
script(type='data/user_id')= req.user._id
|
script(type='data/user_id')= req.user._id
|
||||||
|
@ -18,19 +18,19 @@ block content
|
||||||
table.table.has-mobile-cards
|
table.table.has-mobile-cards
|
||||||
thead
|
thead
|
||||||
th #
|
th #
|
||||||
th(style='width: 15%;') Image
|
th(style='width: 15%;')= lang('WISHLIST_IMAGE')
|
||||||
th(style='width: 25%;') Name
|
th(style='width: 25%;')= lang('WISHLIST_NAME')
|
||||||
th(style='width: 50%;') Note
|
th(style='width: 50%;')= lang('WISHLIST_NOTE')
|
||||||
th(style='width: 10%;') Price
|
th(style='width: 10%;')= lang('WISHLIST_PRICE')
|
||||||
th Edit Item
|
th= lang('WISHLIST_EDIT_ITEM')
|
||||||
th Added By
|
th= lang('WISHLIST_ADDED_BY')
|
||||||
if req.params.user === req.user._id
|
if req.params.user === req.user._id
|
||||||
th Move Top
|
th= lang('WISHLIST_MOVE_TOP')
|
||||||
th Move Up
|
th= lang('WISHLIST_MOVE_UP')
|
||||||
th Move Down
|
th= lang('WISHLIST_MOVE_DOWN')
|
||||||
else
|
else
|
||||||
th Pledge
|
th= lang('WISHLIST_PLEDGE')
|
||||||
th Delete
|
th= lang('WIDHLIST_DELETE')
|
||||||
tbody
|
tbody
|
||||||
each item, index in wishlist
|
each item, index in wishlist
|
||||||
if req.user._id === item.addedBy || req.params.user !== req.user._id
|
if req.user._id === item.addedBy || req.params.user !== req.user._id
|
||||||
|
@ -47,14 +47,14 @@ block content
|
||||||
target='_blank'
|
target='_blank'
|
||||||
)= (item.name ? item.name : item.url)
|
)= (item.name ? item.name : item.url)
|
||||||
else
|
else
|
||||||
td.ugc(data-label='Name')= item.name
|
td.ugc(data-label=lang('WISHLIST_NAME'))= item.name
|
||||||
if _CC.config.wishlist.note.markdown
|
if _CC.config.wishlist.note.markdown
|
||||||
td.ugc(data-label='Note')
|
td.ugc(data-label=lang('WISHLIST_NOTE'))
|
||||||
div!= item.note
|
div!= item.note
|
||||||
else
|
else
|
||||||
td.ugc(data-label='Note')= item.note
|
td.ugc(data-label=lang('WISHLIST_NOTE'))= item.note
|
||||||
td.ugc(data-label='Price')= item.price
|
td.ugc(data-label=lang('WISHLIST_PRICE'))= item.price
|
||||||
td(data-label='Edit Item')
|
td(data-label=lang('WISHLIST_EDIT_ITEM'))
|
||||||
form.inline(method='GET', action=`${_CC.config.base}wishlist/${req.params.user}/note/${item.id}`)
|
form.inline(method='GET', action=`${_CC.config.base}wishlist/${req.params.user}/note/${item.id}`)
|
||||||
.field.inline
|
.field.inline
|
||||||
.control.inline
|
.control.inline
|
||||||
|
@ -65,9 +65,9 @@ block content
|
||||||
)
|
)
|
||||||
span.icon
|
span.icon
|
||||||
i.far.fa-edit
|
i.far.fa-edit
|
||||||
td.ugc(data-label='Added By')= item.addedBy
|
td.ugc(data-label=lang('WISHLIST_ADDED_BY'))= item.addedBy
|
||||||
if req.params.user === req.user._id
|
if req.params.user === req.user._id
|
||||||
td(data-label='Move Item Top')
|
td(data-label=lang('WISHLIST_MOVE_ITEM_TOP'))
|
||||||
form.topForm.inline(method='POST', action=`${_CC.config.base}wishlist/${req.params.user}/move/top/${item.id}`)
|
form.topForm.inline(method='POST', action=`${_CC.config.base}wishlist/${req.params.user}/move/top/${item.id}`)
|
||||||
.field.inline
|
.field.inline
|
||||||
.control.inline
|
.control.inline
|
||||||
|
@ -78,7 +78,7 @@ block content
|
||||||
)
|
)
|
||||||
span.icon
|
span.icon
|
||||||
i.fas.fa-angle-double-up
|
i.fas.fa-angle-double-up
|
||||||
td(data-label='Move Item Up')
|
td(data-label=lang('WISHLIST_MOVE_ITEM_UP'))
|
||||||
form.upForm.inline(method='POST', action=`${_CC.config.base}wishlist/${req.params.user}/move/up/${item.id}`)
|
form.upForm.inline(method='POST', action=`${_CC.config.base}wishlist/${req.params.user}/move/up/${item.id}`)
|
||||||
.field.inline
|
.field.inline
|
||||||
.control.inline
|
.control.inline
|
||||||
|
@ -89,7 +89,7 @@ block content
|
||||||
)
|
)
|
||||||
span.icon
|
span.icon
|
||||||
i.fas.fa-arrow-up
|
i.fas.fa-arrow-up
|
||||||
td(data-label='Move Item Down')
|
td(data-label=lang('WISHLIST_MOVE_ITEM_DOWN'))
|
||||||
form.downForm.inline(method='POST', action=`${_CC.config.base}wishlist/${req.params.user}/move/down/${item.id}`)
|
form.downForm.inline(method='POST', action=`${_CC.config.base}wishlist/${req.params.user}/move/down/${item.id}`)
|
||||||
.field.inline
|
.field.inline
|
||||||
.control.inline
|
.control.inline
|
||||||
|
@ -101,7 +101,7 @@ block content
|
||||||
span.icon
|
span.icon
|
||||||
i.fas.fa-arrow-down
|
i.fas.fa-arrow-down
|
||||||
else
|
else
|
||||||
td(data-label='Pledge')
|
td(data-label=lang('WISHLIST_PLEDGE'))
|
||||||
if req.params.user !== req.user._id && !item.pledgedBy
|
if req.params.user !== req.user._id && !item.pledgedBy
|
||||||
form.inline(method='POST', action=`${_CC.config.base}wishlist/${req.params.user}/pledge/${item.id}`)
|
form.inline(method='POST', action=`${_CC.config.base}wishlist/${req.params.user}/pledge/${item.id}`)
|
||||||
.field.inline
|
.field.inline
|
||||||
|
@ -113,7 +113,7 @@ block content
|
||||||
.control.inline
|
.control.inline
|
||||||
input.inline.button(type='submit' value='Unpledge')
|
input.inline.button(type='submit' value='Unpledge')
|
||||||
if item.pledgedBy && item.pledgedBy !== req.user._id
|
if item.pledgedBy && item.pledgedBy !== req.user._id
|
||||||
span.ugc Pledged for by #{item.pledgedBy}
|
span.ugc=lang('WISHLIST_PLEDGED', item.pledgedBy)
|
||||||
td(data-label='Delete Item')
|
td(data-label='Delete Item')
|
||||||
form.inline(
|
form.inline(
|
||||||
method='POST',
|
method='POST',
|
||||||
|
@ -161,60 +161,60 @@ block content
|
||||||
style='height: 100%;'
|
style='height: 100%;'
|
||||||
readonly
|
readonly
|
||||||
)= item.note
|
)= item.note
|
||||||
span.overflowWrap Added by: #{item.addedBy}
|
span.overflowWrap=lang('WISHLIST_ADDED_BY', item.addedBy)
|
||||||
hr
|
hr
|
||||||
div
|
div
|
||||||
if req.params.user !== req.user._id && !item.pledgedBy
|
if req.params.user !== req.user._id && !item.pledgedBy
|
||||||
form.inline(method='POST', action=`${_CC.config.base}wishlist/${req.params.user}/pledge/${item.id}`)
|
form.inline(method='POST', action=`${_CC.config.base}wishlist/${req.params.user}/pledge/${item.id}`)
|
||||||
.field.inline
|
.field.inline
|
||||||
.control.inline
|
.control.inline
|
||||||
input.inline.button.is-primary(type='submit' value='Pledge')
|
input.inline.button.is-primary(type='submit' value=lang('WISHLIST_PLEDGE'))
|
||||||
if item.pledgedBy === req.user._id
|
if item.pledgedBy === req.user._id
|
||||||
form.inline(method='POST', action=`${_CC.config.base}wishlist/${req.params.user}/unpledge/${item.id}`)
|
form.inline(method='POST', action=`${_CC.config.base}wishlist/${req.params.user}/unpledge/${item.id}`)
|
||||||
.field.inline
|
.field.inline
|
||||||
.control.inline
|
.control.inline
|
||||||
input.inline.button(type='submit' value='Unpledge')
|
input.inline.button(type='submit' value=lang('WISHLIST_UNPLEDGE'))
|
||||||
if req.user._id === req.params.user
|
if req.user._id === req.params.user
|
||||||
form.inline(method='POST', action=`${_CC.config.base}wishlist/${req.params.user}/remove/${item.id}`)
|
form.inline(method='POST', action=`${_CC.config.base}wishlist/${req.params.user}/remove/${item.id}`)
|
||||||
.field.inline
|
.field.inline
|
||||||
.control.inline
|
.control.inline
|
||||||
input.inline.button.is-warning(type='submit' value='Remove')
|
input.inline.button.is-warning(type='submit' value=lang('WISHLIST_DELETE'))
|
||||||
if req.user._id === req.params.user || req.user._id === item.addedBy
|
if req.user._id === req.params.user || req.user._id === item.addedBy
|
||||||
form.inline(method='GET', action=`${_CC.config.base}wishlist/${req.params.user}/note/${item.id}`)
|
form.inline(method='GET', action=`${_CC.config.base}wishlist/${req.params.user}/note/${item.id}`)
|
||||||
.field.inline
|
.field.inline
|
||||||
.control.inline
|
.control.inline
|
||||||
input.inline.button(type='submit', value='Edit item')
|
input.inline.button(type='submit', value=lang('WISHLIST_EDIT_ITEM'))
|
||||||
if index !== firstCanSee && req.user._id === req.params.user
|
if index !== firstCanSee && req.user._id === req.params.user
|
||||||
form.inline(method='POST', action=`${_CC.config.base}wishlist/${req.params.user}/move/up/${item.id}`)
|
form.inline(method='POST', action=`${_CC.config.base}wishlist/${req.params.user}/move/up/${item.id}`)
|
||||||
.field.inline
|
.field.inline
|
||||||
.control.inline
|
.control.inline
|
||||||
input.inline.button(type='submit' value='Move item up')
|
input.inline.button(type='submit' value=lang('WISHLIST_MOVE_ITEM_UP'))
|
||||||
if index !== lastCanSee && req.user._id === req.params.user
|
if index !== lastCanSee && req.user._id === req.params.user
|
||||||
form.inline(method='POST', action=`${_CC.config.base}wishlist/${req.params.user}/move/down/${item.id}`)
|
form.inline(method='POST', action=`${_CC.config.base}wishlist/${req.params.user}/move/down/${item.id}`)
|
||||||
.field.inline
|
.field.inline
|
||||||
.control.inline
|
.control.inline
|
||||||
input.inline.button(type='submit' value='Move item down')
|
input.inline.button(type='submit' value=lang('WISHLIST_MOVE_ITEM_DOWN'))
|
||||||
form(method='POST')
|
form(method='POST')
|
||||||
.field
|
.field
|
||||||
label.label Item URL or Name (<a href="/supported-sites">Supported Sites</a>)
|
label.label!=lang('WISHLIST_URL_LABEL')
|
||||||
.control.has-icons-left
|
.control.has-icons-left
|
||||||
input.input(
|
input.input(
|
||||||
type='text',
|
type='text',
|
||||||
name='itemUrlOrName',
|
name='itemUrlOrName',
|
||||||
placeholder='https://www.amazon.com/dp/B00ZV9RDKK'
|
placeholder=lang('WISHLIST_URL_PLACEHOLDER')
|
||||||
)
|
)
|
||||||
span.icon.is-small.is-left
|
span.icon.is-small.is-left
|
||||||
i.fas.fa-gift
|
i.fas.fa-gift
|
||||||
.field
|
.field
|
||||||
label.label Note
|
label.label= lang('WISHLIST_NOTE')
|
||||||
.control
|
.control
|
||||||
textarea.textarea(
|
textarea.textarea(
|
||||||
name='note',
|
name='note',
|
||||||
placeholder='Optional'
|
placeholder=lang('WISHLIST_OPTIONAL')
|
||||||
)
|
)
|
||||||
.field
|
.field
|
||||||
.control
|
.control
|
||||||
input.button(type='submit' value=(req.user._id === req.params.user ? 'Add item to wishlist' : 'Pledge item'))
|
input.button(type='submit' value=(req.user._id === req.params.user ? lang('WISHLIST_ADD') : lang('WISHLIST_PLEDGE_ITEM')))
|
||||||
script(src=`${_CC.config.base}js/wishlist.js`)
|
script(src=`${_CC.config.base}js/wishlist.js`)
|
||||||
|
|
||||||
block print
|
block print
|
||||||
|
|
|
@ -12,8 +12,8 @@ block content
|
||||||
figure.image.is-square.is-fullwidth.is-marginless(style='display: inline-block;')
|
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;')
|
img.is-rounded.is-fullwidth(src=req.user.pfp, style='object-fit: cover;')
|
||||||
.column
|
.column
|
||||||
span=req.user._id
|
span
|
||||||
span : ???/???
|
span=lang('WISHLISTS_COUNTS_SELF', req.user._id)
|
||||||
progress.progress(value=1, max=1)
|
progress.progress(value=1, max=1)
|
||||||
each user in users
|
each user in users
|
||||||
if req.user._id !== user.id
|
if req.user._id !== user.id
|
||||||
|
@ -26,6 +26,5 @@ block content
|
||||||
figure.image.is-square.is-fullwidth.is-marginless(style='display: inline-block;')
|
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;')
|
img.is-rounded.is-fullwidth(src=user.doc.pfp, style='object-fit: cover;')
|
||||||
.column
|
.column
|
||||||
span= user.id
|
span= lang('WISHLISTS_COUNTS', user.id, totals(user.doc.wishlist).pledged, user.doc.wishlist.length)
|
||||||
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)
|
progress.progress.is-info(value=totals(user.doc.wishlist).pledged, max=user.doc.wishlist.length)
|
Loading…
Reference in a new issue