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,
})
}
翻车了翻车新闻搬运工 直接在
ArticleFeedList里处理会更好。可以看下提交记录https://github.com/Terminus2049/2049bbs/commits/master
我会把issue完善下,免得你做重复工作
张怀义 树洞、水区和垃圾场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) }