comment.js 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. const md = require('markdown-it')
  2. const mdEmoji = require('markdown-it-emoji')
  3. const { JSDOM } = require('jsdom')
  4. const createDOMPurify = require('dompurify')
  5. const _ = require('lodash')
  6. const { AkismetClient } = require('akismet-api')
  7. const moment = require('moment')
  8. /* global WIKI */
  9. const window = new JSDOM('').window
  10. const DOMPurify = createDOMPurify(window)
  11. let akismetClient = null
  12. // ------------------------------------
  13. // Default Comment Provider
  14. // ------------------------------------
  15. module.exports = {
  16. /**
  17. * Init
  18. */
  19. async init (config) {
  20. WIKI.logger.info('(COMMENTS/DEFAULT) Initializing...')
  21. if (WIKI.data.commentProvider.config.akismet && WIKI.data.commentProvider.config.akismet.length > 2) {
  22. akismetClient = new AkismetClient({
  23. key: WIKI.data.commentProvider.config.akismet,
  24. blog: WIKI.config.host,
  25. lang: WIKI.config.lang.namespacing ? WIKI.config.lang.namespaces.join(', ') : WIKI.config.lang.code,
  26. charset: 'UTF-8'
  27. })
  28. try {
  29. const isValid = await akismetClient.verifyKey()
  30. if (!isValid) {
  31. akismetClient = null
  32. WIKI.logger.warn('(COMMENTS/DEFAULT) Akismet Key is invalid! [ DISABLED ]')
  33. } else {
  34. WIKI.logger.info('(COMMENTS/DEFAULT) Akismet key is valid. [ OK ]')
  35. }
  36. } catch (err) {
  37. akismetClient = null
  38. WIKI.logger.warn('(COMMENTS/DEFAULT) Unable to verify Akismet Key: ' + err.message)
  39. }
  40. } else {
  41. akismetClient = null
  42. }
  43. WIKI.logger.info('(COMMENTS/DEFAULT) Initialization completed.')
  44. },
  45. /**
  46. * Create New Comment
  47. */
  48. async create ({ page, replyTo, content, user }) {
  49. // -> Render Markdown
  50. const mkdown = md({
  51. html: false,
  52. breaks: true,
  53. linkify: true,
  54. highlight(str, lang) {
  55. return `<pre><code class="language-${lang}">${_.escape(str)}</code></pre>`
  56. }
  57. })
  58. mkdown.use(mdEmoji)
  59. // -> Build New Comment
  60. const newComment = {
  61. content,
  62. render: DOMPurify.sanitize(mkdown.render(content)),
  63. replyTo,
  64. pageId: page.id,
  65. authorId: user.id,
  66. name: user.name,
  67. email: user.email,
  68. ip: user.ip
  69. }
  70. // -> Check for Spam with Akismet
  71. if (akismetClient) {
  72. let userRole = 'user'
  73. if (user.groups.indexOf(1) >= 0) {
  74. userRole = 'administrator'
  75. } else if (user.groups.indexOf(2) >= 0) {
  76. userRole = 'guest'
  77. }
  78. let isSpam = false
  79. try {
  80. isSpam = await akismetClient.checkSpam({
  81. ip: user.ip,
  82. useragent: user.agentagent,
  83. content,
  84. name: user.name,
  85. email: user.email,
  86. permalink: `${WIKI.config.host}/${page.localeCode}/${page.path}`,
  87. permalinkDate: page.updatedAt,
  88. type: (replyTo > 0) ? 'reply' : 'comment',
  89. role: userRole
  90. })
  91. } catch (err) {
  92. WIKI.logger.warn('Akismet Comment Validation: [ FAILED ]')
  93. WIKI.logger.warn(err)
  94. }
  95. if (isSpam) {
  96. throw new Error('Comment was rejected because it is marked as spam.')
  97. }
  98. }
  99. // -> Check for minimum delay between posts
  100. if (WIKI.data.commentProvider.config.minDelay > 0) {
  101. const lastComment = await WIKI.models.comments.query().select('updatedAt').findOne('authorId', user.id).orderBy('updatedAt', 'desc')
  102. if (lastComment && moment().subtract(WIKI.data.commentProvider.config.minDelay, 'seconds').isBefore(lastComment.updatedAt)) {
  103. throw new Error('Your administrator has set a time limit before you can post another comment. Try again later.')
  104. }
  105. }
  106. // -> Save Comment to DB
  107. const cm = await WIKI.models.comments.query().insert(newComment)
  108. // -> Return Comment ID
  109. return cm.id
  110. },
  111. async update ({ id, content, user, ip }) {
  112. },
  113. /**
  114. * Delete an existing comment by ID
  115. */
  116. async remove ({ id, user, ip }) {
  117. return WIKI.models.comments.query().findById(id).delete()
  118. },
  119. /**
  120. * Get the page ID from a comment ID
  121. */
  122. async getPageIdFromCommentId (id) {
  123. const result = await WIKI.models.comments.query().select('pageId').findById(id)
  124. return (result) ? result.pageId : false
  125. },
  126. /**
  127. * Get the total comments count for a page ID
  128. */
  129. async count (pageId) {
  130. const result = await WIKI.models.comments.query().count('* as total').where('pageId', pageId).first()
  131. return _.toSafeInteger(result.total)
  132. }
  133. }