feat: comments post min delay

This commit is contained in:
NGPixel 2020-05-31 15:54:20 -04:00
parent 8a74904731
commit e74605501f
4 changed files with 133 additions and 103 deletions

View File

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

View File

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

View File

@ -4,6 +4,7 @@ const { JSDOM } = require('jsdom')
const createDOMPurify = require('dompurify') const createDOMPurify = require('dompurify')
const _ = require('lodash') const _ = require('lodash')
const { AkismetClient } = require('akismet-api') const { AkismetClient } = require('akismet-api')
const moment = require('moment')
/* global WIKI */ /* 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 // -> Save Comment to DB
const cm = await WIKI.models.comments.query().insert(newComment) const cm = await WIKI.models.comments.query().insert(newComment)

View File

@ -12,11 +12,12 @@ props:
title: Akismet API Key title: Akismet API Key
default: '' default: ''
hint: 'Prevent spam by using the Akismet service. Enter your API key here to enable. Leave empty to disable.' hint: 'Prevent spam by using the Akismet service. Enter your API key here to enable. Leave empty to disable.'
maxWidth: 650
order: 1 order: 1
minDelay: minDelay:
type: Number type: Number
title: Post delay title: Post delay
default: 30 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 maxWidth: 400
order: 2 order: 2