From f1bebb73260cbb4170bcef3c87de51beb8edc587 Mon Sep 17 00:00:00 2001 From: Azareal Date: Sun, 1 Sep 2019 08:34:43 +1000 Subject: [PATCH] Shorten the names of the IP fields. Shorten some other things. --- cmd/elasticsearch/setup.go | 16 +-- common/audit_logs.go | 24 ++-- common/forum.go | 30 ++--- common/group.go | 26 ++-- common/group_store.go | 2 +- common/misc_logs.go | 52 ++++---- common/pages.go | 2 +- common/permissions.go | 24 ++-- common/profile_reply.go | 14 +-- common/profile_reply_store.go | 2 +- common/reply.go | 54 ++++----- common/reply_store.go | 9 +- common/topic.go | 214 ++++++++++++++++----------------- common/topic_store.go | 4 +- common/user_cache.go | 138 ++++++++++----------- general_test.go | 10 +- misc_test.go | 14 +-- routes/account.go | 16 ++- routes/panel/logs.go | 8 +- templates/account_logins.html | 2 +- templates/panel_adminlogs.html | 2 +- templates/panel_modlogs.html | 2 +- templates/panel_reglogs.html | 2 +- templates/topic.html | 2 +- templates/topic_alt.html | 4 +- templates/topic_alt_posts.html | 4 +- templates/topic_posts.html | 2 +- 27 files changed, 339 insertions(+), 340 deletions(-) diff --git a/cmd/elasticsearch/setup.go b/cmd/elasticsearch/setup.go index ffaa73c5..5ec91683 100644 --- a/cmd/elasticsearch/setup.go +++ b/cmd/elasticsearch/setup.go @@ -163,7 +163,7 @@ type ESTopic struct { Title string `json:"title"` Content string `json:"content"` CreatedBy int `json:"createdBy"` - IPAddress string `json:"ip"` + IP string `json:"ip"` } type ESReply struct { @@ -171,7 +171,7 @@ type ESReply struct { TID int `json:"tid"` Content string `json:"content"` CreatedBy int `json:"createdBy"` - IPAddress string `json:"ip"` + IP string `json:"ip"` } func setupData(client *elastic.Client) error { @@ -198,12 +198,12 @@ func setupData(client *elastic.Client) error { oi := 0 err := qgen.NewAcc().Select("topics").Cols("tid, title, content, createdBy, ipaddress").Each(func(rows *sql.Rows) error { - topic := ESTopic{} - err := rows.Scan(&topic.ID, &topic.Title, &topic.Content, &topic.CreatedBy, &topic.IPAddress) + t := ESTopic{} + err := rows.Scan(&t.ID, &t.Title, &t.Content, &t.CreatedBy, &t.IP) if err != nil { return err } - tin[oi] <- topic + tin[oi] <- t if oi < 3 { oi++ } @@ -234,12 +234,12 @@ func setupData(client *elastic.Client) error { } oi := 0 err := qgen.NewAcc().Select("replies").Cols("rid, tid, content, createdBy, ipaddress").Each(func(rows *sql.Rows) error { - reply := ESReply{} - err := rows.Scan(&reply.ID, &reply.TID, &reply.Content, &reply.CreatedBy, &reply.IPAddress) + r := ESReply{} + err := rows.Scan(&r.ID, &r.TID, &r.Content, &r.CreatedBy, &r.IP) if err != nil { return err } - rin[oi] <- reply + rin[oi] <- r if oi < 3 { oi++ } diff --git a/common/audit_logs.go b/common/audit_logs.go index 125f4785..ab60e531 100644 --- a/common/audit_logs.go +++ b/common/audit_logs.go @@ -14,13 +14,13 @@ type LogItem struct { Action string ElementID int ElementType string - IPAddress string + IP string ActorID int DoneAt string } type LogStore interface { - Create(action string, elementID int, elementType string, ipaddress string, actorID int) (err error) + Create(action string, elementID int, elementType string, ip string, actorID int) (err error) Count() int GetOffset(offset int, perPage int) (logs []LogItem, err error) } @@ -40,8 +40,8 @@ func NewModLogStore(acc *qgen.Accumulator) (*SQLModLogStore, error) { } // TODO: Make a store for this? -func (s *SQLModLogStore) Create(action string, elementID int, elementType string, ipaddress string, actorID int) (err error) { - _, err = s.create.Exec(action, elementID, elementType, ipaddress, actorID) +func (s *SQLModLogStore) Create(action string, elementID int, elementType string, ip string, actorID int) (err error) { + _, err = s.create.Exec(action, elementID, elementType, ip, actorID) return err } @@ -55,20 +55,20 @@ func (s *SQLModLogStore) Count() (count int) { func buildLogList(rows *sql.Rows) (logs []LogItem, err error) { for rows.Next() { - var log LogItem + var l LogItem var doneAt time.Time - err := rows.Scan(&log.Action, &log.ElementID, &log.ElementType, &log.IPAddress, &log.ActorID, &doneAt) + err := rows.Scan(&l.Action, &l.ElementID, &l.ElementType, &l.IP, &l.ActorID, &doneAt) if err != nil { return logs, err } - log.DoneAt = doneAt.Format("2006-01-02 15:04:05") - logs = append(logs, log) + l.DoneAt = doneAt.Format("2006-01-02 15:04:05") + logs = append(logs, l) } return logs, rows.Err() } -func (store *SQLModLogStore) GetOffset(offset int, perPage int) (logs []LogItem, err error) { - rows, err := store.getOffset.Query(offset, perPage) +func (s *SQLModLogStore) GetOffset(offset int, perPage int) (logs []LogItem, err error) { + rows, err := s.getOffset.Query(offset, perPage) if err != nil { return logs, err } @@ -91,8 +91,8 @@ func NewAdminLogStore(acc *qgen.Accumulator) (*SQLAdminLogStore, error) { } // TODO: Make a store for this? -func (s *SQLAdminLogStore) Create(action string, elementID int, elementType string, ipaddress string, actorID int) (err error) { - _, err = s.create.Exec(action, elementID, elementType, ipaddress, actorID) +func (s *SQLAdminLogStore) Create(action string, elementID int, elementType string, ip string, actorID int) (err error) { + _, err = s.create.Exec(action, elementID, elementType, ip, actorID) return err } diff --git a/common/forum.go b/common/forum.go index c70ca69f..cd627223 100644 --- a/common/forum.go +++ b/common/forum.go @@ -68,59 +68,59 @@ func init() { } // Copy gives you a non-pointer concurrency safe copy of the forum -func (forum *Forum) Copy() (fcopy Forum) { - fcopy = *forum +func (f *Forum) Copy() (fcopy Forum) { + fcopy = *f return fcopy } // TODO: Write tests for this -func (forum *Forum) Update(name string, desc string, active bool, preset string) error { +func (f *Forum) Update(name string, desc string, active bool, preset string) error { if name == "" { - name = forum.Name + name = f.Name } // TODO: Do a line sanitise? Does it matter? preset = strings.TrimSpace(preset) - _, err := forumStmts.update.Exec(name, desc, active, preset, forum.ID) + _, err := forumStmts.update.Exec(name, desc, active, preset, f.ID) if err != nil { return err } - if forum.Preset != preset && preset != "custom" && preset != "" { - err = PermmapToQuery(PresetToPermmap(preset), forum.ID) + if f.Preset != preset && preset != "custom" && preset != "" { + err = PermmapToQuery(PresetToPermmap(preset), f.ID) if err != nil { return err } } - _ = Forums.Reload(forum.ID) + _ = Forums.Reload(f.ID) return nil } -func (forum *Forum) SetPreset(preset string, gid int) error { +func (f *Forum) SetPreset(preset string, gid int) error { fperms, changed := GroupForumPresetToForumPerms(preset) if changed { - return forum.SetPerms(fperms, preset, gid) + return f.SetPerms(fperms, preset, gid) } return nil } // TODO: Refactor this -func (forum *Forum) SetPerms(fperms *ForumPerms, preset string, gid int) (err error) { - err = ReplaceForumPermsForGroup(gid, map[int]string{forum.ID: preset}, map[int]*ForumPerms{forum.ID: fperms}) +func (f *Forum) SetPerms(fperms *ForumPerms, preset string, gid int) (err error) { + err = ReplaceForumPermsForGroup(gid, map[int]string{f.ID: preset}, map[int]*ForumPerms{f.ID: fperms}) if err != nil { LogError(err) return errors.New("Unable to update the permissions") } // TODO: Add this and replaceForumPermsForGroup into a transaction? - _, err = forumStmts.setPreset.Exec("", forum.ID) + _, err = forumStmts.setPreset.Exec("", f.ID) if err != nil { LogError(err) return errors.New("Unable to update the forum") } - err = Forums.Reload(forum.ID) + err = Forums.Reload(f.ID) if err != nil { return errors.New("Unable to reload forum") } - err = FPStore.Reload(forum.ID) + err = FPStore.Reload(f.ID) if err != nil { return errors.New("Unable to reload the forum permissions") } diff --git a/common/group.go b/common/group.go index 80767259..a0405282 100644 --- a/common/group.go +++ b/common/group.go @@ -53,45 +53,45 @@ func init() { }) } -func (group *Group) ChangeRank(isAdmin bool, isMod bool, isBanned bool) (err error) { - _, err = groupStmts.updateGroupRank.Exec(isAdmin, isMod, isBanned, group.ID) +func (g *Group) ChangeRank(isAdmin bool, isMod bool, isBanned bool) (err error) { + _, err = groupStmts.updateGroupRank.Exec(isAdmin, isMod, isBanned, g.ID) if err != nil { return err } - Groups.Reload(group.ID) + Groups.Reload(g.ID) return nil } -func (group *Group) Update(name string, tag string) (err error) { - _, err = groupStmts.updateGroup.Exec(name, tag, group.ID) +func (g *Group) Update(name string, tag string) (err error) { + _, err = groupStmts.updateGroup.Exec(name, tag, g.ID) if err != nil { return err } - Groups.Reload(group.ID) + Groups.Reload(g.ID) return nil } // Please don't pass arbitrary inputs to this method -func (group *Group) UpdatePerms(perms map[string]bool) (err error) { +func (g *Group) UpdatePerms(perms map[string]bool) (err error) { pjson, err := json.Marshal(perms) if err != nil { return err } - _, err = groupStmts.updateGroupPerms.Exec(pjson, group.ID) + _, err = groupStmts.updateGroupPerms.Exec(pjson, g.ID) if err != nil { return err } - return Groups.Reload(group.ID) + return Groups.Reload(g.ID) } // Copy gives you a non-pointer concurrency safe copy of the group -func (group *Group) Copy() Group { - return *group +func (g *Group) Copy() Group { + return *g } -func (group *Group) CopyPtr() (co *Group) { +func (g *Group) CopyPtr() (co *Group) { co = new(Group) - *co = *group + *co = *g return co } diff --git a/common/group_store.go b/common/group_store.go index 0b76c248..febff38d 100644 --- a/common/group_store.go +++ b/common/group_store.go @@ -22,7 +22,7 @@ type GroupStore interface { Get(id int) (*Group, error) GetCopy(id int) (Group, error) Exists(id int) bool - Create(name string, tag string, isAdmin bool, isMod bool, isBanned bool) (int, error) + Create(name string, tag string, isAdmin bool, isMod bool, isBanned bool) (id int, err error) GetAll() ([]*Group, error) GetRange(lower int, higher int) ([]*Group, error) Reload(id int) error // ? - Should we move this to GroupCache? It might require us to do some unnecessary casting though diff --git a/common/misc_logs.go b/common/misc_logs.go index 6230caae..36ca9b57 100644 --- a/common/misc_logs.go +++ b/common/misc_logs.go @@ -16,7 +16,7 @@ type RegLogItem struct { Email string FailureReason string Success bool - IPAddress string + IP string DoneAt string } @@ -39,19 +39,19 @@ func init() { // TODO: Reload this item in the store, probably doesn't matter right now, but it might when we start caching this stuff in memory // ! Retroactive updates of date are not permitted for integrity reasons -func (log *RegLogItem) Commit() error { - _, err := regLogStmts.update.Exec(log.Username, log.Email, log.FailureReason, log.Success, log.ID) +func (l *RegLogItem) Commit() error { + _, err := regLogStmts.update.Exec(l.Username, l.Email, l.FailureReason, l.Success, l.ID) return err } -func (log *RegLogItem) Create() (id int, err error) { - res, err := regLogStmts.create.Exec(log.Username, log.Email, log.FailureReason, log.Success, log.IPAddress) +func (l *RegLogItem) Create() (id int, err error) { + res, err := regLogStmts.create.Exec(l.Username, l.Email, l.FailureReason, l.Success, l.IP) if err != nil { return 0, err } id64, err := res.LastInsertId() - log.ID = int(id64) - return log.ID, err + l.ID = int(id64) + return l.ID, err } type RegLogStore interface { @@ -79,22 +79,22 @@ func (s *SQLRegLogStore) Count() (count int) { return count } -func (store *SQLRegLogStore) GetOffset(offset int, perPage int) (logs []RegLogItem, err error) { - rows, err := store.getOffset.Query(offset, perPage) +func (s *SQLRegLogStore) GetOffset(offset int, perPage int) (logs []RegLogItem, err error) { + rows, err := s.getOffset.Query(offset, perPage) if err != nil { return logs, err } defer rows.Close() for rows.Next() { - var log RegLogItem + var l RegLogItem var doneAt time.Time - err := rows.Scan(&log.ID, &log.Username, &log.Email, &log.FailureReason, &log.Success, &log.IPAddress, &doneAt) + err := rows.Scan(&l.ID, &l.Username, &l.Email, &l.FailureReason, &l.Success, &l.IP, &doneAt) if err != nil { return logs, err } - log.DoneAt = doneAt.Format("2006-01-02 15:04:05") - logs = append(logs, log) + l.DoneAt = doneAt.Format("2006-01-02 15:04:05") + logs = append(logs, l) } return logs, rows.Err() } @@ -103,7 +103,7 @@ type LoginLogItem struct { ID int UID int Success bool - IPAddress string + IP string DoneAt string } @@ -126,19 +126,19 @@ func init() { // TODO: Reload this item in the store, probably doesn't matter right now, but it might when we start caching this stuff in memory // ! Retroactive updates of date are not permitted for integrity reasons -func (log *LoginLogItem) Commit() error { - _, err := loginLogStmts.update.Exec(log.UID, log.Success, log.ID) +func (l *LoginLogItem) Commit() error { + _, err := loginLogStmts.update.Exec(l.UID, l.Success, l.ID) return err } -func (log *LoginLogItem) Create() (id int, err error) { - res, err := loginLogStmts.create.Exec(log.UID, log.Success, log.IPAddress) +func (l *LoginLogItem) Create() (id int, err error) { + res, err := loginLogStmts.create.Exec(l.UID, l.Success, l.IP) if err != nil { return 0, err } id64, err := res.LastInsertId() - log.ID = int(id64) - return log.ID, err + l.ID = int(id64) + return l.ID, err } type LoginLogStore interface { @@ -177,22 +177,22 @@ func (s *SQLLoginLogStore) CountUser(uid int) (count int) { return count } -func (store *SQLLoginLogStore) GetOffset(uid int, offset int, perPage int) (logs []LoginLogItem, err error) { - rows, err := store.getOffsetByUser.Query(uid, offset, perPage) +func (s *SQLLoginLogStore) GetOffset(uid int, offset int, perPage int) (logs []LoginLogItem, err error) { + rows, err := s.getOffsetByUser.Query(uid, offset, perPage) if err != nil { return logs, err } defer rows.Close() for rows.Next() { - var log = LoginLogItem{UID: uid} + l := LoginLogItem{UID: uid} var doneAt time.Time - err := rows.Scan(&log.ID, &log.Success, &log.IPAddress, &doneAt) + err := rows.Scan(&l.ID, &l.Success, &l.IP, &doneAt) if err != nil { return logs, err } - log.DoneAt = doneAt.Format("2006-01-02 15:04:05") - logs = append(logs, log) + l.DoneAt = doneAt.Format("2006-01-02 15:04:05") + logs = append(logs, l) } return logs, rows.Err() } diff --git a/common/pages.go b/common/pages.go index 24e07c1c..6654560a 100644 --- a/common/pages.go +++ b/common/pages.go @@ -590,7 +590,7 @@ type PanelBackupPage struct { type PageLogItem struct { Action template.HTML - IPAddress string + IP string DoneAt string } diff --git a/common/permissions.go b/common/permissions.go index ff1d60c7..9f782311 100644 --- a/common/permissions.go +++ b/common/permissions.go @@ -207,18 +207,18 @@ func OverridePerms(perms *Perms, status bool) { } // TODO: We need a better way of overriding forum perms rather than setting them one by one -func OverrideForumPerms(perms *Perms, status bool) { - perms.ViewTopic = status - perms.LikeItem = status - perms.CreateTopic = status - perms.EditTopic = status - perms.DeleteTopic = status - perms.CreateReply = status - perms.EditReply = status - perms.DeleteReply = status - perms.PinTopic = status - perms.CloseTopic = status - perms.MoveTopic = status +func OverrideForumPerms(p *Perms, status bool) { + p.ViewTopic = status + p.LikeItem = status + p.CreateTopic = status + p.EditTopic = status + p.DeleteTopic = status + p.CreateReply = status + p.EditReply = status + p.DeleteReply = status + p.PinTopic = status + p.CloseTopic = status + p.MoveTopic = status } func RegisterPluginPerm(name string) { diff --git a/common/profile_reply.go b/common/profile_reply.go index 9c78132d..fcac0fc0 100644 --- a/common/profile_reply.go +++ b/common/profile_reply.go @@ -20,7 +20,7 @@ type ProfileReply struct { LastEdit int LastEditBy int ContentLines int - IPAddress string + IP string } type ProfileReplyStmts struct { @@ -44,18 +44,18 @@ func BlankProfileReply(id int) *ProfileReply { } // TODO: Write tests for this -func (reply *ProfileReply) Delete() error { - _, err := profileReplyStmts.delete.Exec(reply.ID) +func (r *ProfileReply) Delete() error { + _, err := profileReplyStmts.delete.Exec(r.ID) return err } -func (reply *ProfileReply) SetBody(content string) error { +func (r *ProfileReply) SetBody(content string) error { content = PreparseMessage(html.UnescapeString(content)) - _, err := profileReplyStmts.edit.Exec(content, ParseMessage(content, 0, ""), reply.ID) + _, err := profileReplyStmts.edit.Exec(content, ParseMessage(content, 0, ""), r.ID) return err } // TODO: We can get this from the topic store instead of a query which will always miss the cache... -func (reply *ProfileReply) Creator() (*User, error) { - return Users.Get(reply.CreatedBy) +func (r *ProfileReply) Creator() (*User, error) { + return Users.Get(r.CreatedBy) } diff --git a/common/profile_reply_store.go b/common/profile_reply_store.go index 3483a262..7edd1b41 100644 --- a/common/profile_reply_store.go +++ b/common/profile_reply_store.go @@ -32,7 +32,7 @@ func NewSQLProfileReplyStore(acc *qgen.Accumulator) (*SQLProfileReplyStore, erro func (s *SQLProfileReplyStore) Get(id int) (*ProfileReply, error) { r := ProfileReply{ID: id} - err := s.get.QueryRow(id).Scan(&r.ParentID, &r.Content, &r.CreatedBy, &r.CreatedAt, &r.LastEdit, &r.LastEditBy, &r.IPAddress) + err := s.get.QueryRow(id).Scan(&r.ParentID, &r.Content, &r.CreatedBy, &r.CreatedAt, &r.LastEdit, &r.LastEditBy, &r.IP) return &r, err } diff --git a/common/reply.go b/common/reply.go index 28afa8f7..46b5c1f0 100644 --- a/common/reply.go +++ b/common/reply.go @@ -1,7 +1,7 @@ /* * * Reply Resources File -* Copyright Azareal 2016 - 2019 +* Copyright Azareal 2016 - 2020 * */ package common @@ -37,7 +37,7 @@ type ReplyUser struct { URLPrefix string URLName string Level int - //IPAddress string + //IP string //Liked bool //LikeCount int //AttachCount int @@ -57,7 +57,7 @@ type Reply struct { LastEdit int LastEditBy int ContentLines int - IPAddress string + IP string Liked bool LikeCount int AttachCount int @@ -94,9 +94,9 @@ func init() { // TODO: Write tests for this // TODO: Wrap these queries in a transaction to make sure the state is consistent -func (reply *Reply) Like(uid int) (err error) { +func (r *Reply) Like(uid int) (err error) { var rid int // unused, just here to avoid mutating reply.ID - err = replyStmts.isLiked.QueryRow(uid, reply.ID).Scan(&rid) + err = replyStmts.isLiked.QueryRow(uid, r.ID).Scan(&rid) if err != nil && err != ErrNoRows { return err } else if err != ErrNoRows { @@ -104,66 +104,66 @@ func (reply *Reply) Like(uid int) (err error) { } score := 1 - _, err = replyStmts.createLike.Exec(score, reply.ID, "replies", uid) + _, err = replyStmts.createLike.Exec(score, r.ID, "replies", uid) if err != nil { return err } - _, err = replyStmts.addLikesToReply.Exec(1, reply.ID) + _, err = replyStmts.addLikesToReply.Exec(1, r.ID) if err != nil { return err } _, err = userStmts.incrementLiked.Exec(1, uid) - _ = Rstore.GetCache().Remove(reply.ID) + _ = Rstore.GetCache().Remove(r.ID) return err } -func (reply *Reply) Delete() error { - _, err := replyStmts.delete.Exec(reply.ID) +func (r *Reply) Delete() error { + _, err := replyStmts.delete.Exec(r.ID) if err != nil { return err } // TODO: Move this bit to *Topic - _, err = replyStmts.removeRepliesFromTopic.Exec(1, reply.ParentID) + _, err = replyStmts.removeRepliesFromTopic.Exec(1, r.ParentID) tcache := Topics.GetCache() if tcache != nil { - tcache.Remove(reply.ParentID) + tcache.Remove(r.ParentID) } - _ = Rstore.GetCache().Remove(reply.ID) + _ = Rstore.GetCache().Remove(r.ID) return err } -func (reply *Reply) SetPost(content string) error { - topic, err := reply.Topic() +func (r *Reply) SetPost(content string) error { + topic, err := r.Topic() if err != nil { return err } content = PreparseMessage(html.UnescapeString(content)) parsedContent := ParseMessage(content, topic.ParentID, "forums") - _, err = replyStmts.edit.Exec(content, parsedContent, reply.ID) // TODO: Sniff if this changed anything to see if we hit an existing poll - _ = Rstore.GetCache().Remove(reply.ID) + _, err = replyStmts.edit.Exec(content, parsedContent, r.ID) // TODO: Sniff if this changed anything to see if we hit an existing poll + _ = Rstore.GetCache().Remove(r.ID) return err } // TODO: Write tests for this -func (reply *Reply) SetPoll(pollID int) error { - _, err := replyStmts.setPoll.Exec(pollID, reply.ID) // TODO: Sniff if this changed anything to see if we hit a poll - _ = Rstore.GetCache().Remove(reply.ID) +func (r *Reply) SetPoll(pollID int) error { + _, err := replyStmts.setPoll.Exec(pollID, r.ID) // TODO: Sniff if this changed anything to see if we hit a poll + _ = Rstore.GetCache().Remove(r.ID) return err } -func (reply *Reply) Topic() (*Topic, error) { - return Topics.Get(reply.ParentID) +func (r *Reply) Topic() (*Topic, error) { + return Topics.Get(r.ParentID) } -func (reply *Reply) GetID() int { - return reply.ID +func (r *Reply) GetID() int { + return r.ID } -func (reply *Reply) GetTable() string { +func (r *Reply) GetTable() string { return "replies" } // Copy gives you a non-pointer concurrency safe copy of the reply -func (reply *Reply) Copy() Reply { - return *reply +func (r *Reply) Copy() Reply { + return *r } diff --git a/common/reply_store.go b/common/reply_store.go index d73a7b67..5bf081a6 100644 --- a/common/reply_store.go +++ b/common/reply_store.go @@ -42,7 +42,7 @@ func (s *SQLReplyStore) Get(id int) (*Reply, error) { } r = &Reply{ID: id} - err = s.get.QueryRow(id).Scan(&r.ParentID, &r.Content, &r.CreatedBy, &r.CreatedAt, &r.LastEdit, &r.LastEditBy, &r.IPAddress, &r.LikeCount, &r.AttachCount, &r.ActionType) + err = s.get.QueryRow(id).Scan(&r.ParentID, &r.Content, &r.CreatedBy, &r.CreatedAt, &r.LastEdit, &r.LastEditBy, &r.IP, &r.LikeCount, &r.AttachCount, &r.ActionType) if err == nil { _ = s.cache.Set(r) } @@ -50,9 +50,9 @@ func (s *SQLReplyStore) Get(id int) (*Reply, error) { } // TODO: Write a test for this -func (s *SQLReplyStore) Create(topic *Topic, content string, ipaddress string, uid int) (id int, err error) { +func (s *SQLReplyStore) Create(t *Topic, content string, ip string, uid int) (rid int, err error) { wcount := WordCount(content) - res, err := s.create.Exec(topic.ID, content, ParseMessage(content, topic.ParentID, "forums"), ipaddress, wcount, uid) + res, err := s.create.Exec(t.ID, content, ParseMessage(content, t.ParentID, "forums"), ip, wcount, uid) if err != nil { return 0, err } @@ -61,7 +61,8 @@ func (s *SQLReplyStore) Create(topic *Topic, content string, ipaddress string, u if err != nil { return 0, err } - return int(lastID), topic.AddReply(int(lastID), uid) + rid = int(lastID) + return rid, t.AddReply(rid, uid) } // TODO: Write a test for this diff --git a/common/topic.go b/common/topic.go index 4f4f4356..12638fa2 100644 --- a/common/topic.go +++ b/common/topic.go @@ -38,7 +38,7 @@ type Topic struct { LastReplyID int ParentID int Status string // Deprecated. Marked for removal. - IPAddress string + IP string ViewCount int64 PostCount int LikeCount int @@ -64,7 +64,7 @@ type TopicUser struct { LastReplyID int ParentID int Status string // Deprecated. Marked for removal. - IPAddress string + IP string ViewCount int64 PostCount int LikeCount int @@ -106,7 +106,7 @@ type TopicsRow struct { LastReplyID int ParentID int Status string // Deprecated. Marked for removal. -Is there anything we could use it for? - IPAddress string + IP string ViewCount int64 PostCount int LikeCount int @@ -151,8 +151,8 @@ type WsTopicsRow struct { } // TODO: Can we get the client side to render the relative times instead? -func (row *TopicsRow) WebSockets() *WsTopicsRow { - return &WsTopicsRow{row.ID, row.Link, row.Title, row.CreatedBy, row.IsClosed, row.Sticky, row.CreatedAt, row.LastReplyAt, RelativeTime(row.LastReplyAt), row.LastReplyBy, row.LastReplyID, row.ParentID, row.ViewCount, row.PostCount, row.LikeCount, row.AttachCount, row.ClassName, row.Creator.WebSockets(), row.LastUser.WebSockets(), row.ForumName, row.ForumLink} +func (r *TopicsRow) WebSockets() *WsTopicsRow { + return &WsTopicsRow{r.ID, r.Link, r.Title, r.CreatedBy, r.IsClosed, r.Sticky, r.CreatedAt, r.LastReplyAt, RelativeTime(r.LastReplyAt), r.LastReplyBy, r.LastReplyID, r.ParentID, r.ViewCount, r.PostCount, r.LikeCount, r.AttachCount, r.ClassName, r.Creator.WebSockets(), r.LastUser.WebSockets(), r.ForumName, r.ForumLink} } // TODO: Stop relying on so many struct types? @@ -165,12 +165,12 @@ 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.IPAddress, 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} } // ! 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.IPAddress, t.ViewCount, t.PostCount, t.LikeCount, t.AttachCount, t.ClassName, t.Poll, t.Data, t.Rids} + 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} } // ! Not quite safe as Topic doesn't contain all the data needed to constructs a WsTopicsRow @@ -239,99 +239,99 @@ func init() { // Flush the topic out of the cache // ? - We do a CacheRemove() here instead of mutating the pointer to avoid creating a race condition -func (topic *Topic) cacheRemove() { +func (t *Topic) cacheRemove() { tcache := Topics.GetCache() if tcache != nil { - tcache.Remove(topic.ID) + tcache.Remove(t.ID) } TopicListThaw.Thaw() } // TODO: Write a test for this -func (topic *Topic) AddReply(rid int, uid int) (err error) { - _, err = topicStmts.addReplies.Exec(1, uid, topic.ID) +func (t *Topic) AddReply(rid int, uid int) (err error) { + _, err = topicStmts.addReplies.Exec(1, uid, t.ID) if err != nil { return err } - _, err = topicStmts.updateLastReply.Exec(rid, rid, topic.ID) - topic.cacheRemove() + _, err = topicStmts.updateLastReply.Exec(rid, rid, t.ID) + t.cacheRemove() return err } -func (topic *Topic) Lock() (err error) { - _, err = topicStmts.lock.Exec(topic.ID) - topic.cacheRemove() +func (t *Topic) Lock() (err error) { + _, err = topicStmts.lock.Exec(t.ID) + t.cacheRemove() return err } -func (topic *Topic) Unlock() (err error) { - _, err = topicStmts.unlock.Exec(topic.ID) - topic.cacheRemove() +func (t *Topic) Unlock() (err error) { + _, err = topicStmts.unlock.Exec(t.ID) + t.cacheRemove() return err } -func (topic *Topic) MoveTo(destForum int) (err error) { - _, err = topicStmts.moveTo.Exec(destForum, topic.ID) - topic.cacheRemove() +func (t *Topic) MoveTo(destForum int) (err error) { + _, err = topicStmts.moveTo.Exec(destForum, t.ID) + t.cacheRemove() if err != nil { return err } - err = Attachments.MoveTo(destForum, topic.ID, "topics") + err = Attachments.MoveTo(destForum, t.ID, "topics") if err != nil { return err } - return Attachments.MoveToByExtra(destForum, "replies", strconv.Itoa(topic.ID)) + return Attachments.MoveToByExtra(destForum, "replies", strconv.Itoa(t.ID)) } // TODO: We might want more consistent terminology rather than using stick in some places and pin in others. If you don't understand the difference, there is none, they are one and the same. -func (topic *Topic) Stick() (err error) { - _, err = topicStmts.stick.Exec(topic.ID) - topic.cacheRemove() +func (t *Topic) Stick() (err error) { + _, err = topicStmts.stick.Exec(t.ID) + t.cacheRemove() return err } -func (topic *Topic) Unstick() (err error) { - _, err = topicStmts.unstick.Exec(topic.ID) - topic.cacheRemove() +func (t *Topic) Unstick() (err error) { + _, err = topicStmts.unstick.Exec(t.ID) + t.cacheRemove() return err } // TODO: Test this // TODO: Use a transaction for this -func (topic *Topic) Like(score int, uid int) (err error) { +func (t *Topic) Like(score int, uid int) (err error) { var disp int // Unused - err = topicStmts.hasLikedTopic.QueryRow(uid, topic.ID).Scan(&disp) + err = topicStmts.hasLikedTopic.QueryRow(uid, t.ID).Scan(&disp) if err != nil && err != ErrNoRows { return err } else if err != ErrNoRows { return ErrAlreadyLiked } - _, err = topicStmts.createLike.Exec(score, topic.ID, "topics", uid) + _, err = topicStmts.createLike.Exec(score, t.ID, "topics", uid) if err != nil { return err } - _, err = topicStmts.addLikesToTopic.Exec(1, topic.ID) + _, err = topicStmts.addLikesToTopic.Exec(1, t.ID) if err != nil { return err } _, err = userStmts.incrementLiked.Exec(1, uid) - topic.cacheRemove() + t.cacheRemove() return err } // TODO: Implement this -func (topic *Topic) Unlike(uid int) error { - topic.cacheRemove() +func (t *Topic) Unlike(uid int) error { + t.cacheRemove() return nil } // TODO: Use a transaction here -func (topic *Topic) Delete() error { - topicCreator, err := Users.Get(topic.CreatedBy) +func (t *Topic) Delete() error { + topicCreator, err := Users.Get(t.CreatedBy) if err == nil { - wcount := WordCount(topic.Content) + wcount := WordCount(t.Content) err = topicCreator.DecreasePostStats(wcount, true) if err != nil { return err @@ -340,26 +340,26 @@ func (topic *Topic) Delete() error { return err } - err = Forums.RemoveTopic(topic.ParentID) + err = Forums.RemoveTopic(t.ParentID) if err != nil && err != ErrNoRows { return err } - _, err = topicStmts.delete.Exec(topic.ID) - topic.cacheRemove() + _, err = topicStmts.delete.Exec(t.ID) + t.cacheRemove() if err != nil { return err } - _, err = topicStmts.deleteActivitySubs.Exec(topic.ID) + _, err = topicStmts.deleteActivitySubs.Exec(t.ID) if err != nil { return err } - _, err = topicStmts.deleteActivity.Exec(topic.ID) + _, err = topicStmts.deleteActivity.Exec(t.ID) return err } // TODO: Write tests for this -func (topic *Topic) Update(name string, content string) error { +func (t *Topic) Update(name string, content string) error { name = SanitiseSingleLine(html.UnescapeString(name)) if name == "" { return ErrNoTitle @@ -370,25 +370,25 @@ func (topic *Topic) Update(name string, content string) error { } content = PreparseMessage(html.UnescapeString(content)) - parsedContent := ParseMessage(content, topic.ParentID, "forums") - _, err := topicStmts.edit.Exec(name, content, parsedContent, topic.ID) - topic.cacheRemove() + parsedContent := ParseMessage(content, t.ParentID, "forums") + _, err := topicStmts.edit.Exec(name, content, parsedContent, t.ID) + t.cacheRemove() return err } -func (topic *Topic) SetPoll(pollID int) error { - _, err := topicStmts.setPoll.Exec(pollID, topic.ID) // TODO: Sniff if this changed anything to see if we hit an existing poll - topic.cacheRemove() +func (t *Topic) SetPoll(pollID int) error { + _, err := topicStmts.setPoll.Exec(pollID, t.ID) // TODO: Sniff if this changed anything to see if we hit an existing poll + t.cacheRemove() return err } // TODO: Have this go through the ReplyStore? -func (topic *Topic) CreateActionReply(action string, ipaddress string, uid int) (err error) { - res, err := topicStmts.createAction.Exec(topic.ID, action, ipaddress, uid) +func (t *Topic) CreateActionReply(action string, ip string, uid int) (err error) { + res, err := topicStmts.createAction.Exec(t.ID, action, ip, uid) if err != nil { return err } - _, err = topicStmts.addReplies.Exec(1, uid, topic.ID) + _, err = topicStmts.addReplies.Exec(1, uid, t.ID) if err != nil { return err } @@ -397,8 +397,8 @@ func (topic *Topic) CreateActionReply(action string, ipaddress string, uid int) return err } rid := int(lid) - _, err = topicStmts.updateLastReply.Exec(rid, rid, topic.ID) - topic.cacheRemove() + _, err = topicStmts.updateLastReply.Exec(rid, rid, t.ID) + t.cacheRemove() // ? - Update the last topic cache for the parent forum? return err } @@ -487,23 +487,23 @@ func (ru *ReplyUser) Init() error { } // TODO: Factor TopicUser into a *Topic and *User, as this starting to become overly complicated x.x -func (topic *TopicUser) Replies(offset int, pFrag int, user *User) (rlist []*ReplyUser, ogdesc string, err error) { +func (t *TopicUser) Replies(offset int, pFrag int, user *User) (rlist []*ReplyUser, ogdesc string, err error) { var likedMap map[int]int if user.Liked > 0 { likedMap = make(map[int]int) } - var likedQueryList = []int{user.ID} + likedQueryList := []int{user.ID} var attachMap map[int]int if user.Perms.EditReply { attachMap = make(map[int]int) } - var attachQueryList = []int{} + attachQueryList := []int{} var rid int - if len(topic.Rids) > 0 { + if len(t.Rids) > 0 { //log.Print("have rid") - rid = topic.Rids[0] + rid = t.Rids[0] } re, err := Rstore.GetCache().Get(rid) ucache := Users.GetCache() @@ -524,7 +524,7 @@ func (topic *TopicUser) Replies(offset int, pFrag int, user *User) (rlist []*Rep if err != nil { return nil, "", err } - reply.ContentHtml = ParseMessage(reply.Content, topic.ParentID, "forums") + reply.ContentHtml = ParseMessage(reply.Content, t.ParentID, "forums") // TODO: Do this more efficiently by avoiding the allocations entirely in ParseMessage, if there's nothing to do. if reply.ContentHtml == reply.Content { reply.ContentHtml = reply.Content @@ -549,7 +549,7 @@ func (topic *TopicUser) Replies(offset int, pFrag int, user *User) (rlist []*Rep hTbl.VhookNoRet("topic_reply_row_assign", &rlist, &reply) rlist = append(rlist, reply) } else { - rows, err := topicStmts.getReplies.Query(topic.ID, offset, Config.ItemsPerPage) + rows, err := topicStmts.getReplies.Query(t.ID, offset, Config.ItemsPerPage) if err != nil { return nil, "", err } @@ -557,7 +557,7 @@ func (topic *TopicUser) Replies(offset int, pFrag int, user *User) (rlist []*Rep for rows.Next() { reply = &ReplyUser{} - err := rows.Scan(&reply.ID, &reply.Content, &reply.CreatedBy, &reply.CreatedAt, &reply.LastEdit, &reply.LastEditBy, &reply.Avatar, &reply.CreatedByName, &reply.Group, &reply.URLPrefix, &reply.URLName, &reply.Level, &reply.IPAddress, &reply.LikeCount, &reply.AttachCount, &reply.ActionType) + err := rows.Scan(&reply.ID, &reply.Content, &reply.CreatedBy, &reply.CreatedAt, &reply.LastEdit, &reply.LastEditBy, &reply.Avatar, &reply.CreatedByName, &reply.Group, &reply.URLPrefix, &reply.URLName, &reply.Level, &reply.IP, &reply.LikeCount, &reply.AttachCount, &reply.ActionType) if err != nil { return nil, "", err } @@ -566,7 +566,7 @@ func (topic *TopicUser) Replies(offset int, pFrag int, user *User) (rlist []*Rep if err != nil { return nil, "", err } - reply.ContentHtml = ParseMessage(reply.Content, topic.ParentID, "forums") + reply.ContentHtml = ParseMessage(reply.Content, t.ParentID, "forums") if reply.ID == pFrag { ogdesc = reply.Content @@ -627,28 +627,28 @@ func (topic *TopicUser) Replies(offset int, pFrag int, user *User) (rlist []*Rep } // TODO: Test this -func (topic *Topic) Author() (*User, error) { - return Users.Get(topic.CreatedBy) +func (t *Topic) Author() (*User, error) { + return Users.Get(t.CreatedBy) } -func (topic *Topic) GetID() int { - return topic.ID +func (t *Topic) GetID() int { + return t.ID } -func (topic *Topic) GetTable() string { +func (t *Topic) GetTable() string { return "topics" } // Copy gives you a non-pointer concurrency safe copy of the topic -func (topic *Topic) Copy() Topic { - return *topic +func (t *Topic) Copy() Topic { + return *t } // TODO: Load LastReplyAt and LastReplyID? func TopicByReplyID(rid int) (*Topic, error) { - topic := Topic{ID: 0} - err := topicStmts.getByReplyID.QueryRow(rid).Scan(&topic.ID, &topic.Title, &topic.Content, &topic.CreatedBy, &topic.CreatedAt, &topic.IsClosed, &topic.Sticky, &topic.ParentID, &topic.IPAddress, &topic.ViewCount, &topic.PostCount, &topic.LikeCount, &topic.Poll, &topic.Data) - topic.Link = BuildTopicURL(NameToSlug(topic.Title), topic.ID) - return &topic, err + t := Topic{ID: 0} + err := topicStmts.getByReplyID.QueryRow(rid).Scan(&t.ID, &t.Title, &t.Content, &t.CreatedBy, &t.CreatedAt, &t.IsClosed, &t.Sticky, &t.ParentID, &t.IP, &t.ViewCount, &t.PostCount, &t.LikeCount, &t.Poll, &t.Data) + t.Link = BuildTopicURL(NameToSlug(t.Title), t.ID) + return &t, err } // TODO: Refactor the caller to take a Topic and a User rather than a combined TopicUser @@ -684,49 +684,49 @@ func GetTopicUser(user *User, tid int) (tu TopicUser, err error) { tu = TopicUser{ID: tid} // TODO: This misses some important bits... - err = topicStmts.getTopicUser.QueryRow(tid).Scan(&tu.Title, &tu.Content, &tu.CreatedBy, &tu.CreatedAt, &tu.LastReplyAt, &tu.LastReplyBy, &tu.LastReplyID, &tu.IsClosed, &tu.Sticky, &tu.ParentID, &tu.IPAddress, &tu.ViewCount, &tu.PostCount, &tu.LikeCount, &tu.AttachCount, &tu.Poll, &tu.CreatedByName, &tu.Avatar, &tu.Group, &tu.URLPrefix, &tu.URLName, &tu.Level) + err = topicStmts.getTopicUser.QueryRow(tid).Scan(&tu.Title, &tu.Content, &tu.CreatedBy, &tu.CreatedAt, &tu.LastReplyAt, &tu.LastReplyBy, &tu.LastReplyID, &tu.IsClosed, &tu.Sticky, &tu.ParentID, &tu.IP, &tu.ViewCount, &tu.PostCount, &tu.LikeCount, &tu.AttachCount, &tu.Poll, &tu.CreatedByName, &tu.Avatar, &tu.Group, &tu.URLPrefix, &tu.URLName, &tu.Level) tu.Avatar, tu.MicroAvatar = BuildAvatar(tu.CreatedBy, tu.Avatar) tu.Link = BuildTopicURL(NameToSlug(tu.Title), tu.ID) tu.UserLink = BuildProfileURL(NameToSlug(tu.CreatedByName), tu.CreatedBy) tu.Tag = Groups.DirtyGet(tu.Group).Tag if tcache != nil { - theTopic := Topic{ID: tu.ID, Link: tu.Link, Title: tu.Title, Content: tu.Content, CreatedBy: tu.CreatedBy, IsClosed: tu.IsClosed, Sticky: tu.Sticky, CreatedAt: tu.CreatedAt, LastReplyAt: tu.LastReplyAt, LastReplyID: tu.LastReplyID, ParentID: tu.ParentID, IPAddress: tu.IPAddress, ViewCount: tu.ViewCount, PostCount: tu.PostCount, LikeCount: tu.LikeCount, AttachCount: tu.AttachCount, Poll: tu.Poll} + theTopic := Topic{ID: tu.ID, Link: tu.Link, Title: tu.Title, Content: tu.Content, CreatedBy: tu.CreatedBy, IsClosed: tu.IsClosed, Sticky: tu.Sticky, CreatedAt: tu.CreatedAt, LastReplyAt: tu.LastReplyAt, LastReplyID: tu.LastReplyID, ParentID: tu.ParentID, IP: tu.IP, ViewCount: tu.ViewCount, PostCount: tu.PostCount, LikeCount: tu.LikeCount, AttachCount: tu.AttachCount, Poll: tu.Poll} //log.Printf("theTopic: %+v\n", theTopic) _ = tcache.Set(&theTopic) } return tu, err } -func copyTopicToTopicUser(topic *Topic, user *User) (tu TopicUser) { - tu.UserLink = user.Link - tu.CreatedByName = user.Name - tu.Group = user.Group - tu.Avatar = user.Avatar - tu.MicroAvatar = user.MicroAvatar - tu.URLPrefix = user.URLPrefix - tu.URLName = user.URLName - tu.Level = user.Level +func copyTopicToTopicUser(t *Topic, u *User) (tu TopicUser) { + tu.UserLink = u.Link + tu.CreatedByName = u.Name + tu.Group = u.Group + tu.Avatar = u.Avatar + tu.MicroAvatar = u.MicroAvatar + tu.URLPrefix = u.URLPrefix + tu.URLName = u.URLName + tu.Level = u.Level - tu.ID = topic.ID - tu.Link = topic.Link - tu.Title = topic.Title - tu.Content = topic.Content - tu.CreatedBy = topic.CreatedBy - tu.IsClosed = topic.IsClosed - tu.Sticky = topic.Sticky - tu.CreatedAt = topic.CreatedAt - tu.LastReplyAt = topic.LastReplyAt - tu.LastReplyBy = topic.LastReplyBy - tu.ParentID = topic.ParentID - tu.IPAddress = topic.IPAddress - tu.ViewCount = topic.ViewCount - tu.PostCount = topic.PostCount - tu.LikeCount = topic.LikeCount - tu.AttachCount = topic.AttachCount - tu.Poll = topic.Poll - tu.Data = topic.Data - tu.Rids = topic.Rids + tu.ID = t.ID + tu.Link = t.Link + tu.Title = t.Title + tu.Content = t.Content + tu.CreatedBy = t.CreatedBy + tu.IsClosed = t.IsClosed + tu.Sticky = t.Sticky + tu.CreatedAt = t.CreatedAt + tu.LastReplyAt = t.LastReplyAt + tu.LastReplyBy = t.LastReplyBy + tu.ParentID = t.ParentID + tu.IP = t.IP + tu.ViewCount = t.ViewCount + tu.PostCount = t.PostCount + tu.LikeCount = t.LikeCount + tu.AttachCount = t.AttachCount + tu.Poll = t.Poll + tu.Data = t.Data + tu.Rids = t.Rids return tu } diff --git a/common/topic_store.go b/common/topic_store.go index 1e9d781f..1778d4bc 100644 --- a/common/topic_store.go +++ b/common/topic_store.go @@ -94,7 +94,7 @@ func (s *DefaultTopicStore) Get(id int) (topic *Topic, err error) { // BypassGet will always bypass the cache and pull the topic directly from the database func (s *DefaultTopicStore) BypassGet(id int) (*Topic, error) { t := &Topic{ID: id} - err := s.get.QueryRow(id).Scan(&t.Title, &t.Content, &t.CreatedBy, &t.CreatedAt, &t.LastReplyBy, &t.LastReplyAt, &t.LastReplyID, &t.IsClosed, &t.Sticky, &t.ParentID, &t.IPAddress, &t.ViewCount, &t.PostCount, &t.LikeCount, &t.AttachCount, &t.Poll, &t.Data) + err := s.get.QueryRow(id).Scan(&t.Title, &t.Content, &t.CreatedBy, &t.CreatedAt, &t.LastReplyBy, &t.LastReplyAt, &t.LastReplyID, &t.IsClosed, &t.Sticky, &t.ParentID, &t.IP, &t.ViewCount, &t.PostCount, &t.LikeCount, &t.AttachCount, &t.Poll, &t.Data) if err == nil { t.Link = BuildTopicURL(NameToSlug(t.Title), id) } @@ -151,7 +151,7 @@ func (s *DefaultTopicStore) BulkGetMap(ids []int) (list map[int]*Topic, err erro for rows.Next() { t := &Topic{} - err := rows.Scan(&t.ID, &t.Title, &t.Content, &t.CreatedBy, &t.CreatedAt, &t.LastReplyBy, &t.LastReplyAt, &t.LastReplyID, &t.IsClosed, &t.Sticky, &t.ParentID, &t.IPAddress, &t.ViewCount, &t.PostCount, &t.LikeCount, &t.AttachCount, &t.Poll, &t.Data) + err := rows.Scan(&t.ID, &t.Title, &t.Content, &t.CreatedBy, &t.CreatedAt, &t.LastReplyBy, &t.LastReplyAt, &t.LastReplyID, &t.IsClosed, &t.Sticky, &t.ParentID, &t.IP, &t.ViewCount, &t.PostCount, &t.LikeCount, &t.AttachCount, &t.Poll, &t.Data) if err != nil { return list, err } diff --git a/common/user_cache.go b/common/user_cache.go index 29e27ba5..caefb56f 100644 --- a/common/user_cache.go +++ b/common/user_cache.go @@ -40,11 +40,11 @@ func NewMemoryUserCache(capacity int) *MemoryUserCache { } // TODO: Avoid deallocating topic list users -func (mus *MemoryUserCache) DeallocOverflow(evictPriority bool) (evicted int) { - var toEvict = make([]int, 10) - var evIndex = 0 - mus.RLock() - for _, user := range mus.items { +func (s *MemoryUserCache) DeallocOverflow(evictPriority bool) (evicted int) { + toEvict := make([]int, 10) + evIndex := 0 + s.RLock() + for _, user := range s.items { if /*user.LastActiveAt < lastActiveCutoff && */ user.Score == 0 && !user.IsMod { if EnableWebsockets && WsHub.HasUser(user.ID) { continue @@ -56,13 +56,13 @@ func (mus *MemoryUserCache) DeallocOverflow(evictPriority bool) (evicted int) { } } } - mus.RUnlock() + s.RUnlock() // Clear some of the less active users now with a bit more aggressiveness if evIndex == 0 && evictPriority { toEvict = make([]int, 20) - mus.RLock() - for _, user := range mus.items { + s.RLock() + for _, user := range s.items { if user.Score < 100 && !user.IsMod { if EnableWebsockets && WsHub.HasUser(user.ID) { continue @@ -74,11 +74,11 @@ func (mus *MemoryUserCache) DeallocOverflow(evictPriority bool) (evicted int) { } } } - mus.RUnlock() + s.RUnlock() } // Remove zero IDs from the evictable list, so we don't waste precious cycles locked for those - var lastZero = -1 + lastZero := -1 for i, uid := range toEvict { if uid == 0 { lastZero = i @@ -88,15 +88,15 @@ func (mus *MemoryUserCache) DeallocOverflow(evictPriority bool) (evicted int) { toEvict = toEvict[:lastZero] } - mus.BulkRemove(toEvict) + s.BulkRemove(toEvict) return len(toEvict) } // Get fetches a user by ID. Returns ErrNoRows if not present. -func (mus *MemoryUserCache) Get(id int) (*User, error) { - mus.RLock() - item, ok := mus.items[id] - mus.RUnlock() +func (s *MemoryUserCache) Get(id int) (*User, error) { + s.RLock() + item, ok := s.items[id] + s.RUnlock() if ok { return item, nil } @@ -104,19 +104,19 @@ func (mus *MemoryUserCache) Get(id int) (*User, error) { } // BulkGet fetches multiple users by their IDs. Indices without users will be set to nil, so make sure you check for those, we might want to change this behaviour to make it less confusing. -func (mus *MemoryUserCache) BulkGet(ids []int) (list []*User) { +func (s *MemoryUserCache) BulkGet(ids []int) (list []*User) { list = make([]*User, len(ids)) - mus.RLock() + s.RLock() for i, id := range ids { - list[i] = mus.items[id] + list[i] = s.items[id] } - mus.RUnlock() + s.RUnlock() return list } // GetUnsafe fetches a user by ID. Returns ErrNoRows if not present. THIS METHOD IS NOT THREAD-SAFE. -func (mus *MemoryUserCache) GetUnsafe(id int) (*User, error) { - item, ok := mus.items[id] +func (s *MemoryUserCache) GetUnsafe(id int) (*User, error) { + item, ok := s.items[id] if ok { return item, nil } @@ -124,107 +124,107 @@ func (mus *MemoryUserCache) GetUnsafe(id int) (*User, error) { } // Set overwrites the value of a user in the cache, whether it's present or not. May return a capacity overflow error. -func (mus *MemoryUserCache) Set(item *User) error { - mus.Lock() - user, ok := mus.items[item.ID] +func (s *MemoryUserCache) Set(item *User) error { + s.Lock() + user, ok := s.items[item.ID] if ok { - mus.Unlock() + s.Unlock() *user = *item - } else if int(mus.length) >= mus.capacity { - mus.Unlock() + } else if int(s.length) >= s.capacity { + s.Unlock() return ErrStoreCapacityOverflow } else { - mus.items[item.ID] = item - mus.Unlock() - atomic.AddInt64(&mus.length, 1) + s.items[item.ID] = item + s.Unlock() + atomic.AddInt64(&s.length, 1) } return nil } // Add adds a user to the cache, similar to Set, but it's only intended for new items. This method might be deprecated in the near future, use Set. May return a capacity overflow error. // ? Is this redundant if we have Set? Are the efficiency wins worth this? Is this even used? -func (mus *MemoryUserCache) Add(item *User) error { - mus.Lock() - if int(mus.length) >= mus.capacity { - mus.Unlock() +func (s *MemoryUserCache) Add(item *User) error { + s.Lock() + if int(s.length) >= s.capacity { + s.Unlock() return ErrStoreCapacityOverflow } - mus.items[item.ID] = item - mus.length = int64(len(mus.items)) - mus.Unlock() + s.items[item.ID] = item + s.length = int64(len(s.items)) + s.Unlock() return nil } // AddUnsafe is the unsafe version of Add. May return a capacity overflow error. THIS METHOD IS NOT THREAD-SAFE. -func (mus *MemoryUserCache) AddUnsafe(item *User) error { - if int(mus.length) >= mus.capacity { +func (s *MemoryUserCache) AddUnsafe(item *User) error { + if int(s.length) >= s.capacity { return ErrStoreCapacityOverflow } - mus.items[item.ID] = item - mus.length = int64(len(mus.items)) + s.items[item.ID] = item + s.length = int64(len(s.items)) return nil } // Remove removes a user from the cache by ID, if they exist. Returns ErrNoRows if no items exist. -func (mus *MemoryUserCache) Remove(id int) error { - mus.Lock() - _, ok := mus.items[id] +func (s *MemoryUserCache) Remove(id int) error { + s.Lock() + _, ok := s.items[id] if !ok { - mus.Unlock() + s.Unlock() return ErrNoRows } - delete(mus.items, id) - mus.Unlock() - atomic.AddInt64(&mus.length, -1) + delete(s.items, id) + s.Unlock() + atomic.AddInt64(&s.length, -1) return nil } // RemoveUnsafe is the unsafe version of Remove. THIS METHOD IS NOT THREAD-SAFE. -func (mus *MemoryUserCache) RemoveUnsafe(id int) error { - _, ok := mus.items[id] +func (s *MemoryUserCache) RemoveUnsafe(id int) error { + _, ok := s.items[id] if !ok { return ErrNoRows } - delete(mus.items, id) - atomic.AddInt64(&mus.length, -1) + delete(s.items, id) + atomic.AddInt64(&s.length, -1) return nil } -func (mus *MemoryUserCache) BulkRemove(ids []int) { +func (s *MemoryUserCache) BulkRemove(ids []int) { var rCount int64 - mus.Lock() + s.Lock() for _, id := range ids { - _, ok := mus.items[id] + _, ok := s.items[id] if ok { - delete(mus.items, id) + delete(s.items, id) rCount++ } } - mus.Unlock() - atomic.AddInt64(&mus.length, -rCount) + s.Unlock() + atomic.AddInt64(&s.length, -rCount) } // Flush removes all the users from the cache, useful for tests. -func (mus *MemoryUserCache) Flush() { - mus.Lock() - mus.items = make(map[int]*User) - mus.length = 0 - mus.Unlock() +func (s *MemoryUserCache) Flush() { + s.Lock() + s.items = make(map[int]*User) + s.length = 0 + s.Unlock() } // ! Is this concurrent? // Length returns the number of users in the memory cache -func (mus *MemoryUserCache) Length() int { - return int(mus.length) +func (s *MemoryUserCache) Length() int { + return int(s.length) } // SetCapacity sets the maximum number of users which this cache can hold -func (mus *MemoryUserCache) SetCapacity(capacity int) { +func (s *MemoryUserCache) SetCapacity(capacity int) { // Ints are moved in a single instruction, so this should be thread-safe - mus.capacity = capacity + s.capacity = capacity } // GetCapacity returns the maximum number of users this cache can hold -func (mus *MemoryUserCache) GetCapacity() int { - return mus.capacity +func (s *MemoryUserCache) GetCapacity() int { + return s.capacity } diff --git a/general_test.go b/general_test.go index e9fc6419..657508d7 100644 --- a/general_test.go +++ b/general_test.go @@ -793,7 +793,7 @@ func BenchmarkQueryTopicParallel(b *testing.B) { b.RunParallel(func(pb *testing.PB) { var tu c.TopicUser for pb.Next() { - err := db.QueryRow("select topics.title, topics.content, topics.createdBy, topics.createdAt, topics.is_closed, topics.sticky, topics.parentID, topics.ipaddress, topics.views, topics.postCount, topics.likeCount, users.name, users.avatar, users.group, users.url_prefix, users.url_name, users.level from topics left join users ON topics.createdBy = users.uid where tid = ?", 1).Scan(&tu.Title, &tu.Content, &tu.CreatedBy, &tu.CreatedAt, &tu.IsClosed, &tu.Sticky, &tu.ParentID, &tu.IPAddress, &tu.ViewCount, &tu.PostCount, &tu.LikeCount, &tu.CreatedByName, &tu.Avatar, &tu.Group, &tu.URLPrefix, &tu.URLName, &tu.Level) + err := db.QueryRow("select topics.title, topics.content, topics.createdBy, topics.createdAt, topics.is_closed, topics.sticky, topics.parentID, topics.ipaddress, topics.views, topics.postCount, topics.likeCount, users.name, users.avatar, users.group, users.url_prefix, users.url_name, users.level from topics left join users ON topics.createdBy = users.uid where tid = ?", 1).Scan(&tu.Title, &tu.Content, &tu.CreatedBy, &tu.CreatedAt, &tu.IsClosed, &tu.Sticky, &tu.ParentID, &tu.IP, &tu.ViewCount, &tu.PostCount, &tu.LikeCount, &tu.CreatedByName, &tu.Avatar, &tu.Group, &tu.URLPrefix, &tu.URLName, &tu.Level) if err == ErrNoRows { log.Fatal("No rows found!") return @@ -822,7 +822,7 @@ func BenchmarkQueryPreparedTopicParallel(b *testing.B) { defer getTopicUser.Close() for pb.Next() { - err := getTopicUser.QueryRow(1).Scan(&tu.Title, &tu.Content, &tu.CreatedBy, &tu.CreatedAt, &tu.IsClosed, &tu.Sticky, &tu.ParentID, &tu.IPAddress, &tu.PostCount, &tu.LikeCount, &tu.CreatedByName, &tu.Avatar, &tu.Group, &tu.URLPrefix, &tu.URLName, &tu.Level) + err := getTopicUser.QueryRow(1).Scan(&tu.Title, &tu.Content, &tu.CreatedBy, &tu.CreatedAt, &tu.IsClosed, &tu.Sticky, &tu.ParentID, &tu.IP, &tu.PostCount, &tu.LikeCount, &tu.CreatedByName, &tu.Avatar, &tu.Group, &tu.URLPrefix, &tu.URLName, &tu.Level) if err == ErrNoRows { b.Fatal("No rows found!") return @@ -878,7 +878,7 @@ func BenchmarkQueriesSerial(b *testing.B) { var tu c.TopicUser b.Run("topic", func(b *testing.B) { for i := 0; i < b.N; i++ { - err := db.QueryRow("select topics.title, topics.content, topics.createdBy, topics.createdAt, topics.is_closed, topics.sticky, topics.parentID, topics.ipaddress, topics.postCount, topics.likeCount, users.name, users.avatar, users.group, users.url_prefix, users.url_name, users.level from topics left join users ON topics.createdBy = users.uid where tid = ?", 1).Scan(&tu.Title, &tu.Content, &tu.CreatedBy, &tu.CreatedAt, &tu.IsClosed, &tu.Sticky, &tu.ParentID, &tu.IPAddress, &tu.PostCount, &tu.LikeCount, &tu.CreatedByName, &tu.Avatar, &tu.Group, &tu.URLPrefix, &tu.URLName, &tu.Level) + err := db.QueryRow("select topics.title, topics.content, topics.createdBy, topics.createdAt, topics.is_closed, topics.sticky, topics.parentID, topics.ipaddress, topics.postCount, topics.likeCount, users.name, users.avatar, users.group, users.url_prefix, users.url_name, users.level from topics left join users ON topics.createdBy = users.uid where tid = ?", 1).Scan(&tu.Title, &tu.Content, &tu.CreatedBy, &tu.CreatedAt, &tu.IsClosed, &tu.Sticky, &tu.ParentID, &tu.IP, &tu.PostCount, &tu.LikeCount, &tu.CreatedByName, &tu.Avatar, &tu.Group, &tu.URLPrefix, &tu.URLName, &tu.Level) if err == ErrNoRows { b.Fatal("No rows found!") return @@ -907,7 +907,7 @@ func BenchmarkQueriesSerial(b *testing.B) { } }) - var replyItem c.ReplyUser + var r c.ReplyUser var isSuperAdmin bool var group int b.Run("topic_replies_scan", func(b *testing.B) { @@ -918,7 +918,7 @@ func BenchmarkQueriesSerial(b *testing.B) { return } for rows.Next() { - err := rows.Scan(&replyItem.ID, &replyItem.Content, &replyItem.CreatedBy, &replyItem.CreatedAt, &replyItem.LastEdit, &replyItem.LastEditBy, &replyItem.Avatar, &replyItem.CreatedByName, &isSuperAdmin, &group, &replyItem.URLPrefix, &replyItem.URLName, &replyItem.Level, &replyItem.IPAddress) + err := rows.Scan(&r.ID, &r.Content, &r.CreatedBy, &r.CreatedAt, &r.LastEdit, &r.LastEditBy, &r.Avatar, &r.CreatedByName, &isSuperAdmin, &group, &r.URLPrefix, &r.URLName, &r.Level, &r.IP) if err != nil { b.Fatal(err) return diff --git a/misc_test.go b/misc_test.go index 51582294..77a46dee 100644 --- a/misc_test.go +++ b/misc_test.go @@ -497,7 +497,7 @@ func topicStoreTest(t *testing.T, newID int) { return "" } - var testTopic = func(tid int, title string, content string, createdBy int, ip string, parentID int, isClosed bool, sticky bool) { + testTopic := func(tid int, title string, content string, createdBy int, ip string, parentID int, isClosed bool, sticky bool) { topic, err = c.Topics.Get(tid) recordMustExist(t, err, fmt.Sprintf("Couldn't find TID #%d", tid)) expect(t, topic.ID == tid, fmt.Sprintf("topic.ID does not match the requested TID. Got '%d' instead.", topic.ID)) @@ -505,7 +505,7 @@ func topicStoreTest(t *testing.T, newID int) { expect(t, topic.Title == title, fmt.Sprintf("The topic's name should be '%s', not %s", title, topic.Title)) expect(t, topic.Content == content, fmt.Sprintf("The topic's body should be '%s', not %s", content, topic.Content)) expect(t, topic.CreatedBy == createdBy, fmt.Sprintf("The topic's creator should be %d, not %d", createdBy, topic.CreatedBy)) - expect(t, topic.IPAddress == ip, fmt.Sprintf("The topic's IP Address should be '%s', not %s", ip, topic.IPAddress)) + expect(t, topic.IP == ip, fmt.Sprintf("The topic's IP should be '%s', not %s", ip, topic.IP)) expect(t, topic.ParentID == parentID, fmt.Sprintf("The topic's parent forum should be %d, not %d", parentID, topic.ParentID)) expect(t, topic.IsClosed == isClosed, fmt.Sprintf("This topic should%s be locked", iFrag(topic.IsClosed))) expect(t, topic.Sticky == sticky, fmt.Sprintf("This topic should%s be sticky", iFrag(topic.Sticky))) @@ -933,16 +933,16 @@ func TestReplyStore(t *testing.T) { _, err = c.Rstore.Get(0) recordMustNotExist(t, err, "RID #0 shouldn't exist") - var replyTest2 = func(reply *c.Reply, err error, rid int, parentID int, createdBy int, content string, ip string) { + replyTest2 := func(reply *c.Reply, err error, rid int, parentID int, createdBy int, content string, ip string) { expectNilErr(t, err) expect(t, reply.ID == rid, fmt.Sprintf("RID #%d has the wrong ID. It should be %d not %d", rid, rid, reply.ID)) expect(t, reply.ParentID == parentID, fmt.Sprintf("The parent topic of RID #%d should be %d not %d", rid, parentID, reply.ParentID)) expect(t, reply.CreatedBy == createdBy, fmt.Sprintf("The creator of RID #%d should be %d not %d", rid, createdBy, reply.CreatedBy)) expect(t, reply.Content == content, fmt.Sprintf("The contents of RID #%d should be '%s' not %s", rid, content, reply.Content)) - expect(t, reply.IPAddress == ip, fmt.Sprintf("The IPAddress of RID#%d should be '%s' not %s", rid, ip, reply.IPAddress)) + expect(t, reply.IP == ip, fmt.Sprintf("The IP of RID#%d should be '%s' not %s", rid, ip, reply.IP)) } - var replyTest = func(rid int, parentID int, createdBy int, content string, ip string) { + replyTest := func(rid int, parentID int, createdBy int, content string, ip string) { reply, err := c.Rstore.Get(rid) replyTest2(reply, err, rid, parentID, createdBy, content, ip) reply, err = c.Rstore.GetCache().Get(rid) @@ -1043,7 +1043,7 @@ func TestProfileReplyStore(t *testing.T) { expect(t, profileReply.ParentID == 1, fmt.Sprintf("The parent ID of the profile reply should be 1 not %d", profileReply.ParentID)) expect(t, profileReply.Content == "Haha", fmt.Sprintf("The profile reply's contents should be 'Haha' not '%s'", profileReply.Content)) expect(t, profileReply.CreatedBy == 1, fmt.Sprintf("The profile reply's creator should be 1 not %d", profileReply.CreatedBy)) - expect(t, profileReply.IPAddress == "::1", fmt.Sprintf("The profile reply's IP Address should be '::1' not '%s'", profileReply.IPAddress)) + expect(t, profileReply.IP == "::1", fmt.Sprintf("The profile reply's IP should be '::1' not '%s'", profileReply.IP)) err = profileReply.Delete() expectNilErr(t, err) @@ -1104,7 +1104,7 @@ func TestLogs(t *testing.T) { expect(t, log.Action == "something", "log.Action is not something") expect(t, log.ElementID == 0, "log.ElementID is not 0") expect(t, log.ElementType == "bumblefly", "log.ElementType is not bumblefly") - expect(t, log.IPAddress == "::1", "log.IPAddress is not ::1") + expect(t, log.IP == "::1", "log.IP is not ::1") expect(t, log.ActorID == 1, "log.ActorID is not 1") // TODO: Add a test for log.DoneAt? Maybe throw in some dates and times which are clearly impossible but which may occur due to timezone bugs? } diff --git a/routes/account.go b/routes/account.go index 0ef1826d..1e9e1648 100644 --- a/routes/account.go +++ b/routes/account.go @@ -39,19 +39,17 @@ func AccountLoginSubmit(w http.ResponseWriter, r *http.Request, user c.User) c.R username := c.SanitiseSingleLine(r.PostFormValue("username")) uid, err, requiresExtraAuth := c.Auth.Authenticate(username, r.PostFormValue("password")) if err != nil { - { - // TODO: uid is currently set to 0 as authenticate fetches the user by username and password. Get the actual uid, so we can alert the user of attempted logins? What if someone takes advantage of the response times to deduce if an account exists? - logItem := &c.LoginLogItem{UID: uid, Success: false, IPAddress: user.LastIP} - _, err := logItem.Create() - if err != nil { - return c.InternalError(err, w, r) - } + // TODO: uid is currently set to 0 as authenticate fetches the user by username and password. Get the actual uid, so we can alert the user of attempted logins? What if someone takes advantage of the response times to deduce if an account exists? + logItem := &c.LoginLogItem{UID: uid, Success: false, IP: user.LastIP} + _, err := logItem.Create() + if err != nil { + return c.InternalError(err, w, r) } return c.LocalError(err.Error(), w, r, user) } // TODO: Take 2FA into account - logItem := &c.LoginLogItem{UID: uid, Success: true, IPAddress: user.LastIP} + logItem := &c.LoginLogItem{UID: uid, Success: true, IP: user.LastIP} _, err = logItem.Create() if err != nil { return c.InternalError(err, w, r) @@ -263,7 +261,7 @@ func AccountRegisterSubmit(w http.ResponseWriter, r *http.Request, user c.User) } } - regLog := c.RegLogItem{Username: username, Email: email, FailureReason: regErrReason, Success: regSuccess, IPAddress: user.LastIP} + regLog := c.RegLogItem{Username: username, Email: email, FailureReason: regErrReason, Success: regSuccess, IP: user.LastIP} _, err = regLog.Create() if err != nil { return c.InternalError(err, w, r) diff --git a/routes/panel/logs.go b/routes/panel/logs.go index 904fb366..2f043ba3 100644 --- a/routes/panel/logs.go +++ b/routes/panel/logs.go @@ -116,11 +116,11 @@ func LogsMod(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError { if err != nil { return c.InternalError(err, w, r) } - var llist = make([]c.PageLogItem, len(logs)) + llist := make([]c.PageLogItem, len(logs)) for index, log := range logs { actor := handleUnknownUser(c.Users.Get(log.ActorID)) action := modlogsElementType(log.Action, log.ElementType, log.ElementID, actor) - llist[index] = c.PageLogItem{Action: template.HTML(action), IPAddress: log.IPAddress, DoneAt: log.DoneAt} + llist[index] = c.PageLogItem{Action: template.HTML(action), IP: log.IP, DoneAt: log.DoneAt} } pageList := c.Paginate(page, lastPage, 5) @@ -143,11 +143,11 @@ func LogsAdmin(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError if err != nil { return c.InternalError(err, w, r) } - var llist = make([]c.PageLogItem, len(logs)) + llist := make([]c.PageLogItem, len(logs)) for index, log := range logs { actor := handleUnknownUser(c.Users.Get(log.ActorID)) action := modlogsElementType(log.Action, log.ElementType, log.ElementID, actor) - llist[index] = c.PageLogItem{Action: template.HTML(action), IPAddress: log.IPAddress, DoneAt: log.DoneAt} + llist[index] = c.PageLogItem{Action: template.HTML(action), IP: log.IP, DoneAt: log.DoneAt} } pageList := c.Paginate(page, lastPage, 5) diff --git a/templates/account_logins.html b/templates/account_logins.html index 289bc274..d5ec8e0d 100644 --- a/templates/account_logins.html +++ b/templates/account_logins.html @@ -7,7 +7,7 @@
{{if .Success}}{{lang "account_logins_success"}}{{else}}{{lang "account_logins_failure"}}"{{end}}
- {{.IPAddress}} + {{.IP}}
{{.DoneAt}} diff --git a/templates/panel_adminlogs.html b/templates/panel_adminlogs.html index 1d5fff7c..fc11f93a 100644 --- a/templates/panel_adminlogs.html +++ b/templates/panel_adminlogs.html @@ -6,7 +6,7 @@
{{.Action}} - {{if $.CurrentUser.Perms.ViewIPs}}
{{.IPAddress}}{{end}} + {{if $.CurrentUser.Perms.ViewIPs}}
{{.IP}}{{end}}
{{.DoneAt}} diff --git a/templates/panel_modlogs.html b/templates/panel_modlogs.html index b1fb61e4..11a94ed6 100644 --- a/templates/panel_modlogs.html +++ b/templates/panel_modlogs.html @@ -6,7 +6,7 @@
{{.Action}} - {{if $.CurrentUser.Perms.ViewIPs}}
{{.IPAddress}}{{end}} + {{if $.CurrentUser.Perms.ViewIPs}}
{{.IP}}{{end}}
{{.DoneAt}} diff --git a/templates/panel_reglogs.html b/templates/panel_reglogs.html index 10e94d37..c7502f06 100644 --- a/templates/panel_reglogs.html +++ b/templates/panel_reglogs.html @@ -6,7 +6,7 @@
{{if not .Success}}{{lang "panel_logs_registration_attempt"}}: {{end}}{{.Username}} ({{lang "panel_logs_registration_email"}}: {{.Email}}){{if .ParsedReason}} ({{lang "panel_logs_registration_reason"}}: {{.ParsedReason}}){{end}} - {{if $.CurrentUser.Perms.ViewIPs}}
{{.IPAddress}}{{end}} + {{if $.CurrentUser.Perms.ViewIPs}}
{{.IP}}{{end}}
{{.DoneAt}} diff --git a/templates/topic.html b/templates/topic.html index 2c144266..c8da2f69 100644 --- a/templates/topic.html +++ b/templates/topic.html @@ -54,7 +54,7 @@ {{if .CurrentUser.Perms.CloseTopic}}{{if .Topic.IsClosed}}{{else}}{{end}}{{end}} {{if .CurrentUser.Perms.PinTopic}}{{if .Topic.Sticky}}{{else}}{{end}}{{end}} - {{if .CurrentUser.Perms.ViewIPs}}{{end}} + {{if .CurrentUser.Perms.ViewIPs}}{{end}} {{end}} diff --git a/templates/topic_alt.html b/templates/topic_alt.html index d11b3d42..ee27cafd 100644 --- a/templates/topic_alt.html +++ b/templates/topic_alt.html @@ -95,7 +95,7 @@ {{if .Topic.IsClosed}}{{else}}{{end}}{{end}} {{if .CurrentUser.Perms.PinTopic}} {{if .Topic.Sticky}}{{else}}{{end}}{{end}} - {{if .CurrentUser.Perms.ViewIPs}}{{end}} + {{if .CurrentUser.Perms.ViewIPs}}{{end}} {{end}} @@ -103,7 +103,7 @@
{{reltime .Topic.CreatedAt}} - {{if .CurrentUser.Perms.ViewIPs}}{{end}} + {{if .CurrentUser.Perms.ViewIPs}}{{end}}
diff --git a/templates/topic_alt_posts.html b/templates/topic_alt_posts.html index 7ab619ef..f6d601cf 100644 --- a/templates/topic_alt_posts.html +++ b/templates/topic_alt_posts.html @@ -37,7 +37,7 @@ {{if $.CurrentUser.Perms.EditReply}}{{end}} {{end}} {{if $.CurrentUser.Perms.DeleteReply}}{{end}} - {{if $.CurrentUser.Perms.ViewIPs}}{{end}} + {{if $.CurrentUser.Perms.ViewIPs}}{{end}} {{end}} @@ -45,7 +45,7 @@
{{reltime .CreatedAt}} - {{if $.CurrentUser.Loggedin}}{{if $.CurrentUser.Perms.ViewIPs}}{{end}}{{end}} + {{if $.CurrentUser.Loggedin}}{{if $.CurrentUser.Perms.ViewIPs}}{{end}}{{end}}
{{end}} diff --git a/templates/topic_posts.html b/templates/topic_posts.html index 376bf43f..5dca6e21 100644 --- a/templates/topic_posts.html +++ b/templates/topic_posts.html @@ -22,7 +22,7 @@ {{end}} {{if $.CurrentUser.Perms.DeleteReply}}{{end}} - {{if $.CurrentUser.Perms.ViewIPs}}{{end}} + {{if $.CurrentUser.Perms.ViewIPs}}{{end}}