Shortening some things.
Fix the ordering of the lock in WsHubImpl.GuestCount.
This commit is contained in:
parent
85b0522955
commit
ff48ec9d86
@ -198,7 +198,7 @@ func ReplaceForumPermsForGroupTx(tx *sql.Tx, gid int, presetSets map[int]string,
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
addForumPermsToGroupTx, err := qgen.Builder.SimpleInsertTx(tx, "forums_permissions", "gid, fid, preset, permissions", "?,?,?,?")
|
addForumPermsToGroupTx, err := qgen.Builder.SimpleInsertTx(tx, "forums_permissions", "gid,fid,preset,permissions", "?,?,?,?")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -222,19 +222,19 @@ func ReplaceForumPermsForGroupTx(tx *sql.Tx, gid int, presetSets map[int]string,
|
|||||||
|
|
||||||
// TODO: Refactor this and write tests for it
|
// TODO: Refactor this and write tests for it
|
||||||
// TODO: We really need to improve the thread safety of this
|
// TODO: We really need to improve the thread safety of this
|
||||||
func ForumPermsToGroupForumPreset(fperms *ForumPerms) string {
|
func ForumPermsToGroupForumPreset(fp *ForumPerms) string {
|
||||||
if !fperms.Overrides {
|
if !fp.Overrides {
|
||||||
return "default"
|
return "default"
|
||||||
}
|
}
|
||||||
if !fperms.ViewTopic {
|
if !fp.ViewTopic {
|
||||||
return "no_access"
|
return "no_access"
|
||||||
}
|
}
|
||||||
canPost := (fperms.LikeItem && fperms.CreateTopic && fperms.CreateReply)
|
canPost := (fp.LikeItem && fp.CreateTopic && fp.CreateReply)
|
||||||
canModerate := (canPost && fperms.EditTopic && fperms.DeleteTopic && fperms.EditReply && fperms.DeleteReply && fperms.PinTopic && fperms.CloseTopic && fperms.MoveTopic)
|
canModerate := (canPost && fp.EditTopic && fp.DeleteTopic && fp.EditReply && fp.DeleteReply && fp.PinTopic && fp.CloseTopic && fp.MoveTopic)
|
||||||
if canModerate {
|
if canModerate {
|
||||||
return "can_moderate"
|
return "can_moderate"
|
||||||
}
|
}
|
||||||
if fperms.EditTopic || fperms.DeleteTopic || fperms.EditReply || fperms.DeleteReply || fperms.PinTopic || fperms.CloseTopic || fperms.MoveTopic {
|
if fp.EditTopic || fp.DeleteTopic || fp.EditReply || fp.DeleteReply || fp.PinTopic || fp.CloseTopic || fp.MoveTopic {
|
||||||
//if !canPost {
|
//if !canPost {
|
||||||
return "custom"
|
return "custom"
|
||||||
//}
|
//}
|
||||||
@ -244,7 +244,7 @@ func ForumPermsToGroupForumPreset(fperms *ForumPerms) string {
|
|||||||
if canPost {
|
if canPost {
|
||||||
return "can_post"
|
return "can_post"
|
||||||
}
|
}
|
||||||
if fperms.ViewTopic && !fperms.LikeItem && !fperms.CreateTopic && !fperms.CreateReply {
|
if fp.ViewTopic && !fp.LikeItem && !fp.CreateTopic && !fp.CreateReply {
|
||||||
return "read_only"
|
return "read_only"
|
||||||
}
|
}
|
||||||
return "custom"
|
return "custom"
|
||||||
|
@ -35,9 +35,9 @@ func NewSQLSearcher(acc *qgen.Accumulator) (*SQLSearcher, error) {
|
|||||||
}, acc.FirstError()
|
}, acc.FirstError()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (search *SQLSearcher) queryAll(q string) ([]int, error) {
|
func (s *SQLSearcher) queryAll(q string) ([]int, error) {
|
||||||
var ids []int
|
var ids []int
|
||||||
var run = func(stmt *sql.Stmt, q ...interface{}) error {
|
run := func(stmt *sql.Stmt, q ...interface{}) error {
|
||||||
rows, err := stmt.Query(q...)
|
rows, err := stmt.Query(q...)
|
||||||
if err == sql.ErrNoRows {
|
if err == sql.ErrNoRows {
|
||||||
return nil
|
return nil
|
||||||
@ -57,11 +57,11 @@ func (search *SQLSearcher) queryAll(q string) ([]int, error) {
|
|||||||
return rows.Err()
|
return rows.Err()
|
||||||
}
|
}
|
||||||
|
|
||||||
err := run(search.queryReplies, q)
|
err := run(s.queryReplies, q)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
err = run(search.queryTopics, q, q)
|
err = run(s.queryTopics, q, q)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -71,11 +71,11 @@ func (search *SQLSearcher) queryAll(q string) ([]int, error) {
|
|||||||
return ids, err
|
return ids, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (search *SQLSearcher) Query(q string, zones []int) (ids []int, err error) {
|
func (s *SQLSearcher) Query(q string, zones []int) (ids []int, err error) {
|
||||||
if len(zones) == 0 {
|
if len(zones) == 0 {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
var run = func(rows *sql.Rows, err error) error {
|
run := func(rows *sql.Rows, err error) error {
|
||||||
if err == sql.ErrNoRows {
|
if err == sql.ErrNoRows {
|
||||||
return nil
|
return nil
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
@ -95,7 +95,7 @@ func (search *SQLSearcher) Query(q string, zones []int) (ids []int, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if len(zones) == 1 {
|
if len(zones) == 1 {
|
||||||
err = run(search.queryZone.Query(q, q, q, zones[0]))
|
err = run(s.queryZone.Query(q, q, q, zones[0]))
|
||||||
} else {
|
} else {
|
||||||
var zList string
|
var zList string
|
||||||
for _, zone := range zones {
|
for _, zone := range zones {
|
||||||
@ -128,6 +128,6 @@ func NewElasticSearchSearcher() (*ElasticSearchSearcher, error) {
|
|||||||
return &ElasticSearchSearcher{}, nil
|
return &ElasticSearchSearcher{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (search *ElasticSearchSearcher) Query(q string, zones []int) ([]int, error) {
|
func (s *ElasticSearchSearcher) Query(q string, zones []int) ([]int, error) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
@ -53,7 +53,6 @@ func init() {
|
|||||||
|
|
||||||
func NewThemeList() (themes ThemeList, err error) {
|
func NewThemeList() (themes ThemeList, err error) {
|
||||||
themes = make(map[string]*Theme)
|
themes = make(map[string]*Theme)
|
||||||
|
|
||||||
themeFiles, err := ioutil.ReadDir("./themes")
|
themeFiles, err := ioutil.ReadDir("./themes")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return themes, err
|
return themes, err
|
||||||
@ -76,7 +75,7 @@ func NewThemeList() (themes ThemeList, err error) {
|
|||||||
return themes, err
|
return themes, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var theme = &Theme{Name: ""}
|
theme := &Theme{Name: ""}
|
||||||
err = json.Unmarshal(themeFile, theme)
|
err = json.Unmarshal(themeFile, theme)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return themes, err
|
return themes, err
|
||||||
@ -151,7 +150,7 @@ func NewThemeList() (themes ThemeList, err error) {
|
|||||||
if override.IsDir() {
|
if override.IsDir() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
var ext = filepath.Ext(themePath + "/overrides/" + override.Name())
|
ext := filepath.Ext(themePath + "/overrides/" + override.Name())
|
||||||
log.Print("attempting to add " + themePath + "/overrides/" + override.Name())
|
log.Print("attempting to add " + themePath + "/overrides/" + override.Name())
|
||||||
if ext != ".html" {
|
if ext != ".html" {
|
||||||
log.Print("not a html file")
|
log.Print("not a html file")
|
||||||
@ -192,7 +191,7 @@ func NewThemeList() (themes ThemeList, err error) {
|
|||||||
|
|
||||||
// TODO: Make the initThemes and LoadThemes functions less confusing
|
// TODO: Make the initThemes and LoadThemes functions less confusing
|
||||||
// ? - Delete themes which no longer exist in the themes folder from the database?
|
// ? - Delete themes which no longer exist in the themes folder from the database?
|
||||||
func (themes ThemeList) LoadActiveStatus() error {
|
func (t ThemeList) LoadActiveStatus() error {
|
||||||
ChangeDefaultThemeMutex.Lock()
|
ChangeDefaultThemeMutex.Lock()
|
||||||
defer ChangeDefaultThemeMutex.Unlock()
|
defer ChangeDefaultThemeMutex.Unlock()
|
||||||
|
|
||||||
@ -211,7 +210,7 @@ func (themes ThemeList) LoadActiveStatus() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Was the theme deleted at some point?
|
// Was the theme deleted at some point?
|
||||||
theme, ok := themes[uname]
|
theme, ok := t[uname]
|
||||||
if !ok {
|
if !ok {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -226,13 +225,13 @@ func (themes ThemeList) LoadActiveStatus() error {
|
|||||||
theme.Active = false
|
theme.Active = false
|
||||||
}
|
}
|
||||||
|
|
||||||
themes[uname] = theme
|
t[uname] = theme
|
||||||
}
|
}
|
||||||
return rows.Err()
|
return rows.Err()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (themes ThemeList) LoadStaticFiles() error {
|
func (t ThemeList) LoadStaticFiles() error {
|
||||||
for _, theme := range themes {
|
for _, theme := range t {
|
||||||
err := theme.LoadStaticFiles()
|
err := theme.LoadStaticFiles()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -290,10 +290,10 @@ var adminStatsMutex sync.RWMutex
|
|||||||
func adminStatsTicker() {
|
func adminStatsTicker() {
|
||||||
time.Sleep(time.Second)
|
time.Sleep(time.Second)
|
||||||
|
|
||||||
var lastUonline = -1
|
lastUonline := -1
|
||||||
var lastGonline = -1
|
lastGonline := -1
|
||||||
var lastTotonline = -1
|
lastTotonline := -1
|
||||||
var lastCPUPerc = -1
|
lastCPUPerc := -1
|
||||||
var lastAvailableRAM int64 = -1
|
var lastAvailableRAM int64 = -1
|
||||||
var noStatUpdates, noRAMUpdates bool
|
var noStatUpdates, noRAMUpdates bool
|
||||||
|
|
||||||
|
@ -32,9 +32,9 @@ func widgetSearchAndFilter(widget *Widget, hvars interface{}) (out string, err e
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, fid := range canSee {
|
for _, fid := range canSee {
|
||||||
forum := Forums.DirtyGet(fid)
|
f := Forums.DirtyGet(fid)
|
||||||
if forum.ParentID == 0 && forum.Name != "" && forum.Active {
|
if f.ParentID == 0 && f.Name != "" && f.Active {
|
||||||
forums = append(forums, filterForum{forum, (header.Zone == "view_forum" || header.Zone == "topics") && header.ZoneID == forum.ID})
|
forums = append(forums, filterForum{f, (header.Zone == "view_forum" || header.Zone == "topics") && header.ZoneID == f.ID})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
185
common/ws_hub.go
185
common/ws_hub.go
@ -2,9 +2,9 @@ package common
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"log"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
"log"
|
|
||||||
|
|
||||||
"github.com/gorilla/websocket"
|
"github.com/gorilla/websocket"
|
||||||
)
|
)
|
||||||
@ -38,7 +38,7 @@ func init() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (hub *WsHubImpl) Start() {
|
func (h *WsHubImpl) Start() {
|
||||||
log.Print("Setting up the WebSocket ticks")
|
log.Print("Setting up the WebSocket ticks")
|
||||||
ticker := time.NewTicker(time.Minute * 5)
|
ticker := time.NewTicker(time.Minute * 5)
|
||||||
defer func() {
|
defer func() {
|
||||||
@ -47,9 +47,9 @@ func (hub *WsHubImpl) Start() {
|
|||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
item := func(lock *sync.RWMutex, userMap map[int]*WSUser) {
|
item := func(l *sync.RWMutex, userMap map[int]*WSUser) {
|
||||||
lock.RLock()
|
l.RLock()
|
||||||
defer lock.RUnlock()
|
defer l.RUnlock()
|
||||||
// TODO: Copy to temporary slice for less contention?
|
// TODO: Copy to temporary slice for less contention?
|
||||||
for _, user := range userMap {
|
for _, user := range userMap {
|
||||||
user.Ping()
|
user.Ping()
|
||||||
@ -57,26 +57,26 @@ func (hub *WsHubImpl) Start() {
|
|||||||
}
|
}
|
||||||
select {
|
select {
|
||||||
case <-ticker.C:
|
case <-ticker.C:
|
||||||
item(&hub.evenUserLock, hub.evenOnlineUsers)
|
item(&h.evenUserLock, h.evenOnlineUsers)
|
||||||
item(&hub.oddUserLock, hub.oddOnlineUsers)
|
item(&h.oddUserLock, h.oddOnlineUsers)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
if Config.DisableLiveTopicList {
|
if Config.DisableLiveTopicList {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
hub.lastTick = time.Now()
|
h.lastTick = time.Now()
|
||||||
AddScheduledSecondTask(hub.Tick)
|
AddScheduledSecondTask(h.Tick)
|
||||||
}
|
}
|
||||||
|
|
||||||
// This Tick is separate from the admin one, as we want to process that in parallel with this due to the blocking calls to gopsutil
|
// This Tick is separate from the admin one, as we want to process that in parallel with this due to the blocking calls to gopsutil
|
||||||
func (hub *WsHubImpl) Tick() error {
|
func (h *WsHubImpl) Tick() error {
|
||||||
return wsTopicListTick(hub)
|
return wsTopicListTick(h)
|
||||||
}
|
}
|
||||||
|
|
||||||
func wsTopicListTick(hub *WsHubImpl) error {
|
func wsTopicListTick(h *WsHubImpl) error {
|
||||||
// Avoid hitting GetList when the topic list hasn't changed
|
// Avoid hitting GetList when the topic list hasn't changed
|
||||||
if !TopicListThaw.Thawed() && hub.lastTopicList != nil {
|
if !TopicListThaw.Thawed() && h.lastTopicList != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
tickStart := time.Now()
|
tickStart := time.Now()
|
||||||
@ -85,12 +85,12 @@ func wsTopicListTick(hub *WsHubImpl) error {
|
|||||||
// TODO: Get a topic list method which strips stickies?
|
// TODO: Get a topic list method which strips stickies?
|
||||||
tList, _, _, err := TopicList.GetList(1, "", nil)
|
tList, _, _, err := TopicList.GetList(1, "", nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
hub.lastTick = tickStart
|
h.lastTick = tickStart
|
||||||
return err // TODO: Do we get ErrNoRows here?
|
return err // TODO: Do we get ErrNoRows here?
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
hub.lastTick = tickStart
|
h.lastTick = tickStart
|
||||||
hub.lastTopicList = tList
|
h.lastTopicList = tList
|
||||||
}()
|
}()
|
||||||
if len(tList) == 0 {
|
if len(tList) == 0 {
|
||||||
return nil
|
return nil
|
||||||
@ -99,11 +99,11 @@ func wsTopicListTick(hub *WsHubImpl) error {
|
|||||||
// TODO: Optimise this by only sniffing the top non-sticky
|
// TODO: Optimise this by only sniffing the top non-sticky
|
||||||
// TODO: Optimise this by getting back an unsorted list so we don't have to hop around the stickies
|
// TODO: Optimise this by getting back an unsorted list so we don't have to hop around the stickies
|
||||||
// TODO: Add support for new stickies / replies to them
|
// TODO: Add support for new stickies / replies to them
|
||||||
if len(tList) == len(hub.lastTopicList) {
|
if len(tList) == len(h.lastTopicList) {
|
||||||
var hasItem = false
|
hasItem := false
|
||||||
for j, tItem := range tList {
|
for j, tItem := range tList {
|
||||||
if !tItem.Sticky {
|
if !tItem.Sticky {
|
||||||
if tItem.ID != hub.lastTopicList[j].ID || !tItem.LastReplyAt.Equal(hub.lastTopicList[j].LastReplyAt) {
|
if tItem.ID != h.lastTopicList[j].ID || !tItem.LastReplyAt.Equal(h.lastTopicList[j].LastReplyAt) {
|
||||||
hasItem = true
|
hasItem = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -122,9 +122,9 @@ func wsTopicListTick(hub *WsHubImpl) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Copy these over so we close this loop as fast as possible so we can release the read lock, especially if the group gets are backed by calls to the database
|
// Copy these over so we close this loop as fast as possible so we can release the read lock, especially if the group gets are backed by calls to the database
|
||||||
var groupIDs = make(map[int]bool)
|
groupIDs := make(map[int]bool)
|
||||||
var currentWatchers = make([]*WSUser, len(topicListWatchers))
|
currentWatchers := make([]*WSUser, len(topicListWatchers))
|
||||||
var i = 0
|
i := 0
|
||||||
for wsUser, _ := range topicListWatchers {
|
for wsUser, _ := range topicListWatchers {
|
||||||
currentWatchers[i] = wsUser
|
currentWatchers[i] = wsUser
|
||||||
groupIDs[wsUser.User.Group] = true
|
groupIDs[wsUser.User.Group] = true
|
||||||
@ -132,8 +132,8 @@ func wsTopicListTick(hub *WsHubImpl) error {
|
|||||||
}
|
}
|
||||||
topicListMutex.RUnlock()
|
topicListMutex.RUnlock()
|
||||||
|
|
||||||
var groups = make(map[int]*Group)
|
groups := make(map[int]*Group)
|
||||||
var canSeeMap = make(map[string][]int)
|
canSeeMap := make(map[string][]int)
|
||||||
for groupID, _ := range groupIDs {
|
for groupID, _ := range groupIDs {
|
||||||
group, err := Groups.Get(groupID)
|
group, err := Groups.Get(groupID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -142,14 +142,14 @@ func wsTopicListTick(hub *WsHubImpl) error {
|
|||||||
}
|
}
|
||||||
groups[group.ID] = group
|
groups[group.ID] = group
|
||||||
|
|
||||||
var canSee = make([]byte, len(group.CanSee))
|
canSee := make([]byte, len(group.CanSee))
|
||||||
for i, item := range group.CanSee {
|
for i, item := range group.CanSee {
|
||||||
canSee[i] = byte(item)
|
canSee[i] = byte(item)
|
||||||
}
|
}
|
||||||
canSeeMap[string(canSee)] = group.CanSee
|
canSeeMap[string(canSee)] = group.CanSee
|
||||||
}
|
}
|
||||||
|
|
||||||
var canSeeRenders = make(map[string][]byte)
|
canSeeRenders := make(map[string][]byte)
|
||||||
for name, canSee := range canSeeMap {
|
for name, canSee := range canSeeMap {
|
||||||
topicList, forumList, _, err := TopicList.GetListByCanSee(canSee, 1, "", nil)
|
topicList, forumList, _, err := TopicList.GetListByCanSee(canSee, 1, "", nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -161,7 +161,7 @@ func wsTopicListTick(hub *WsHubImpl) error {
|
|||||||
_ = forumList // Might use this later after we get the base feature working
|
_ = forumList // Might use this later after we get the base feature working
|
||||||
|
|
||||||
if topicList[0].Sticky {
|
if topicList[0].Sticky {
|
||||||
var lastSticky = 0
|
lastSticky := 0
|
||||||
for i, row := range topicList {
|
for i, row := range topicList {
|
||||||
if !row.Sticky {
|
if !row.Sticky {
|
||||||
lastSticky = i
|
lastSticky = i
|
||||||
@ -175,7 +175,7 @@ func wsTopicListTick(hub *WsHubImpl) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Compare to previous tick to eliminate unnecessary work and data
|
// TODO: Compare to previous tick to eliminate unnecessary work and data
|
||||||
var wsTopicList = make([]*WsTopicsRow, len(topicList))
|
wsTopicList := make([]*WsTopicsRow, len(topicList))
|
||||||
for i, topicRow := range topicList {
|
for i, topicRow := range topicList {
|
||||||
wsTopicList[i] = topicRow.WebSockets()
|
wsTopicList[i] = topicRow.WebSockets()
|
||||||
}
|
}
|
||||||
@ -191,7 +191,7 @@ func wsTopicListTick(hub *WsHubImpl) error {
|
|||||||
//fmt.Println("writing to the clients")
|
//fmt.Println("writing to the clients")
|
||||||
for _, wsUser := range currentWatchers {
|
for _, wsUser := range currentWatchers {
|
||||||
group := groups[wsUser.User.Group]
|
group := groups[wsUser.User.Group]
|
||||||
var canSee = make([]byte, len(group.CanSee))
|
canSee := make([]byte, len(group.CanSee))
|
||||||
for i, item := range group.CanSee {
|
for i, item := range group.CanSee {
|
||||||
canSee[i] = byte(item)
|
canSee[i] = byte(item)
|
||||||
}
|
}
|
||||||
@ -213,38 +213,39 @@ func wsTopicListTick(hub *WsHubImpl) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (hub *WsHubImpl) GuestCount() int {
|
func (h *WsHubImpl) GuestCount() int {
|
||||||
defer hub.GuestLock.RUnlock()
|
h.GuestLock.RLock()
|
||||||
hub.GuestLock.RLock()
|
defer h.GuestLock.RUnlock()
|
||||||
return len(hub.OnlineGuests)
|
return len(h.OnlineGuests)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (hub *WsHubImpl) UserCount() (count int) {
|
func (h *WsHubImpl) UserCount() (count int) {
|
||||||
hub.evenUserLock.RLock()
|
h.evenUserLock.RLock()
|
||||||
count += len(hub.evenOnlineUsers)
|
count += len(h.evenOnlineUsers)
|
||||||
hub.evenUserLock.RUnlock()
|
h.evenUserLock.RUnlock()
|
||||||
hub.oddUserLock.RLock()
|
h.oddUserLock.RLock()
|
||||||
count += len(hub.oddOnlineUsers)
|
count += len(h.oddOnlineUsers)
|
||||||
hub.oddUserLock.RUnlock()
|
h.oddUserLock.RUnlock()
|
||||||
return count
|
return count
|
||||||
}
|
}
|
||||||
|
|
||||||
func (hub *WsHubImpl) HasUser(uid int) (exists bool) {
|
func (h *WsHubImpl) HasUser(uid int) (exists bool) {
|
||||||
hub.evenUserLock.RLock()
|
h.evenUserLock.RLock()
|
||||||
_, exists = hub.evenOnlineUsers[uid]
|
_, exists = h.evenOnlineUsers[uid]
|
||||||
hub.evenUserLock.RUnlock()
|
h.evenUserLock.RUnlock()
|
||||||
if exists {
|
if exists {
|
||||||
return exists
|
return exists
|
||||||
}
|
}
|
||||||
hub.oddUserLock.RLock()
|
h.oddUserLock.RLock()
|
||||||
_, exists = hub.oddOnlineUsers[uid]
|
_, exists = h.oddOnlineUsers[uid]
|
||||||
hub.oddUserLock.RUnlock()
|
h.oddUserLock.RUnlock()
|
||||||
return exists
|
return exists
|
||||||
}
|
}
|
||||||
|
|
||||||
func (hub *WsHubImpl) broadcastMessage(msg string) error {
|
func (h *WsHubImpl) broadcastMessage(msg string) error {
|
||||||
var userLoop = func(users map[int]*WSUser, mutex *sync.RWMutex) error {
|
userLoop := func(users map[int]*WSUser, m *sync.RWMutex) error {
|
||||||
defer mutex.RUnlock()
|
m.RLock()
|
||||||
|
defer m.RUnlock()
|
||||||
for _, wsUser := range users {
|
for _, wsUser := range users {
|
||||||
err := wsUser.WriteAll(msg)
|
err := wsUser.WriteAll(msg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -254,25 +255,23 @@ func (hub *WsHubImpl) broadcastMessage(msg string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
// TODO: Can we move this RLock inside the closure safely?
|
// TODO: Can we move this RLock inside the closure safely?
|
||||||
hub.evenUserLock.RLock()
|
err := userLoop(h.evenOnlineUsers, &h.evenUserLock)
|
||||||
err := userLoop(hub.evenOnlineUsers, &hub.evenUserLock)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
hub.oddUserLock.RLock()
|
return userLoop(h.oddOnlineUsers, &h.oddUserLock)
|
||||||
return userLoop(hub.oddOnlineUsers, &hub.oddUserLock)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (hub *WsHubImpl) getUser(uid int) (wsUser *WSUser, err error) {
|
func (h *WsHubImpl) getUser(uid int) (wsUser *WSUser, err error) {
|
||||||
var ok bool
|
var ok bool
|
||||||
if uid%2 == 0 {
|
if uid%2 == 0 {
|
||||||
hub.evenUserLock.RLock()
|
h.evenUserLock.RLock()
|
||||||
wsUser, ok = hub.evenOnlineUsers[uid]
|
wsUser, ok = h.evenOnlineUsers[uid]
|
||||||
hub.evenUserLock.RUnlock()
|
h.evenUserLock.RUnlock()
|
||||||
} else {
|
} else {
|
||||||
hub.oddUserLock.RLock()
|
h.oddUserLock.RLock()
|
||||||
wsUser, ok = hub.oddOnlineUsers[uid]
|
wsUser, ok = h.oddOnlineUsers[uid]
|
||||||
hub.oddUserLock.RUnlock()
|
h.oddUserLock.RUnlock()
|
||||||
}
|
}
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, errWsNouser
|
return nil, errWsNouser
|
||||||
@ -281,20 +280,20 @@ func (hub *WsHubImpl) getUser(uid int) (wsUser *WSUser, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Warning: For efficiency, some of the *WSUsers may be nil pointers, DO NOT EXPORT
|
// Warning: For efficiency, some of the *WSUsers may be nil pointers, DO NOT EXPORT
|
||||||
func (hub *WsHubImpl) getUsers(uids []int) (wsUsers []*WSUser, err error) {
|
func (h *WsHubImpl) getUsers(uids []int) (wsUsers []*WSUser, err error) {
|
||||||
if len(uids) == 0 {
|
if len(uids) == 0 {
|
||||||
return nil, errWsNouser
|
return nil, errWsNouser
|
||||||
}
|
}
|
||||||
var appender = func(lock *sync.RWMutex, users map[int]*WSUser) {
|
appender := func(l *sync.RWMutex, users map[int]*WSUser) {
|
||||||
lock.RLock()
|
l.RLock()
|
||||||
defer lock.RUnlock()
|
defer l.RUnlock()
|
||||||
// We don't want to keep a lock on this for too long, so we'll accept some nil pointers
|
// We don't want to keep a lock on this for too long, so we'll accept some nil pointers
|
||||||
for _, uid := range uids {
|
for _, uid := range uids {
|
||||||
wsUsers = append(wsUsers, users[uid])
|
wsUsers = append(wsUsers, users[uid])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
appender(&hub.evenUserLock, hub.evenOnlineUsers)
|
appender(&h.evenUserLock, h.evenOnlineUsers)
|
||||||
appender(&hub.oddUserLock, hub.oddOnlineUsers)
|
appender(&h.oddUserLock, h.oddOnlineUsers)
|
||||||
if len(wsUsers) == 0 {
|
if len(wsUsers) == 0 {
|
||||||
return nil, errWsNouser
|
return nil, errWsNouser
|
||||||
}
|
}
|
||||||
@ -302,32 +301,32 @@ func (hub *WsHubImpl) getUsers(uids []int) (wsUsers []*WSUser, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// For Widget WOL, please avoid using this as it might wind up being really long and slow without the right safeguards
|
// For Widget WOL, please avoid using this as it might wind up being really long and slow without the right safeguards
|
||||||
func (hub *WsHubImpl) AllUsers() (users []*User) {
|
func (h *WsHubImpl) AllUsers() (users []*User) {
|
||||||
var appender = func(lock *sync.RWMutex, userMap map[int]*WSUser) {
|
appender := func(l *sync.RWMutex, userMap map[int]*WSUser) {
|
||||||
lock.RLock()
|
l.RLock()
|
||||||
defer lock.RUnlock()
|
defer l.RUnlock()
|
||||||
for _, user := range userMap {
|
for _, user := range userMap {
|
||||||
users = append(users, user.User)
|
users = append(users, user.User)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
appender(&hub.evenUserLock, hub.evenOnlineUsers)
|
appender(&h.evenUserLock, h.evenOnlineUsers)
|
||||||
appender(&hub.oddUserLock, hub.oddOnlineUsers)
|
appender(&h.oddUserLock, h.oddOnlineUsers)
|
||||||
return users
|
return users
|
||||||
}
|
}
|
||||||
|
|
||||||
func (hub *WsHubImpl) removeUser(uid int) {
|
func (h *WsHubImpl) removeUser(uid int) {
|
||||||
if uid%2 == 0 {
|
if uid%2 == 0 {
|
||||||
hub.evenUserLock.Lock()
|
h.evenUserLock.Lock()
|
||||||
delete(hub.evenOnlineUsers, uid)
|
delete(h.evenOnlineUsers, uid)
|
||||||
hub.evenUserLock.Unlock()
|
h.evenUserLock.Unlock()
|
||||||
} else {
|
} else {
|
||||||
hub.oddUserLock.Lock()
|
h.oddUserLock.Lock()
|
||||||
delete(hub.oddOnlineUsers, uid)
|
delete(h.oddOnlineUsers, uid)
|
||||||
hub.oddUserLock.Unlock()
|
h.oddUserLock.Unlock()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (hub *WsHubImpl) AddConn(user User, conn *websocket.Conn) (*WSUser, error) {
|
func (h *WsHubImpl) AddConn(user User, conn *websocket.Conn) (*WSUser, error) {
|
||||||
if user.ID == 0 {
|
if user.ID == 0 {
|
||||||
wsUser := new(WSUser)
|
wsUser := new(WSUser)
|
||||||
wsUser.User = new(User)
|
wsUser.User = new(User)
|
||||||
@ -348,11 +347,11 @@ func (hub *WsHubImpl) AddConn(user User, conn *websocket.Conn) (*WSUser, error)
|
|||||||
var mutex *sync.RWMutex
|
var mutex *sync.RWMutex
|
||||||
var theMap map[int]*WSUser
|
var theMap map[int]*WSUser
|
||||||
if user.ID%2 == 0 {
|
if user.ID%2 == 0 {
|
||||||
mutex = &hub.evenUserLock
|
mutex = &h.evenUserLock
|
||||||
theMap = hub.evenOnlineUsers
|
theMap = h.evenOnlineUsers
|
||||||
} else {
|
} else {
|
||||||
mutex = &hub.oddUserLock
|
mutex = &h.oddUserLock
|
||||||
theMap = hub.oddOnlineUsers
|
theMap = h.oddOnlineUsers
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex.Lock()
|
mutex.Lock()
|
||||||
@ -370,25 +369,25 @@ func (hub *WsHubImpl) AddConn(user User, conn *websocket.Conn) (*WSUser, error)
|
|||||||
return wsUser, nil
|
return wsUser, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (hub *WsHubImpl) RemoveConn(wsUser *WSUser, conn *websocket.Conn) {
|
func (h *WsHubImpl) RemoveConn(wsUser *WSUser, conn *websocket.Conn) {
|
||||||
wsUser.RemoveSocket(conn)
|
wsUser.RemoveSocket(conn)
|
||||||
wsUser.Lock()
|
wsUser.Lock()
|
||||||
if len(wsUser.Sockets) == 0 {
|
if len(wsUser.Sockets) == 0 {
|
||||||
hub.removeUser(wsUser.User.ID)
|
h.removeUser(wsUser.User.ID)
|
||||||
}
|
}
|
||||||
wsUser.Unlock()
|
wsUser.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (hub *WsHubImpl) PushMessage(targetUser int, msg string) error {
|
func (h *WsHubImpl) PushMessage(targetUser int, msg string) error {
|
||||||
wsUser, err := hub.getUser(targetUser)
|
wsUser, err := h.getUser(targetUser)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return wsUser.WriteAll(msg)
|
return wsUser.WriteAll(msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (hub *WsHubImpl) pushAlert(targetUser int, alert Alert) error {
|
func (h *WsHubImpl) pushAlert(targetUser int, alert Alert) error {
|
||||||
wsUser, err := hub.getUser(targetUser)
|
wsUser, err := h.getUser(targetUser)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -399,8 +398,8 @@ func (hub *WsHubImpl) pushAlert(targetUser int, alert Alert) error {
|
|||||||
return wsUser.WriteAll(astr)
|
return wsUser.WriteAll(astr)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (hub *WsHubImpl) pushAlerts(users []int, alert Alert) error {
|
func (h *WsHubImpl) pushAlerts(users []int, alert Alert) error {
|
||||||
wsUsers, err := hub.getUsers(users)
|
wsUsers, err := h.getUsers(users)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -22,8 +22,8 @@ type WSUserSocket struct {
|
|||||||
Page string
|
Page string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (wsUser *WSUser) Ping() error {
|
func (u *WSUser) Ping() error {
|
||||||
for _, socket := range wsUser.Sockets {
|
for _, socket := range u.Sockets {
|
||||||
if socket == nil {
|
if socket == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -36,9 +36,9 @@ func (wsUser *WSUser) Ping() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (wsUser *WSUser) WriteAll(msg string) error {
|
func (u *WSUser) WriteAll(msg string) error {
|
||||||
msgbytes := []byte(msg)
|
msgbytes := []byte(msg)
|
||||||
for _, socket := range wsUser.Sockets {
|
for _, socket := range u.Sockets {
|
||||||
if socket == nil {
|
if socket == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -52,14 +52,14 @@ func (wsUser *WSUser) WriteAll(msg string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (wsUser *WSUser) WriteToPage(msg string, page string) error {
|
func (u *WSUser) WriteToPage(msg string, page string) error {
|
||||||
return wsUser.WriteToPageBytes([]byte(msg), page)
|
return u.WriteToPageBytes([]byte(msg), page)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inefficient as it looks for sockets for a page even if there are none
|
// Inefficient as it looks for sockets for a page even if there are none
|
||||||
func (wsUser *WSUser) WriteToPageBytes(msg []byte, page string) error {
|
func (u *WSUser) WriteToPageBytes(msg []byte, page string) error {
|
||||||
var success bool
|
var success bool
|
||||||
for _, socket := range wsUser.Sockets {
|
for _, socket := range u.Sockets {
|
||||||
if socket == nil {
|
if socket == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -80,34 +80,34 @@ func (wsUser *WSUser) WriteToPageBytes(msg []byte, page string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (wsUser *WSUser) AddSocket(conn *websocket.Conn, page string) {
|
func (u *WSUser) AddSocket(conn *websocket.Conn, page string) {
|
||||||
wsUser.Lock()
|
u.Lock()
|
||||||
// If the number of the sockets is small, then we can keep the size of the slice mostly static and just walk through it looking for empty slots
|
// If the number of the sockets is small, then we can keep the size of the slice mostly static and just walk through it looking for empty slots
|
||||||
if len(wsUser.Sockets) < 6 {
|
if len(u.Sockets) < 6 {
|
||||||
for i, socket := range wsUser.Sockets {
|
for i, socket := range u.Sockets {
|
||||||
if socket == nil {
|
if socket == nil {
|
||||||
wsUser.Sockets[i] = &WSUserSocket{conn, page}
|
u.Sockets[i] = &WSUserSocket{conn, page}
|
||||||
wsUser.Unlock()
|
u.Unlock()
|
||||||
//fmt.Printf("%+v\n", wsUser.Sockets)
|
//fmt.Printf("%+v\n", u.Sockets)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
wsUser.Sockets = append(wsUser.Sockets, &WSUserSocket{conn, page})
|
u.Sockets = append(u.Sockets, &WSUserSocket{conn, page})
|
||||||
//fmt.Printf("%+v\n", wsUser.Sockets)
|
//fmt.Printf("%+v\n", u.Sockets)
|
||||||
wsUser.Unlock()
|
u.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (wsUser *WSUser) RemoveSocket(conn *websocket.Conn) {
|
func (u *WSUser) RemoveSocket(conn *websocket.Conn) {
|
||||||
wsUser.Lock()
|
u.Lock()
|
||||||
if len(wsUser.Sockets) < 6 {
|
if len(u.Sockets) < 6 {
|
||||||
for i, socket := range wsUser.Sockets {
|
for i, socket := range u.Sockets {
|
||||||
if socket == nil {
|
if socket == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if socket.conn == conn {
|
if socket.conn == conn {
|
||||||
wsUser.Sockets[i] = nil
|
u.Sockets[i] = nil
|
||||||
wsUser.Unlock()
|
u.Unlock()
|
||||||
//fmt.Printf("%+v\n", wsUser.Sockets)
|
//fmt.Printf("%+v\n", wsUser.Sockets)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -115,25 +115,25 @@ func (wsUser *WSUser) RemoveSocket(conn *websocket.Conn) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var key int
|
var key int
|
||||||
for i, socket := range wsUser.Sockets {
|
for i, socket := range u.Sockets {
|
||||||
if socket.conn == conn {
|
if socket.conn == conn {
|
||||||
key = i
|
key = i
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
wsUser.Sockets = append(wsUser.Sockets[:key], wsUser.Sockets[key+1:]...)
|
u.Sockets = append(u.Sockets[:key], u.Sockets[key+1:]...)
|
||||||
//fmt.Printf("%+v\n", wsUser.Sockets)
|
//fmt.Printf("%+v\n", u.Sockets)
|
||||||
|
|
||||||
wsUser.Unlock()
|
u.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (wsUser *WSUser) SetPageForSocket(conn *websocket.Conn, page string) error {
|
func (u *WSUser) SetPageForSocket(conn *websocket.Conn, page string) error {
|
||||||
if conn == nil {
|
if conn == nil {
|
||||||
return ErrInvalidSocket
|
return ErrInvalidSocket
|
||||||
}
|
}
|
||||||
|
|
||||||
wsUser.Lock()
|
u.Lock()
|
||||||
for _, socket := range wsUser.Sockets {
|
for _, socket := range u.Sockets {
|
||||||
if socket == nil {
|
if socket == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -141,15 +141,15 @@ func (wsUser *WSUser) SetPageForSocket(conn *websocket.Conn, page string) error
|
|||||||
socket.Page = page
|
socket.Page = page
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
wsUser.Unlock()
|
u.Unlock()
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (wsUser *WSUser) InPage(page string) bool {
|
func (u *WSUser) InPage(page string) bool {
|
||||||
wsUser.Lock()
|
u.Lock()
|
||||||
defer wsUser.Unlock()
|
defer u.Unlock()
|
||||||
for _, socket := range wsUser.Sockets {
|
for _, socket := range u.Sockets {
|
||||||
if socket == nil {
|
if socket == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -160,10 +160,10 @@ func (wsUser *WSUser) InPage(page string) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (wsUser *WSUser) FinalizePage(page string, handle func()) {
|
func (u *WSUser) FinalizePage(page string, handle func()) {
|
||||||
wsUser.Lock()
|
u.Lock()
|
||||||
defer wsUser.Unlock()
|
defer u.Unlock()
|
||||||
for _, socket := range wsUser.Sockets {
|
for _, socket := range u.Sockets {
|
||||||
if socket == nil {
|
if socket == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -37,7 +37,7 @@ func SitemapXml(w http.ResponseWriter, r *http.Request) c.RouteError {
|
|||||||
if c.Site.EnableSsl {
|
if c.Site.EnableSsl {
|
||||||
sslBit = "s"
|
sslBit = "s"
|
||||||
}
|
}
|
||||||
var sitemapItem = func(path string) {
|
sitemapItem := func(path string) {
|
||||||
w.Write([]byte(`<sitemap>
|
w.Write([]byte(`<sitemap>
|
||||||
<loc>http` + sslBit + `://` + c.Site.URL + "/" + path + `</loc>
|
<loc>http` + sslBit + `://` + c.Site.URL + "/" + path + `</loc>
|
||||||
</sitemap>
|
</sitemap>
|
||||||
@ -72,10 +72,10 @@ var fuzzySitemapRoutes = map[string]FuzzyRoute{
|
|||||||
}
|
}
|
||||||
|
|
||||||
func sitemapSwitch(w http.ResponseWriter, r *http.Request) c.RouteError {
|
func sitemapSwitch(w http.ResponseWriter, r *http.Request) c.RouteError {
|
||||||
var path = r.URL.Path[len("/sitemaps/"):]
|
path := r.URL.Path[len("/sitemaps/"):]
|
||||||
for name, fuzzy := range fuzzySitemapRoutes {
|
for name, fuzzy := range fuzzySitemapRoutes {
|
||||||
if strings.HasPrefix(path, name) && strings.HasSuffix(path, ".xml") {
|
if strings.HasPrefix(path, name) && strings.HasSuffix(path, ".xml") {
|
||||||
var spath = strings.TrimPrefix(path, name)
|
spath := strings.TrimPrefix(path, name)
|
||||||
spath = strings.TrimSuffix(spath, ".xml")
|
spath = strings.TrimSuffix(spath, ".xml")
|
||||||
page, err := strconv.Atoi(spath)
|
page, err := strconv.Atoi(spath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -99,7 +99,7 @@ func SitemapForums(w http.ResponseWriter, r *http.Request) c.RouteError {
|
|||||||
if c.Site.EnableSsl {
|
if c.Site.EnableSsl {
|
||||||
sslBit = "s"
|
sslBit = "s"
|
||||||
}
|
}
|
||||||
var sitemapItem = func(path string) {
|
sitemapItem := func(path string) {
|
||||||
w.Write([]byte(`<url>
|
w.Write([]byte(`<url>
|
||||||
<loc>http` + sslBit + `://` + c.Site.URL + path + `</loc>
|
<loc>http` + sslBit + `://` + c.Site.URL + path + `</loc>
|
||||||
</url>
|
</url>
|
||||||
@ -116,9 +116,9 @@ func SitemapForums(w http.ResponseWriter, r *http.Request) c.RouteError {
|
|||||||
|
|
||||||
for _, fid := range group.CanSee {
|
for _, fid := range group.CanSee {
|
||||||
// Avoid data races by copying the struct into something we can freely mold without worrying about breaking something somewhere else
|
// Avoid data races by copying the struct into something we can freely mold without worrying about breaking something somewhere else
|
||||||
var forum = c.Forums.DirtyGet(fid).Copy()
|
f := c.Forums.DirtyGet(fid).Copy()
|
||||||
if forum.ParentID == 0 && forum.Name != "" && forum.Active {
|
if f.ParentID == 0 && f.Name != "" && f.Active {
|
||||||
sitemapItem(c.BuildForumURL(c.NameToSlug(forum.Name), forum.ID))
|
sitemapItem(c.BuildForumURL(c.NameToSlug(f.Name), f.ID))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -133,7 +133,7 @@ func SitemapTopics(w http.ResponseWriter, r *http.Request) c.RouteError {
|
|||||||
if c.Site.EnableSsl {
|
if c.Site.EnableSsl {
|
||||||
sslBit = "s"
|
sslBit = "s"
|
||||||
}
|
}
|
||||||
var sitemapItem = func(path string) {
|
sitemapItem := func(path string) {
|
||||||
w.Write([]byte(`<sitemap>
|
w.Write([]byte(`<sitemap>
|
||||||
<loc>http` + sslBit + `://` + c.Site.URL + "/" + path + `</loc>
|
<loc>http` + sslBit + `://` + c.Site.URL + "/" + path + `</loc>
|
||||||
</sitemap>
|
</sitemap>
|
||||||
@ -158,7 +158,7 @@ func SitemapTopics(w http.ResponseWriter, r *http.Request) c.RouteError {
|
|||||||
return c.InternalErrorXML(err, w, r)
|
return c.InternalErrorXML(err, w, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
var pageCount = topicCount / sitemapPageCap
|
pageCount := topicCount / sitemapPageCap
|
||||||
//log.Print("topicCount", topicCount)
|
//log.Print("topicCount", topicCount)
|
||||||
//log.Print("pageCount", pageCount)
|
//log.Print("pageCount", pageCount)
|
||||||
writeXMLHeader(w, r)
|
writeXMLHeader(w, r)
|
||||||
@ -201,7 +201,7 @@ func SitemapTopic(w http.ResponseWriter, r *http.Request, page int) c.RouteError
|
|||||||
return c.InternalErrorXML(err, w, r)
|
return c.InternalErrorXML(err, w, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
var pageCount = topicCount / sitemapPageCap
|
pageCount := topicCount / sitemapPageCap
|
||||||
//log.Print("topicCount", topicCount)
|
//log.Print("topicCount", topicCount)
|
||||||
//log.Print("pageCount", pageCount)
|
//log.Print("pageCount", pageCount)
|
||||||
//log.Print("page",page)
|
//log.Print("page",page)
|
||||||
@ -243,7 +243,6 @@ func APIMe(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError {
|
|||||||
w.Header().Set("Cache-Control", "private")
|
w.Header().Set("Cache-Control", "private")
|
||||||
|
|
||||||
me := JsonMe{(&user).Me(), MeSite{c.Site.MaxRequestSize}}
|
me := JsonMe{(&user).Me(), MeSite{c.Site.MaxRequestSize}}
|
||||||
|
|
||||||
jsonBytes, err := json.Marshal(me)
|
jsonBytes, err := json.Marshal(me)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.InternalErrorJS(err, w, r)
|
return c.InternalErrorJS(err, w, r)
|
||||||
@ -258,13 +257,13 @@ func OpenSearchXml(w http.ResponseWriter, r *http.Request) c.RouteError {
|
|||||||
if c.Site.EnableSsl {
|
if c.Site.EnableSsl {
|
||||||
furl += "s"
|
furl += "s"
|
||||||
}
|
}
|
||||||
furl += "://"+c.Site.URL
|
furl += "://" + c.Site.URL
|
||||||
w.Write([]byte(`<OpenSearchDescription xmlns="http://a9.com/-/spec/opensearch/1.1/" xmlns:moz="http://www.mozilla.org/2006/browser/search/">
|
w.Write([]byte(`<OpenSearchDescription xmlns="http://a9.com/-/spec/opensearch/1.1/" xmlns:moz="http://www.mozilla.org/2006/browser/search/">
|
||||||
<ShortName>`+c.Site.Name+`</ShortName>
|
<ShortName>` + c.Site.Name + `</ShortName>
|
||||||
<InputEncoding>UTF-8</InputEncoding>
|
<InputEncoding>UTF-8</InputEncoding>
|
||||||
<Url type="text/html" template="`+furl+`/topics/?q={searchTerms}" />
|
<Url type="text/html" template="` + furl + `/topics/?q={searchTerms}" />
|
||||||
<Url type="application/opensearchdescription+xml" rel="self" template="`+furl+`/opensearch.xml" />
|
<Url type="application/opensearchdescription+xml" rel="self" template="` + furl + `/opensearch.xml" />
|
||||||
<moz:SearchForm>`+furl+`</moz:SearchForm>
|
<moz:SearchForm>` + furl + `</moz:SearchForm>
|
||||||
</OpenSearchDescription>`))
|
</OpenSearchDescription>`))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -35,15 +35,15 @@ func ShowAttachment(w http.ResponseWriter, r *http.Request, user c.User, filenam
|
|||||||
return c.LocalError("Bad extension", w, r, user)
|
return c.LocalError("Bad extension", w, r, user)
|
||||||
}
|
}
|
||||||
|
|
||||||
sectionID, err := strconv.Atoi(r.FormValue("sid"))
|
sid, err := strconv.Atoi(r.FormValue("sid"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.LocalError("The sectionID is not an integer", w, r, user)
|
return c.LocalError("The sid is not an integer", w, r, user)
|
||||||
}
|
}
|
||||||
sectionTable := r.FormValue("stype")
|
sectionTable := r.FormValue("stype")
|
||||||
|
|
||||||
var originTable string
|
var originTable string
|
||||||
var originID, uploadedBy int
|
var originID, uploadedBy int
|
||||||
err = attachmentStmts.get.QueryRow(filename, sectionID, sectionTable).Scan(§ionID, §ionTable, &originID, &originTable, &uploadedBy, &filename)
|
err = attachmentStmts.get.QueryRow(filename, sid, sectionTable).Scan(&sid, §ionTable, &originID, &originTable, &uploadedBy, &filename)
|
||||||
if err == sql.ErrNoRows {
|
if err == sql.ErrNoRows {
|
||||||
return c.NotFound(w, r, nil)
|
return c.NotFound(w, r, nil)
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
@ -51,7 +51,7 @@ func ShowAttachment(w http.ResponseWriter, r *http.Request, user c.User, filenam
|
|||||||
}
|
}
|
||||||
|
|
||||||
if sectionTable == "forums" {
|
if sectionTable == "forums" {
|
||||||
_, ferr := c.SimpleForumUserCheck(w, r, &user, sectionID)
|
_, ferr := c.SimpleForumUserCheck(w, r, &user, sid)
|
||||||
if ferr != nil {
|
if ferr != nil {
|
||||||
return ferr
|
return ferr
|
||||||
}
|
}
|
||||||
@ -70,7 +70,7 @@ func ShowAttachment(w http.ResponseWriter, r *http.Request, user c.User, filenam
|
|||||||
w.Header().Set("Cache-Control", "max-age="+strconv.Itoa(int(c.Year)))
|
w.Header().Set("Cache-Control", "max-age="+strconv.Itoa(int(c.Year)))
|
||||||
} else {
|
} else {
|
||||||
guest := c.GuestUser
|
guest := c.GuestUser
|
||||||
_, ferr := c.SimpleForumUserCheck(w, r, &guest, sectionID)
|
_, ferr := c.SimpleForumUserCheck(w, r, &guest, sid)
|
||||||
if ferr != nil {
|
if ferr != nil {
|
||||||
return ferr
|
return ferr
|
||||||
}
|
}
|
||||||
|
@ -7,8 +7,8 @@ import (
|
|||||||
|
|
||||||
c "github.com/Azareal/Gosora/common"
|
c "github.com/Azareal/Gosora/common"
|
||||||
"github.com/Azareal/Gosora/common/counters"
|
"github.com/Azareal/Gosora/common/counters"
|
||||||
"github.com/Azareal/Gosora/common/phrases"
|
p "github.com/Azareal/Gosora/common/phrases"
|
||||||
"github.com/Azareal/Gosora/query_gen"
|
qgen "github.com/Azareal/Gosora/query_gen"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ForumStmts struct {
|
type ForumStmts struct {
|
||||||
@ -32,7 +32,7 @@ func ViewForum(w http.ResponseWriter, r *http.Request, user c.User, header *c.He
|
|||||||
page, _ := strconv.Atoi(r.FormValue("page"))
|
page, _ := strconv.Atoi(r.FormValue("page"))
|
||||||
_, fid, err := ParseSEOURL(sfid)
|
_, fid, err := ParseSEOURL(sfid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.SimpleError(phrases.GetErrorPhrase("url_id_must_be_integer"),w,r,header)
|
return c.SimpleError(p.GetErrorPhrase("url_id_must_be_integer"), w, r, header)
|
||||||
}
|
}
|
||||||
|
|
||||||
ferr := c.ForumUserCheck(header, w, r, &user, fid)
|
ferr := c.ForumUserCheck(header, w, r, &user, fid)
|
||||||
@ -66,23 +66,23 @@ func ViewForum(w http.ResponseWriter, r *http.Request, user c.User, header *c.He
|
|||||||
|
|
||||||
// TODO: Use something other than TopicsRow as we don't need to store the forum name and link on each and every topic item?
|
// TODO: Use something other than TopicsRow as we don't need to store the forum name and link on each and every topic item?
|
||||||
var topicList []*c.TopicsRow
|
var topicList []*c.TopicsRow
|
||||||
var reqUserList = make(map[int]bool)
|
reqUserList := make(map[int]bool)
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var topicItem = c.TopicsRow{ID: 0}
|
t := c.TopicsRow{ID: 0}
|
||||||
err := rows.Scan(&topicItem.ID, &topicItem.Title, &topicItem.Content, &topicItem.CreatedBy, &topicItem.IsClosed, &topicItem.Sticky, &topicItem.CreatedAt, &topicItem.LastReplyAt, &topicItem.LastReplyBy, &topicItem.LastReplyID, &topicItem.ParentID, &topicItem.ViewCount, &topicItem.PostCount, &topicItem.LikeCount)
|
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)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.InternalError(err, w, r)
|
return c.InternalError(err, w, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
topicItem.Link = c.BuildTopicURL(c.NameToSlug(topicItem.Title), topicItem.ID)
|
t.Link = c.BuildTopicURL(c.NameToSlug(t.Title), t.ID)
|
||||||
// TODO: Create a specialised function with a bit less overhead for getting the last page for a post count
|
// TODO: Create a specialised function with a bit less overhead for getting the last page for a post count
|
||||||
_, _, lastPage := c.PageOffset(topicItem.PostCount, 1, c.Config.ItemsPerPage)
|
_, _, lastPage := c.PageOffset(t.PostCount, 1, c.Config.ItemsPerPage)
|
||||||
topicItem.LastPage = lastPage
|
t.LastPage = lastPage
|
||||||
|
|
||||||
header.Hooks.VhookNoRet("forum_trow_assign", &topicItem, &forum)
|
header.Hooks.VhookNoRet("forum_trow_assign", &t, &forum)
|
||||||
topicList = append(topicList, &topicItem)
|
topicList = append(topicList, &t)
|
||||||
reqUserList[topicItem.CreatedBy] = true
|
reqUserList[t.CreatedBy] = true
|
||||||
reqUserList[topicItem.LastReplyBy] = true
|
reqUserList[t.LastReplyBy] = true
|
||||||
}
|
}
|
||||||
err = rows.Err()
|
err = rows.Err()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -90,7 +90,7 @@ func ViewForum(w http.ResponseWriter, r *http.Request, user c.User, header *c.He
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Convert the user ID map to a slice, then bulk load the users
|
// Convert the user ID map to a slice, then bulk load the users
|
||||||
var idSlice = make([]int, len(reqUserList))
|
idSlice := make([]int, len(reqUserList))
|
||||||
var i int
|
var i int
|
||||||
for userID := range reqUserList {
|
for userID := range reqUserList {
|
||||||
idSlice[i] = userID
|
idSlice[i] = userID
|
||||||
@ -105,9 +105,9 @@ func ViewForum(w http.ResponseWriter, r *http.Request, user c.User, header *c.He
|
|||||||
|
|
||||||
// Second pass to the add the user data
|
// Second pass to the add the user data
|
||||||
// TODO: Use a pointer to TopicsRow instead of TopicsRow itself?
|
// TODO: Use a pointer to TopicsRow instead of TopicsRow itself?
|
||||||
for _, topicItem := range topicList {
|
for _, t := range topicList {
|
||||||
topicItem.Creator = userList[topicItem.CreatedBy]
|
t.Creator = userList[t.CreatedBy]
|
||||||
topicItem.LastUser = userList[topicItem.LastReplyBy]
|
t.LastUser = userList[t.LastReplyBy]
|
||||||
}
|
}
|
||||||
header.Zone = "view_forum"
|
header.Zone = "view_forum"
|
||||||
header.ZoneID = forum.ID
|
header.ZoneID = forum.ID
|
||||||
@ -128,8 +128,8 @@ func ViewForum(w http.ResponseWriter, r *http.Request, user c.User, header *c.He
|
|||||||
if tmpl == "" {
|
if tmpl == "" {
|
||||||
ferr = renderTemplate("forum", w, r, header, pi)
|
ferr = renderTemplate("forum", w, r, header, pi)
|
||||||
} else {
|
} else {
|
||||||
tmpl = "forum_"+tmpl
|
tmpl = "forum_" + tmpl
|
||||||
err = renderTemplate3(tmpl, tmpl,w, r, header, pi)
|
err = renderTemplate3(tmpl, tmpl, w, r, header, pi)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ferr = renderTemplate("forum", w, r, header, pi)
|
ferr = renderTemplate("forum", w, r, header, pi)
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@ func IPSearch(w http.ResponseWriter, r *http.Request, user c.User, header *c.Hea
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Reject IP Addresses with illegal characters
|
// TODO: Reject IP Addresses with illegal characters
|
||||||
var ip = c.SanitiseSingleLine(r.FormValue("ip"))
|
ip := c.SanitiseSingleLine(r.FormValue("ip"))
|
||||||
uids, err := c.IPSearch.Lookup(ip)
|
uids, err := c.IPSearch.Lookup(ip)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.InternalError(err, w, r)
|
return c.InternalError(err, w, r)
|
||||||
|
@ -81,7 +81,6 @@ func PagesEdit(w http.ResponseWriter, r *http.Request, user c.User, spid string)
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return c.LocalError("Page ID needs to be an integer", w, r, user)
|
return c.LocalError("Page ID needs to be an integer", w, r, user)
|
||||||
}
|
}
|
||||||
|
|
||||||
page, err := c.Pages.Get(pid)
|
page, err := c.Pages.Get(pid)
|
||||||
if err == sql.ErrNoRows {
|
if err == sql.ErrNoRows {
|
||||||
return c.NotFound(w, r, basePage.Header)
|
return c.NotFound(w, r, basePage.Header)
|
||||||
@ -103,7 +102,6 @@ func PagesEditSubmit(w http.ResponseWriter, r *http.Request, user c.User, spid s
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return c.LocalError("Page ID needs to be an integer", w, r, user)
|
return c.LocalError("Page ID needs to be an integer", w, r, user)
|
||||||
}
|
}
|
||||||
|
|
||||||
pname := r.PostFormValue("name")
|
pname := r.PostFormValue("name")
|
||||||
if pname == "" {
|
if pname == "" {
|
||||||
return c.LocalError("No name was provided for this page", w, r, user)
|
return c.LocalError("No name was provided for this page", w, r, user)
|
||||||
@ -143,7 +141,6 @@ func PagesDeleteSubmit(w http.ResponseWriter, r *http.Request, user c.User, spid
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return c.LocalError("Page ID needs to be an integer", w, r, user)
|
return c.LocalError("Page ID needs to be an integer", w, r, user)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = c.Pages.Delete(pid)
|
err = c.Pages.Delete(pid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.InternalError(err, w, r)
|
return c.InternalError(err, w, r)
|
||||||
|
@ -10,8 +10,8 @@ import (
|
|||||||
|
|
||||||
c "github.com/Azareal/Gosora/common"
|
c "github.com/Azareal/Gosora/common"
|
||||||
"github.com/Azareal/Gosora/common/counters"
|
"github.com/Azareal/Gosora/common/counters"
|
||||||
"github.com/Azareal/Gosora/common/phrases"
|
p "github.com/Azareal/Gosora/common/phrases"
|
||||||
"github.com/Azareal/Gosora/query_gen"
|
qgen "github.com/Azareal/Gosora/query_gen"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ReplyStmts struct {
|
type ReplyStmts struct {
|
||||||
@ -353,7 +353,7 @@ func ReplyDeleteSubmit(w http.ResponseWriter, r *http.Request, user c.User, srid
|
|||||||
func AddAttachToReplySubmit(w http.ResponseWriter, r *http.Request, user c.User, srid string) c.RouteError {
|
func AddAttachToReplySubmit(w http.ResponseWriter, r *http.Request, user c.User, srid string) c.RouteError {
|
||||||
rid, err := strconv.Atoi(srid)
|
rid, err := strconv.Atoi(srid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.LocalErrorJS(phrases.GetErrorPhrase("id_must_be_integer"), w, r)
|
return c.LocalErrorJS(p.GetErrorPhrase("id_must_be_integer"), w, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
reply, err := c.Rstore.Get(rid)
|
reply, err := c.Rstore.Get(rid)
|
||||||
@ -410,7 +410,7 @@ func AddAttachToReplySubmit(w http.ResponseWriter, r *http.Request, user c.User,
|
|||||||
func RemoveAttachFromReplySubmit(w http.ResponseWriter, r *http.Request, user c.User, srid string) c.RouteError {
|
func RemoveAttachFromReplySubmit(w http.ResponseWriter, r *http.Request, user c.User, srid string) c.RouteError {
|
||||||
rid, err := strconv.Atoi(srid)
|
rid, err := strconv.Atoi(srid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.LocalErrorJS(phrases.GetErrorPhrase("id_must_be_integer"), w, r)
|
return c.LocalErrorJS(p.GetErrorPhrase("id_must_be_integer"), w, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
reply, err := c.Rstore.Get(rid)
|
reply, err := c.Rstore.Get(rid)
|
||||||
@ -443,7 +443,7 @@ func RemoveAttachFromReplySubmit(w http.ResponseWriter, r *http.Request, user c.
|
|||||||
for _, said := range saids {
|
for _, said := range saids {
|
||||||
aid, err := strconv.Atoi(said)
|
aid, err := strconv.Atoi(said)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.LocalErrorJS(phrases.GetErrorPhrase("id_must_be_integer"), w, r)
|
return c.LocalErrorJS(p.GetErrorPhrase("id_must_be_integer"), w, r)
|
||||||
}
|
}
|
||||||
rerr := deleteAttachment(w, r, user, aid, true)
|
rerr := deleteAttachment(w, r, user, aid, true)
|
||||||
if rerr != nil {
|
if rerr != nil {
|
||||||
@ -574,7 +574,6 @@ func ProfileReplyDeleteSubmit(w http.ResponseWriter, r *http.Request, user c.Use
|
|||||||
|
|
||||||
func ReplyLikeSubmit(w http.ResponseWriter, r *http.Request, user c.User, srid string) c.RouteError {
|
func ReplyLikeSubmit(w http.ResponseWriter, r *http.Request, user c.User, srid string) c.RouteError {
|
||||||
js := (r.PostFormValue("js") == "1")
|
js := (r.PostFormValue("js") == "1")
|
||||||
|
|
||||||
rid, err := strconv.Atoi(srid)
|
rid, err := strconv.Atoi(srid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.PreErrorJSQ("The provided Reply ID is not a valid number.", w, r, js)
|
return c.PreErrorJSQ("The provided Reply ID is not a valid number.", w, r, js)
|
||||||
|
@ -281,8 +281,8 @@ func CreateTopic(w http.ResponseWriter, r *http.Request, user c.User, header *c.
|
|||||||
|
|
||||||
// Lock this to the forum being linked?
|
// Lock this to the forum being linked?
|
||||||
// Should we always put it in strictmode when it's linked from another forum? Well, the user might end up changing their mind on what forum they want to post in and it would be a hassle, if they had to switch pages, even if it is a single click for many (exc. mobile)
|
// Should we always put it in strictmode when it's linked from another forum? Well, the user might end up changing their mind on what forum they want to post in and it would be a hassle, if they had to switch pages, even if it is a single click for many (exc. mobile)
|
||||||
var strictmode bool
|
var strict bool
|
||||||
header.Hooks.VhookNoRet("topic_create_pre_loop", w, r, fid, &header, &user, &strictmode)
|
header.Hooks.VhookNoRet("topic_create_pre_loop", w, r, fid, &header, &user, &strict)
|
||||||
|
|
||||||
// TODO: Re-add support for plugin_guilds
|
// TODO: Re-add support for plugin_guilds
|
||||||
var forumList []c.Forum
|
var forumList []c.Forum
|
||||||
@ -306,7 +306,7 @@ func CreateTopic(w http.ResponseWriter, r *http.Request, user c.User, header *c.
|
|||||||
// TODO: plugin_superadmin needs to be able to override this loop. Skip flag on topic_create_pre_loop?
|
// TODO: plugin_superadmin needs to be able to override this loop. Skip flag on topic_create_pre_loop?
|
||||||
for _, ffid := range canSee {
|
for _, ffid := range canSee {
|
||||||
// TODO: Surely, there's a better way of doing this. I've added it in for now to support plugin_guilds, but we really need to clean this up
|
// TODO: Surely, there's a better way of doing this. I've added it in for now to support plugin_guilds, but we really need to clean this up
|
||||||
if strictmode && ffid != fid {
|
if strict && ffid != fid {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -339,10 +339,10 @@ func CreateTopicSubmit(w http.ResponseWriter, r *http.Request, user c.User) c.Ro
|
|||||||
return c.NoPermissions(w, r, user)
|
return c.NoPermissions(w, r, user)
|
||||||
}
|
}
|
||||||
|
|
||||||
topicName := c.SanitiseSingleLine(r.PostFormValue("topic-name"))
|
tname := c.SanitiseSingleLine(r.PostFormValue("topic-name"))
|
||||||
content := c.PreparseMessage(r.PostFormValue("topic-content"))
|
content := c.PreparseMessage(r.PostFormValue("topic-content"))
|
||||||
// TODO: Fully parse the post and store it in the parsed column
|
// TODO: Fully parse the post and store it in the parsed column
|
||||||
tid, err := c.Topics.Create(fid, topicName, content, user.ID, user.LastIP)
|
tid, err := c.Topics.Create(fid, tname, content, user.ID, user.LastIP)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
switch err {
|
switch err {
|
||||||
case c.ErrNoRows:
|
case c.ErrNoRows:
|
||||||
@ -362,8 +362,8 @@ func CreateTopicSubmit(w http.ResponseWriter, r *http.Request, user c.User) c.Ro
|
|||||||
return c.LocalError("Unable to load the topic", w, r, user)
|
return c.LocalError("Unable to load the topic", w, r, user)
|
||||||
}
|
}
|
||||||
if r.PostFormValue("has_poll") == "1" {
|
if r.PostFormValue("has_poll") == "1" {
|
||||||
var maxPollOptions = 10
|
maxPollOptions := 10
|
||||||
var pollInputItems = make(map[int]string)
|
pollInputItems := make(map[int]string)
|
||||||
for key, values := range r.Form {
|
for key, values := range r.Form {
|
||||||
for _, value := range values {
|
for _, value := range values {
|
||||||
if !strings.HasPrefix(key, "pollinputitem[") {
|
if !strings.HasPrefix(key, "pollinputitem[") {
|
||||||
@ -394,7 +394,7 @@ func CreateTopicSubmit(w http.ResponseWriter, r *http.Request, user c.User) c.Ro
|
|||||||
|
|
||||||
if len(pollInputItems) > 0 {
|
if len(pollInputItems) > 0 {
|
||||||
// Make sure the indices are sequential to avoid out of bounds issues
|
// Make sure the indices are sequential to avoid out of bounds issues
|
||||||
var seqPollInputItems = make(map[int]string)
|
seqPollInputItems := make(map[int]string)
|
||||||
for i := 0; i < len(pollInputItems); i++ {
|
for i := 0; i < len(pollInputItems); i++ {
|
||||||
seqPollInputItems[i] = pollInputItems[i]
|
seqPollInputItems[i] = pollInputItems[i]
|
||||||
}
|
}
|
||||||
@ -666,7 +666,7 @@ func topicActionPre(stid string, action string, w http.ResponseWriter, r *http.R
|
|||||||
return nil, nil, c.PreError(phrases.GetErrorPhrase("id_must_be_integer"), w, r)
|
return nil, nil, c.PreError(phrases.GetErrorPhrase("id_must_be_integer"), w, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
topic, err := c.Topics.Get(tid)
|
t, err := c.Topics.Get(tid)
|
||||||
if err == sql.ErrNoRows {
|
if err == sql.ErrNoRows {
|
||||||
return nil, nil, c.PreError("The topic you tried to "+action+" doesn't exist.", w, r)
|
return nil, nil, c.PreError("The topic you tried to "+action+" doesn't exist.", w, r)
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
@ -674,12 +674,11 @@ func topicActionPre(stid string, action string, w http.ResponseWriter, r *http.R
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Add hooks to make use of headerLite
|
// TODO: Add hooks to make use of headerLite
|
||||||
lite, ferr := c.SimpleForumUserCheck(w, r, &user, topic.ParentID)
|
lite, ferr := c.SimpleForumUserCheck(w, r, &user, t.ParentID)
|
||||||
if ferr != nil {
|
if ferr != nil {
|
||||||
return nil, nil, ferr
|
return nil, nil, ferr
|
||||||
}
|
}
|
||||||
|
return t, lite, nil
|
||||||
return topic, lite, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func topicActionPost(err error, action string, w http.ResponseWriter, r *http.Request, lite *c.HeaderLite, topic *c.Topic, user c.User) c.RouteError {
|
func topicActionPost(err error, action string, w http.ResponseWriter, r *http.Request, lite *c.HeaderLite, topic *c.Topic, user c.User) c.RouteError {
|
||||||
@ -698,15 +697,15 @@ func topicActionPost(err error, action string, w http.ResponseWriter, r *http.Re
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func UnstickTopicSubmit(w http.ResponseWriter, r *http.Request, user c.User, stid string) c.RouteError {
|
func UnstickTopicSubmit(w http.ResponseWriter, r *http.Request, u c.User, stid string) c.RouteError {
|
||||||
topic, lite, rerr := topicActionPre(stid, "unpin", w, r, user)
|
t, lite, rerr := topicActionPre(stid, "unpin", w, r, u)
|
||||||
if rerr != nil {
|
if rerr != nil {
|
||||||
return rerr
|
return rerr
|
||||||
}
|
}
|
||||||
if !user.Perms.ViewTopic || !user.Perms.PinTopic {
|
if !u.Perms.ViewTopic || !u.Perms.PinTopic {
|
||||||
return c.NoPermissions(w, r, user)
|
return c.NoPermissions(w, r, u)
|
||||||
}
|
}
|
||||||
return topicActionPost(topic.Unstick(), "unstick", w, r, lite, topic, user)
|
return topicActionPost(t.Unstick(), "unstick", w, r, lite, t, u)
|
||||||
}
|
}
|
||||||
|
|
||||||
func LockTopicSubmit(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError {
|
func LockTopicSubmit(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError {
|
||||||
@ -773,15 +772,15 @@ func LockTopicSubmit(w http.ResponseWriter, r *http.Request, user c.User) c.Rout
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func UnlockTopicSubmit(w http.ResponseWriter, r *http.Request, user c.User, stid string) c.RouteError {
|
func UnlockTopicSubmit(w http.ResponseWriter, r *http.Request, u c.User, stid string) c.RouteError {
|
||||||
topic, lite, rerr := topicActionPre(stid, "unlock", w, r, user)
|
t, lite, rerr := topicActionPre(stid, "unlock", w, r, u)
|
||||||
if rerr != nil {
|
if rerr != nil {
|
||||||
return rerr
|
return rerr
|
||||||
}
|
}
|
||||||
if !user.Perms.ViewTopic || !user.Perms.CloseTopic {
|
if !u.Perms.ViewTopic || !u.Perms.CloseTopic {
|
||||||
return c.NoPermissions(w, r, user)
|
return c.NoPermissions(w, r, u)
|
||||||
}
|
}
|
||||||
return topicActionPost(topic.Unlock(), "unlock", w, r, lite, topic, user)
|
return topicActionPost(t.Unlock(), "unlock", w, r, lite, t, u)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ! JS only route
|
// ! JS only route
|
||||||
@ -853,12 +852,12 @@ func MoveTopicSubmit(w http.ResponseWriter, r *http.Request, user c.User, sfid s
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func addTopicAction(action string, topic *c.Topic, user c.User) error {
|
func addTopicAction(action string, t *c.Topic, u c.User) error {
|
||||||
err := c.ModLogs.Create(action, topic.ID, "topic", user.LastIP, user.ID)
|
err := c.ModLogs.Create(action, t.ID, "topic", u.LastIP, u.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return topic.CreateActionReply(action, user.LastIP, user.ID)
|
return t.CreateActionReply(action, u.LastIP, u.ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Refactor this
|
// TODO: Refactor this
|
||||||
|
Loading…
Reference in New Issue
Block a user