feat: comments - default provider create (wip) + permissions

This commit is contained in:
NGPixel
2020-05-26 22:56:11 -04:00
parent 2fe2e6210d
commit 1222355046
14 changed files with 412 additions and 24 deletions

View File

@@ -447,12 +447,24 @@ router.get('/*', async (req, res, next) => {
})
}
// -> Comments Permissions
const commentsPermissions = WIKI.config.features.featurePageComments ? {
read: WIKI.auth.checkAccess(req.user, ['read:comments'], pageArgs),
write: WIKI.auth.checkAccess(req.user, ['write:comments'], pageArgs),
manage: WIKI.auth.checkAccess(req.user, ['manage:comments'], pageArgs)
} : {
read: false,
write: false,
manage: false
}
// -> Render view
res.render('page', {
page,
sidebar,
injectCode,
comments: WIKI.data.commentProvider
comments: WIKI.data.commentProvider,
commentsPermissions
})
}
} else if (pageArgs.path === 'home') {

View File

@@ -0,0 +1,8 @@
exports.up = knex => {
return knex.schema
.alterTable('comments', table => {
table.integer('replyTo').unsigned().notNullable().defaultTo(0)
})
}
exports.down = knex => { }

View File

@@ -0,0 +1,8 @@
exports.up = knex => {
return knex.schema
.alterTable('comments', table => {
table.integer('replyTo').unsigned().notNullable().defaultTo(0)
})
}
exports.down = knex => { }

View File

@@ -11,6 +11,9 @@ module.exports = {
async comments() { return {} }
},
CommentQuery: {
/**
* Fetch list of Comments Providers
*/
async providers(obj, args, context, info) {
const providers = await WIKI.models.commentProviders.getProviders()
return providers.map(provider => {
@@ -33,11 +36,33 @@ module.exports = {
}
})
},
/**
* Fetch list of comments for a page
*/
async list (obj, args, context) {
return []
}
},
CommentMutation: {
/**
* Create New Comment
*/
async create (obj, args, context) {
try {
// WIKI.data.commentProvider.create({
// ...args,
// user: context.req.user
// })
return {
responseResult: graphHelper.generateSuccess('New comment posted successfully')
}
} catch (err) {
return graphHelper.generateError(err)
}
},
/**
* Update Comments Providers
*/
async updateProviders(obj, args, context) {
try {
for (let provider of args.providers) {

View File

@@ -39,12 +39,18 @@ type CommentMutation {
pageId: Int!
replyTo: Int
content: String!
guestName: String
guestEmail: String
): DefaultResponse @auth(requires: ["write:comments", "manage:system"])
update(
id: Int!
content: String!
): DefaultResponse @auth(requires: ["write:comments", "manage:comments", "manage:system"])
delete(
id: Int!
): DefaultResponse @auth(requires: ["manage:comments", "manage:system"])
}
# -----------------------------------------------

55
server/models/comments.js Normal file
View File

@@ -0,0 +1,55 @@
const Model = require('objection').Model
/**
* Comments model
*/
module.exports = class Comment extends Model {
static get tableName() { return 'comments' }
static get jsonSchema () {
return {
type: 'object',
required: [],
properties: {
id: {type: 'integer'},
content: {type: 'string'},
render: {type: 'string'},
name: {type: 'string'},
email: {type: 'string'},
ip: {type: 'string'},
createdAt: {type: 'string'},
updatedAt: {type: 'string'}
}
}
}
static get relationMappings() {
return {
author: {
relation: Model.BelongsToOneRelation,
modelClass: require('./users'),
join: {
from: 'comments.authorId',
to: 'users.id'
}
},
page: {
relation: Model.BelongsToOneRelation,
modelClass: require('./pages'),
join: {
from: 'comments.pageId',
to: 'pages.id'
}
}
}
}
$beforeUpdate() {
this.updatedAt = new Date().toISOString()
}
$beforeInsert() {
this.createdAt = new Date().toISOString()
this.updatedAt = new Date().toISOString()
}
}

View File

@@ -1,11 +1,115 @@
const md = require('markdown-it')
const mdEmoji = require('markdown-it-emoji')
const { JSDOM } = require('jsdom')
const createDOMPurify = require('dompurify')
const _ = require('lodash')
const { AkismetClient } = require('akismet-api')
/* global WIKI */
const window = new JSDOM('').window
const DOMPurify = createDOMPurify(window)
md.use(mdEmoji)
let akismetClient = null
// ------------------------------------
// Default Comment Provider
// ------------------------------------
module.exports = {
add (args) {
/**
* Init
*/
async init (config) {
if (WIKI.data.commentProvider.config.akismet && WIKI.data.commentProvider.config.akismet.length > 2) {
akismetClient = new AkismetClient({
key: WIKI.data.commentProvider.config.akismet,
blog: WIKI.config.host,
lang: WIKI.config.lang.namespacing ? WIKI.config.lang.namespaces.join(', ') : WIKI.config.lang.code,
charset: 'UTF-8'
})
try {
const isValid = await akismetClient.verifyKey()
if (!isValid) {
WIKI.logger.warn('Akismet Key is invalid!')
}
} catch (err) {
WIKI.logger.warn('Unable to verify Akismet Key: ' + err.message)
}
} else {
akismetClient = null
}
},
/**
* Create New Comment
*/
async create ({ page, replyTo, content, user }) {
// -> Render Markdown
const mkdown = md({
html: false,
breaks: true,
linkify: true,
highlight(str, lang) {
return `<pre><code class="language-${lang}">${_.escape(str)}</code></pre>`
}
})
// -> Build New Comment
const newComment = {
content,
render: DOMPurify.sanitize(mkdown.render(content)),
replyTo,
pageId: page.id,
authorId: user.id,
name: user.name,
email: user.email,
ip: user.ip
}
// Check for Spam with Akismet
if (akismetClient) {
let userRole = 'user'
if (user.groups.indexOf(1) >= 0) {
userRole = 'administrator'
} else if (user.groups.indexOf(2) >= 0) {
userRole = 'guest'
}
let isSpam = false
try {
isSpam = await akismetClient.checkSpam({
ip: user.ip,
useragent: user.agentagent,
content,
name: user.name,
email: user.email,
permalink: `${WIKI.config.host}/${page.localeCode}/${page.path}`,
permalinkDate: page.updatedAt,
type: (replyTo > 0) ? 'reply' : 'comment',
role: userRole
})
} catch (err) {
WIKI.logger.warn('Akismet Comment Validation: [ FAILED ]')
WIKI.logger.warn(err)
}
if (isSpam) {
throw new Error('Comment was rejected because it is marked as spam.')
}
}
// Save Comment
await WIKI.models.comments.query().insert(newComment)
},
async update ({ id, content, user, ip }) {
},
async remove ({ id, user, ip }) {
},
async count ({ pageId }) {
}
}

View File

@@ -26,7 +26,7 @@ block body
sidebar=Buffer.from(JSON.stringify(sidebar)).toString('base64')
nav-mode=config.nav.mode
comments-enabled=config.features.featurePageComments
comments-provider=comments.key
comments-permissions=Buffer.from(JSON.stringify(commentsPermissions)).toString('base64')
comments-external=comments.codeTemplate
)
template(slot='contents')