diff --git a/app/controllers/admin/user.js b/app/controllers/admin/user.js index a98dda8..24bf324 100644 --- a/app/controllers/admin/user.js +++ b/app/controllers/admin/user.js @@ -47,7 +47,7 @@ class UserController extends SiteController { async postUpdateUser (req, res, next) { const { user: userService } = this.dtp.services; try { - await userService.update(res.locals.userAccount, req.body); + await userService.updateForAdmin(res.locals.userAccount, req.body); res.redirect('/admin/user'); } catch (error) { return next(error); diff --git a/app/models/lib/resource-stats.js b/app/models/lib/resource-stats.js index 420c064..64c1098 100644 --- a/app/models/lib/resource-stats.js +++ b/app/models/lib/resource-stats.js @@ -16,4 +16,16 @@ module.exports.ResourceStats = new Schema({ module.exports.ResourceStatsDefaults = { uniqueVisitCount: 0, totalVisitCount: 0, -}; \ No newline at end of file +}; + +module.exports.CommentStats = new Schema({ + upvoteCount: { type: Number, default: 0, required: true }, + downvoteCount: { type: Number, default: 0, required: true }, + replyCount: { type: Number, default: 0, required: true }, +}); + +module.exports.CommentStatsDefaults = { + upvoteCount: 0, + downvoteCount: 0, + replyCount: 0, +}; diff --git a/app/services/display-engine.js b/app/services/display-engine.js index 77d322f..dcd95c3 100644 --- a/app/services/display-engine.js +++ b/app/services/display-engine.js @@ -102,6 +102,13 @@ class DisplayList { params: { remove, add }, }); } + + navigateTo (href) { + this.commands.push({ + action: 'navigateTo', + params: { href }, + }); + } } class DisplayEngineService extends SiteService { diff --git a/app/services/user.js b/app/services/user.js index 51ddc00..9c29dbb 100644 --- a/app/services/user.js +++ b/app/services/user.js @@ -114,6 +114,32 @@ class UserService { } async update (user, userDefinition) { + if (!user.flags.canLogin) { + throw SiteError(403, 'Invalid user account operation'); + } + + // strip characters we don't want to allow in username + userDefinition.username = striptags(userDefinition.username.trim().replace(/[^A-Za-z0-9\-_]/gi, '')); + const username_lc = userDefinition.username.toLowerCase(); + + userDefinition.displayName = striptags(userDefinition.displayName.trim()); + userDefinition.bio = striptags(userDefinition.bio.trim()); + + this.log.info('updating user', { userDefinition }); + await User.updateOne( + { _id: user._id }, + { + $set: { + username: userDefinition.username, + username_lc, + displayName: userDefinition.displayName, + bio: userDefinition.bio, + }, + }, + ); + } + + async updateForAdmin (user, userDefinition) { // strip characters we don't want to allow in username userDefinition.username = striptags(userDefinition.username.trim().replace(/[^A-Za-z0-9\-_]/gi, '')); const username_lc = userDefinition.username.toLowerCase(); diff --git a/app/views/admin/user/form.pug b/app/views/admin/user/form.pug index 475fac9..350112d 100644 --- a/app/views/admin/user/form.pug +++ b/app/views/admin/user/form.pug @@ -4,14 +4,14 @@ block content div(uk-grid).uk-grid-small div(class="uk-width-1-1 uk-width-2-3@l") form(method="POST", action=`/admin/user/${userAccount._id}`).uk-form + input(type="hidden", name="username", value= userAccount.username) + input(type="hidden", name="displayName", value= userAccount.displayName) .uk-card.uk-card-secondary.uk-card-small .uk-card-header .uk-text-large= userAccount.displayName || userAccount.email div= userAccount.username .uk-card-body - input(type="hidden", name="username", value= userAccount.username) - input(type="hidden", name="displayName", value= userAccount.displayName) .uk-margin label(for="bio").uk-form-label.sr-only Bio textarea(id="bio", name="bio", rows="4", placeholder= "Enter profile bio").uk-textarea.uk-resize-vertical= userAccount.bio diff --git a/client/js/site-app.js b/client/js/site-app.js index b6f044e..44babee 100644 --- a/client/js/site-app.js +++ b/client/js/site-app.js @@ -49,6 +49,19 @@ export default class DtpSiteApp extends DtpApp { } this.charts = {/* will hold rendered charts */}; + + this.scrollToHash(); + } + + async scrollToHash ( ) { + const { hash } = window.location; + if (hash === '') { + return; + } + const target = document.getElementById(hash.slice(1)); + if (target && target.scrollIntoView) { + target.scrollIntoView({ behavior: 'smooth' }); + } } async connect ( ) { @@ -231,6 +244,14 @@ export default class DtpSiteApp extends DtpApp { return; } + async closeCurrentDialog ( ) { + if (!this.currentDialog) { + return; + } + this.currentDialog.hide(); + delete this.currentDialog; + } + async copyHtmlToText (event, textContentId) { const content = this.editor.getContent({ format: 'text' }); const text = document.getElementById(textContentId); diff --git a/client/less/site/button.less b/client/less/site/button.less index e1f6060..b7e0b10 100644 --- a/client/less/site/button.less +++ b/client/less/site/button.less @@ -120,6 +120,8 @@ button.uk-button.dtp-button-primary { } } + + a.uk-button.dtp-button-secondary, button.uk-button.dtp-button-secondary { background: none; diff --git a/lib/client/js/dtp-display-engine.js b/lib/client/js/dtp-display-engine.js index 1be3f98..1308ed2 100644 --- a/lib/client/js/dtp-display-engine.js +++ b/lib/client/js/dtp-display-engine.js @@ -209,6 +209,10 @@ export default class DtpDisplayEngine { } async showModal (displayList, command) { - UIkit.modal.dialog(command.html); + UIkit.modal.dialog(command.params.html); } -} \ No newline at end of file + + async navigateTo (displayList, command) { + window.location = command.params.href; + } +} diff --git a/lib/site-platform.js b/lib/site-platform.js index 77d3895..270aed9 100644 --- a/lib/site-platform.js +++ b/lib/site-platform.js @@ -322,26 +322,9 @@ module.exports.startWebServer = async (dtp) => { res.locals.dtp = { request: req, }; - res.locals.socialIcons = [ - { - url: 'https://facebook.com', - label: 'Facebook', - icon: 'fa-facebook' - }, - { - url: 'https://twitter.com', - label: 'Twitter', - icon: 'fa-twitter' - }, - { - url: 'https://instagram.com', - label: 'Instagram', - icon: 'fa-instagram' - }, - ]; const settingsKey = `settings:${dtp.config.site.domainKey}:site`; - res.locals.site = dtp.config.site; + res.locals.site = Object.assign({ }, dtp.config.site); const settings = await cacheService.getObject(settingsKey); if (settings) { @@ -383,4 +366,4 @@ module.exports.startWebServer = async (dtp) => { module.exports.shutdown = async ( ) => { module.log.info('platform shutting down'); -}; \ No newline at end of file +};