b9973719a5
Preloaded a small number of users and topics. Use cache.Set instead of cache.Add in a few spots for topics to avoid issues with the counter falling out of sync with the cache length. Embed Reply in ReplyUser instead of duplicating the same fields. Add the missing AttachCount and ActionType fields to Reply. Add the missing Poll field to TopicsRow. Added the TopicUser.Replies method to better abstract the reply list generation logic. Shortened some common.s to c.s Moved memStuff out of the analytics memory panes and into analytics.js Removed the temporary preStats fix for label overflow now that we have a better solution. Added the panel_analytics_script_memory template to help de-dupe logic in the analytics memory panes. Added the Topic method to TopicsRow. Added the GetRidsForTopic method to help cache replies in a small set of scenarios. Added the ReplyCache config.json setting. Added the ReplyCacheCapacity config.json setting. Added a parser test case. Added more Reply and ReplyStore related test cases.
114 lines
3.5 KiB
Go
114 lines
3.5 KiB
Go
package routes
|
|
|
|
import (
|
|
"database/sql"
|
|
"net/http"
|
|
"time"
|
|
|
|
c "github.com/Azareal/Gosora/common"
|
|
"github.com/Azareal/Gosora/common/phrases"
|
|
"github.com/Azareal/Gosora/query_gen"
|
|
)
|
|
|
|
type ProfileStmts struct {
|
|
getReplies *sql.Stmt
|
|
}
|
|
|
|
var profileStmts ProfileStmts
|
|
|
|
// TODO: Move these DbInits into some sort of abstraction
|
|
func init() {
|
|
c.DbInits.Add(func(acc *qgen.Accumulator) error {
|
|
profileStmts = ProfileStmts{
|
|
getReplies: acc.SimpleLeftJoin("users_replies", "users", "users_replies.rid, users_replies.content, users_replies.createdBy, users_replies.createdAt, users_replies.lastEdit, users_replies.lastEditBy, users.avatar, users.name, users.group", "users_replies.createdBy = users.uid", "users_replies.uid = ?", "", ""),
|
|
}
|
|
return acc.FirstError()
|
|
})
|
|
}
|
|
|
|
// TODO: Remove the View part of the name?
|
|
func ViewProfile(w http.ResponseWriter, r *http.Request, user c.User, header *c.Header) c.RouteError {
|
|
// TODO: Preload this?
|
|
header.AddSheet(header.Theme.Name + "/profile.css")
|
|
if user.Loggedin {
|
|
header.AddScriptAsync("profile_member.js")
|
|
}
|
|
|
|
var err error
|
|
var replyCreatedAt time.Time
|
|
var replyContent, replyCreatedByName, replyAvatar string
|
|
var rid, replyCreatedBy, replyLastEdit, replyLastEditBy, replyGroup int
|
|
var replyList []*c.ReplyUser
|
|
|
|
// TODO: Do a 301 if it's the wrong username? Do a canonical too?
|
|
_, pid, err := ParseSEOURL(r.URL.Path[len("/user/"):])
|
|
if err != nil {
|
|
return c.LocalError("The provided UserID is not a valid number.", w, r, user)
|
|
}
|
|
|
|
var puser *c.User
|
|
if pid == user.ID {
|
|
user.IsMod = true
|
|
puser = &user
|
|
} else {
|
|
// Fetch the user data
|
|
// TODO: Add a shared function for checking for ErrNoRows and internal erroring if it's not that case?
|
|
puser, err = c.Users.Get(pid)
|
|
if err == sql.ErrNoRows {
|
|
return c.NotFound(w, r, header)
|
|
} else if err != nil {
|
|
return c.InternalError(err, w, r)
|
|
}
|
|
puser.Init()
|
|
}
|
|
header.Title = phrases.GetTitlePhrasef("profile", puser.Name)
|
|
header.Path = c.BuildProfileURL(c.NameToSlug(puser.Name), puser.ID)
|
|
|
|
// Get the replies..
|
|
rows, err := profileStmts.getReplies.Query(puser.ID)
|
|
if err != nil {
|
|
return c.InternalError(err, w, r)
|
|
}
|
|
defer rows.Close()
|
|
|
|
for rows.Next() {
|
|
err := rows.Scan(&rid, &replyContent, &replyCreatedBy, &replyCreatedAt, &replyLastEdit, &replyLastEditBy, &replyAvatar, &replyCreatedByName, &replyGroup)
|
|
if err != nil {
|
|
return c.InternalError(err, w, r)
|
|
}
|
|
|
|
replyLiked := false
|
|
replyLikeCount := 0
|
|
ru := &c.ReplyUser{Reply: c.Reply{rid, 0, replyContent, replyCreatedBy, replyGroup, replyCreatedAt, replyLastEdit, replyLastEditBy, 0, "", replyLiked, replyLikeCount, 0, ""}, ContentHtml: c.ParseMessage(replyContent, 0, ""), CreatedByName: replyCreatedByName, Avatar: replyAvatar, Level: 0}
|
|
ru.Init(puser.ID)
|
|
|
|
group, err := c.Groups.Get(ru.Group)
|
|
if err != nil {
|
|
return c.InternalError(err, w, r)
|
|
}
|
|
|
|
if group.Tag != "" {
|
|
ru.Tag = group.Tag
|
|
} else if puser.ID == ru.CreatedBy {
|
|
ru.Tag = phrases.GetTmplPhrase("profile_owner_tag")
|
|
} else {
|
|
ru.Tag = ""
|
|
}
|
|
|
|
// TODO: Add a hook here
|
|
replyList = append(replyList, ru)
|
|
}
|
|
err = rows.Err()
|
|
if err != nil {
|
|
return c.InternalError(err, w, r)
|
|
}
|
|
|
|
// Normalise the score so that the user sees their relative progress to the next level rather than showing them their total score
|
|
prevScore := c.GetLevelScore(puser.Level)
|
|
currentScore := puser.Score - prevScore
|
|
nextScore := c.GetLevelScore(puser.Level+1) - prevScore
|
|
|
|
ppage := c.ProfilePage{header, replyList, *puser, currentScore, nextScore}
|
|
return renderTemplate("profile", w, r, header, ppage)
|
|
}
|