func IncrTopicReply(tid string, uid int) (err error) { err = model.NewTopic().Where("tid="+tid).Increment("reply", 1) if err != nil { logger.Errorln("更新帖子reply数失败:", err) } return }
// 新建帖子 // uri: /topics/new{json:(|.json)} func NewTopicHandler(rw http.ResponseWriter, req *http.Request) { nodes := genNodes() vars := mux.Vars(req) title := req.FormValue("title") // 请求新建帖子页面 if title == "" || req.Method != "POST" || vars["json"] == "" { req.Form.Set(filter.CONTENT_TPL_KEY, "/template/topics/new.html") filter.SetData(req, map[string]interface{}{"nodes": nodes}) return } user, _ := filter.CurrentUser(req) // 入库 topic := model.NewTopic() topic.Uid = user["uid"].(int) topic.Nid = util.MustInt(req.FormValue("nid")) topic.Title = req.FormValue("title") topic.Content = req.FormValue("content") errMsg, err := service.PublishTopic(topic) if err != nil { fmt.Fprint(rw, `{"errno": 1, "error":"`, errMsg, `"}`) return } fmt.Fprint(rw, `{"errno": 0, "error":""}`) }
// 获得帖子详细信息(包括详细回复) // 为了避免转换,tid传string类型 func FindTopicByTid(tid string) (topicMap map[string]interface{}, replies []map[string]interface{}, err error) { condition := "tid=" + tid // 帖子信息 topic := model.NewTopic() err = topic.Where(condition).Find() if err != nil { logger.Errorln("topic service FindTopicByTid Error:", err) return } // 帖子不存在 if topic.Tid == 0 { return } topicMap = make(map[string]interface{}) util.Struct2Map(topicMap, topic) // 节点名字 topicMap["node"] = model.GetNodeName(topic.Nid) // 回复信息(评论) replies, owerUser, lastReplyUser := FindObjComments(tid, strconv.Itoa(model.TYPE_TOPIC), topic.Uid, topic.Lastreplyuid) topicMap["user"] = owerUser // 有人回复 if topic.Lastreplyuid != 0 { topicMap["lastreplyusername"] = lastReplyUser.Username } return }
// 话题总数 func TopicsTotal() (total int) { total, err := model.NewTopic().Count() if err != nil { logger.Errorln("topic service TopicsTotal error:", err) } return }
// 获得帖子详细信息(包括详细回复) // 为了避免转换,tid传string类型 func FindTopicByTid(tid string) (topicMap map[string]interface{}, replies []map[string]interface{}, err error) { condition := "tid=" + tid // 帖子信息 topic := model.NewTopic() err = topic.Where(condition).Find() if err != nil { logger.Errorln("topic service FindTopicByTid Error:", err) return } // 帖子不存在 if topic.Tid == 0 { return } topicMap = make(map[string]interface{}) util.Struct2Map(topicMap, topic) topicEx := model.NewTopicEx() err = topicEx.Where(condition).Find() if err != nil { logger.Errorln("topic service FindTopicByTid Error:", err) return } if topicEx.Tid == 0 { return } util.Struct2Map(topicMap, topicEx) // 节点名字 topicMap["node"] = model.GetNodeName(topic.Nid) // 回复信息(评论) replyList, err := model.NewComment().Where("objid=" + tid + " and objtype=" + strconv.Itoa(model.TYPE_TOPIC)).FindAll() if err != nil { logger.Errorln("topic service FindTopicByTid Error:", err) return } replyNum := len(replyList) uids := make(map[int]int, replyNum+1) uids[topic.Uid] = topic.Uid for _, reply := range replyList { uids[reply.Uid] = reply.Uid } // 获得用户信息 userMap := getUserInfos(uids) topicMap["user"] = userMap[topic.Uid] // 有人回复 if topic.Lastreplyuid != 0 { topicMap["lastreplyusername"] = userMap[topicMap["lastreplyuid"].(int)].Username } replies = make([]map[string]interface{}, 0, replyNum) for _, reply := range replyList { tmpMap := make(map[string]interface{}) util.Struct2Map(tmpMap, reply) tmpMap["user"] = userMap[reply.Uid] replies = append(replies, tmpMap) } return }
// 获取单个 Topic 信息(用于编辑) func FindTopic(tid string) *model.Topic { topic := model.NewTopic() err := topic.Where("tid=?", tid).Find() if err != nil { logger.Errorf("FindTopic [%s] error:%s\n", tid, err) } return topic }
// 索引帖子 func IndexingTopic(isAll bool) { solrClient := NewSolrClient() topicObj := model.NewTopic() topicExObj := model.NewTopicEx() limit := strconv.Itoa(MaxRows) if isAll { id := 0 for { topicList, err := topicObj.Where("tid>?", id).Limit(limit).FindAll() if err != nil { logger.Errorln("IndexingTopic error:", err) break } if len(topicList) == 0 { break } tids := util.Models2Intslice(topicList, "Tid") tmpStr := strings.Repeat("?,", len(tids)) query := "tid in(" + tmpStr[:len(tmpStr)-1] + ")" args := make([]interface{}, len(tids)) for i, tid := range tids { args[i] = tid } topicExList, err := topicExObj.Where(query, args...).FindAll() if err != nil { logger.Errorln("IndexingTopic error:", err) break } topicExMap := make(map[int]*model.TopicEx, len(topicExList)) for _, topicEx := range topicExList { topicExMap[topicEx.Tid] = topicEx } for _, topic := range topicList { if id < topic.Tid { id = topic.Tid } topicEx, _ := topicExMap[topic.Tid] document := model.NewDocument(topic, topicEx) addCommand := model.NewDefaultArgsAddCommand(document) solrClient.Push(addCommand) } solrClient.Post() } } }
// 获取多个帖子详细信息 func FindTopicsByTids(tids []int) []*model.Topic { inTids := util.Join(tids, ",") topics, err := model.NewTopic().Where("tid in(" + inTids + ")").FindAll() if err != nil { logger.Errorln("topic service FindRecentReplies error:", err) return nil } return topics }
// 获得某个节点下的帖子列表(侧边栏推荐) func FindTopicsByNid(nid, curTid string) (topics []*model.Topic) { var err error topics, err = model.NewTopic().Where("nid=" + nid + " and tid!=" + curTid).Limit("0,10").FindAll() if err != nil { logger.Errorln("topic service FindTopicsByNid Error:", err) return } return }
// 通过tid获得话题的所有者 func getTopicOwner(tid int) int { // 帖子信息 topic := model.NewTopic() err := topic.Where("tid=" + strconv.Itoa(tid)).Find() if err != nil { logger.Errorln("topic service getTopicOwner Error:", err) return 0 } return topic.Uid }
// 更新该帖子的回复信息 // cid:评论id;objid:被评论对象id;uid:评论者;cmttime:评论时间 func (self TopicComment) UpdateComment(cid, objid, uid int, cmttime string) { tid := strconv.Itoa(objid) // 更新最后回复信息 stringBuilder := util.NewBuffer().Append("lastreplyuid=").AppendInt(uid).Append(",lastreplytime=").Append(cmttime) err := model.NewTopic().Set(stringBuilder.String()).Where("tid=" + tid).Update() if err != nil { logger.Errorln("更新帖子最后回复人信息失败:", err) } // 更新回复数(TODO:暂时每次都更新表) IncrTopicReply(tid, uid) }
// 获得社区最新公告 func FindNoticeTopic() (topic *model.Topic) { topics, err := model.NewTopic().Where("nid=15").Limit("0,1").Order("mtime DESC").FindAll() if err != nil { logger.Errorln("topic service FindTopicsByNid Error:", err) return } if len(topics) > 0 { topic = topics[0] } return }
// 获得某个用户最近的帖子 func FindRecentTopics(uid int) []*model.Topic { topics, err := model.NewTopic().Where("uid=" + strconv.Itoa(uid)).Order("ctime DESC").Limit("0, 5").FindAll() if err != nil { logger.Errorln("topic service FindRecentTopics error:", err) return nil } for _, topic := range topics { topic.Node = model.GetNodeName(topic.Nid) } return topics }
func FindTopicsByWhere(where, order, limit string) (topics []map[string]interface{}, total int) { topicObj := model.NewTopic() if where != "" { topicObj.Where(where) } if order != "" { topicObj.Order(order) } if limit != "" { topicObj.Limit(limit) } topicList, err := topicObj.FindAll() if err != nil { logger.Errorln("topic service topicObj.FindAll Error:", err) return } // 获得总帖子数 total, err = topicObj.Count() if err != nil { logger.Errorln("topic service topicObj.Count Error:", err) return } count := len(topicList) tids := make([]int, count) uids := make(map[int]int) nids := make([]int, count) for i, topic := range topicList { tids[i] = topic.Tid uids[topic.Uid] = topic.Uid if topic.Lastreplyuid != 0 { uids[topic.Lastreplyuid] = topic.Lastreplyuid } nids[i] = topic.Nid } userMap := getUserInfos(uids) // 获取节点信息 nodes := model.GetNodesName(nids) topics = make([]map[string]interface{}, count) for i, topic := range topicList { tmpMap := make(map[string]interface{}) util.Struct2Map(tmpMap, topic) tmpMap["user"] = userMap[topic.Uid] // 有人回复 if tmpMap["lastreplyuid"].(int) != 0 { tmpMap["lastreplyusername"] = userMap[tmpMap["lastreplyuid"].(int)].Username } tmpMap["node"] = nodes[tmpMap["nid"].(int)] topics[i] = tmpMap } return }
// 获取多个主题详细信息 func FindTopicsByIds(ids []int) []*model.Topic { if len(ids) == 0 { return nil } inIds := util.Join(ids, ",") topics, err := model.NewTopic().Where("tid in(" + inIds + ")").FindAll() if err != nil { logger.Errorln("topic service FindTopicsByIds error:", err) return nil } return topics }
// 获得主题详细信息(包括详细回复) // 为了避免转换,tid传string类型 func FindTopicByTid(tid string) (topicMap map[string]interface{}, replies []map[string]interface{}, err error) { condition := "tid=" + tid // 主题信息 topic := model.NewTopic() err = topic.Where(condition).Find() if err != nil { logger.Errorln("topic service FindTopicByTid Error:", err) return } // 主题不存在 if topic.Tid == 0 { err = errors.New("The topic of tid is not exists") return } topicMap = make(map[string]interface{}) util.Struct2Map(topicMap, topic) // 解析内容中的 @ topicMap["content"] = decodeTopicContent(topic) topicEx := model.NewTopicEx() err = topicEx.Where(condition).Find() if err != nil { logger.Errorln("topic service FindTopicByTid Error:", err) return } if topicEx.Tid == 0 { return } util.Struct2Map(topicMap, topicEx) // 节点名字 topicMap["node"] = GetNodeName(topic.Nid) // 回复信息(评论) replies, owerUser, lastReplyUser := FindObjComments(tid, strconv.Itoa(model.TYPE_TOPIC), topic.Uid, topic.Lastreplyuid) topicMap["user"] = owerUser // 有人回复 if topic.Lastreplyuid != 0 { topicMap["lastreplyusername"] = lastReplyUser.Username } if topic.EditorUid != 0 { topicMap["editor_username"] = FindUsernameByUid(topic.EditorUid) } return }
// 获得最近的主题(如果uid!=0,则获取某个用户最近的主题) func FindRecentTopics(uid int, limit string) []*model.Topic { cond := "" if uid != 0 { cond = "uid=" + strconv.Itoa(uid) } topics, err := model.NewTopic().Where(cond).Order("ctime DESC").Limit(limit).FindAll() if err != nil { logger.Errorln("topic service FindRecentTopics error:", err) return nil } for _, topic := range topics { topic.Node = GetNodeName(topic.Nid) } return topics }
func FindVote(tid int, uid int, ip string) (err error) { condition := "tid=" + strconv.Itoa(tid) + " and uid=" + strconv.Itoa(uid) + " and ip=" + ip // 帖子信息 topic := model.NewTopic() err = topic.Where(condition).Find() if err != nil { logger.Errorln("topic service FindTopicByTid Error:", err) return } if topic.Tid == 0 { return } logger.Traceln(topic) return }
func FindTopicPopular(tid string) (like int, hate int, err error) { condition := "tid=" + tid // 帖子信息 topic := model.NewTopic() err = topic.Where(condition).Find() if err != nil { logger.Errorln("topic service FindTopicByTid Error:", err) return } if topic.Tid == 0 { return } like = topic.Like hate = topic.Hate return }
func main() { var uid, nid int var title, content string flag.IntVar(&uid, "u", 1, "用户uid") flag.IntVar(&nid, "n", 1, "节点nid") flag.StringVar(&title, "t", "", "帖子标题") flag.StringVar(&content, "c", "", "帖子内容") flag.Parse() // 入库 topic := model.NewTopic() topic.Uid = uid topic.Nid = nid topic.Title = title topic.Content = content _, err := service.PublishTopic(topic) if err != nil { panic(err) } }
// 获得回复最多的10条帖子(TODO:避免一直显示相同的) func FindHotTopics() []map[string]interface{} { topics, err := model.NewTopic().Order("reply DESC").Limit("0,10").FindAll() if err != nil { logger.Errorln("topic service FindHotReplies error:", err) return nil } uidMap := make(map[int]int, len(topics)) for _, topic := range topics { uidMap[topic.Uid] = topic.Uid } userMap := getUserInfos(uidMap) result := make([]map[string]interface{}, len(topics)) for i, topic := range topics { oneTopic := make(map[string]interface{}) util.Struct2Map(oneTopic, topic) oneTopic["user"] = userMap[topic.Uid] result[i] = oneTopic } return result }
// 新建帖子 // uri: /topics/new{json:(|.json)} func NewTopicHandler(rw http.ResponseWriter, req *http.Request) { nodes := genNodes() vars := mux.Vars(req) content := req.FormValue("content") // 请求新建帖子页面 if content == "" || req.Method != "POST" || vars["json"] == "" { req.Form.Set(filter.CONTENT_TPL_KEY, "/template/topics/new.html") filter.SetData(req, map[string]interface{}{"nodes": nodes}) return } // 入库 topic := model.NewTopic() logger.Traceln("anonymous") logger.Traceln(req.FormValue("anonymous")) if req.FormValue("anonymous") == "1" { topic.Uid, _ = strconv.Atoi(Config["auid"]) } else { user, _ := filter.CurrentUser(req) if user != nil { topic.Uid = user["uid"].(int) } else { topic.Uid, _ = strconv.Atoi(Config["auid"]) } } logger.Traceln(topic) topic.Nid = util.MustInt(req.FormValue("nid")) topic.Title = req.FormValue("title") topic.Content = req.FormValue("content") logger.Traceln(topic) errMsg, err := service.PublishTopic(topic) logger.Traceln("PublishTopic end") logger.Traceln(errMsg) if err != nil { fmt.Fprint(rw, `{"errno": 1, "error":"`, errMsg, `"}`) return } fmt.Fprint(rw, `{"errno": 0, "error":""}`) }
// 修改主题 // user 修改人的(有可能是作者或管理员) func ModifyTopic(user map[string]interface{}, form url.Values) (errMsg string, err error) { uid := user["uid"].(int) form.Set("editor_uid", strconv.Itoa(uid)) fields := []string{"title", "content", "nid", "editor_uid"} query, args := updateSetClause(form, fields) tid := form.Get("tid") err = model.NewTopic().Set(query, args...).Where("tid=" + tid).Update() if err != nil { logger.Errorf("更新主题 【%s】 信息失败:%s\n", tid, err) errMsg = "对不起,服务器内部错误,请稍后再试!" return } username := user["username"].(string) // 修改主题,活跃度+2 go IncUserWeight("username="+username, 2) return }
// 获取话题列表(分页),目前供后台使用 func FindTopicsByPage(conds map[string]string, curPage, limit int) ([]*model.Topic, int) { conditions := make([]string, 0, len(conds)) for k, v := range conds { conditions = append(conditions, k+"="+v) } topic := model.NewTopic() limitStr := strconv.Itoa((curPage-1)*limit) + "," + strconv.Itoa(limit) topicList, err := topic.Where(strings.Join(conditions, " AND ")).Order("tid DESC").Limit(limitStr). FindAll() if err != nil { logger.Errorln("topic service FindTopicsByPage Error:", err) return nil, 0 } total, err := topic.Count() if err != nil { logger.Errorln("topic service FindTopicsByPage COUNT Error:", err) return nil, 0 } return topicList, total }
// 获得热门节点 func FindHotNodes() []map[string]interface{} { strSql := "SELECT nid, COUNT(1) AS topicnum FROM topics GROUP BY nid ORDER BY topicnum DESC LIMIT 10" rows, err := model.NewTopic().DoSql(strSql) if err != nil { logger.Errorln("topic service FindHotNodes error:", err) return nil } nodes := make([]map[string]interface{}, 0, 10) for rows.Next() { var nid, topicnum int err = rows.Scan(&nid, &topicnum) if err != nil { logger.Errorln("rows.Scan error:", err) continue } name := model.GetNodeName(nid) node := map[string]interface{}{ "name": name, "nid": nid, } nodes = append(nodes, node) } return nodes }
func GenSitemap() { sitemapFiles := []string{} // 首页 home := map[string]string{ "loc": "http://" + config.Config["domain"], "lastmode": time.Now().Format(time.RFC3339), } var ( little = 1 step = 4999 large = little + step ) // 文章 article := model.NewArticle() for { sitemapFile := "sitemap_article_" + strconv.Itoa(large) + ".xml" articles, err := article.Where("id BETWEEN ? AND ? AND status!=?", little, large, model.StatusOffline).FindAll("id", "mtime") little = large + 1 large = little + step if err != nil { continue } if len(articles) == 0 { break } data := map[string]interface{}{ "home": home, "articles": articles, } if err = output(sitemapFile, data); err == nil { sitemapFiles = append(sitemapFiles, sitemapFile) } } little = 1 large = little + step // 主题(帖子) topic := model.NewTopic() for { sitemapFile := "sitemap_topic_" + strconv.Itoa(large) + ".xml" topics, err := topic.Where("tid BETWEEN ? AND ? AND flag IN(?,?)", little, large, 0, 1).FindAll("tid", "mtime") little, large = large+1, little+step if err != nil { continue } if len(topics) == 0 { break } data := map[string]interface{}{ "home": home, "topics": topics, } if err = output(sitemapFile, data); err == nil { sitemapFiles = append(sitemapFiles, sitemapFile) } } little = 1 large = little + step // 资源 resource := model.NewResource() for { sitemapFile := "sitemap_resource_" + strconv.Itoa(large) + ".xml" resources, err := resource.Where("id BETWEEN ? AND ?", little, large).FindAll("id", "mtime") little, large = large+1, little+step if err != nil { continue } if len(resources) == 0 { break } data := map[string]interface{}{ "home": home, "resources": resources, } if err = output(sitemapFile, data); err == nil { sitemapFiles = append(sitemapFiles, sitemapFile) } } little = 1 large = little + step // 项目 project := model.NewOpenProject() for { sitemapFile := "sitemap_project_" + strconv.Itoa(large) + ".xml" projects, err := project.Where("id BETWEEN ? AND ? AND status=?", little, large, model.StatusOnline).FindAll("id", "uri", "mtime") little, large = large+1, little+step if err != nil { continue } if len(projects) == 0 { break } data := map[string]interface{}{ "home": home, "projects": projects, } if err = output(sitemapFile, data); err == nil { sitemapFiles = append(sitemapFiles, sitemapFile) } } little = 1 large = little + step // wiki wiki := model.NewWiki() for { sitemapFile := "sitemap_wiki_" + strconv.Itoa(large) + ".xml" wikis, err := wiki.Where("id BETWEEN ? AND ?", little, large).FindAll("id", "uri", "mtime") little, large = large+1, little+step if err != nil { continue } if len(wikis) == 0 { break } data := map[string]interface{}{ "home": home, "wikis": wikis, } if err = output(sitemapFile, data); err == nil { sitemapFiles = append(sitemapFiles, sitemapFile) } } file, err := os.Create(sitemapPath + "sitemapindex.xml") if err != nil { logger.Errorln("gen sitemap index file error:", err) return } defer file.Close() err = sitemapIndexTpl.Execute(file, map[string]interface{}{ "home": home, "sitemapFiles": sitemapFiles, }) if err != nil { logger.Errorln("execute sitemap index template error:", err) } }
// 发布主题。入topics和topics_ex库 func PublishTopic(user map[string]interface{}, form url.Values) (err error) { uid := user["uid"].(int) topic := model.NewTopic() if form.Get("tid") != "" { err = topic.Where("tid=?", form.Get("tid")).Find() if err != nil { logger.Errorln("Publish Topic find error:", err) return } isAdmin := false if _, ok := user["isadmin"]; ok { isAdmin = user["isadmin"].(bool) } if topic.Uid != uid && !isAdmin { err = NotModifyAuthorityErr return } _, err = ModifyTopic(user, form) if err != nil { logger.Errorln("Publish Topic error:", err) return } } else { util.ConvertAssign(topic, form) topic.Uid = uid topic.Ctime = util.TimeNow() var tid int tid, err = topic.Insert() if err != nil { logger.Errorln("Publish Topic error:", err) return } // 存扩展信息 topicEx := model.NewTopicEx() topicEx.Tid = tid _, err = topicEx.Insert() if err != nil { logger.Errorln("Insert TopicEx error:", err) return } // 给 被@用户 发系统消息 ext := map[string]interface{}{ "objid": tid, "objtype": model.TYPE_TOPIC, "uid": user["uid"], "msgtype": model.MsgtypePublishAtMe, } go SendSysMsgAtUsernames(form.Get("usernames"), ext) // 发布主题,活跃度+10 go IncUserWeight("uid="+strconv.Itoa(uid), 10) } return }
// 订阅邮件通知 func EmailNotice() { beginDate := time.Now().Add(-7 * 24 * time.Hour).Format("2006-01-02") endDate := time.Now().Add(-24 * time.Hour).Format("2006-01-02") beginTime := beginDate + " 00:00:00" // 本周晨读(过去 7 天) readings, err := model.NewMorningReading().Where("ctime>? AND rtype=0", beginTime).Order("id DESC").FindAll() if err != nil { logger.Errorln("find morning reading error:", err) } // 本周精彩文章 articles, err := model.NewArticle().Where("ctime>? AND status!=2", beginTime).Order("cmtnum DESC, likenum DESC, viewnum DESC").Limit("10").FindAll() if err != nil { logger.Errorln("find article error:", err) } // 本周热门主题 topics, err := model.NewTopic().Where("ctime>? AND flag IN(0,1)", beginTime).Order("tid DESC").Limit("10").FindAll() if err != nil { logger.Errorln("find topic error:", err) } data := map[string]interface{}{ "readings": readings, "articles": articles, "topics": topics, "beginDate": beginDate, "endDate": endDate, } // 给所有用户发送邮件 userModel := model.NewUser() var ( lastUid = 0 limit = "500" users []*model.User ) for { users, err = userModel.Where("uid>?", lastUid).Order("uid ASC").Limit(limit).FindAll() if err != nil { logger.Errorln("find user error:", err) continue } if len(users) == 0 { break } for _, user := range users { if user.Unsubscribe == 1 { logger.Infoln("user unsubscribe", user) continue } data["email"] = user.Email data["token"] = GenUnsubscribeToken(user) content, err := genEmailContent(data) if err != nil { logger.Errorln("from email.html gen email content error:", err) continue } SendMail("每周精选", content, []string{user.Email}) if lastUid < user.Uid { lastUid = user.Uid } // 控制发信速度 time.Sleep(30 * time.Second) } } }