Added the Online Users Context widget.
Commented out a couple lines of debug code. Fixed a data race where the Online Users widget would sometimes show more users than it should. Added a new phrase.
This commit is contained in:
parent
dc8079f581
commit
89a5eafa48
|
@ -34,6 +34,7 @@ var errWsNouser = errors.New("This user isn't connected via WebSockets")
|
||||||
func init() {
|
func init() {
|
||||||
adminStatsWatchers = make(map[*websocket.Conn]*WSUser)
|
adminStatsWatchers = make(map[*websocket.Conn]*WSUser)
|
||||||
topicListWatchers = make(map[*WSUser]bool)
|
topicListWatchers = make(map[*WSUser]bool)
|
||||||
|
topicWatchers = make(map[int]map[*WSUser]bool)
|
||||||
}
|
}
|
||||||
|
|
||||||
type WsTopicList struct {
|
type WsTopicList struct {
|
||||||
|
@ -122,6 +123,7 @@ func wsPageResponses(wsUser *WSUser, conn *websocket.Conn, page string) {
|
||||||
topicListMutex.Lock()
|
topicListMutex.Lock()
|
||||||
topicListWatchers[wsUser] = true
|
topicListWatchers[wsUser] = true
|
||||||
topicListMutex.Unlock()
|
topicListMutex.Unlock()
|
||||||
|
// TODO: Evict from page when permissions change? Or check user perms every-time before sending data?
|
||||||
case strings.HasPrefix(page, "/topic/"):
|
case strings.HasPrefix(page, "/topic/"):
|
||||||
//fmt.Println("entering topic prefix websockets zone")
|
//fmt.Println("entering topic prefix websockets zone")
|
||||||
_, tid, err := ParseSEOURL(page)
|
_, tid, err := ParseSEOURL(page)
|
||||||
|
@ -132,13 +134,12 @@ func wsPageResponses(wsUser *WSUser, conn *websocket.Conn, page string) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var usercpy *User = BlankUser()
|
|
||||||
*usercpy = *wsUser.User
|
|
||||||
usercpy.Init()
|
|
||||||
|
|
||||||
if !Forums.Exists(topic.ParentID) {
|
if !Forums.Exists(topic.ParentID) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
var usercpy *User = BlankUser()
|
||||||
|
*usercpy = *wsUser.User
|
||||||
|
usercpy.Init()
|
||||||
|
|
||||||
/*skip, rerr := header.Hooks.VhookSkippable("ws_topic_check_pre_perms", w, r, usercpy, &fid, &header)
|
/*skip, rerr := header.Hooks.VhookSkippable("ws_topic_check_pre_perms", w, r, usercpy, &fid, &header)
|
||||||
if skip || rerr != nil {
|
if skip || rerr != nil {
|
||||||
|
@ -155,6 +156,14 @@ func wsPageResponses(wsUser *WSUser, conn *websocket.Conn, page string) {
|
||||||
if !usercpy.Perms.ViewTopic {
|
if !usercpy.Perms.ViewTopic {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
topicMutex.Lock()
|
||||||
|
_, ok := topicWatchers[topic.ID]
|
||||||
|
if !ok {
|
||||||
|
topicWatchers[topic.ID] = make(map[*WSUser]bool)
|
||||||
|
}
|
||||||
|
topicWatchers[topic.ID][wsUser] = true
|
||||||
|
topicMutex.Unlock()
|
||||||
case page == "/panel/":
|
case page == "/panel/":
|
||||||
if !wsUser.User.IsSuperMod {
|
if !wsUser.User.IsSuperMod {
|
||||||
return
|
return
|
||||||
|
@ -180,9 +189,7 @@ func wsPageResponses(wsUser *WSUser, conn *websocket.Conn, page string) {
|
||||||
func wsLeavePage(wsUser *WSUser, conn *websocket.Conn, page string) {
|
func wsLeavePage(wsUser *WSUser, conn *websocket.Conn, page string) {
|
||||||
if page == "/" {
|
if page == "/" {
|
||||||
page = Config.DefaultPath
|
page = Config.DefaultPath
|
||||||
}
|
} else if page != "" {
|
||||||
|
|
||||||
if page != "" {
|
|
||||||
DebugLog("Leaving page " + page)
|
DebugLog("Leaving page " + page)
|
||||||
}
|
}
|
||||||
switch {
|
switch {
|
||||||
|
@ -194,6 +201,26 @@ func wsLeavePage(wsUser *WSUser, conn *websocket.Conn, page string) {
|
||||||
})
|
})
|
||||||
case strings.HasPrefix(page, "/topic/"):
|
case strings.HasPrefix(page, "/topic/"):
|
||||||
//fmt.Println("leaving topic prefix websockets zone")
|
//fmt.Println("leaving topic prefix websockets zone")
|
||||||
|
wsUser.FinalizePage(page, func() {
|
||||||
|
_, tid, err := ParseSEOURL(page)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
topicMutex.Lock()
|
||||||
|
defer topicMutex.Unlock()
|
||||||
|
topic, ok := topicWatchers[tid]
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, ok = topic[wsUser]
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
delete(topic, wsUser)
|
||||||
|
if len(topic) == 0 {
|
||||||
|
delete(topicWatchers, tid)
|
||||||
|
}
|
||||||
|
})
|
||||||
case page == "/panel/":
|
case page == "/panel/":
|
||||||
adminStatsMutex.Lock()
|
adminStatsMutex.Lock()
|
||||||
delete(adminStatsWatchers, conn)
|
delete(adminStatsWatchers, conn)
|
||||||
|
@ -209,6 +236,8 @@ func wsLeavePage(wsUser *WSUser, conn *websocket.Conn, page string) {
|
||||||
// TODO: Use odd-even sharding
|
// TODO: Use odd-even sharding
|
||||||
var topicListWatchers map[*WSUser]bool
|
var topicListWatchers map[*WSUser]bool
|
||||||
var topicListMutex sync.RWMutex
|
var topicListMutex sync.RWMutex
|
||||||
|
var topicWatchers map[int]map[*WSUser]bool // map[tid]watchers
|
||||||
|
var topicMutex sync.RWMutex
|
||||||
var adminStatsWatchers map[*websocket.Conn]*WSUser
|
var adminStatsWatchers map[*websocket.Conn]*WSUser
|
||||||
var adminStatsMutex sync.RWMutex
|
var adminStatsMutex sync.RWMutex
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,9 @@ func wolBuild(widget *Widget, hvars interface{}) (string, error) {
|
||||||
var users []*User
|
var users []*User
|
||||||
if ucount < 30 {
|
if ucount < 30 {
|
||||||
users = WsHub.AllUsers()
|
users = WsHub.AllUsers()
|
||||||
|
if len(users) >= 30 {
|
||||||
|
users = nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
wol := &wolUsers{hvars.(*Header), phrases.GetTmplPhrase("widget.online_name"), users, ucount}
|
wol := &wolUsers{hvars.(*Header), phrases.GetTmplPhrase("widget.online_name"), users, ucount}
|
||||||
err := wol.Header.Theme.RunTmpl("widget_online", wol, wol.Header.Writer)
|
err := wol.Header.Theme.RunTmpl("widget_online", wol, wol.Header.Writer)
|
||||||
|
|
|
@ -3,13 +3,24 @@ package common
|
||||||
import "github.com/Azareal/Gosora/common/phrases"
|
import "github.com/Azareal/Gosora/common/phrases"
|
||||||
|
|
||||||
func wolContextRender(widget *Widget, hvars interface{}) (string, error) {
|
func wolContextRender(widget *Widget, hvars interface{}) (string, error) {
|
||||||
ucount := WsHub.UserCount()
|
header := hvars.(*Header)
|
||||||
// We don't want a ridiculously long list, so we'll show the number if it's too high and only show staff individually
|
if header.Zone != "view_topic" {
|
||||||
var users []*User
|
return "", nil
|
||||||
if ucount < 30 {
|
|
||||||
users = WsHub.AllUsers()
|
|
||||||
}
|
}
|
||||||
wol := &wolUsers{hvars.(*Header), phrases.GetTmplPhrase("widget.online_name"), users, ucount}
|
var ucount int
|
||||||
err := wol.Header.Theme.RunTmpl("widget_online", wol, wol.Header.Writer)
|
var users []*User
|
||||||
|
topicMutex.RLock()
|
||||||
|
topic, ok := topicWatchers[header.ZoneID]
|
||||||
|
if ok {
|
||||||
|
ucount = len(topic)
|
||||||
|
if ucount < 30 {
|
||||||
|
for wsUser, _ := range topic {
|
||||||
|
users = append(users, wsUser.User)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
topicMutex.RUnlock()
|
||||||
|
wol := &wolUsers{header, phrases.GetTmplPhrase("widget.online_view_topic_name"), users, ucount}
|
||||||
|
err := header.Theme.RunTmpl("widget_online", wol, header.Writer)
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
|
@ -669,6 +669,7 @@
|
||||||
"widget.online_name":"Online Users",
|
"widget.online_name":"Online Users",
|
||||||
"widget.online_none_online":"No one is online.",
|
"widget.online_none_online":"No one is online.",
|
||||||
"widget.online_some_online":"There are %d users online.",
|
"widget.online_some_online":"There are %d users online.",
|
||||||
|
"widget.online_view_topic_name":"In Topic",
|
||||||
|
|
||||||
"option_yes":"Yes",
|
"option_yes":"Yes",
|
||||||
"option_no":"No",
|
"option_no":"No",
|
||||||
|
|
|
@ -4,7 +4,6 @@ import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -386,7 +385,7 @@ func widgetsParseInputs(r *http.Request, widget *common.Widget) (*common.WidgetE
|
||||||
return nil, errors.New("You need to fill in the body for this widget.")
|
return nil, errors.New("You need to fill in the body for this widget.")
|
||||||
}
|
}
|
||||||
widget.Type = wtype // ? - Are we sure we should be directly assigning user provided data even if it's validated?
|
widget.Type = wtype // ? - Are we sure we should be directly assigning user provided data even if it's validated?
|
||||||
case "wol", "search_and_filter":
|
case "wol", "wol_context", "search_and_filter":
|
||||||
widget.Type = wtype // ? - Are we sure we should be directly assigning user provided data even if it's validated?
|
widget.Type = wtype // ? - Are we sure we should be directly assigning user provided data even if it's validated?
|
||||||
default:
|
default:
|
||||||
return nil, errors.New("Unknown widget type")
|
return nil, errors.New("Unknown widget type")
|
||||||
|
@ -397,7 +396,7 @@ func widgetsParseInputs(r *http.Request, widget *common.Widget) (*common.WidgetE
|
||||||
|
|
||||||
// ThemesWidgetsEditSubmit is an action which is triggered when someone sends an update request for a widget
|
// ThemesWidgetsEditSubmit is an action which is triggered when someone sends an update request for a widget
|
||||||
func ThemesWidgetsEditSubmit(w http.ResponseWriter, r *http.Request, user common.User, swid string) common.RouteError {
|
func ThemesWidgetsEditSubmit(w http.ResponseWriter, r *http.Request, user common.User, swid string) common.RouteError {
|
||||||
fmt.Println("in ThemesWidgetsEditSubmit")
|
//fmt.Println("in ThemesWidgetsEditSubmit")
|
||||||
_, ferr := common.SimplePanelUserCheck(w, r, &user)
|
_, ferr := common.SimplePanelUserCheck(w, r, &user)
|
||||||
if ferr != nil {
|
if ferr != nil {
|
||||||
return ferr
|
return ferr
|
||||||
|
@ -434,7 +433,7 @@ func ThemesWidgetsEditSubmit(w http.ResponseWriter, r *http.Request, user common
|
||||||
|
|
||||||
// ThemesWidgetsCreateSubmit is an action which is triggered when someone sends a create request for a widget
|
// ThemesWidgetsCreateSubmit is an action which is triggered when someone sends a create request for a widget
|
||||||
func ThemesWidgetsCreateSubmit(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError {
|
func ThemesWidgetsCreateSubmit(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError {
|
||||||
fmt.Println("in ThemesWidgetsCreateSubmit")
|
//fmt.Println("in ThemesWidgetsCreateSubmit")
|
||||||
isJs := (r.PostFormValue("js") == "1")
|
isJs := (r.PostFormValue("js") == "1")
|
||||||
_, ferr := common.SimplePanelUserCheck(w, r, &user)
|
_, ferr := common.SimplePanelUserCheck(w, r, &user)
|
||||||
if ferr != nil {
|
if ferr != nil {
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<option value="about"{{if eq .Type "about"}} selected{{end}}>{{lang "panel_themes_widgets_type_about"}}</option>
|
<option value="about"{{if eq .Type "about"}} selected{{end}}>{{lang "panel_themes_widgets_type_about"}}</option>
|
||||||
<option value="simple"{{if eq .Type "simple"}} selected{{end}}>{{lang "panel_themes_widgets_type_simple"}}</option>
|
<option value="simple"{{if eq .Type "simple"}} selected{{end}}>{{lang "panel_themes_widgets_type_simple"}}</option>
|
||||||
<option value="wol"{{if eq .Type "wol"}} selected{{end}}>{{lang "panel_themes_widgets_type_wol"}}</option>
|
<option value="wol"{{if eq .Type "wol"}} selected{{end}}>{{lang "panel_themes_widgets_type_wol"}}</option>
|
||||||
<!--<option value="wol_context"{{if eq .Type "wol_context"}} selected{{end}}>{{lang "panel_themes_widgets_type_wol_context"}}</option>-->
|
<option value="wol_context"{{if eq .Type "wol_context"}} selected{{end}}>{{lang "panel_themes_widgets_type_wol_context"}}</option>
|
||||||
<!--<option value="search_and_filter"{{if eq .Type "search_and_filter"}} selected{{end}}>{{lang "panel_themes_widgets_type_search_and_filter"}}</option>-->
|
<!--<option value="search_and_filter"{{if eq .Type "search_and_filter"}} selected{{end}}>{{lang "panel_themes_widgets_type_search_and_filter"}}</option>-->
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
Loading…
Reference in New Issue