83.最佳回复(四)
- 本系列文章为
laracasts.com
的系列视频教程——Let's Build A Forum with Laravel and TDD 的学习笔记。若喜欢该系列视频,可去该网站订阅后下载该系列视频, 支持正版 ;- 视频源码地址:github.com/laracasts/Lets-Build-a-...;
- 本项目为一个 forum(论坛)项目,与本站的第二本实战教程 《Laravel 教程 - Web 开发实战进阶》 类似,可互相参照。
本节说明
- 对应视频教程第 83 小节:Thread Authorization
本节内容
到目前为止,我们的最佳回复功能还剩最后一个小地方需要处理,那就是Best Rply
按钮的权限问题。在目前,所有人都能看见按钮,这与我们的初衷不符。我们只让话题的创建者有权限看见。首先我们来重构下权限文件:
forum\resources\assets\js\authorizations.js
let user = window.App.user;
module.exports = {
owns (model,prop = 'user_id') {
return model[prop] == user.id;
}
};
现在我们可以只用owns
方法,就可以判断当前用户是否是thread
、reply
的owner
。我们来加上权限控制:
forum\resources\assets\js\components\Reply.vue
.
.
<div class="panel-footer level" v-if="authorize('owns',reply) || authorize('owns',reply.thread)">
<div v-if="authorize('owns',reply)">
<button class="btn btn-xs mr-1" @click="editReply">Edit</button>
<button class="btn btn-xs btn-danger mr-1" @click="destroy">Delete</button>
</div>
<button class="btn btn-xs btn-default ml-a" @click="markBestReply" v-if="authorize('owns',reply.thread)">Best Reply</button>
</div>
.
.
最后地最后,我们对组件做点小重构。我们为Reply
组件设置了data
属性,但是可读性不如直接命名为reply
。我们按照这个方向进行重构:
forum\resources\assets\js\components\Replies.vue
.
.
<div v-for="(reply ,index) in items" :key="reply.id">
<reply :reply="reply" @deleted="remove(index)"></reply>
</div>
.
.
用reply
代替data
,this.id
代替this.data.id
:
forum\resources\assets\js\components\Reply.vue
<template>
<div :id="'reply'+id" class="panel" :class="isBest ? 'panel-success' : 'panel-default'">
<div class="panel-heading">
<div class="level">
<h5 class="flex">
<a :href="'/profiles/'+reply.owner.name"
v-text="reply.owner.name">
</a> said <span v-text="ago"></span>
</h5>
<div v-if="signedIn">
<favorite :reply="reply"></favorite>
</div>
</div>
</div>
<div class="panel-body">
<div v-if="editing">
<form @submit.prevent="update">
<div class="form-group">
<textarea class="form-control" v-model="body" required></textarea>
</div>
<button class="btn btn-xs btn-primary" >Update</button>
<button class="btn btn-xs btn-link" @click="cancelReply" type="button">Cancel</button>
</form>
</div>
<div v-else v-html="body"> </div>
</div>
<div class="panel-footer level" v-if="authorize('owns',reply) || authorize('owns',reply.thread)">
<div v-if="authorize('owns',reply)">
<button class="btn btn-xs mr-1" @click="editReply">Edit</button>
<button class="btn btn-xs btn-danger mr-1" @click="destroy">Delete</button>
</div>
<button class="btn btn-xs btn-default ml-a" @click="markBestReply" v-if="authorize('owns',reply.thread)">Best Reply</button>
</div>
</div>
</template>
<script>
import Favorite from './Favorite.vue';
import moment from 'moment';
export default {
props: ['reply'],
components: { Favorite },
data() {
return {
editing: false,
id: this.reply.id,
body: this.reply.body,
isBest: this.reply.isBest,
};
},
computed: {
ago() {
return moment(this.reply.created_at).fromNow() + '...';
}
},
created() {
window.events.$on('best-reply-selected',id => {
this.isBest = (id === this.id)
});
},
methods:{
update() {
axios.patch('/replies/' + this.reply.id,{
body:this.body
})
.catch(error => {
flash(error.response.data,'danger');
});
this.editing = false;
flash('Updated!');
},
destroy() {
axios.delete('/replies/' + this.id);
this.$emit('deleted',this.id);
},
editReply(){
this.old_body_data = this.body;
this.editing = true;
},
cancelReply(){
this.body = this.old_body_data;
this.old_body_data = '';
this.editing = false;
},
markBestReply() {
this.isBest = true;
axios.post('/replies/' + this.id + '/best');
window.events.$emit('best-reply-selected',this.id);
}
}
}
</script>
下一节我们进入下一个功能的开发,Good Luck!