2018-02-22 02:27:17 +00:00
|
|
|
package routes
|
|
|
|
|
|
|
|
import (
|
|
|
|
"database/sql"
|
|
|
|
"net/http"
|
|
|
|
"strconv"
|
|
|
|
|
2019-04-19 06:36:26 +00:00
|
|
|
c "github.com/Azareal/Gosora/common"
|
2018-10-27 03:21:02 +00:00
|
|
|
"github.com/Azareal/Gosora/common/counters"
|
2019-10-01 21:06:22 +00:00
|
|
|
p "github.com/Azareal/Gosora/common/phrases"
|
|
|
|
qgen "github.com/Azareal/Gosora/query_gen"
|
2018-02-22 02:27:17 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
type ForumStmts struct {
|
|
|
|
getTopics *sql.Stmt
|
|
|
|
}
|
|
|
|
|
|
|
|
var forumStmts ForumStmts
|
|
|
|
|
|
|
|
// TODO: Move these DbInits into *Forum as Topics()
|
|
|
|
func init() {
|
2019-04-19 06:36:26 +00:00
|
|
|
c.DbInits.Add(func(acc *qgen.Accumulator) error {
|
2018-02-22 02:27:17 +00:00
|
|
|
forumStmts = ForumStmts{
|
2018-12-27 05:42:41 +00:00
|
|
|
getTopics: acc.Select("topics").Columns("tid, title, content, createdBy, is_closed, sticky, createdAt, lastReplyAt, lastReplyBy, lastReplyID, parentID, views, postCount, likeCount").Where("parentID = ?").Orderby("sticky DESC, lastReplyAt DESC, createdBy DESC").Limit("?,?").Prepare(),
|
2018-02-22 02:27:17 +00:00
|
|
|
}
|
|
|
|
return acc.FirstError()
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2019-02-10 05:52:26 +00:00
|
|
|
// TODO: Retire this in favour of an alias for /topics/?
|
2019-04-19 06:36:26 +00:00
|
|
|
func ViewForum(w http.ResponseWriter, r *http.Request, user c.User, header *c.Header, sfid string) c.RouteError {
|
2018-02-22 02:27:17 +00:00
|
|
|
page, _ := strconv.Atoi(r.FormValue("page"))
|
2018-11-12 09:23:36 +00:00
|
|
|
_, fid, err := ParseSEOURL(sfid)
|
2018-02-22 02:27:17 +00:00
|
|
|
if err != nil {
|
2019-10-01 21:06:22 +00:00
|
|
|
return c.SimpleError(p.GetErrorPhrase("url_id_must_be_integer"), w, r, header)
|
2018-02-22 02:27:17 +00:00
|
|
|
}
|
|
|
|
|
2019-04-19 06:36:26 +00:00
|
|
|
ferr := c.ForumUserCheck(header, w, r, &user, fid)
|
2018-02-22 02:27:17 +00:00
|
|
|
if ferr != nil {
|
|
|
|
return ferr
|
|
|
|
}
|
|
|
|
if !user.Perms.ViewTopic {
|
2019-04-19 06:36:26 +00:00
|
|
|
return c.NoPermissions(w, r, user)
|
2018-02-22 02:27:17 +00:00
|
|
|
}
|
2018-12-08 06:49:14 +00:00
|
|
|
header.Path = "/forums/"
|
2018-02-22 02:27:17 +00:00
|
|
|
|
|
|
|
// TODO: Fix this double-check
|
2019-04-19 06:36:26 +00:00
|
|
|
forum, err := c.Forums.Get(fid)
|
2018-02-22 02:27:17 +00:00
|
|
|
if err == sql.ErrNoRows {
|
2019-04-19 06:36:26 +00:00
|
|
|
return c.NotFound(w, r, header)
|
2018-02-22 02:27:17 +00:00
|
|
|
} else if err != nil {
|
2019-04-19 06:36:26 +00:00
|
|
|
return c.InternalError(err, w, r)
|
2018-02-22 02:27:17 +00:00
|
|
|
}
|
2018-05-27 09:36:35 +00:00
|
|
|
header.Title = forum.Name
|
2019-02-24 08:02:00 +00:00
|
|
|
header.OGDesc = forum.Desc
|
2018-02-22 02:27:17 +00:00
|
|
|
|
|
|
|
// TODO: Does forum.TopicCount take the deleted items into consideration for guests? We don't have soft-delete yet, only hard-delete
|
2019-04-19 06:36:26 +00:00
|
|
|
offset, page, lastPage := c.PageOffset(forum.TopicCount, page, c.Config.ItemsPerPage)
|
2018-02-22 02:27:17 +00:00
|
|
|
|
|
|
|
// TODO: Move this to *Forum
|
2019-04-19 06:36:26 +00:00
|
|
|
rows, err := forumStmts.getTopics.Query(fid, offset, c.Config.ItemsPerPage)
|
2018-02-22 02:27:17 +00:00
|
|
|
if err != nil {
|
2019-04-19 06:36:26 +00:00
|
|
|
return c.InternalError(err, w, r)
|
2018-02-22 02:27:17 +00:00
|
|
|
}
|
|
|
|
defer rows.Close()
|
|
|
|
|
|
|
|
// TODO: Use something other than TopicsRow as we don't need to store the forum name and link on each and every topic item?
|
2019-04-19 06:36:26 +00:00
|
|
|
var topicList []*c.TopicsRow
|
2019-10-01 21:06:22 +00:00
|
|
|
reqUserList := make(map[int]bool)
|
2018-02-22 02:27:17 +00:00
|
|
|
for rows.Next() {
|
2019-10-01 21:06:22 +00:00
|
|
|
t := c.TopicsRow{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.ParentID, &t.ViewCount, &t.PostCount, &t.LikeCount)
|
2018-02-22 02:27:17 +00:00
|
|
|
if err != nil {
|
2019-04-19 06:36:26 +00:00
|
|
|
return c.InternalError(err, w, r)
|
2018-02-22 02:27:17 +00:00
|
|
|
}
|
|
|
|
|
2019-10-01 21:06:22 +00:00
|
|
|
t.Link = c.BuildTopicURL(c.NameToSlug(t.Title), t.ID)
|
2018-12-17 04:58:55 +00:00
|
|
|
// TODO: Create a specialised function with a bit less overhead for getting the last page for a post count
|
2019-10-01 21:06:22 +00:00
|
|
|
_, _, lastPage := c.PageOffset(t.PostCount, 1, c.Config.ItemsPerPage)
|
|
|
|
t.LastPage = lastPage
|
2018-02-22 02:27:17 +00:00
|
|
|
|
2019-10-01 21:06:22 +00:00
|
|
|
header.Hooks.VhookNoRet("forum_trow_assign", &t, &forum)
|
|
|
|
topicList = append(topicList, &t)
|
|
|
|
reqUserList[t.CreatedBy] = true
|
|
|
|
reqUserList[t.LastReplyBy] = true
|
2018-02-22 02:27:17 +00:00
|
|
|
}
|
|
|
|
err = rows.Err()
|
|
|
|
if err != nil {
|
2019-04-19 06:36:26 +00:00
|
|
|
return c.InternalError(err, w, r)
|
2018-02-22 02:27:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Convert the user ID map to a slice, then bulk load the users
|
2019-10-01 21:06:22 +00:00
|
|
|
idSlice := make([]int, len(reqUserList))
|
2018-02-22 02:27:17 +00:00
|
|
|
var i int
|
|
|
|
for userID := range reqUserList {
|
|
|
|
idSlice[i] = userID
|
|
|
|
i++
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: What if a user is deleted via the Control Panel?
|
2019-04-19 06:36:26 +00:00
|
|
|
userList, err := c.Users.BulkGetMap(idSlice)
|
2018-02-22 02:27:17 +00:00
|
|
|
if err != nil {
|
2019-04-19 06:36:26 +00:00
|
|
|
return c.InternalError(err, w, r)
|
2018-02-22 02:27:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Second pass to the add the user data
|
|
|
|
// TODO: Use a pointer to TopicsRow instead of TopicsRow itself?
|
2019-10-01 21:06:22 +00:00
|
|
|
for _, t := range topicList {
|
|
|
|
t.Creator = userList[t.CreatedBy]
|
|
|
|
t.LastUser = userList[t.LastReplyBy]
|
2018-02-22 02:27:17 +00:00
|
|
|
}
|
2019-02-10 05:52:26 +00:00
|
|
|
header.Zone = "view_forum"
|
|
|
|
header.ZoneID = forum.ID
|
|
|
|
|
|
|
|
// TODO: Reduce the amount of boilerplate here
|
|
|
|
if r.FormValue("js") == "1" {
|
2019-02-10 09:32:05 +00:00
|
|
|
outBytes, err := wsTopicList(topicList, lastPage).MarshalJSON()
|
2019-02-10 05:52:26 +00:00
|
|
|
if err != nil {
|
2019-04-19 06:36:26 +00:00
|
|
|
return c.InternalError(err, w, r)
|
2019-02-10 05:52:26 +00:00
|
|
|
}
|
|
|
|
w.Write(outBytes)
|
|
|
|
return nil
|
|
|
|
}
|
2018-02-22 02:27:17 +00:00
|
|
|
|
2019-06-04 05:48:12 +00:00
|
|
|
pageList := c.Paginate(page, lastPage, 5)
|
2019-04-19 06:36:26 +00:00
|
|
|
pi := c.ForumPage{header, topicList, forum, c.Paginator{pageList, page, lastPage}}
|
2019-06-01 12:31:48 +00:00
|
|
|
tmpl := forum.Tmpl
|
2019-05-27 09:00:40 +00:00
|
|
|
if tmpl == "" {
|
2019-06-01 12:31:48 +00:00
|
|
|
ferr = renderTemplate("forum", w, r, header, pi)
|
|
|
|
} else {
|
2019-10-01 21:06:22 +00:00
|
|
|
tmpl = "forum_" + tmpl
|
|
|
|
err = renderTemplate3(tmpl, tmpl, w, r, header, pi)
|
2019-06-01 12:31:48 +00:00
|
|
|
if err != nil {
|
|
|
|
ferr = renderTemplate("forum", w, r, header, pi)
|
|
|
|
}
|
2019-05-27 09:00:40 +00:00
|
|
|
}
|
2018-02-22 02:27:17 +00:00
|
|
|
counters.ForumViewCounter.Bump(forum.ID)
|
2018-11-12 09:23:36 +00:00
|
|
|
return ferr
|
2018-02-22 02:27:17 +00:00
|
|
|
}
|