2018-02-26 09:07:00 +00:00
|
|
|
package routes
|
|
|
|
|
|
|
|
import (
|
|
|
|
"database/sql"
|
|
|
|
"net/http"
|
|
|
|
"strconv"
|
|
|
|
"strings"
|
|
|
|
"time"
|
|
|
|
|
2018-10-27 03:21:02 +00:00
|
|
|
"github.com/Azareal/Gosora/common"
|
|
|
|
"github.com/Azareal/Gosora/query_gen"
|
2018-02-26 09:07:00 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
type ProfileStmts struct {
|
|
|
|
getReplies *sql.Stmt
|
|
|
|
}
|
|
|
|
|
|
|
|
var profileStmts ProfileStmts
|
|
|
|
|
|
|
|
// TODO: Move these DbInits into some sort of abstraction
|
|
|
|
func init() {
|
|
|
|
common.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()
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2018-10-14 05:08:44 +00:00
|
|
|
// TODO: Remove the View part of the name?
|
2018-02-26 09:07:00 +00:00
|
|
|
func ViewProfile(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError {
|
2018-04-22 12:33:56 +00:00
|
|
|
header, ferr := common.UserCheck(w, r, &user)
|
2018-02-26 09:07:00 +00:00
|
|
|
if ferr != nil {
|
|
|
|
return ferr
|
|
|
|
}
|
2018-05-27 09:36:35 +00:00
|
|
|
// TODO: Preload this?
|
2018-06-06 00:21:22 +00:00
|
|
|
header.AddSheet(header.Theme.Name + "/profile.css")
|
2018-02-26 09:07:00 +00:00
|
|
|
|
|
|
|
var err error
|
|
|
|
var replyCreatedAt time.Time
|
2018-07-28 12:52:23 +00:00
|
|
|
var replyContent, replyCreatedByName, replyRelativeCreatedAt, replyAvatar, replyMicroAvatar, replyTag, replyClassName string
|
2018-02-26 09:07:00 +00:00
|
|
|
var rid, replyCreatedBy, replyLastEdit, replyLastEditBy, replyLines, replyGroup int
|
|
|
|
var replyList []common.ReplyUser
|
|
|
|
|
|
|
|
// SEO URLs...
|
|
|
|
// TODO: Do a 301 if it's the wrong username? Do a canonical too?
|
|
|
|
halves := strings.Split(r.URL.Path[len("/user/"):], ".")
|
|
|
|
if len(halves) < 2 {
|
|
|
|
halves = append(halves, halves[0])
|
|
|
|
}
|
|
|
|
pid, err := strconv.Atoi(halves[1])
|
|
|
|
if err != nil {
|
|
|
|
return common.LocalError("The provided UserID is not a valid number.", w, r, user)
|
|
|
|
}
|
|
|
|
|
|
|
|
var puser *common.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 = common.Users.Get(pid)
|
|
|
|
if err == sql.ErrNoRows {
|
2018-04-22 12:33:56 +00:00
|
|
|
return common.NotFound(w, r, header)
|
2018-02-26 09:07:00 +00:00
|
|
|
} else if err != nil {
|
|
|
|
return common.InternalError(err, w, r)
|
|
|
|
}
|
2018-10-14 06:16:42 +00:00
|
|
|
puser.Init()
|
2018-02-26 09:07:00 +00:00
|
|
|
}
|
2018-10-14 06:09:25 +00:00
|
|
|
header.Title = common.GetTitlePhrasef("profile", puser.Name)
|
2018-10-14 05:08:44 +00:00
|
|
|
header.Path = common.BuildProfileURL(common.NameToSlug(puser.Name), puser.ID)
|
2018-02-26 09:07:00 +00:00
|
|
|
|
|
|
|
// Get the replies..
|
|
|
|
rows, err := profileStmts.getReplies.Query(puser.ID)
|
|
|
|
if err != nil {
|
|
|
|
return common.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 common.InternalError(err, w, r)
|
|
|
|
}
|
|
|
|
|
|
|
|
group, err := common.Groups.Get(replyGroup)
|
|
|
|
if err != nil {
|
|
|
|
return common.InternalError(err, w, r)
|
|
|
|
}
|
|
|
|
|
|
|
|
replyLines = strings.Count(replyContent, "\n")
|
2018-06-24 13:49:29 +00:00
|
|
|
if group.IsMod {
|
2018-02-26 09:07:00 +00:00
|
|
|
replyClassName = common.Config.StaffCSS
|
|
|
|
} else {
|
|
|
|
replyClassName = ""
|
|
|
|
}
|
2018-07-28 12:52:23 +00:00
|
|
|
replyAvatar, replyMicroAvatar = common.BuildAvatar(replyCreatedBy, replyAvatar)
|
2018-02-26 09:07:00 +00:00
|
|
|
|
|
|
|
if group.Tag != "" {
|
|
|
|
replyTag = group.Tag
|
|
|
|
} else if puser.ID == replyCreatedBy {
|
2018-10-14 06:09:25 +00:00
|
|
|
replyTag = common.GetTmplPhrase("profile_owner_tag")
|
2018-02-26 09:07:00 +00:00
|
|
|
} else {
|
|
|
|
replyTag = ""
|
|
|
|
}
|
|
|
|
|
|
|
|
replyLiked := false
|
|
|
|
replyLikeCount := 0
|
|
|
|
replyRelativeCreatedAt = common.RelativeTime(replyCreatedAt)
|
|
|
|
|
|
|
|
// TODO: Add a hook here
|
|
|
|
|
2018-07-28 12:52:23 +00:00
|
|
|
replyList = append(replyList, common.ReplyUser{rid, puser.ID, replyContent, common.ParseMessage(replyContent, 0, ""), replyCreatedBy, common.BuildProfileURL(common.NameToSlug(replyCreatedByName), replyCreatedBy), replyCreatedByName, replyGroup, replyCreatedAt, replyRelativeCreatedAt, replyLastEdit, replyLastEditBy, replyAvatar, replyMicroAvatar, replyClassName, replyLines, replyTag, "", "", "", 0, "", replyLiked, replyLikeCount, "", ""})
|
2018-02-26 09:07:00 +00:00
|
|
|
}
|
|
|
|
err = rows.Err()
|
|
|
|
if err != nil {
|
|
|
|
return common.InternalError(err, w, r)
|
|
|
|
}
|
|
|
|
|
2018-10-08 05:34:25 +00:00
|
|
|
// Normalise the score so that the user sees their relative progress to the next level rather than showing them their total score
|
|
|
|
prevScore := common.GetLevelScore(puser.Level)
|
|
|
|
currentScore := puser.Score - prevScore
|
|
|
|
nextScore := common.GetLevelScore(puser.Level+1) - prevScore
|
|
|
|
|
|
|
|
ppage := common.ProfilePage{header, replyList, *puser, currentScore, nextScore}
|
2018-02-26 09:07:00 +00:00
|
|
|
if common.RunPreRenderHook("pre_render_profile", w, r, &user, &ppage) {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2018-04-22 12:33:56 +00:00
|
|
|
err = common.RunThemeTemplate(header.Theme.Name, "profile", ppage, w)
|
2018-02-26 09:07:00 +00:00
|
|
|
if err != nil {
|
|
|
|
return common.InternalError(err, w, r)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|