在过去的一年,许多评论系统相继扑街了。这个博客也没有评论系统裸奔了不少时间。
国内的服务商都苟延残喘,而外国的则难以触及。
在可见的未来由于政策与环境原因,国内想来是没什么能用的评论系统了,是时候着眼开源方案了。

现在较为成熟的方案有

  • gitment 基于github issue 系统与API
  • Valine 利用 learn cloud 的免费对象存储开发的方案
  • ISSO 小果然翁,传统后端方案,自给自足型

其实对于不怎么折腾的人,第一个与第二个方案开箱即用体验很好。
但这两个方案都有致命的缺陷,由于依赖公共服务而必须在前端暴露 apiKey,这简直不能忍。
做个比喻的话,就像出门不锁门一样,叫人浑身难受。

当然这两个方案可以通过自己架设代理处理请求来确保安全性,但这样就又变成了的后端方案。相比之下,当然是先从现成的轮子着手。

前言

官网提供了pip,可执行文件,和源码安装三种方案。
官网上的安装步骤比较详细,这里就不多赘述,准备好环境就好。当然,此外也有人整合了docker方案,开箱即用。

当然如果仅仅是这样,这篇文章就不会诞生了。现有的ISSO版本为0.10.6,是16年释出的。诸如gravater头像、邮箱提醒、回复等都评论系统的主流功能都未实装。虽然在这两年里,有开发者完成了这些功能并提交给ISSO,但最新的master版本,不出意料并不能顺利运行。下一个release版本看上去也是遥遥无期,没办法,需要自己动手,丰衣足食了。

折腾记录

现在探查的时候,在网上发现了一个修改版本,实现了gravatar头像功能,从他开始,再将emial功能的request并入代码。

当然事情不会这么一帆风顺,在ISSO停更的时间里,他所用的markdown渲染器更新了,如果发生了下述报错,需要修改渲染方法的参数

1
2
3
4
File "/home/pi/ISSO/isso/utils/html.py", line 70, in Markdown
md = misaka.Markdown(renderer, extensions=extensions)
File "misaka.pyx", line 194, in misaka.Markdown.__cinit__ (src/misaka.c:1481)
TypeError: an integer is required

需要将extensions的字符串参数改为常量参数

html.py:46
1
2
3
4
def Markdown(extensions=("strikethrough", "superscript", "autolink",
"fenced-code")):
renderer = Unofficial()
md = misaka.Markdown(renderer, extensions=extensions)

to

1
2
3
def Markdown():
renderer = Unofficial()
md = misaka.Markdown(renderer, misaka.EXT_STRIKETHROUGH|misaka.EXT_SUPERSCRIPT| misaka.EXT_AUTOLINK|misaka.EXT_FENCED_CODE)

ISSO使用SMTP邮件服务发送邮件,对于大多数的邮件服务供应商,都存在发信频率限制,当出现下述错误时,就要注意分离发信请求的时间间隔了。

1
2
3
File "/home/pi/ISSO/isso/ext/notifications.py", line 84, in __enter__
v = self._sslobj.read(len, buffer)
socket.timeout: The read operation timed out

ISSO本身并没有为短时间多次发生邮件设计,这里需要将邮件提醒模块改为队列形式

notifications.py 178
1
2
3
4
5
6
7
8
9
def _retry(self):
while (not self.mailQ.empty()):
mail = self.mailQ.get()
for x in range(5):
try:
elf._sendmail(mail[0], mail[1], mail[2])
time.sleep(1)
except smtplib.SMTPConnectError:
time.sleep(60)

第一次有了自己的博客,第一次搭了自己的评论系统,可是。。ISSO的邮件提醒还是简陋的文字版
为了视觉的统一性,这里加入了邮件模板,并修改了邮件生成机制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
def format(self, thread, comment, admin=False):
class safesub(dict):
def __missing__(self, key):
return '{' + key + '}'
# admin: url title comments author ipaddr delete
# reply: url title comments author
author = comment["author"] or "Anonymous"
if comment["author"] and comment["website"]:
author = "<a href=\"%s\">%s</a>" % (comment["website"],
comment["author"])
if comment["email"]:
author += " <%s>" % comment["email"]

comments = comment["text"]
title = unquote(thread["uri"], encoding='utf-8', errors='replace')
title=title.split('/')[-2]
url = local("origin") + thread["uri"] + "#isso-%i" % comment["id"]
ipaddr = comment["remote_addr"]
delete = local(
"host") + "/id/%i" % comment["id"] + "/delete/" + self.isso.sign(
comment["id"])

if (admin):
return self.manageText.format_map(safesub(vars()))
else:
return self.notifyText.format_map(safesub(vars()))

需要注意的是,css语法中的{,}与python的模板字符串系列方法冲突,需要写成双大括号来忽略

尾声

到这里ISSO改造算是告一段落了,诸位可以在这里下载源码自行安装
https://github.com/oodavy41/isso