评论功能

评论功能主要有:

发表评论  POST /comments/new

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

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

设计评论的模型

// models/comment.js
const mongoose = require('mongoose')
const Schema = mongoose.Schema

const CommentSchema = new Schema({
  postId: {
    type: Schema.Types.ObjectId,
    ref: 'Post'
  },
  from: {
    type: Schema.Types.ObjectId,
    ref: 'User',
    require: true
  },
  to: {
    type: Schema.Types.ObjectId,
    ref: 'User'
  },
  content: {
    type: String,
    required: true
  },
  meta: {
    createAt: {
      type: Date,
      default: Date.now()
    }
  }
})

module.exports = mongoose.model('Comment', CommentSchema)

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

发布留言

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

// components/comments.html
<form action="/comments/new" method="POST" class="media">
    <div class="media-content">
        <div class="field">
            <input type="hidden" name="postId" value="{{post._id}}">
            <p class="control">
                <textarea name="content" class="textarea" placeholder="发表评论…"></textarea>
            </p>
        </div>
        <button class="button is-info is-pulled-right">Submit</button>
    </div>
</form>

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

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

const CommentModel = require('../models/comment')

module.exports = {
  async create (ctx, next) {
    const comment = Object.assign(ctx.request.body, {
      from: ctx.session.user._id
    })
    await CommentModel.create(comment)
    ctx.flash = { success: '留言成功' }
    ctx.redirect('back')
  }
}

显示留言

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

<form action="/comments/new" method="POST" class="media">
    <div class="media-content">
        <div class="field">
            <input type="hidden" name="postId" value="{{post._id}}">
            <p class="control">
                <textarea name="content" class="textarea" placeholder="发表评论…"></textarea>
            </p>
        </div>
        <button class="button is-info is-pulled-right">Submit</button>
    </div>
</form>
{% for comment in comments %}
<article class="media comment">
    <figure class="media-left">
        <p class="image is-24x24">
            <img src="/storage/201811/34eb0997e5fbe677cb6327980982226f.png">
        </p>
    </figure>
    <div class="media-content">
        <div class="content">
            <p>
                <strong>{{comment.from.name}}</strong>
                <br>
                {{marked(comment.content) | safe}}
            </p>
        </div>
        <nav>
        </nav>
    </div>
    <div class="media-right is-invisible">
        <button id="reply" class="button is-small is-primary">回复</button>
        <a href="/comments/{{comment._id}}/delete" class="button is-small">删除</a>
    </div>
</article>
{% endfor %}

我们让评论也支持了markdown。

修改posts.js 控制器

...
const CommentModel = require('../models/comment')
...
async show (ctx, next) {
    const post = await PostModel.findById(ctx.params.id)
      .populate({ path: 'author', select: 'name' })
    // 查找评论
    const comments = await CommentModel.find({ postId: ctx.params.id })
      .populate({ path: 'from', select: 'name' })
    await ctx.render('post', {
      title: post.title,
      post,
      comments
    })
}

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

删除留言

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