Browse Source

feat: comments post min delay

pull/1975/head
NGPixel 4 years ago
parent
commit
e74605501f
4 changed files with 132 additions and 102 deletions
  1. 220
      client/components/comments.vue
  2. 2
      server/graph/schemas/comment.graphql
  3. 9
      server/modules/comments/default/comment.js
  4. 3
      server/modules/comments/default/definition.yml

220
client/components/comments.vue

@ -131,40 +131,51 @@ export default {
methods: {
onIntersect (entries, observer, isIntersecting) {
if (isIntersecting) {
this.fetch()
this.fetch(true)
}
},
async fetch () {
async fetch (silent = false) {
this.isLoading = true
const results = await this.$apollo.query({
query: gql`
query ($locale: String!, $path: String!) {
comments {
list(locale: $locale, path: $path) {
id
render
authorName
createdAt
updatedAt
try {
const results = await this.$apollo.query({
query: gql`
query ($locale: String!, $path: String!) {
comments {
list(locale: $locale, path: $path) {
id
render
authorName
createdAt
updatedAt
}
}
}
`,
variables: {
locale: this.$store.get('page/locale'),
path: this.$store.get('page/path')
},
fetchPolicy: 'network-only'
})
this.comments = _.get(results, 'data.comments.list', []).map(c => {
const nameParts = c.authorName.toUpperCase().split(' ')
let initials = _.head(nameParts).charAt(0)
if (nameParts.length > 1) {
initials += _.last(nameParts).charAt(0)
}
`,
variables: {
locale: this.$store.get('page/locale'),
path: this.$store.get('page/path')
},
fetchPolicy: 'network-only'
})
this.comments = _.get(results, 'data.comments.list', []).map(c => {
const nameParts = c.authorName.toUpperCase().split(' ')
let initials = _.head(nameParts).charAt(0)
if (nameParts.length > 1) {
initials += _.last(nameParts).charAt(0)
c.initials = initials
return c
})
} catch (err) {
console.warn(err)
if (!silent) {
this.$store.commit('showNotification', {
style: 'red',
message: err.message,
icon: 'alert'
})
}
c.initials = initials
return c
})
}
this.isLoading = false
this.hasLoadedOnce = true
},
@ -214,59 +225,63 @@ export default {
return
}
const resp = await this.$apollo.mutate({
mutation: gql`
mutation (
$pageId: Int!
$replyTo: Int
$content: String!
$guestName: String
$guestEmail: String
) {
comments {
create (
pageId: $pageId
replyTo: $replyTo
content: $content
guestName: $guestName
guestEmail: $guestEmail
) {
responseResult {
succeeded
errorCode
slug
message
try {
const resp = await this.$apollo.mutate({
mutation: gql`
mutation (
$pageId: Int!
$replyTo: Int
$content: String!
$guestName: String
$guestEmail: String
) {
comments {
create (
pageId: $pageId
replyTo: $replyTo
content: $content
guestName: $guestName
guestEmail: $guestEmail
) {
responseResult {
succeeded
errorCode
slug
message
}
id
}
id
}
}
`,
variables: {
pageId: this.pageId,
replyTo: 0,
content: this.newcomment,
guestName: this.guestName,
guestEmail: this.guestEmail
}
`,
variables: {
pageId: this.pageId,
replyTo: 0,
content: this.newcomment,
guestName: this.guestName,
guestEmail: this.guestEmail
}
})
if (_.get(resp, 'data.comments.create.responseResult.succeeded', false)) {
this.$store.commit('showNotification', {
style: 'success',
message: 'New comment posted successfully.',
icon: 'check'
})
this.newcomment = ''
await this.fetch()
this.$nextTick(() => {
this.$vuetify.goTo(`#comment-post-id-${_.get(resp, 'data.comments.create.id', 0)}`, this.scrollOpts)
})
} else {
if (_.get(resp, 'data.comments.create.responseResult.succeeded', false)) {
this.$store.commit('showNotification', {
style: 'success',
message: 'New comment posted successfully.',
icon: 'check'
})
this.newcomment = ''
await this.fetch()
this.$nextTick(() => {
this.$vuetify.goTo(`#comment-post-id-${_.get(resp, 'data.comments.create.id', 0)}`, this.scrollOpts)
})
} else {
throw new Error(_.get(resp, 'data.comments.create.responseResult.message', 'An unexpected error occured.'))
}
} catch (err) {
this.$store.commit('showNotification', {
style: 'red',
message: _.get(resp, 'data.comments.create.responseResult.message', 'An unexpected error occured.'),
message: err.message,
icon: 'alert'
})
}
@ -286,42 +301,46 @@ export default {
this.isBusy = true
this.deleteCommentDialogShown = false
const resp = await this.$apollo.mutate({
mutation: gql`
mutation (
$id: Int!
) {
comments {
delete (
id: $id
) {
responseResult {
succeeded
errorCode
slug
message
try {
const resp = await this.$apollo.mutate({
mutation: gql`
mutation (
$id: Int!
) {
comments {
delete (
id: $id
) {
responseResult {
succeeded
errorCode
slug
message
}
}
}
}
`,
variables: {
id: this.commentToDelete.id
}
`,
variables: {
id: this.commentToDelete.id
}
})
if (_.get(resp, 'data.comments.delete.responseResult.succeeded', false)) {
this.$store.commit('showNotification', {
style: 'success',
message: 'Comment was deleted successfully.',
icon: 'check'
})
this.comments = _.reject(this.comments, ['id', this.commentToDelete.id])
} else {
if (_.get(resp, 'data.comments.delete.responseResult.succeeded', false)) {
this.$store.commit('showNotification', {
style: 'success',
message: 'Comment was deleted successfully.',
icon: 'check'
})
this.comments = _.reject(this.comments, ['id', this.commentToDelete.id])
} else {
throw new Error(_.get(resp, 'data.comments.delete.responseResult.message', 'An unexpected error occured.'))
}
} catch (err) {
this.$store.commit('showNotification', {
style: 'red',
message: _.get(resp, 'data.comments.delete.responseResult.message', 'An unexpected error occured.'),
message: err.message,
icon: 'alert'
})
}
@ -362,6 +381,7 @@ export default {
img {
max-width: 100%;
border-radius: 5px;
}
code {

2
server/graph/schemas/comment.graphql

@ -42,7 +42,7 @@ type CommentMutation {
content: String!
guestName: String
guestEmail: String
): CommentCreateResponse @auth(requires: ["write:comments", "manage:system"])
): CommentCreateResponse @auth(requires: ["write:comments", "manage:system"]) @rateLimit(limit: 1, duration: 15)
update(
id: Int!

9
server/modules/comments/default/comment.js

@ -4,6 +4,7 @@ const { JSDOM } = require('jsdom')
const createDOMPurify = require('dompurify')
const _ = require('lodash')
const { AkismetClient } = require('akismet-api')
const moment = require('moment')
/* global WIKI */
@ -106,6 +107,14 @@ module.exports = {
}
}
// -> Check for minimum delay between posts
if (WIKI.data.commentProvider.config.minDelay > 0) {
const lastComment = await WIKI.models.comments.query().select('updatedAt').findOne('authorId', user.id).orderBy('updatedAt', 'desc')
if (lastComment && moment().subtract(WIKI.data.commentProvider.config.minDelay, 'seconds').isBefore(lastComment.updatedAt)) {
throw new Error('Your administrator has set a time limit before you can post another comment. Try again later.')
}
}
// -> Save Comment to DB
const cm = await WIKI.models.comments.query().insert(newComment)

3
server/modules/comments/default/definition.yml

@ -12,11 +12,12 @@ props:
title: Akismet API Key
default: ''
hint: 'Prevent spam by using the Akismet service. Enter your API key here to enable. Leave empty to disable.'
maxWidth: 650
order: 1
minDelay:
type: Number
title: Post delay
default: 30
hint: 'Minimum delay (in seconds) between comments per IP address.'
hint: 'Minimum delay (in seconds) between comments per account. Note that all guests are considered as a single account.'
maxWidth: 400
order: 2
Loading…
Cancel
Save