张怀义 在小组 2049BBS
动态 帖子 71 评论 356 短评 0 收到的赞 送出的赞
  1. 张怀义   在小组 2049BBS 回复文章

    今天量体温,37.8度

    我今天体温已经下降,后天就要入职了

    多谢大家关心

    我真的没有被感染瘟疫。。。

  2. 张怀义   在小组 2049BBS 回复文章

    今天量体温,37.8度

    @爱狗却养猫 #33 她没说,我没问

    加菲猫不小心走丢了,被卖到了一个宠物店,它非常担心它的主人乔恩会思念它成伤。在一个清晨,乔恩走进了这家宠物店,店主热情的问他要不要买宠物,然后乔恩发现了走失的加菲,再次把它买回去了,然后皆大欢喜。在故事的最后,那个世界著名的肥猫加菲说,我永远也不会问乔恩,那天为什么走进那家宠物店。
    
  3. 张怀义   在小组 2049BBS 回复文章

    今天量体温,37.8度

    @爱狗却养猫 #31 简单讲,觉得她好看。

    当年大二,她为我缝裤子,照顾我,对我好。第一次觉得有女孩子值得我去追。后来我和她认识,虽然她拒绝和我交往,却每年会给我买蛋糕。

    我不知道那些条条框框,我就是觉得她很好看,我想娶她

  4. 张怀义   在小组 2049BBS 回复文章

    今天量体温,37.8度

    @Ananas #29 她估计不喜欢我,所以对我冷淡

  5. 张怀义   在小组 2049BBS 回复文章

    预览功能支持 LaTex 渲染了

    @WFH #8 参考代码 https://github.com/mathjax/MathJax/blob/legacy-v2-develop/test/sample-dynamic-2.html

    重点看

      MathJax.Hub.Config({
    

    还有

    MathJax.Hub.Queue(
    

    其他问题,我还在研究。。。

    为什么我的代码,怎么写,在2049都是错误的,显示不出来!!!

  6. 张怀义   在小组 2049BBS 回复文章

    【转载】初恋情人是个鬼

    youtu.be/30JuuGyYAXo

    我学妹,大概给人的感觉就是这样的

    她就是特别活泼,穿什么衣服都好看。夏天的时候,会穿一字肩,露出锁骨

    看着流口水那种,所以她虽然对我脾气不好,但是我都忍下来了

    所以,我一直以为她是我的红玫瑰。可惜我还是觉得白玫瑰适合我。。。

  7. 张怀义   在小组 2049BBS 回复文章

    【转载】初恋情人是个鬼

    我在B站刷《月色真美》。

    眼睛看着《月色真美》,耳朵听着《初恋情人是个鬼》,脑子里想着我初中喜欢我的那个女生。

    我对她不了解,就知道她家很穷,学费都是欠着,交不起。学习一般,经常问我数学题。

    她喜欢学习好的男生(比如我),不知道为什么,后来和一个不良少年在一起了(他成绩学校里都是倒数的,经常出去打架)

    我的初中,印象里一直在准备中考,打算离开自己的家乡,考一个好的高中,现在想想,如果我没有考到当年的高中,是不是就会在老家,也不会来一线城市读大学,我不知道读书有什么用。

    兜兜转转,努力学习,考上了所谓的一线城市大学,最后留不下来。还是会老家上班

    我不想参加同学会了,见到别人,我觉得没面子,明明是初中里读书的翘楚,最后什么都没有。

    说好的衣锦还乡,说好 的光耀门楣。最后连个工作都找不到,只能回老家托关系。

  8. 张怀义   在小组 2049BBS 发表文章

    【转载】初恋情人是个鬼

    作曲 : 嫂嫂 作词 : 苏少安 演唱/混音:流芒菌

    无非是夜色撩人
    皮囊都好看逼真
    暗火点燃一口烟雾
    醉眼挑笑眉梢春
    你好呀 门口的先生
    你丢了一位初恋情人
    风来了 风又走了
    行人都睡了
    
    伪活者偏生最从容
    赴死之人总归是愚蠢
    好巧 好久 不见
    追忆者总归是狼狈
    潇洒之人偏生最天真
    “再给我来一杯vodka”
    
    无非是酒精作祟
    深吻也难以抗违
    暗火点燃眼底迷雾
    胸口蝴蝶飞一对
    飞啊飞 真假迷了神
    不如随我一起往下坠
    风走了 风又来了
    行人都醒了
    
    自大者偏生不屈身
    卑微之人总归最无畏
    可嘲 可哀
    散了
    糊涂者总归最好为
    清醒之人偏生不喜悲
    “我的初恋情人是个鬼”
    
  9. 张怀义   在小组 2049BBS 回复文章

    今天量体温,37.8度

    @饱读书名 #27 我没有接触过任何人,不可能感染的。也不可能传染给别人

    我和女朋友现在是异地。

  10. 张怀义   在小组 2049BBS 回复文章

    今天量体温,37.8度

    @Tom #23

    是我的问题,是我还没给她密码。我自己慢慢解决吧

    @梅菲斯特 #25

    今天测过来是37.4,已经降温了。我不可能有事,除了坐火车和公交,我就没和陌生人接触。

  11. 张怀义   在小组 2049BBS 回复文章

    男女朋友应该互相查看对方微信吗?

    我就不一一回复了

    这个帖子的前情提要

    https://2049bbs.xyz/t/3829

    https://2049bbs.xyz/t/4021

    初恋应该是我学妹,我是处男。。。

    我只是觉得她很漂亮,我下半身思考,想和她交往并结婚。

    我不像各位条件这么好,还可以对女孩子挑三拣四。我觉得有女生答应做我女朋友,已经很幸福了。

    我保证,和她在一起,不会做对不起她的事情。就这样吧。。。

    你们要讨论题目里的问题就讨论吧,不要再拉上我了。。。

  12. 张怀义   在小组 2049BBS 回复文章

    预览功能支持 LaTex 渲染了

    @小二 #5 给大神点赞。我就是好奇,ipynb可以正常显示的公式,在tex2jax这里就不行,所以我想把math库换成ipynb那个

  13. 张怀义   在小组 2049BBS 回复文章

    男女朋友应该互相查看对方微信吗?

    前辈,你说的应该是我。

    人家女孩子,不要我房,不要我车。只是想要我的微信密码,这都不给,是不是不大好?

    她和我说,她是单亲家庭,跟妈妈长大,从小就缺安全感。我很想给她点什么。

    另外,我以为这个事情很正常。你们都不给的么?你老婆要看你微信,你不给,你想过后果么?如果没结婚,你知道后果么?

  14. 张怀义   在小组 2049BBS 回复文章

    今天量体温,37.8度

    @natasha #9 希望前辈是你另一半的白月光也是朱砂痣。我只是觉得女朋友对我很冷淡

  15. 张怀义   在小组 2049BBS 回复文章

    预览功能支持 LaTex 渲染了

    我自己研究下看看吧,这里的人,写公式就少。不急

  16. 张怀义   在小组 2049BBS 回复文章

    滄海映雪歌

  17. 张怀义   在小组 2049BBS 回复文章

    今天量体温,37.8度

  18. 张怀义   在小组 2049BBS 回复文章

    今天量体温,37.8度

    @natasha #7 想看故事的话,自己去读《红玫瑰与白玫瑰》。

    我的事情已经定下来了,选择了白月光,完~

    我也挺喜欢都师太的小说的,比如《一点旧一点新》。

    《我的前半生》我也在读,《她比烟花寂寞》、《她的二三事》以前读的。

    我女朋友老说我不会哄女孩子,让我多学习怎么哄她开心。我不会哄她,我脸皮薄,爱面子。

    我就是,不知道该怎么做。除了逢年过节送礼物,我也不知道怎么追女孩子啊

  19. 张怀义   在小组 2049BBS 回复文章

    中文互联网中“讨论”的消亡

    @饱读书名 #52 去中心化存储访问。我的理解。ipfs那样吧?

  20. 张怀义   在小组 2049BBS 回复文章

    2049增加Google验证码代码

    @小二 #10 最近感觉不行。有空我去试试。我不是大神,你才是

  21. 张怀义   在小组 2049BBS 回复文章

    今天量体温,37.8度

    我想起张爱玲的《红玫瑰与白玫瑰》。

    张爱玲在开篇就说,也许每一个男子全都有过这样的两个女人,至少两个。娶了红玫瑰,久而久之,红的变了墙上的一抹蚊子血,白的还是“床前明月光”;娶了白玫瑰,白的便是衣服上沾的一粒饭粘子,红的却是心口上一颗朱砂痣

    我不知道大家的选择是什么,但是我选择了白月光,她是一个永远成为不了朱砂痣的女人。未来对我就是白米粒。

    朱砂痣,她也不会成为蚊子血,和她在一起,青春,热血,潮气蓬勃。火爆脾气吧,是唯一的缺点了。有些事情只能埋藏心底。

    一生可以得到两个我觉得对我不差的女生的好感。我觉得这辈子挺值得的。

    可惜她们两个不知道我内心的矛盾,选择的时候,我有种内疚。

    不是因为没选择另一个而对她内疚,而是我连自己想娶谁都要做选择题,我感觉对爱情不忠。所以内疚

    明明只可能爱一个女人,心里应该早有答案,为什么要朝三暮四,脚踩两条船,所以内疚

    而且我现在也不敢把自己微信密码告诉我女朋友。。。

    我在想,是我删了她的微信以后,再把密码给女朋友,还是应该和她坦白自己已经有女朋友了,再把密码给女朋友?

    脑袋都要炸了!

  22. 张怀义   在小组 2049BBS 回复文章

    今天量体温,37.8度

    另外一个女孩子是我的学妹。长得是很漂亮,就是不知道为什么脾气那么差,老是打我。

    不过也就是拳头锤几下,也不疼。不过对我总是用吼的,态度也不好。

    但是,她其实对我有种很奇怪的感觉吧。我生日,她也会订蛋糕。。。

    额外一点,去年我生日,她专门去学了织围巾。她亲手织了围巾送给我。记得当时天很冷,她约我出来,把围巾送给我,还对我说,这是她一生中第一次织围巾,她想把这个送给我,当作毕业留念吧,也当作生日礼物。

    我说实话,第一次收到女生亲手制作的生日礼物。我也对她有好感啊。其实她为了我的生日礼物,专门去学习织围巾,我挺开心的。相对于我女友,我感觉她付出挺多的。

    我也追过她,但是她对我态度,和女友比,就是两个字“暴力”!

    感觉还是吃不消。

  23. 张怀义   在小组 2049BBS 回复文章

    今天量体温,37.8度

    女人就是很复杂。

    大二,我在学校里不小心摔倒了,裤子破了,膝盖流了血。她过来帮我,后来还帮我缝了裤子,我们就这么认识了。

    我以为她喜欢我呢,我就追她。但是她不答应。也不收我礼物。但是却在我生日的时候,总是给我订蛋糕。

    虽然不会陪我过生日,也不让我碰她,所以连牵手也没有,

    她后来和我说喜欢一个学长,周末要去和他打羽毛球。然后就没有然后了。。。。

    现在我们都要毕业了,她和学长什么情况我不知道,我只知道她说喜欢我,想和我交往

    我其实,也想知道她和学长发生了什么没有。算了,就当自己什么都不知道吧。她在我印象里,很保守,不让男生碰的。。。反正我想和她牵手,她都不答应

  24. 张怀义   在小组 2049BBS 回复文章

    今天量体温,37.8度

    @小二 #2 我和保安说是设备坏了

    但是我用温度计也有37度了

    还是自己家里隔离下吧

  25. 张怀义   在小组 2049BBS 回复文章

    今天量体温,37.8度

    我女朋友对我很冷淡!我找她约会,从来不答应。

    但是自己很喜欢她啊。她老说我不会哄女孩子。

    以前从来不说我是她男朋友,最近突然对我表白,我们就成为了男女朋友。

    她要我帮她做毕业设计。

    我是真不懂化学啊

  26. 张怀义   在小组 2049BBS 回复文章

    中文互联网中“讨论”的消亡

  27. 张怀义   在小组 2049BBS 回复文章

    2049增加Google验证码代码

    @yourmom #7 何苦认为i我是小二呢?我可能真的发高烧了。。。得隔离了,你暂时见不到我了

  28. 张怀义   在小组 2049BBS 回复文章

    utc 时间 13:30:00 停机维护,大约五分钟恢复正常。

    想想还是php好,改完代码直接ftp上传就生效了,因为是脚本。

    golang因为是编译型语言,每次替换,都需要重启服务。

    最好开个nginx作为前置,需要替换的时候,nginx还可以给个静态网页说在服务器升级,而不是521报错

  29. 张怀义   在小组 2049BBS 发表文章

    今天量体温,37.8度

    我感觉,头晕,发热,不舒服,而且拉肚子。

    进出小区保安量体温37.8度,我和保安说是设备坏了,让他去修下,他就放我进小区了。

    我想休息一会了。下周估计也没法入职了!!!

    也没法帮女朋友写毕业论文了。。。还有好多事情没有做。。。

  30. 张怀义   在小组 2049BBS 回复文章

    2049bbs有onion地址么?刚才看到了

    @小二 #2 我测试了很多遍,无法复现刚才这个现象。

    应该是cloudflare的bug吧。

    你没有在服务器上部署tor,应该不可能出现刚才的提示。

    应该是cloudflare提示的

    alt-svc	h3-27=":443"; ma=86400, h3-25=":443"; ma=86400, h3-24=":443"; ma=86400, h3-23=":443"; ma=86400
    

    这个字符串,出现了一个xxxxxxx.onion:443 这样的地址

  31. 张怀义   在小组 2049BBS 回复文章

    2049bbs有onion地址么?刚才看到了

    alt-svc: h2="cflareub6dtu7nvs3kqmoigcjdwap2azrkx5zohb2yk7gqjkwoyotwqd.onion:443"; ma=86400; persist=1

  32. 张怀义   在小组 2049BBS 回复文章

    2049bbs有onion地址么?刚才看到了

    cat /var/lib/tor/hidden_service/hostname
    

    执行上面这个命令,小二应该就可以看到2049bbs.xyz的onion域名了

  33. 张怀义   在小组 2049BBS 发表文章

    2049bbs有onion地址么?刚才看到了

    刚才打开2049bbs的时候,提示了一个cfluare打头的onion地址。我还没有保存,这个地址就没了

    有人知道么?

  34. 张怀义   在小组 2049BBS 回复文章

    rss 不输出树洞、水区和垃圾场内容

    @小二 #3 不知道,点了“发表”,什么反应都没有。。

    算了,有空把那些代码都改了吧。我是手机,没法git clone完整的项目,所以我都是怎么改简单,怎么来的

  35. 张怀义   在小组 2049BBS 回复文章

    rss 不输出树洞、水区和垃圾场内容

    树洞、水区和垃圾场at无效

    https://github.com/Terminus2049/2049bbs/issues/8

    修改代码 https://github.com/Terminus2049/2049bbs/blob/master/controller/article.go

    package controller
    
    import (
    	"crypto/md5"
    	"encoding/hex"
    	"encoding/json"
    	"html/template"
    	"math/rand"
    	"net/http"
    	"strconv"
    	"strings"
    	"time"
    
    	"github.com/ego008/youdb"
    	"github.com/rs/xid"
    	"github.com/terminus2049/2049bbs/model"
    	"github.com/terminus2049/2049bbs/util"
    	"goji.io/pat"
    )
    
    func (h *BaseHandler) ArticleAdd(w http.ResponseWriter, r *http.Request) {
    	cid := pat.Param(r, "cid")
    	_, err := strconv.Atoi(cid)
    	if err != nil {
    		w.Write([]byte(`{"retcode":400,"retmsg":"cid type err"}`))
    		return
    	}
    
    	currentUser, _ := h.CurrentUser(w, r)
    	if currentUser.Id == 0 {
    		w.Write([]byte(`{"retcode":401,"retmsg":"authored err"}`))
    		return
    	}
    	if currentUser.Flag < 5 {
    		var msg string
    		if currentUser.Flag == 1 {
    			msg = "注册验证中,等待管理员通过"
    		} else {
    			msg = "您已被禁用"
    		}
    		w.Write([]byte(`{"retcode":401,"retmsg":"` + msg + `"}`))
    		return
    	}
    
    	db := h.App.Db
    
    	cobj, err := model.CategoryGetById(db, cid)
    	if err != nil {
    		w.Write([]byte(`{"retcode":404,"retmsg":"` + err.Error() + `"}`))
    		return
    	}
    
    	type pageData struct {
    		PageData
    		Cobj      model.Category
    		MainNodes []model.CategoryMini
    	}
    
    	tpl := h.CurrentTpl(r)
    	evn := &pageData{}
    	evn.SiteCf = h.App.Cf.Site
    	evn.Title = "发表文章"
    	evn.IsMobile = tpl == "mobile"
    	evn.CurrentUser = currentUser
    	evn.ShowSideAd = true
    	evn.PageName = "article_add"
    
    	evn.Cobj = cobj
    	evn.MainNodes = model.CategoryGetMain(db, cobj)
    
    	h.SetCookie(w, "token", xid.New().String(), 1)
    	h.Render(w, tpl, evn, "layout.html", "articlecreate.html")
    }
    
    func (h *BaseHandler) ArticleAddPost(w http.ResponseWriter, r *http.Request) {
    	w.Header().Set("Content-Type", "application/json; charset=UTF-8")
    
    	token := h.GetCookie(r, "token")
    	if len(token) == 0 {
    		w.Write([]byte(`{"retcode":400,"retmsg":"token cookie missed"}`))
    		return
    	}
    
    	currentUser, _ := h.CurrentUser(w, r)
    	if currentUser.Id == 0 {
    		w.Write([]byte(`{"retcode":401,"retmsg":"authored require"}`))
    		return
    	}
    	if currentUser.Flag < 5 {
    		w.Write([]byte(`{"retcode":403,"retmsg":"user flag err"}`))
    		return
    	}
    
    	type recForm struct {
    		Act     string `json:"act"`
    		Cid     uint64 `json:"cid"`
    		Title   string `json:"title"`
    		Content string `json:"content"`
    	}
    
    	decoder := json.NewDecoder(r.Body)
    	var rec recForm
    	err := decoder.Decode(&rec)
    	if err != nil {
    		w.Write([]byte(`{"retcode":400,"retmsg":"json Decode err:` + err.Error() + `"}`))
    		return
    	}
    	defer r.Body.Close()
    
    	rec.Title = strings.TrimSpace(rec.Title)
    	rec.Content = strings.TrimSpace(rec.Content)
    
    	db := h.App.Db
    	if rec.Act == "preview" {
    		tmp := struct {
    			normalRsp
    			Html string `json:"html"`
    		}{
    			normalRsp{200, ""},
    			util.ContentFmt(db, rec.Content),
    		}
    		json.NewEncoder(w).Encode(tmp)
    		return
    	}
    
    	// check title
    	hash := md5.Sum([]byte(rec.Title))
    	titleMd5 := hex.EncodeToString(hash[:])
    	if db.Hget("title_md5", []byte(titleMd5)).State == "ok" {
    		w.Write([]byte(`{"retcode":403,"retmsg":"title has existed"}`))
    		return
    	}
    
    	now := uint64(time.Now().UTC().Unix())
    	scf := h.App.Cf.Site
    
    	if currentUser.Flag < 99 && currentUser.LastPostTime > 0 {
    		if (now - currentUser.LastPostTime) < uint64(scf.PostInterval) {
    			w.Write([]byte(`{"retcode":403,"retmsg":"PostInterval limited"}`))
    			return
    		}
    	}
    
    	if rec.Cid == 0 || len(rec.Title) == 0 {
    		w.Write([]byte(`{"retcode":400,"retmsg":"missed args"}`))
    		return
    	}
    	if len(rec.Title) > scf.TitleMaxLen {
    		w.Write([]byte(`{"retcode":403,"retmsg":"TitleMaxLen limited"}`))
    		return
    	}
    	if len(rec.Content) > scf.ContentMaxLen {
    		w.Write([]byte(`{"retcode":403,"retmsg":"ContentMaxLen limited"}`))
    		return
    	}
    
    	newAid, _ := db.HnextSequence("article")
    	aobj := model.Article{
    		Id:       newAid,
    		Uid:      currentUser.Id,
    		Cid:      rec.Cid,
    		Title:    rec.Title,
    		Content:  rec.Content,
    		AddTime:  now,
    		EditTime: now,
    		ClientIp: "",
    	}
    
    	jb, _ := json.Marshal(aobj)
    	aidB := youdb.I2b(newAid)
    	db.Hset("article", aidB, jb)
    	// 总文章列表
    	ignorenodes := scf.NotHomeNodeIds
    	if len(ignorenodes) > 0 {
    		for _, node := range strings.Split(ignorenodes, ",") {
    			node, err := strconv.Atoi(node)
    			if err == nil && aobj.Cid != uint64(node) {
    				db.Zset("article_timeline", aidB, aobj.EditTime)
    			}
    		}
    	}
    
    	// 分类文章列表
    	db.Zset("category_article_timeline:"+strconv.FormatUint(aobj.Cid, 10), aidB, aobj.EditTime)
    	// 用户文章列表
    	db.Hset("user_article_timeline:"+strconv.FormatUint(aobj.Uid, 10), youdb.I2b(aobj.Id), []byte(""))
    	// 分类下文章数
    	db.Zincr("category_article_num", youdb.I2b(aobj.Cid), 1)
    
    	currentUser.LastPostTime = now
    	currentUser.Articles++
    
    	jb, _ = json.Marshal(currentUser)
    	db.Hset("user", youdb.I2b(aobj.Uid), jb)
    
    	// title md5
    	db.Hset("title_md5", []byte(titleMd5), aidB)
    
    	// send task work
    	// get tag from title
    	if scf.AutoGetTag {
    		db.Hset("task_to_get_tag", aidB, []byte(rec.Title))
    	}
    
    	// @ somebody in content
    if rec.Cid != 19 && rec.Cid != 20 {
    	sbs := util.GetMention(rec.Content,
    		[]string{currentUser.Name, strconv.FormatUint(currentUser.Id, 10)})
    
    	aid := strconv.FormatUint(newAid, 10)
    	for _, sb := range sbs {
    		var sbObj model.User
    		sbu, err := strconv.ParseUint(sb, 10, 64)
    		if err != nil {
    			// @ user name
    			sbObj, err = model.UserGetByName(db, strings.ToLower(sb))
    		} else {
    			// @ user id
    			sbObj, err = model.UserGetById(db, sbu)
    		}
    
    		if err == nil {
    			if len(sbObj.Notice) > 0 {
    				aidList := util.SliceUniqStr(strings.Split(aid+","+sbObj.Notice, ","))
    				if len(aidList) > 100 {
    					aidList = aidList[:100]
    				}
    				sbObj.Notice = strings.Join(aidList, ",")
    				sbObj.NoticeNum = len(aidList)
    			} else {
    				sbObj.Notice = aid
    				sbObj.NoticeNum = 1
    			}
    			jb, _ := json.Marshal(sbObj)
    			db.Hset("user", youdb.I2b(sbObj.Id), jb)
    		}
    }
    	}
    
    	h.DelCookie(w, "token")
    
    	tmp := struct {
    		normalRsp
    		Aid uint64 `json:"aid"`
    	}{
    		normalRsp{200, "ok"},
    		aobj.Id,
    	}
    	json.NewEncoder(w).Encode(tmp)
    }
    
    func (h *BaseHandler) ArticleHomeList(w http.ResponseWriter, r *http.Request) {
    	btn, key, score := r.FormValue("btn"), r.FormValue("key"), r.FormValue("score")
    	if len(key) > 0 {
    		_, err := strconv.ParseUint(key, 10, 64)
    		if err != nil {
    			w.Write([]byte(`{"retcode":400,"retmsg":"key type err"}`))
    			return
    		}
    	}
    	if len(score) > 0 {
    		_, err := strconv.ParseUint(score, 10, 64)
    		if err != nil {
    			w.Write([]byte(`{"retcode":400,"retmsg":"score type err"}`))
    			return
    		}
    	}
    
    	cmd := "zrscan"
    	if btn == "prev" {
    		cmd = "zscan"
    	}
    
    	db := h.App.Db
    	scf := h.App.Cf.Site
    	pageInfo := model.ArticleList(db, cmd, "article_timeline", key, score, scf.HomeShowNum*2, scf.TimeZone, scf.NotHomeNodeIds)
    	currentUser, _ := h.CurrentUser(w, r)
    
    	// 首页第二栏节点
    	if currentUser.Theme != "2" {
    		cid := scf.HomeNode
    		cobj, err := model.CategoryGetById(db, cid)
    		if err == nil {
    			cobj.Articles = db.Zget("category_article_num", youdb.I2b(cobj.Id)).Uint64()
    			pageInfo2 := model.ArticleList(db, cmd, "category_article_timeline:"+cid, key, score, scf.HomeShowNum, scf.TimeZone, "")
    			pageInfo.Items = append(pageInfo.Items, pageInfo2.Items...)
    		}
    	}
    
    	type siteInfo struct {
    		Days     int
    		UserNum  uint64
    		NodeNum  uint64
    		TagNum   uint64
    		PostNum  uint64
    		ReplyNum uint64
    	}
    
    	type pageData struct {
    		PageData
    		SiteInfo     siteInfo
    		PageInfo     model.ArticlePageInfo
    		Links        []model.Link
    		Announcement string
    		Proverb      template.HTML
    	}
    
    	si := siteInfo{}
    	rs := db.Hget("count", []byte("site_create_time"))
    	var siteCreateTime uint64
    	if rs.State == "ok" {
    		siteCreateTime = rs.Data[0].Uint64()
    	} else {
    		rs2 := db.Hscan("user", []byte(""), 1)
    		if rs2.State == "ok" {
    			user := model.User{}
    			json.Unmarshal(rs2.Data[1], &user)
    			siteCreateTime = user.RegTime
    		} else {
    			siteCreateTime = uint64(time.Now().UTC().Unix())
    		}
    		db.Hset("count", []byte("site_create_time"), youdb.I2b(siteCreateTime))
    	}
    	then := time.Unix(int64(siteCreateTime), 0)
    	diff := time.Now().UTC().Sub(then)
    	si.Days = int(diff.Hours()/24) + 1
    	si.UserNum = db.Hsequence("user")
    	si.NodeNum = db.Hsequence("category")
    	si.TagNum = db.Hsequence("tag")
    	si.PostNum = db.Hsequence("article")
    	si.ReplyNum = db.Hget("count", []byte("comment_num")).Uint64()
    
    	// fix
    	if si.NodeNum == 0 {
    		newCid, err2 := db.HnextSequence("category")
    		if err2 == nil {
    			cobj := model.Category{
    				Id:    newCid,
    				Name:  "默认分类",
    				About: "默认第一个分类",
    			}
    			jb, _ := json.Marshal(cobj)
    			db.Hset("category", youdb.I2b(cobj.Id), jb)
    			si.NodeNum = 1
    		}
    		// link
    		model.LinkSet(db, model.Link{
    			Name:  "youBBS",
    			Url:   "https://www.youbbs.org",
    			Score: 100,
    		})
    	}
    
    	tpl := h.CurrentTpl(r)
    	evn := &pageData{}
    	evn.SiteCf = scf
    	evn.Title = scf.Name
    	evn.Keywords = evn.Title
    	evn.Description = scf.Desc
    	evn.IsMobile = tpl == "mobile"
    	evn.CurrentUser = currentUser
    	evn.ShowSideAd = true
    	evn.PageName = "home"
    	evn.HotNodes = model.CategoryHot(db, scf.CategoryShowNum, scf.MustLoginNodeIds)
    
    	if currentUser.IgnoreNode != "" {
    		for _, node := range strings.Split(currentUser.IgnoreNode, ",") {
    			node, err := strconv.ParseUint(node, 10, 64)
    
    			if err != nil {
    				w.Write([]byte(`{"retcode":400,"retmsg":"忽略节点id应为整数,请在设置中检查。"}`))
    				return
    			}
    
    			for i := 0; i < len(pageInfo.Items); i++ {
    				if pageInfo.Items[i].Cid == node {
    					pageInfo.Items = append(pageInfo.Items[:i], pageInfo.Items[i+1:]...)
    					i--
    				}
    			}
    		}
    	}
    
    	if currentUser.IgnoreUser != "" {
    		for _, uid := range strings.Split(currentUser.IgnoreUser, ",") {
    			uid, err := strconv.ParseUint(uid, 10, 64)
    
    			if err != nil {
    				w.Write([]byte(`{"retcode":400,"retmsg":"忽略用户id应为整数,请在设置中检查。"}`))
    				return
    			}
    
    			for i := 0; i < len(pageInfo.Items); i++ {
    				if pageInfo.Items[i].Uid == uid {
    					pageInfo.Items = append(pageInfo.Items[:i], pageInfo.Items[i+1:]...)
    					i--
    				}
    			}
    		}
    	}
    
    	// 类似 solidot 格言
    	if !evn.IsMobile {
    		proverbs := model.CommentList(db, "hscan", "article_comment:"+scf.ProverbId, "", 500, scf.TimeZone, false)
    		// 剔除折叠的回复
    		for i := 0; i < len(proverbs.Items); i++ {
    			if proverbs.Items[i].Fold {
    				proverbs.Items = append(proverbs.Items[:i], proverbs.Items[i+1:]...)
    				i--
    			}
    		}
    
    		rand.Seed(time.Now().Unix())
    		if len(proverbs.Items) > 0 {
    			evn.Proverb = proverbs.Items[rand.Intn(len(proverbs.Items))].ContentFmt
    		}
    	}
    
    	evn.SiteInfo = si
    	evn.PageInfo = pageInfo
    	evn.Links = model.LinkList(db, false)
    
    	// 公告板功能
    	uobj, err := model.UserGetById(db, 1)
    	if err != nil {
    		evn.Announcement = "公告板,可修改1号用户的个人简介进行修改。"
    	} else {
    		evn.Announcement = uobj.About
    	}
    
    	if currentUser.Theme == "2" && !evn.IsMobile {
    		h.Render(w, tpl, evn, "layout.html", "index2.html")
    	} else {
    		h.Render(w, tpl, evn, "layout.html", "index.html")
    	}
    }
    
    func (h *BaseHandler) ArticleDetail(w http.ResponseWriter, r *http.Request) {
    	btn, key, score := r.FormValue("btn"), r.FormValue("key"), r.FormValue("score")
    	if len(key) > 0 {
    		_, err := strconv.ParseUint(key, 10, 64)
    		if err != nil {
    			w.Write([]byte(`{"retcode":400,"retmsg":"key type err"}`))
    			return
    		}
    	}
    	if len(score) > 0 {
    		_, err := strconv.ParseUint(score, 10, 64)
    		if err != nil {
    			w.Write([]byte(`{"retcode":400,"retmsg":"score type err"}`))
    			return
    		}
    	}
    
    	aid := pat.Param(r, "aid")
    	_, err := strconv.Atoi(aid)
    	if err != nil {
    		w.Write([]byte(`{"retcode":400,"retmsg":"aid type err"}`))
    		return
    	}
    
    	cmd := "hscan"
    	if btn == "prev" {
    		cmd = "hrscan"
    	}
    
    	db := h.App.Db
    	scf := h.App.Cf.Site
    	aobj, err := model.ArticleGetById(db, aid)
    	if err != nil {
    		w.Write([]byte(err.Error()))
    		return
    	}
    	currentUser, _ := h.CurrentUser(w, r)
    
    	if len(currentUser.Notice) > 0 && len(currentUser.Notice) >= len(aid) {
    		if len(aid) == len(currentUser.Notice) && aid == currentUser.Notice {
    			currentUser.Notice = ""
    			currentUser.NoticeNum = 0
    			jb, _ := json.Marshal(currentUser)
    			db.Hset("user", youdb.I2b(currentUser.Id), jb)
    		} else {
    			subStr := "," + aid + ","
    			newNotice := "," + currentUser.Notice + ","
    			if strings.Index(newNotice, subStr) >= 0 {
    				currentUser.Notice = strings.Trim(strings.Replace(newNotice, subStr, "", 1), ",")
    				currentUser.NoticeNum = len(strings.Split(currentUser.Notice, ","))
    				jb, _ := json.Marshal(currentUser)
    				db.Hset("user", youdb.I2b(currentUser.Id), jb)
    			}
    		}
    	}
    
    	if aobj.Hidden && currentUser.Flag < 1 {
    		w.WriteHeader(http.StatusNotFound)
    		w.Write([]byte(`{"retcode":404,"retmsg":"仅登录用户可见"}`))
    		return
    	}
    	cobj, err := model.CategoryGetById(db, strconv.FormatUint(aobj.Cid, 10))
    	if err != nil {
    		w.Write([]byte(err.Error()))
    		return
    	}
    
    	if cobj.Hidden && currentUser.Flag < 1 {
    		w.WriteHeader(http.StatusNotFound)
    		w.Write([]byte(`{"retcode":404,"retmsg":"仅登录用户可见"}`))
    		return
    	}
    
    	if cobj.Id == 20 && currentUser.Flag < 99 {
    		w.WriteHeader(http.StatusNotFound)
    		w.Write([]byte(`{"retcode":404,"retmsg":"请勿在垃圾场逗留"}`))
    		return
    	}
    
    	// Authorized
    	if scf.Authorized && currentUser.Flag < 5 {
    		w.WriteHeader(http.StatusUnauthorized)
    		w.Write([]byte(`{"retcode":401,"retmsg":"Unauthorized"}`))
    		return
    	}
    
    	cobj.Articles = db.Zget("category_article_num", youdb.I2b(cobj.Id)).Uint64()
    	pageInfo := model.CommentList(db, cmd, "article_comment:"+aid, key, scf.CommentListNum, scf.TimeZone, currentUser.IgnoreLimitedUsers)
    
    	if currentUser.IgnoreUser != "" {
    		for _, uid := range strings.Split(currentUser.IgnoreUser, ",") {
    			uid, err := strconv.ParseUint(uid, 10, 64)
    
    			if err != nil {
    				w.Write([]byte(`{"retcode":400,"retmsg":"type err"}`))
    				return
    			}
    
    			for i := 0; i < len(pageInfo.Items); i++ {
    				if pageInfo.Items[i].Uid == uid {
    					pageInfo.Items = append(pageInfo.Items[:i], pageInfo.Items[i+1:]...)
    					i--
    				}
    			}
    		}
    	}
    
    	type articleForDetail struct {
    		model.Article
    		ContentFmt  template.HTML
    		TagStr      template.HTML
    		Name        string
    		Avatar      string
    		Views       uint64
    		AddTimeFmt  string
    		EditTimeFmt string
    	}
    
    	type pageData struct {
    		PageData
    		Aobj     articleForDetail
    		Author   model.User
    		Cobj     model.Category
    		Relative model.ArticleRelative
    		PageInfo model.CommentPageInfo
    		Views    uint64
    	}
    
    	tpl := h.CurrentTpl(r)
    	evn := &pageData{}
    	evn.SiteCf = scf
    	evn.Title = aobj.Title + " - " + cobj.Name + " - " + scf.Name
    	evn.Keywords = aobj.Tags
    	evn.Description = cobj.Name + " - " + aobj.Title + " - " + aobj.Tags
    	evn.IsMobile = tpl == "mobile"
    
    	evn.CurrentUser = currentUser
    	evn.ShowSideAd = true
    	evn.PageName = "article_detail"
    	evn.HotNodes = model.CategoryHot(db, scf.CategoryShowNum, scf.MustLoginNodeIds)
    
    	author, _ := model.UserGetById(db, aobj.Uid)
    	viewsNum, _ := db.Hincr("article_views", youdb.I2b(aobj.Id), 1)
    	evn.Aobj = articleForDetail{
    		Article:     aobj,
    		ContentFmt:  template.HTML(util.ContentFmt(db, aobj.Content)),
    		Name:        author.Name,
    		Avatar:      author.Avatar,
    		Views:       viewsNum,
    		AddTimeFmt:  util.TimeFmt(aobj.AddTime, "2006-01-02", scf.TimeZone),
    		EditTimeFmt: util.TimeFmt(aobj.EditTime, "2006-01-02", scf.TimeZone),
    	}
    
    	if len(aobj.Tags) > 0 {
    		var tags []string
    		for _, v := range strings.Split(aobj.Tags, ",") {
    			tags = append(tags, `<a href="/tag/`+v+`">`+v+`</a>`)
    		}
    		evn.Aobj.TagStr = template.HTML(strings.Join(tags, ", "))
    	}
    
    	evn.Cobj = cobj
    	evn.Relative = model.ArticleGetRelative(db, aobj.Id, aobj.Tags)
    	evn.PageInfo = pageInfo
    
    	token := h.GetCookie(r, "token")
    	if len(token) == 0 {
    		token := xid.New().String()
    		h.SetCookie(w, "token", token, 1)
    	}
    
    	h.Render(w, tpl, evn, "layout.html", "article.html")
    }
    
    func (h *BaseHandler) ArticleDetailPost(w http.ResponseWriter, r *http.Request) {
    	w.Header().Set("Content-Type", "application/json; charset=UTF-8")
    	token := h.GetCookie(r, "token")
    	if len(token) == 0 {
    		w.Write([]byte(`{"retcode":400,"retmsg":"token cookie missed"}`))
    		return
    	}
    
    	aid := pat.Param(r, "aid")
    	_, err := strconv.Atoi(aid)
    	if err != nil {
    		w.Write([]byte(`{"retcode":400,"retmsg":"aid type err:` + err.Error() + `"}`))
    		return
    	}
    
    	type recForm struct {
    		Act     string `json:"act"`
    		Link    string `json:"link"`
    		Content string `json:"content"`
    	}
    
    	type response struct {
    		normalRsp
    		Content string        `json:"content"`
    		Html    template.HTML `json:"html"`
    	}
    
    	decoder := json.NewDecoder(r.Body)
    	var rec recForm
    	err = decoder.Decode(&rec)
    	if err != nil {
    		w.Write([]byte(`{"retcode":400,"retmsg":"json Decode err:` + err.Error() + `"}`))
    		return
    	}
    	defer r.Body.Close()
    
    	db := h.App.Db
    	rsp := response{}
    
    	if rec.Act == "link_click" {
    		rsp.Retcode = 200
    		if len(rec.Link) > 0 {
    			hash := md5.Sum([]byte(rec.Link))
    			urlMd5 := hex.EncodeToString(hash[:])
    			bn := "article_detail_token"
    			clickKey := []byte(token + ":click:" + urlMd5)
    			if db.Zget(bn, clickKey).State == "ok" {
    				w.Write([]byte(`{"retcode":403,"retmsg":"err"}`))
    				return
    			}
    			db.Zset(bn, clickKey, uint64(time.Now().UTC().Unix()))
    			db.Hincr("url_md5_click", []byte(urlMd5), 1)
    
    			w.Write([]byte(`{"retcode":200,"retmsg":"ok"}`))
    			return
    		}
    	} else if rec.Act == "comment_preview" {
    		rsp.Retcode = 200
    		rsp.Html = template.HTML(util.ContentFmt(db, rec.Content))
    	} else if rec.Act == "comment_submit" {
    		timeStamp := uint64(time.Now().UTC().Unix())
    		currentUser, _ := h.CurrentUser(w, r)
    		if currentUser.Flag < 5 {
    			w.Write([]byte(`{"retcode":403,"retmsg":"forbidden"}`))
    			return
    		}
    		if (timeStamp - currentUser.LastReplyTime) < uint64(h.App.Cf.Site.CommentInterval) {
    			w.Write([]byte(`{"retcode":403,"retmsg":"out off comment interval"}`))
    			return
    		}
    		aobj, err := model.ArticleGetById(db, aid)
    		if err != nil {
    			w.Write([]byte(`{"retcode":404,"retmsg":"not found"}`))
    			return
    		}
    		if aobj.CloseComment {
    			w.Write([]byte(`{"retcode":403,"retmsg":"comment forbidden"}`))
    			return
    		}
    		commentId, _ := db.HnextSequence("article_comment:" + aid)
    
    		scf := h.App.Cf.Site
    
    		if currentUser.Flag == 99 && (strings.Contains(rec.Content, "警告一次") ||
    			strings.Contains(rec.Content, "管理员回复")) {
    			currentUser, err = model.UserGetById(db, uint64(scf.AdminBotId))
    			if err != nil {
    				w.Write([]byte(`{"retcode":400,"retmsg":"json Decode err:` + err.Error() + `"}`))
    				return
    			}
    		}
    
    		if currentUser.Flag >= 96 && strings.Contains(rec.Content, "匿名者说") {
    			currentUser, err = model.UserGetById(db, uint64(scf.AnonymousBotId))
    			if err != nil {
    				w.Write([]byte(`{"retcode":400,"retmsg":"json Decode err:` + err.Error() + `"}`))
    				return
    			}
    		}
    
    		obj := model.Comment{
    			Id:       commentId,
    			Aid:      aobj.Id,
    			Uid:      currentUser.Id,
    			Content:  rec.Content,
    			AddTime:  timeStamp,
    			ClientIp: "",
    		}
    		jb, _ := json.Marshal(obj)
    
    		db.Hset("article_comment:"+aid, youdb.I2b(obj.Id), jb) // 文章评论bucket
    		db.Hincr("count", []byte("comment_num"), 1)            // 评论总数
    		// 用户回复文章列表
    		db.Zset("user_article_reply:"+strconv.FormatUint(obj.Uid, 10), youdb.I2b(obj.Aid), obj.AddTime)
    
    		// 更新文章列表时间
    
    		aobj.Comments = commentId
    		aobj.RUid = currentUser.Id
    		aobj.EditTime = timeStamp
    		jb2, _ := json.Marshal(aobj)
    		db.Hset("article", youdb.I2b(aobj.Id), jb2)
    
    		currentUser.LastReplyTime = timeStamp
    		currentUser.Replies += 1
    		jb3, _ := json.Marshal(currentUser)
    		db.Hset("user", youdb.I2b(currentUser.Id), jb3)
    
    		// 不顶帖用户组
    		if currentUser.Flag != 6 {
    			// 总文章列表
    			db.Zset("article_timeline", youdb.I2b(aobj.Id), timeStamp)
    			// 分类文章列表
    			db.Zset("category_article_timeline:"+strconv.FormatUint(aobj.Cid, 10), youdb.I2b(aobj.Id), timeStamp)
    		}
    
    		// @ somebody in comment & topic author
    if aobj.Cid != 19 && aobj.Cid != 20 {
    		sbs := util.GetMention("@"+strconv.FormatUint(aobj.Uid, 10)+" "+rec.Content,
    			[]string{currentUser.Name, strconv.FormatUint(currentUser.Id, 10)})
    		for _, sb := range sbs {
    			var sbObj model.User
    			sbu, err := strconv.ParseUint(sb, 10, 64)
    			if err != nil {
    				// @ user name
    				sbObj, err = model.UserGetByName(db, strings.ToLower(sb))
    			} else {
    				// @ user id
    				sbObj, err = model.UserGetById(db, sbu)
    			}
    
    			if err == nil {
    				if len(sbObj.Notice) > 0 {
    					aidList := util.SliceUniqStr(strings.Split(aid+","+sbObj.Notice, ","))
    					if len(aidList) > 100 {
    						aidList = aidList[:100]
    					}
    					sbObj.Notice = strings.Join(aidList, ",")
    					sbObj.NoticeNum = len(aidList)
    				} else {
    					sbObj.Notice = aid
    					sbObj.NoticeNum = 1
    				}
    				jb, _ := json.Marshal(sbObj)
    				db.Hset("user", youdb.I2b(sbObj.Id), jb)
    			}
    		}
    }
    
    		rsp.Retcode = 200
    	}
    
    	json.NewEncoder(w).Encode(rsp)
    }
    
    func (h *BaseHandler) ContentPreviewPost(w http.ResponseWriter, r *http.Request) {
    	w.Header().Set("Content-Type", "application/json; charset=UTF-8")
    	token := h.GetCookie(r, "token")
    	if len(token) == 0 {
    		w.Write([]byte(`{"retcode":400,"retmsg":"token cookie missed"}`))
    		return
    	}
    
    	currentUser, _ := h.CurrentUser(w, r)
    	if currentUser.Flag < 5 {
    		w.Write([]byte(`{"retcode":403,"retmsg":"forbidden"}`))
    		return
    	}
    
    	type recForm struct {
    		Act     string `json:"act"`
    		Link    string `json:"link"`
    		Content string `json:"content"`
    	}
    
    	type response struct {
    		normalRsp
    		Content string        `json:"content"`
    		Html    template.HTML `json:"html"`
    	}
    
    	decoder := json.NewDecoder(r.Body)
    	var rec recForm
    	err := decoder.Decode(&rec)
    	if err != nil {
    		w.Write([]byte(`{"retcode":400,"retmsg":"json Decode err:` + err.Error() + `"}`))
    		return
    	}
    	defer r.Body.Close()
    
    	db := h.App.Db
    	rsp := response{}
    
    	if rec.Act == "preview" && len(rec.Content) > 0 {
    		rsp.Retcode = 200
    		rsp.Html = template.HTML(util.ContentFmt(db, rec.Content))
    	}
    	json.NewEncoder(w).Encode(rsp)
    }
    
  36. 张怀义   在小组 2049BBS 回复文章

    rss 不输出树洞、水区和垃圾场内容

    @翻车了 #1 我发不了帖子了!!!

    我觉得,feed那段代码,实在不敢恭维!

    feed下,走的是 ArticleFeedList

    feed节点下,走的是 ArticleFeedCategoryList

    我也想在ArticleFeedList里写,但是我觉得很多代码完全是重复而且冗余

    如果我来改,我是从route层就已经改掉了,后面的代码会精简很多

  37. 张怀义   在小组 2049BBS 发表文章

    rss 不输出树洞、水区和垃圾场内容

    https://github.com/Terminus2049/2049bbs/issues/7

    修改代码路径 https://github.com/Terminus2049/2049bbs/blob/master/controller/feed.go

    package controller
    
    
    
    import (
    
    	"net/http"
    
    	"strconv"
    
    	"text/template"
    
    
    
    	"github.com/terminus2049/2049bbs/model"
    
    	"goji.io/pat"
    
    )
    
    
    
    func (h *BaseHandler) FeedHandler(w http.ResponseWriter, r *http.Request) {
    
    	w.Header().Set("Content-Type", "application/atom+xml; charset=utf-8")
    
    
    
    	scf := h.App.Cf.Site
    
    
    
    	var feed = `<?xml version="1.0" encoding="utf-8"?>
    
    <feed xmlns="http://www.w3.org/2005/Atom">
    
    	<title>` + scf.Name + `</title>
    
    	<link rel="self" type="application/atom+xml" href="` + scf.MainDomain + `/feed"/>
    
    	<link rel="hub" href="https://pubsubhubbub.appspot.com"/>
    
    	<updated>{ {.Update} }</updated>
    
    	<id>` + scf.MainDomain + `/feed</id>
    
    	<author>
    
    		<name>` + scf.Name + `</name>
    
    	</author>
    
    	{ {range $_, $item := .Items} }
    
    	<entry>
    
    		<title>{ {$item.Title} }</title>
    
    		<id>` + scf.MainDomain + `/t/{ {$item.Id} }</id>
    
    		<link rel="alternate" type="text/html" href="` + scf.MainDomain + `/t/{ {$item.Id} }" />
    
    		<published>{ {$item.AddTimeFmt} }</published>
    
    		<updated>{ {$item.EditTimeFmt} }</updated>
    
    		<content type="text/plain">
    
    		  { {$item.Cname} } - { {$item.Name} } - { {$item.Des} }
    
    		</content>
    
        </entry>
    
    	{ {end} }
    
    </feed>
    
    `
    
    
    
    	db := h.App.Db
    
    
    
    	items := model.ArticleFeedList(db, 20, h.App.Cf.Site.TimeZone)
    
    
    
    	var upDate string
    
    	if len(items) > 0 {
    
    		upDate = items[0].AddTimeFmt
    
    	}
    
    
    
    	t := template.Must(template.New("feed").Parse(feed))
    
    	t.Execute(w, struct {
    
    		Update string
    
    		Items  []model.ArticleFeedListItem
    
    	}{
    
    		Update: upDate,
    
    		Items:  items,
    
    	})
    
    }
    
    
    
    func (h *BaseHandler) FeedCategoryHandler(w http.ResponseWriter, r *http.Request) {
    
    	w.Header().Set("Content-Type", "application/atom+xml; charset=utf-8")
    
    
    
    	scf := h.App.Cf.Site
    
    
    
    	var feed = `<?xml version="1.0" encoding="utf-8"?>
    
    <feed xmlns="http://www.w3.org/2005/Atom">
    
    	<title>` + scf.Name + `</title>
    
    	<link rel="self" type="application/atom+xml" href="` + scf.MainDomain + `/feed"/>
    
    	<link rel="hub" href="https://pubsubhubbub.appspot.com"/>
    
    	<updated>{ {.Update} }</updated>
    
    	<id>` + scf.MainDomain + `/feed</id>
    
    	<author>
    
    		<name>` + scf.Name + `</name>
    
    	</author>
    
    	{ {range $_, $item := .Items} }
    
    	<entry>
    
    		<title>{ {$item.Title} }</title>
    
    		<id>` + scf.MainDomain + `/t/{ {$item.Id} }</id>
    
    		<link rel="alternate" type="text/html" href="` + scf.MainDomain + `/t/{ {$item.Id} }" />
    
    		<published>{ {$item.AddTimeFmt} }</published>
    
    		<updated>{ {$item.EditTimeFmt} }</updated>
    
    		<content type="text/plain">
    
    		  { {$item.Cname} } - { {$item.Name} } - { {$item.Des} }
    
    		</content>
    
        </entry>
    
    	{ {end} }
    
    </feed>
    
    `
    
    
    
    	cid := pat.Param(r, "cid")
    
    	_, err := strconv.Atoi(cid)
    
    	if err != nil {
    
    		w.Write([]byte(`{"retcode":400,"retmsg":"cid type err"}`))
    
    		return
    
    	}
    
    			if cid == 19 || cid == 20 {
    
    		w.Write([]byte(`{"retcode":400,"retmsg":"cid is illeage"}`))
    
    		return
    
    					}
    
    	db := h.App.Db
    
    
    
    	items := model.ArticleFeedCategoryList(db, cid, 20, h.App.Cf.Site.TimeZone)
    
    
    
    	var upDate string
    
    	if len(items) > 0 {
    
    		upDate = items[0].AddTimeFmt
    
    	}
    
    
    
    	t := template.Must(template.New("feed").Parse(feed))
    
    	t.Execute(w, struct {
    
    		Update string
    
    		Items  []model.ArticleFeedListItem
    
    	}{
    
    		Update: upDate,
    
    		Items:  items,
    
    	})
    
    }
    
  38. 张怀义   在小组 2049BBS 回复文章

    征集antispam方案

    @小二 #94 很多issue没明白你想做什么 关于@相关功能,我可以 https://github.com/Terminus2049/2049bbs/blob/master/controller/article.go 关于rss相关功能,我可以 https://github.com/Terminus2049/2049bbs/blob/master/controller/feed.go

    写好了我发出来

  39. 张怀义   在小组 2049BBS 回复文章

    征集antispam方案

    如果小二有什么想实现的功能,我能帮忙实现的,我都会写好放到2049,你可以自己看看接受与否。GitHub上就不提pr了

  40. 张怀义   在小组 2049BBS 回复文章

    征集antispam方案

    @张三 #84 正常成年人都需要上班,不可能熊熊那样24小时水帖。如果你看熊熊的发帖时间和规律就能知道,绝对不可能在上班时间。她是不是女生不知道。但肯定是因为瘟疫,没上学的学生

  41. 张怀义   在小组 2049BBS 回复文章

    征集antispam方案

    @小二 #91 你说的1700威望那个人,反共反魔怔了。他经常发一些悲剧,不去同情受害人,却幸灾乐祸,觉得又是乳化,乳包的好材料。它就是一个把自己快乐建立在别人的痛苦之上的人。

    这次熊熊被欺负,不是第一时间去关心熊熊身心健康。反而处处刁难Rebecca,然后泼2049脏水。

    这个人灵魂都已经扭曲了。

  42. 张怀义   在小组 2049BBS 回复文章

    2049增加Google验证码代码

    @小二 #4 不知道能帮到多少忙

  43. 张怀义   在小组 2049BBS 回复文章

    征集antispam方案

    @Phragmites #78 小二的意思,你不要把事情弄得太严肃

  44. 张怀义   在小组 2049BBS 回复文章

    征集antispam方案

    @Phragmites #83 大家都对这个事情很严肃,我已经帮忙写了代码给小二参考。说的不是熊熊的事情,是你。所以你没有明白

  45. 张怀义   在小组 2049BBS 回复文章

    搜索

    @小二 #1 我明天给他做个吧

  46. 张怀义   在小组 2049BBS 回复文章

    2049代码记录

    https://zhuanlan.zhihu.com/p/47681576

    https://zhuanlan.zhihu.com/p/47682212

  47. 张怀义   在小组 2049BBS 回复文章

    2049代码记录

    这里没法排版,看这里好了

    https://nbviewer.jupyter.org/github/quantumlib/OpenFermion/blob/master/examples/jordan_wigner_and_bravyi_kitaev_transforms.ipynb

  48. 张怀义   在小组 2049BBS 回复文章

    2049代码记录

    狄拉克符号 打不出来!!!! 全乱码了!!!

    神奇了,矩阵伪逆符号居然显示是正确的,这个markdown编辑器功能真的是缩水啊