更新
4/4 前端:修改首页最新评论的锚记名字;添加加载后滑动到指定锚记;添加用cookies记录已经发送评论的昵称邮箱网址。
4/5 添加Comments.post.commentCount.check(callback); 添加js端排序;修改所有comments返回的格式。以上修改是为了动态导入野狗数据准备
4/5 从多说迁移数据成功
碎碎念
这件事情的起因是这样的
多说网 webmaster@duoshuo.com 3月22日 (10天前)
发送至 我 你好!
因公司业务调整,非常遗憾的向大家宣布多说项目即将关闭。
我们将于2017年6月1日正式关停服务,在此之前您可以通过后台的数据导出功能导出自己站点的评论数据。
对此给您造成的不便,我们深表歉意,感谢您的一路相伴。
其实我第一个反应就是直接迁移野狗。
迁移评论这种事儿我也不是第一次做了,上次新浪云迁移过来的时候已经做了一次从django/mysql迁移多说的工作(上次用的脚本去哪儿了,不知道能不能找到利用一下)。
其实我还是希望玩一玩最近的新技术,也搜索了一圈,结果没什么好的发现。
那继续野狗吧。
顺手撸的代码在: firebase-comments
一开始比较拙劣,弄到一半的时候我就去逛逛知乎了。不出我的所料,已经有那么点儿讨论了,比如 知乎:如何评价“多说”即将关闭?有什么替代方案? 。看了一圈,各种推荐网易跟帖,换Disqus的,还有个韩国弄的什么的。里面有几个回答有点吸引我,有个是把评论推到github上的。然后就发现了一个小伙伴 Frank Lin 在干和我一样的事儿,有点儿小兴奋呢。
关于代码
具体怎么用我在 Demo Page 里面已经写了2个,当然比较粗糙了
firebase/wilddog 设置
安全域名
这就没什么好说的了,防止偷跑流量(去死啦,就那么点评论有几个流量)
数据操作规则
在这个问题上面我这次好好研(在Frank的页面上各种捣蛋)究了一下,最后写了这堆复杂的东西
{
"rules": {
".read": true,
"comments": {
".indexOn": ["post", "timestamp"],
"$commentid": {
".write": "!data.exists() && newData.hasChild('name') && newData.hasChild('email') && newData.hasChild('post') && newData.hasChild('comment')",
".validate": "newData.child('name').val().length > 0 && newData.child('name').val().length < 20 && newData.child('name').isString() && newData.child('email').val().matches(/^[\\.a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\\.[a-zA-Z0-9_-]+)+$/) && newData.child('post').val().length > 0 && newData.child('comment').val().length > 0 && newData.child('comment').val().length < 2048 && newData.child('comment').isString() && newData.child('timestamp').isNumber() && (!newData.hasChild('url') || newData.child('url').val().matches(/^http(s?):\\/\\/[0-9a-zA-Z]([-.\\w]*[0-9a-zA-Z])*((0-9)*)*(\\/?)([a-zA-Z0-9\\-\\.\\?\\,\\'\\/\\\\+&=%\\$#_]*)?$/))"
}
},
"posts": {
"blog":{
"post":{
"$number":{
".write": "newData.hasChild('count')",
".validate": "newData.child('count').isNumber() && newData.child('count').val() >= 0"
}
}
}
}
}
}
这里有一点 posts的嵌套规则是和各人的路径有关的,我因为改过jekyll的配置,所以和默认的不一样,默认的应该是这样的
"posts": {
// the path format depends on your own jekyll permalink setting
"$year":{
"$month":{
"$day":{
"$title":{
".write": "newData.hasChild('count')",
".validate": "newData.child('count').isNumber() && newData.child('count').val() >= 0"
}
}
}
}
}
所谓前端的validate都是耍流氓,就是这样
翻译成人话是这样的:
- 所有用户可读
- 用post和index对comments索引
- comments只允许新写数据
- comments新写数据必须包含name, email, post, comment
- name长度在1-19,name类型是string
- email符合regex
- post长度大于0
- comment长度在1-2047,comment类型必须是string
- timestamp必须是数字
- url如果存在符合regex
- posts的必须包含count且count>=0
不要问我上面的1-19和1-2047怎么来的,拍脑袋决定的。
遇到如下的的坑:
- firebase/wilddog里面正则和javascript里面略有不同,转义有的地方需要双斜杠
- write和validate是不同的,没弄清楚会造成set({})等于remove()的恶劣效果,这个其实在firebase文档里面写了,我没仔细看
关于comments.js
因为很大一部分代码都是复用了抓鬼的代码,所以风格和抓鬼的一致,比如:
- callback各种嵌套
- 原生js
methods
Comments.handleError(error)
这里可以用来重载错误处理,比如我这里就bootstrapt调用一个模态框
Comments.errors
整理的错误列表,如果其他人用可以翻译一下或者改成其他文字什么的
errors: {
NO_POST: "没有指定文章",
NO_NAME: "昵称为空",
NAME_TOO_LONG: "昵称太长",
NO_EMAIL: "邮件地址为空",
EMAIL_INVALD: "邮件地址无效",
URL_INVALD: "网址无效",
NO_COMMENT: "评论为空",
COMMENT_TOO_LONG: "评论太长",
NO_COUNT: "没有指定数量"
}
Comments.comment.list(post, callback)
列出某个post的所有comment,因为是异步,所以就带了callback。下面所有带callback的都是因为异步
这里有个TODO问题,firebase/wilddog在查询上都有限制说最多500条,所以有个分页问题。但是我这里评论啥时候能超过500条呢,我再做吧(去死啦)
Comments.comment.listCallback(post, callback)
上面那个方法的监听版本
Comments.comment.add(name, email, post, comment, url, reply, callback)
添加评论,在方法里面校验了所有需要的东西,校验规则和上面firebase的规则设置一样,这里是前端先保护下
Comments.comment.recent.get(count, callback)
获取最近count条评论,这个就是用来显示在主页上的东西
Comments.comment.recent.updateCallback(count, callback)
上面那个方法的监听版本
Comments.comment.recent.removeCallback()
保留的删除最近条数监听的的方法,虽然我没有用到(咦我为什么要提出来这个,难道是因为抓鬼用到了类似的吗?)
Comments.post.commentCount.get(post, callback)
获取某个post的评论条数。Frank因为只在当前post上需要,所以他直接用了ChildrenCount。考虑到我列表页满屏的数字,我还是用数据冗余另提一个出来
在这里有坑
- 因为异步操作,我一开始的版本是直接返回了count,然后再循环的时候就各种一团乱了。我的解决方案是直接让这个方法返回{“post”: “XXX”, “count”: X}
- 因为数据冗余,造成新建评论的时候需要维护post的count,为了节省流量我就忍了
- 同样因为数据冗余,后面我要写的多说转firebase格式有个大坑。还好我是直接空的迁移,如果更新迁移就晕菜了
Comments.post.commentCount.updateCallback(post, callback)
上面那个方法的监听版本,会返回的监听Ref,可以remove来关闭监听
Comments.post.commentCount.set(post, count, callback)
设置某个post的评论数量。我在考虑要不要把这个方法给_了,因为毕竟是内部方法。不过也可以考虑以后写个校验评论数量的方法之类的。
Comments.post.commentCount.check(callback)
校验所有post的评论数量并更新。这个也可以用来防止数据冗余造成不配对的情况,可以手动校验一下。这里有坑:
- 同样还是分页问题
- 在使用之前必须要给posts加上.write是true,不然它没法工作
具体用法
先是引用firebase/wilddog的库,然后引用comments(.min).js
<script src="https://www.gstatic.com/firebasejs/3.7.3/firebase.js"></script>
<script src="/js/comments.min.js"></script>
或者
<script src="https://cdn.wilddog.com/sdk/js/2.5.2/wilddog.js"></script>
<script src="/js/comments.min.js"></script>
然后初始化
<script type="text/javascript">
//firebase
var config = {
apiKey: "*******",
authDomain: "*******.firebaseapp.com",
databaseURL: "https://*******.firebaseio.com",
storageBucket: "*******.appspot.com",
messagingSenderId: "*******"
};
Comments.init("firebase",config);
</script>
或者
<script type="text/javascript">
//Wilddog
var config = {
authDomain: "*******.wilddog.com",
syncURL: "https://*******.wilddogio.com"
};
Comments.init("wilddog",config);
</script>
在然后就是看jekyll怎么写的了,这个各人博客都不太一样。
之后就是各种jquery和js+ES6的大坑,就是前端的问题了。
我自己的博客直接提了3个独立的js出来为了防止代码太乱(去死啦)
还碰到奇怪的坑,到手机端全都看不到了。怀疑是MD5方法坏了,后来才发现是comment.js里面的格式带了ES6特性,手机的(以及IE)都不认识就挂了。
迁移自多说
为了迁移我做了一些有点古怪的事儿,首先是下面2个框,我放这里只是为了自己不想把双引号转成单引号
迁移有2种方法
一种是如果firebase或者野狗还没有新评论的时候,直接用上面我这个框转换一下,然后手工导入进去,接着开一下posts的write权限,然后Comments.post.commentCount.check(),最后关掉posts的write权限
另一种情况是这样的,firebase或者野狗已经有新评论稍微有一点儿费劲,我写了个方法Comments.comment.transferFromDuoShuo(sourceJson, callback),先打开comments和posts的Write权限(且关掉所有其他的乱七八糟限制),sourceJson里面填写上面框的结果里面的comments的值部分(不包括”comments”:),然后调用,然后再把comments和posts权限给关了
我在写这段文字的时候还没迁移,我先去试一试成不成功
更新:已经迁移成功了,同时发现一个小问题,因为我不记得多说有没有引用了,我的脚本里面没有写引用,如果有小伙伴的数据里面有关于引用的东西,可以借我来实验一下,不过这种转换也是一次性的,挺不高兴维护……
还没干的事儿
- callback说:我想变成Promise_(:зゝ∠)_
- Reply说:我的UI为什么那么丑_(:зゝ∠)_
(╯‵□′)╯︵┻━┻ 事儿是干不完的