评论功能

评论功能主要有:

发表评论 POST /comments/new

删除评论 GET /comments/:id/delete

  1. router.post('/comments/new', isLoginUser, require('./comments').create)
  2. router.get('/comments/:id/delete', isLoginUser, require('./comments').destroy)

设计评论的模型

  1. // models/comment.js
  2. const mongoose = require('mongoose')
  3. const Schema = mongoose.Schema
  4. const CommentSchema = new Schema({
  5. postId: {
  6. type: Schema.Types.ObjectId,
  7. ref: 'Post'
  8. },
  9. from: {
  10. type: Schema.Types.ObjectId,
  11. ref: 'User',
  12. require: true
  13. },
  14. to: {
  15. type: Schema.Types.ObjectId,
  16. ref: 'User'
  17. },
  18. content: {
  19. type: String,
  20. required: true
  21. },
  22. meta: {
  23. createAt: {
  24. type: Date,
  25. default: Date.now()
  26. }
  27. }
  28. })
  29. module.exports = mongoose.model('Comment', CommentSchema)

postId 代表评论对应的文章ID,from 代表发表评论者,to 代表需要艾特的人(本文暂不实现该功能)content为内容

发布留言

先来写一个发表评论的表单。同时将它引入到post.html

  1. // components/comments.html
  2. <form action="/comments/new" method="POST" class="media">
  3. <div class="media-content">
  4. <div class="field">
  5. <input type="hidden" name="postId" value="{{post._id}}">
  6. <p class="control">
  7. <textarea name="content" class="textarea" placeholder="发表评论…"></textarea>
  8. </p>
  9. </div>
  10. <button class="button is-info is-pulled-right">Submit</button>
  11. </div>
  12. </form>

注意,这儿加了个隐藏域来存放postId

编写留言控制器routes/comments.js

  1. const CommentModel = require('../models/comment')
  2. module.exports = {
  3. async create (ctx, next) {
  4. const comment = Object.assign(ctx.request.body, {
  5. from: ctx.session.user._id
  6. })
  7. await CommentModel.create(comment)
  8. ctx.flash = { success: '留言成功' }
  9. ctx.redirect('back')
  10. }
  11. }

显示留言

更改components/comments.html 添加一个留言列表

  1. <form action="/comments/new" method="POST" class="media">
  2. <div class="media-content">
  3. <div class="field">
  4. <input type="hidden" name="postId" value="{{post._id}}">
  5. <p class="control">
  6. <textarea name="content" class="textarea" placeholder="发表评论…"></textarea>
  7. </p>
  8. </div>
  9. <button class="button is-info is-pulled-right">Submit</button>
  10. </div>
  11. </form>
  12. {% for comment in comments %}
  13. <article class="media comment">
  14. <figure class="media-left">
  15. <p class="image is-24x24">
  16. <img src="https://bulma.io/images/placeholders/128x128.png">
  17. </p>
  18. </figure>
  19. <div class="media-content">
  20. <div class="content">
  21. <p>
  22. <strong>{{comment.from.name}}</strong>
  23. <br>
  24. {{marked(comment.content) | safe}}
  25. </p>
  26. </div>
  27. <nav>
  28. </nav>
  29. </div>
  30. <div class="media-right is-invisible">
  31. <button id="reply" class="button is-small is-primary">回复</button>
  32. <a href="/comments/{{comment._id}}/delete" class="button is-small">删除</a>
  33. </div>
  34. </article>
  35. {% endfor %}

我们让评论也支持了markdown。

修改posts.js 控制器

  1. ...
  2. const CommentModel = require('../models/comment')
  3. ...
  4. async show (ctx, next) {
  5. const post = await PostModel.findById(ctx.params.id)
  6. .populate({ path: 'author', select: 'name' })
  7. // 查找评论
  8. const comments = await CommentModel.find({ postId: ctx.params.id })
  9. .populate({ path: 'from', select: 'name' })
  10. await ctx.render('post', {
  11. title: post.title,
  12. post,
  13. comments
  14. })
  15. }

现在我们就完成了评论以及评论的展示。接下来实现删除功能

删除留言

  1. async destroy (ctx, next) {
  2. const comment = await CommentModel.findById(ctx.params.id)
  3. if (!comment) {
  4. throw new Error('留言不存在')
  5. }
  6. if (comment.from.toString() !== ctx.session.user._id.toString()) {
  7. throw new Error('没有权限')
  8. }
  9. await CommentModel.findByIdAndRemove(ctx.params.id)
  10. ctx.flash = { success: '成功删除留言' }
  11. ctx.redirect('back')
  12. }