diff --git a/common/template_init.go b/common/template_init.go index 1b8fc2d5..1020cb6d 100644 --- a/common/template_init.go +++ b/common/template_init.go @@ -227,7 +227,8 @@ func compileCommons(c *tmpl.CTemplateSet, head, head2 *Header, forumList []Forum }*/ var topicsList []TopicsRowMut - topicsList = append(topicsList, TopicsRowMut{&TopicsRow{1, "topic-title", "Topic Title", "The topic content.", 1, false, false, now, now, user3.ID, 1, 1, "", "::1", 1, 0, 1, 1, 0, "classname", 0, "", user2, "", 0, user3, "General", "/forum/general.2", nil}, false}) + topic := Topic{1, "/topic/topic-title.1","Topic Title", "The topic content.", 1, false, false, now, now, user3.ID, 1, 1, "", "::1", 1, 0, 1, 1, "classname",0,"",nil} + topicsList = append(topicsList, TopicsRowMut{&TopicsRow{topic,1, user2, "", 0, user3, "General", "/forum/general.2"}, false}) topicListPage := TopicListPage{htitle("Topic List"), topicsList, forumList, Config.DefaultForum, TopicListSort{"lastupdated", false}, QuickTools{false, false, false}, Paginator{[]int{1}, 1, 1}} o.Add("topics", "c.TopicListPage", topicListPage) o.Add("topics_mini", "c.TopicListPage", topicListPage) @@ -243,14 +244,14 @@ func compileCommons(c *tmpl.CTemplateSet, head, head2 *Header, forumList []Forum }, VoteCount: 7} avatar, microAvatar := BuildAvatar(62, "") miniAttach := []*MiniAttachment{&MiniAttachment{Path: "/"}} - topic := TopicUser{1, "blah", "Blah", "Hey there!", 0, false, false, now, now, 1, 1, 0, "", "127.0.0.1", 1, 0, 1, 0, "classname", poll.ID, "weird-data", BuildProfileURL("fake-user", 62), "Fake User", Config.DefaultGroup, avatar, microAvatar, 0, "", "", "", 58, false, miniAttach, nil, false} + tu := TopicUser{1, "blah", "Blah", "Hey there!", 0, false, false, now, now, 1, 1, 0, "", "127.0.0.1", 1, 0, 1, 0, "classname", poll.ID, "weird-data", BuildProfileURL("fake-user", 62), "Fake User", Config.DefaultGroup, avatar, microAvatar, 0, "", "", "", 58, false, miniAttach, nil, false} var replyList []*ReplyUser reply := Reply{1, 1, "Yo!", 1 /*, Config.DefaultGroup*/, now, 0, 0, 1, "::1", true, 1, 1, ""} ru := &ReplyUser{ClassName: "", Reply: reply, CreatedByName: "Alice", Avatar: avatar, Group: Config.DefaultGroup, Level: 0, Attachments: miniAttach} ru.Init(user2) replyList = append(replyList, ru) - tpage := TopicPage{htitle("Topic Name"), replyList, topic, &Forum{ID: 1, Name: "Hahaha"}, &poll, Paginator{[]int{1}, 1, 1}} + tpage := TopicPage{htitle("Topic Name"), replyList, tu, &Forum{ID: 1, Name: "Hahaha"}, &poll, Paginator{[]int{1}, 1, 1}} tpage.Forum.Link = BuildForumURL(NameToSlug(tpage.Forum.Name), tpage.Forum.ID) o.Add("topic", "c.TopicPage", tpage) o.Add("topic_mini", "c.TopicPage", tpage) @@ -310,7 +311,8 @@ func compileTemplates(wg *sync.WaitGroup, c *tmpl.CTemplateSet, themeName string t.Add("profile", "c.ProfilePage", ppage) var topicsList []TopicsRowMut - topicsList = append(topicsList, TopicsRowMut{&TopicsRow{1, "topic-title", "Topic Title", "The topic content.", 1, false, false, now, now, user3.ID, 1, 1, "", "127.0.0.1", 1, 0, 1, 1, 0, "classname", 0, "", user2, "", 0, user3, "General", "/forum/general.2", nil}, false}) + topic := Topic{1, "topic-title", "Topic Title", "The topic content.", 1, false, false, now, now, user3.ID, 1, 1, "", "::1", 1, 0, 1, 1, "classname",0,"",nil} + topicsList = append(topicsList, TopicsRowMut{&TopicsRow{topic,0, user2, "", 0, user3, "General", "/forum/general.2"}, false}) topicListPage := TopicListPage{htitle("Topic List"), topicsList, forumList, Config.DefaultForum, TopicListSort{"lastupdated", false}, QuickTools{false, false, false}, Paginator{[]int{1}, 1, 1}} forumItem := BlankForum(1, "general-forum.1", "General Forum", "Where the general stuff happens", true, "all", 0, "", 0) @@ -349,7 +351,7 @@ func compileTemplates(wg *sync.WaitGroup, c *tmpl.CTemplateSet, themeName string } t.AddStd("login", "c.Page", Page{htitle("Login Page"), tList, nil}) - t.AddStd("register", "c.RegisterPage", RegisterPage{htitle("Registration Page"), false, ""}) + t.AddStd("register", "c.RegisterPage", RegisterPage{htitle("Registration Page"), false, "",[]RegisterVerify{RegisterVerify{true,&RegisterVerifyImageGrid{"What?",[]RegisterVerifyImageGridImage{RegisterVerifyImageGridImage{"something.png"}}}}}}) t.AddStd("error", "c.ErrorPage", ErrorPage{htitle("Error"), "A problem has occurred in the system."}) ipSearchPage := IPSearchPage{htitle("IP Search"), map[int]*User{1: user2}, "::1"} @@ -538,7 +540,8 @@ func compileJSTemplates(wg *sync.WaitGroup, c *tmpl.CTemplateSet, themeName stri t := TItemHold(make(map[string]TItem)) - topicsRow := TopicsRowMut{&TopicsRow{1, "topic-title", "Topic Title", "The topic content.", 1, false, false, now, now, user3.ID, 1, 1, "", "::1", 1, 0, 1, 0, 1, "classname", 0, "", user2, "", 0, user3, "General", "/forum/general.2", nil}, false} + topic := Topic{1, "topic-title", "Topic Title", "The topic content.", 1, false, false, now, now, user3.ID, 1, 1, "", "::1", 1, 0, 1, 0, "classname",1,"",nil} + topicsRow := TopicsRowMut{&TopicsRow{topic, 0, user2, "", 0, user3, "General", "/forum/general.2"}, false} t.AddStd("topics_topic", "c.TopicsRowMut", topicsRow) poll := Poll{ID: 1, Type: 0, Options: map[int]string{0: "Nothing", 1: "Something"}, Results: map[int]int{0: 5, 1: 2}, QuickOptions: []PollOption{ @@ -547,7 +550,7 @@ func compileJSTemplates(wg *sync.WaitGroup, c *tmpl.CTemplateSet, themeName stri }, VoteCount: 7} avatar, microAvatar := BuildAvatar(62, "") miniAttach := []*MiniAttachment{&MiniAttachment{Path: "/"}} - topic := TopicUser{1, "blah", "Blah", "Hey there!", 62, false, false, now, now, 1, 1, 0, "", "::1", 1, 0, 1, 0, "classname", poll.ID, "weird-data", BuildProfileURL("fake-user", 62), "Fake User", Config.DefaultGroup, avatar, microAvatar, 0, "", "", "", 58, false, miniAttach, nil, false} + tu := TopicUser{1, "blah", "Blah", "Hey there!", 62, false, false, now, now, 1, 1, 0, "", "::1", 1, 0, 1, 0, "classname", poll.ID, "weird-data", BuildProfileURL("fake-user", 62), "Fake User", Config.DefaultGroup, avatar, microAvatar, 0, "", "", "", 58, false, miniAttach, nil, false} var replyList []*ReplyUser // TODO: Do we really want the UID here to be zero? avatar, microAvatar = BuildAvatar(0, "") @@ -558,7 +561,7 @@ func compileJSTemplates(wg *sync.WaitGroup, c *tmpl.CTemplateSet, themeName stri varList = make(map[string]tmpl.VarItem) header.Title = "Topic Name" - tpage := TopicPage{header, replyList, topic, &Forum{ID: 1, Name: "Hahaha"}, &poll, Paginator{[]int{1}, 1, 1}} + tpage := TopicPage{header, replyList, tu, &Forum{ID: 1, Name: "Hahaha"}, &poll, Paginator{[]int{1}, 1, 1}} tpage.Forum.Link = BuildForumURL(NameToSlug(tpage.Forum.Name), tpage.Forum.ID) t.AddStd("topic_posts", "c.TopicPage", tpage) t.AddStd("topic_alt_posts", "c.TopicPage", tpage) diff --git a/common/topic.go b/common/topic.go index 69a8238c..809e0b56 100644 --- a/common/topic.go +++ b/common/topic.go @@ -39,7 +39,7 @@ type Topic struct { LastReplyBy int LastReplyID int ParentID int - Status string // Deprecated. Marked for removal. + Status string // Deprecated. Marked for removal. -Is there anything we could use it for? IP string ViewCount int64 PostCount int @@ -101,28 +101,8 @@ type TopicsRowMut struct { // TODO: Embed TopicUser to simplify this structure and it's related logic? type TopicsRow struct { - ID int - Link string - Title string - Content string - CreatedBy int - IsClosed bool - Sticky bool - CreatedAt time.Time - LastReplyAt time.Time - LastReplyBy int - LastReplyID int - ParentID int - Status string // Deprecated. Marked for removal. -Is there anything we could use it for? - IP string - ViewCount int64 - PostCount int - LikeCount int - AttachCount int - LastPage int - ClassName string - Poll int - Data string // Used for report metadata + Topic + LastPage int Creator *User CSS template.CSS @@ -131,7 +111,6 @@ type TopicsRow struct { ForumName string //TopicsRow ForumLink string - Rids []int } type WsTopicsRow struct { @@ -179,13 +158,15 @@ func (t *Topic) TopicsRow() *TopicsRow { forumName := "" forumLink := "" - return &TopicsRow{t.ID, t.Link, t.Title, t.Content, t.CreatedBy, t.IsClosed, t.Sticky, t.CreatedAt, t.LastReplyAt, t.LastReplyBy, t.LastReplyID, t.ParentID, t.Status, t.IP, t.ViewCount, t.PostCount, t.LikeCount, t.AttachCount, lastPage, t.ClassName, t.Poll, t.Data, creator, "", contentLines, lastUser, forumName, forumLink, t.Rids} + //return &TopicsRow{t.ID, t.Link, t.Title, t.Content, t.CreatedBy, t.IsClosed, t.Sticky, t.CreatedAt, t.LastReplyAt, t.LastReplyBy, t.LastReplyID, t.ParentID, t.Status, t.IP, t.ViewCount, t.PostCount, t.LikeCount, t.AttachCount, lastPage, t.ClassName, t.Poll, t.Data, creator, "", contentLines, lastUser, forumName, forumLink, t.Rids} + return &TopicsRow{*t, lastPage, creator, "", contentLines, lastUser, forumName, forumLink} } // ! Some data may be lost in the conversion -func (t *TopicsRow) Topic() *Topic { - return &Topic{t.ID, t.Link, t.Title, t.Content, t.CreatedBy, t.IsClosed, t.Sticky, t.CreatedAt, t.LastReplyAt, t.LastReplyBy, t.LastReplyID, t.ParentID, t.Status, t.IP, t.ViewCount, t.PostCount, t.LikeCount, t.AttachCount, t.ClassName, t.Poll, t.Data, t.Rids} -} +/*func (t *TopicsRow) Topic() *Topic { + //return &Topic{t.ID, t.Link, t.Title, t.Content, t.CreatedBy, t.IsClosed, t.Sticky, t.CreatedAt, t.LastReplyAt, t.LastReplyBy, t.LastReplyID, t.ParentID, t.Status, t.IP, t.ViewCount, t.PostCount, t.LikeCount, t.AttachCount, t.ClassName, t.Poll, t.Data, t.Rids} + return &t.Topic +}*/ // ! Not quite safe as Topic doesn't contain all the data needed to constructs a WsTopicsRow /*func (t *Topic) WsTopicsRows() *WsTopicsRow { @@ -864,6 +845,12 @@ func (t *TopicUser) Replies(offset int /*pFrag int, */, user *User) (rlist []*Re //log.Printf("r: %d-%d", r.ID, len(rlist)-1) } else { //log.Print("reply query serve") + ap1 := func(r *ReplyUser) { + H_topic_reply_row_assign_hook(hTbl, r) + // TODO: Use a pointer instead to make it easier to abstract this loop? What impact would this have on escape analysis? + rlist = append(rlist, r) + //log.Printf("r: %d-%d", r.ID, len(rlist)-1) + } rf2 := func(r *ReplyUser) { if r.LikeCount > 0 && user.Liked > 0 { if likedMap == nil { @@ -883,31 +870,27 @@ func (t *TopicUser) Replies(offset int /*pFrag int, */, user *User) (rlist []*Re attachQueryList = append(attachQueryList, r.ID) } } - - H_topic_reply_row_assign_hook(hTbl, r) - // TODO: Use a pointer instead to make it easier to abstract this loop? What impact would this have on escape analysis? - rlist = append(rlist, r) - //log.Printf("r: %d-%d", r.ID, len(rlist)-1) } if !user.Perms.ViewIPs && ruser != nil { - rows, err := topicStmts.getReplies3.Query(t.ID, offset, Config.ItemsPerPage) + rows, e := topicStmts.getReplies3.Query(t.ID, offset, Config.ItemsPerPage) if err != nil { - return nil, externalHead, err + return nil, externalHead, e } defer rows.Close() for rows.Next() { r := &ReplyUser{Avatar: ruser.Avatar, MicroAvatar: ruser.MicroAvatar, UserLink: ruser.Link, CreatedByName: ruser.Name, Group: ruser.Group, Level: ruser.Level} - err := rows.Scan(&r.ID, &r.Content, &r.CreatedBy, &r.CreatedAt, &r.LastEdit, &r.LastEditBy, &r.LikeCount, &r.AttachCount, &r.ActionType) - if err != nil { - return nil, externalHead, err + e := rows.Scan(&r.ID, &r.Content, &r.CreatedBy, &r.CreatedAt, &r.LastEdit, &r.LastEditBy, &r.LikeCount, &r.AttachCount, &r.ActionType) + if e != nil { + return nil, externalHead, e } - if err = rf3(r); err != nil { - return nil, externalHead, err + if e = rf3(r); e != nil { + return nil, externalHead, e } rf2(r) + ap1(r) } - if err = rows.Err(); err != nil { - return nil, externalHead, err + if e = rows.Err(); e != nil { + return nil, externalHead, e } } else if user.Perms.ViewIPs { rows, err := topicStmts.getReplies.Query(t.ID, offset, Config.ItemsPerPage) @@ -925,11 +908,13 @@ func (t *TopicUser) Replies(offset int /*pFrag int, */, user *User) (rlist []*Re return nil, externalHead, err } rf2(r) + ap1(r) } if err = rows.Err(); err != nil { return nil, externalHead, err } } else if t.PostCount >= 20 { + //log.Print("t.PostCount >= 20") rows, err := topicStmts.getReplies3.Query(t.ID, offset, Config.ItemsPerPage) if err != nil { return nil, externalHead, err @@ -945,12 +930,14 @@ func (t *TopicUser) Replies(offset int /*pFrag int, */, user *User) (rlist []*Re if r.CreatedBy != t.CreatedBy && r.CreatedBy != user.ID { reqUserList[r.CreatedBy] = true } + ap1(r) } if err = rows.Err(); err != nil { return nil, externalHead, err } if len(reqUserList) == 1 { + //log.Print("len(reqUserList) == 1: ", len(reqUserList) == 1) var uitem *User for uid, _ := range reqUserList { uitem, err = Users.Get(uid) @@ -984,8 +971,10 @@ func (t *TopicUser) Replies(offset int /*pFrag int, */, user *User) (rlist []*Re rf2(r) } } else { + //log.Print("len(reqUserList) != 1: ", len(reqUserList) != 1) var userList map[int]*User if len(reqUserList) > 0 { + //log.Print("len(reqUserList) > 0: ", len(reqUserList) > 0) // Convert the user ID map to a slice, then bulk load the users idSlice := make([]int, len(reqUserList)) var i int @@ -1026,6 +1015,7 @@ func (t *TopicUser) Replies(offset int /*pFrag int, */, user *User) (rlist []*Re } } } else { + //log.Print("reply fallback") rows, err := topicStmts.getReplies2.Query(t.ID, offset, Config.ItemsPerPage) if err != nil { return nil, externalHead, err @@ -1041,6 +1031,7 @@ func (t *TopicUser) Replies(offset int /*pFrag int, */, user *User) (rlist []*Re return nil, externalHead, err } rf2(r) + ap1(r) } if err = rows.Err(); err != nil { return nil, externalHead, err diff --git a/common/topic_list.go b/common/topic_list.go index 418bc567..71f7c6d2 100644 --- a/common/topic_list.go +++ b/common/topic_list.go @@ -309,7 +309,7 @@ func (tList *DefaultTopicList) GetListByForum(f *Forum, page, orderby int) (topi // TODO: Use something other than TopicsRow as we don't need to store the forum name and link on each and every topic item? reqUserList := make(map[int]bool) for rows.Next() { - t := TopicsRow{ID: 0} + t := TopicsRow{Topic:Topic{ID: 0}} err := rows.Scan(&t.ID, &t.Title, &t.Content, &t.CreatedBy, &t.IsClosed, &t.Sticky, &t.CreatedAt, &t.LastReplyAt, &t.LastReplyBy, &t.LastReplyID, &t.ViewCount, &t.PostCount, &t.LikeCount) if err != nil { return nil, Paginator{nil, 1, 1}, err @@ -391,7 +391,7 @@ func (tList *DefaultTopicList) GetListByCanSee(canSee []int, page, orderby int, f := Forums.DirtyGet(fid) if f.Name != "" && f.Active && (f.ParentType == "" || f.ParentType == "forum") && f.TopicCount != 0 { fcopy := f.Copy() - // TODO: Add a hook here for plugin_guilds + // TODO: Add a hook here for plugin_guilds !! forumList = append(forumList, fcopy) } } @@ -592,8 +592,9 @@ func (tList *DefaultTopicList) getList(page, orderby, topicCount int, argList [] } if tc != nil { - if _, err := tc.Get(t.ID); err == sql.ErrNoRows { - _ = tc.Set(t.Topic()) + if _, e := tc.Get(t.ID); e == sql.ErrNoRows { + //_ = tc.Set(t.Topic()) + _ = tc.Set(&t.Topic) } } } @@ -601,25 +602,40 @@ func (tList *DefaultTopicList) getList(page, orderby, topicCount int, argList [] return nil, Paginator{nil, 1, 1}, err } - // Convert the user ID map to a slice, then bulk load the users - idSlice := make([]int, len(reqUserList)) - var i int - for userID := range reqUserList { - idSlice[i] = userID - i++ - } + // TODO: specialcase for when reqUserList only has one or two items to avoid map alloc + if len(reqUserList) == 1 { + var u *User + for uid, _ := range reqUserList { + u, err = Users.Get(uid) + if err != nil { + return nil, Paginator{nil, 1, 1}, err + } + } + for _, t := range topicList { + t.Creator = u + t.LastUser = u + } + } else if len(reqUserList) > 0 { + // Convert the user ID map to a slice, then bulk load the users + idSlice := make([]int, len(reqUserList)) + var i int + for userID := range reqUserList { + idSlice[i] = userID + i++ + } - // TODO: What if a user is deleted via the Control Panel? - userList, err := Users.BulkGetMap(idSlice) - if err != nil { - return nil, Paginator{nil, 1, 1}, err - } + // TODO: What if a user is deleted via the Control Panel? + userList, err := Users.BulkGetMap(idSlice) + if err != nil { + return nil, Paginator{nil, 1, 1}, err + } - // Second pass to the add the user data - // TODO: Use a pointer to TopicsRow instead of TopicsRow itself? - for _, t := range topicList { - t.Creator = userList[t.CreatedBy] - t.LastUser = userList[t.LastReplyBy] + // Second pass to the add the user data + // TODO: Use a pointer to TopicsRow instead of TopicsRow itself? + for _, t := range topicList { + t.Creator = userList[t.CreatedBy] + t.LastUser = userList[t.LastReplyBy] + } } pageList := Paginate(page, lastPage, 5)