小编叨叨叨
暑期 2021 项目研发正在火热进行中,开源之夏公众号面向广大社区及项目承担学生征稿,欢迎大家热情分享!
发送投稿文章至官方联络邮箱:
summer@iscas.ac.cn
添加公众号小编微信投稿:

本期的项目经验分享来自一位导师:Casbin社区的张军洁导师,而张军洁导师去年还是开源之夏的参与学生,凭借其出色的表现,已成为社区积极的维护者和贡献者。越来越多的同学通过开源之夏活动,了解、学习开源,深入参与开源社区,贡献开源。
项目名称
Casbin官方核心论坛(前端React + Javascript,后端Golang)
项目介绍
在2020年时,已经颇具规模的 Casbin 社区主要采用QQ群(中文),Gitter(英文)进行社区交流,交流渠道比较有限。于是社区打算开发一个开源的,同时面向Casbin开发者和用户的官方论坛:
casnode(https://github.com/casbin/casnode )。
该论坛主要是完成一个界面风格类似V2EX的论坛,前后台兼顾。
项目功能特点
• 支持多种方式的第三方登录/注册,现有手机,邮箱,QQ,微信,github,Google 多达六种注册登录方式,同时支持图形验证码进行人机验证,防止盗刷短信。
• 采用 casbin 社区 casdoor 进行身份验证登录。
• UI 适配 pc 端和移动端。
• 支持 xorm 所支持的所有数据库,如 MySQL,Oracle,MsSql,SQLite,Postgres。可以自由选择最适合和最熟悉的数据库,便于迁移和管理。
• 支持多种置顶模式,全局置顶,类别置顶,节点置顶。
• 具有后端 swagger api 文档,使开发更加容易。
• 编辑器支持 markdown,富文本等。
• 支持管理员后台,更加方便和专一的管理论坛,无需另外维护。
• 支持与 Google Groups 双向同步。
• 贴子支持自定义标签或自动生成标签,不同的主题标签聚合在一起,探索更丰富的世界。
• 支持设置站内广告,通过后台自主投放。
• 支持站内搜索,当然也支持通过 Google 等各种引擎搜索。
• 支持服务端渲染,对搜索引擎 SEO 友好。
• 支持拖拽上传图片和附件,同时每个账户都拥有自己的文件库及配额,文件库中的文件也可以当作分享链接分享出去,贴子配图更加方便。支持阿里云,腾讯云等多种 oss 存储。
• 更多的用户角色——用户,版主,管理员。
• 论坛开源,代码可读性高,符合规范,所有第三方服务都为可插拔形式,易于自定义,选择合适的服务。
部分技术架构
01 总体架构
论坛主体由前端和后端两个部分组成。
前端使用的是 JavaScript + React 技术,后端使用 Go 语言的 Beego 框架和 Xorm 搭建。
特别地,论坛虽然有用户系统,但是 Casnode 的用户管理系统已经全部迁移到了 Casdoor 上,而且也在逐步推进对 Casdoor 的支持,成为展现 Casbin 权限管理拓展应用的有力展示。
02 服务器渲染
论坛的服务端会分析每一条请求的用户特征,来判断这条请求是否来自搜索引擎的机器人。针对各大搜索引擎的机器人,后端使用 Chromedp 实现服务端渲染,返回正常的结果。这样,访客就能从各大搜索引擎查到本论坛的帖子及回复。
03 帖子标签自动生成原理
用户在发表新帖子的时候可以自定义帖子的标签。如果用户没有自己添加标签,论坛后端就会根据帖子的内容,自动生成标签。
论坛后端使用 sego 中文分词库,将帖子内容分成单独的词语。随后后台接口会统计出现频率最高的 4 个词语,作为这个帖子的标签。
04 Google Groups同步功能
基于邮件服务,论坛可以将新的帖子、回复同步至任何邮件列表。
同时,论坛还支持对 Google Groups 的双向同步。只要在配置文件中启用同步,并且在后台管理中正确设置节点的 Google Groups 信息,本论坛就能保证这个节点内的对话与 Google Groups 实时保持一致。
下图为本项目的文件结构:

其中后端架构遵守 MVC 模式,分包清晰,API 基本遵守 Restful 风格。

所有流量都通过 routers 过滤,来到 controller 层,根据具体业务细节,调用对应 object 及 service,每个下层对象都抽象出来,使得项目方便拓展与维护。代码逻辑也更清晰。
前端部分,因为同时具有后台及前台,所以分为 admin 部分页面与 main 前台部分页面,components为通用组件。论坛同时也实现了国际化,所以具有多种语言文件,并且还在翻译中。
项目部分展示
首先是前台部分
这是论坛中的位面部分:位面 -> 节点 -> 主题,还有另外的 Tab 部分:Tab -> 节点 -> 主题

文件库部分:每个用户都有自己的文件库,可以用来方便论坛上的交流,从论坛编辑界面上传的文件也都会统一规划到这里。

节点部分,此节点为从
casbin@googlegroups.com 同步而来。

后台管理部分:论坛管理员可以访问论坛的管理部分,可以管理绝大部分论坛资源。

等等,论坛有若干页面及其功能特点,目前已经上线的实例地址:https://forum.casbin.com/
部分具体实现设计
以基本功能回帖的编辑部分功能为例:
最初版本的回帖是基于 codemirror 实现的 markdown 编辑器,主要支持的拓展功能为文件上传,@ 功能等。
然而最基本的 codemirror 并不支持理想中的实现效果,所以转而寻找合适的第三方插件,但是第三方插件也并没有足够合适的插件,于是继续更改 inline-attachment 的功能部分,从而实现对应的拖拽上传/直接上传功能。
最初的上传功能是直接将阿里云的 OSS 服务集成到前端中,同时通过具体的角色管理和 STS 令牌方式严格管控权限细节。后期将此功能放至后端,从而实现更细节的控制和拓展性。
而 mention 部分的功能则魔改了 codemirror 的补全特性,通过阅读文档,调整细节,在回复列表中收集相应信息,整理成完整的列表,从而实现 @ 的功能。
对于 React 的组件管理,则设计为 TopicBox 为上层父组件,渲染回复的组件及新建回复部分分为两个子组件—— ReplyBox 与 NewReplyBox,其中公用的状态信息放在 TopicBox 组件中,其他信息按需传递和放在相应父组件,包括感谢情况,删除与编辑等等功能,根据具体的用户渲染具体的样式。
逐层传递伪代码结构如下:
<TopicBox account={this.state.account} ... />=><ReplyBox account={this.props.account} topic={this.state.topic} ... /> // collect related info ...=><NewReplyBoxaccount={this.props.account}onReplyChange={this.handleReply}content={this.state.reply}sticky={this.state.sticky}member={this.props.account?.name}memberList={this.state.memberList}refreshReplies={this.getReplies.bind(this)}parent={this.state.parent}.../>
后期我们又支持了回帖的级联样式,每个回复都维护自己的深度及父节点。
笔者后记
源起:作为学生参与 Summer2020
开发感悟
在完成项目的过程中,我主要将一个新功能的开发分为以下三步:
1. 详细了解新功能的具体效果。
和其他现有论坛相仿的功能,我会去认真测试他的每一种情况,收集全相关的功能信息,完善功能具体效果设计。
2. 以开发者的角度分析每一步需要的细节,设计实现。
作为一个开发者,应该认真根据自己具体的需求,设计实现。我一直十分向往一个简单且明了的实现,而不是追求十分复杂的代码,尽可能的用更好的设计来避免十分复杂的实现细节,而对于一个开源项目来说,更复杂的代码逻辑也就意味着增高后面维护者的难度。
3. 测试新功能的实际使用体验,及时发现开发、设计上的问题。
因为是一个工程类项目,所以也要格外注重实际的使用体验,及时发现问题,反馈给自己,再进行继续的开发和修改。
项目收获
提升自身的代码能力
经历一套完整的开发过程,无疑是对开发经验尚浅的我的绝佳历练,是一个非常有价值的学习和实践的机会。
经过了本次项目的开发,从技术上来说,经历了很多需求的实现,比如认证系统,资源管理,各种插件的使用开发,等等。
在学习的同时,也开拓了自身的视野,掌握了更多的实用技术及部分的实现原理,使得各种功能变得不再那么神秘。
大量的代码,也是对我更加深入计算机世界的一次洗礼。
亲身体验开源世界
本次的项目经历,也让我亲自体验到了开源社区运行的种种。从提 PR 到解决 issue ,再到各种开发流程,每一项都让我对开源世界更加的了解。
作为第一个亲身参与其中的开源项目,成为开源项目的维护者也让我很自豪。同时这个经历也让我学到了无数宝贵的开源经验,使我对开源的理解变得更加深刻的同时也更加尊敬各位无私奉献的开发者。
从 summer2020 开始到结束,一共经历了三个月,大部分时间我都投入到新的 feature 开发及 BUG 维护上,所以在结束的时期,该论坛已经实现了一个正常论坛的基本功能,并且支持了多种登陆方式,实现了多个拓展功能。
可以看着有着自己参与过的开源项目还在继续走下去,是一种莫大的自豪与欣慰。
传承:作为导师参与 Summer2021
成为导师
时间到了今年的 summer2021 活动,很荣幸的,因为对项目的主要架构和实现较为熟悉,在这次活动中我是以一名社区导师的身份参加。
作为 summer2020 的参与者,通过了一个暑期的开发、学习,能够不断的为社区贡献力量,成为新的社区维护者,我认为这是极其具有意义的一个转变。
在荣升导师这个身份后,看待每一个问题的角度明显的发生了变化,更加注重功能的效果实现,更加关心其他相似论坛的异同,也更加关注社区的发展,而不是仅仅的想要如何完成一个功能。同时,也因为过了一年的时间,我自身对这些技术的理解也更加深刻,更能体会到不同的工具、不同的设计直接的区别,也有了不一样的理解与设计。比如去年刚加入时的我并不了解 Oauth 这种登录方式的具体实现,并不了解 golint,并不了解 react 的各种使用方法,但是今年的我已经对各种工具链,应用场景有了一定的了解,能够帮助刚进入社区的小伙伴解决一些问题。
同时,因为有去年慢慢融入社区的经历,今年也可以更好的帮助新的成员融入社区,快速的了解项目结构,了解自己应该在那些方面着重研究,告诉他们我们之前的设计缺陷在哪里,需要修复的是那里,可以在那些方面作出新的突破与贡献,而不是只能通过慢慢的看全部的代码和文档来了解项目。
社区活动
今年的开源之夏,我和中选的学生 @oranges-eating 一起完成一整个暑期的开发过程,作为一个开源项目,同时解决不同 issue 的还有 @Kininaru、@WindSpiritSR等等社区的小伙伴,大家都是通过不同的活动聚集到这里一起积极的维护这个项目,当然日常的维护社区还有我去年的罗导师 @hsluoyz。我们会在 QQ 中的群聊,私聊等一起讨论一个功能该如何实现,如何实现更好,如何实现更高的效率,如何具备更好的可拓展性,如何避免被攻击,以及如何让这个项目更久远的走下去,如何让这个项目更具有影响力。
当然我们也经常会在 Github 上去根据具体的代码来提出自己认为的好的实现,好的设计,活跃的成员们一起认真去发现每个即将被合并进去的代码的问题,一起助力这个项目发展。
可以看到,每个 PR 或多或少都会有一些讨论或是赞成。

这些讨论中,小到一个路由传参的方式或者是代码格式,大到整个功能的重构。每个问题的指出,每一次的更新都使代码本身更健壮,更优美。
比如在成员加入社区最初的时候会有很多命名、设计上的小问题:

在尚不熟悉所有的功能的时候,提供一些帮助:


在社区中关于生产平台部署的设计上社区成员的讨论:

这个活动本身就是招募有技术热情的同伴们一起走开源这条长路,在融入了社区之后,就会比较顺利的进行下去,在使项目自身走的更加长远的同时,参与者的代码风格和质量也能获得一个比较明显的提升,可以学到很多 git 工作流及其使用,工程标准和实现,我认为这也是这次活动意义很明显的体现。
未来:传递开源精神
从我去年的导师罗老师,到我,再到今年中选的戴同学,每个人都为了同一个项目的开源发展尽着自己的一份力,最初接触社区的时候都不是很熟悉,但是慢慢的经过了暑期的活动,都已经成长为一个真正的开源社区积极的维护者,为开源社区添砖加瓦,通过了这次的经历,也都有了一定的代码能力与开源意识,成为了开源社区的新生力量。
每当遇到一个优秀的开源项目,我都会发自内心的感谢其作者,感谢互联网的开源精神。正是开源精神,让我们有机会站在更高的地方,支持我们每个人走的更远。
这个项目在两年的时间里,也经历了各种不同人为了实现不同功能或着修复不同问题的 commit,比如上述提到的一些小伙伴,虽然习惯不同,但都遵守着相同的代码规范,一起帮助项目发展,使得这个项目从最初的只有一两个页面,到现在的基本成熟,拥有了各种各样神奇的 feature,融入了更多的插件,同时拥有更少的 BUG。经历了几次的推广之后,他也有了一些用户和在 Github 上的 Star。
我也相信未来这个项目会不断拥有更多更神奇更实用的功能,获得更多来自开源社区力量的支持,不断发展壮大,回馈开源社区。
在不久前,casbin-forum 拥有了一个更简短的新名字—— casnode,和新的主要维护者们在开源的路上继续走下去。
本文为张军洁原创文章。
张军洁(kocoler),擅长Go语言,
summer2020学生、summer2021casbin社区导师。





