feat: comments - default provider create (wip) + permissions
This commit is contained in:
@@ -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') {
|
||||
|
8
server/db/migrations-sqlite/2.4.61.js
Normal file
8
server/db/migrations-sqlite/2.4.61.js
Normal file
@@ -0,0 +1,8 @@
|
||||
exports.up = knex => {
|
||||
return knex.schema
|
||||
.alterTable('comments', table => {
|
||||
table.integer('replyTo').unsigned().notNullable().defaultTo(0)
|
||||
})
|
||||
}
|
||||
|
||||
exports.down = knex => { }
|
8
server/db/migrations/2.4.61.js
Normal file
8
server/db/migrations/2.4.61.js
Normal file
@@ -0,0 +1,8 @@
|
||||
exports.up = knex => {
|
||||
return knex.schema
|
||||
.alterTable('comments', table => {
|
||||
table.integer('replyTo').unsigned().notNullable().defaultTo(0)
|
||||
})
|
||||
}
|
||||
|
||||
exports.down = knex => { }
|
@@ -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) {
|
||||
|
@@ -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
55
server/models/comments.js
Normal 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()
|
||||
}
|
||||
}
|
@@ -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 }) {
|
||||
|
||||
}
|
||||
}
|
||||
|
@@ -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')
|
||||
|
Reference in New Issue
Block a user