Variables which are computed multiple times in templates should only be computed once now.
Enabled the Watchdog Goroutine. Moved a couple of parser tests into their own file. Eliminated the hard-coded URLs in TestParser() Refactored the alert system so that a specific actor is only loaded once rather than once for each alert. This isn't a problem in practice due to the user cache, but it might be on high traffic sites. Don't run HandleServerSync() on single server setups. Don't load the user in GetTopicUser(), if the topic creator is the current user. Fixed a bug in the template generator where endloop nodes were being pushed instead of endif ones.
This commit is contained in:
parent
87b3f9107d
commit
52c8be4173
100
common/alerts.go
100
common/alerts.go
|
@ -12,10 +12,21 @@ import (
|
|||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/Azareal/Gosora/query_gen"
|
||||
"github.com/Azareal/Gosora/common/phrases"
|
||||
"github.com/Azareal/Gosora/query_gen"
|
||||
)
|
||||
|
||||
type Alert struct {
|
||||
ASID int
|
||||
ActorID int
|
||||
TargetUserID int
|
||||
Event string
|
||||
ElementType string
|
||||
ElementID int
|
||||
|
||||
Actor *User
|
||||
}
|
||||
|
||||
type AlertStmts struct {
|
||||
addActivity *sql.Stmt
|
||||
notifyWatchers *sql.Stmt
|
||||
|
@ -50,81 +61,82 @@ func escapeTextInJson(in string) string {
|
|||
return strings.Replace(in, "/", "\\/", -1)
|
||||
}
|
||||
|
||||
func BuildAlert(asid int, event string, elementType string, actorID int, targetUserID int, elementID int, user User /* The current user */) (string, error) {
|
||||
func BuildAlert(alert Alert, user User /* The current user */) (out string, err error) {
|
||||
var targetUser *User
|
||||
|
||||
actor, err := Users.Get(actorID)
|
||||
if err != nil {
|
||||
return "", errors.New(phrases.GetErrorPhrase("alerts_no_actor"))
|
||||
if alert.Actor == nil {
|
||||
alert.Actor, err = Users.Get(alert.ActorID)
|
||||
if err != nil {
|
||||
return "", errors.New(phrases.GetErrorPhrase("alerts_no_actor"))
|
||||
}
|
||||
}
|
||||
|
||||
/*if elementType != "forum" {
|
||||
targetUser, err = users.Get(targetUserID)
|
||||
/*if alert.ElementType != "forum" {
|
||||
targetUser, err = users.Get(alert.TargetUserID)
|
||||
if err != nil {
|
||||
LocalErrorJS("Unable to find the target user",w,r)
|
||||
return
|
||||
}
|
||||
}*/
|
||||
|
||||
if event == "friend_invite" {
|
||||
return buildAlertString(phrases.GetTmplPhrase("alerts.new_friend_invite"), []string{actor.Name}, actor.Link, actor.Avatar, asid), nil
|
||||
if alert.Event == "friend_invite" {
|
||||
return buildAlertString(phrases.GetTmplPhrase("alerts.new_friend_invite"), []string{alert.Actor.Name}, alert.Actor.Link, alert.Actor.Avatar, alert.ASID), nil
|
||||
}
|
||||
|
||||
// Not that many events for us to handle in a forum
|
||||
if elementType == "forum" {
|
||||
if event == "reply" {
|
||||
topic, err := Topics.Get(elementID)
|
||||
if alert.ElementType == "forum" {
|
||||
if alert.Event == "reply" {
|
||||
topic, err := Topics.Get(alert.ElementID)
|
||||
if err != nil {
|
||||
DebugLogf("Unable to find linked topic %d", elementID)
|
||||
DebugLogf("Unable to find linked topic %d", alert.ElementID)
|
||||
return "", errors.New(phrases.GetErrorPhrase("alerts_no_linked_topic"))
|
||||
}
|
||||
// Store the forum ID in the targetUser column instead of making a new one? o.O
|
||||
// Add an additional column for extra information later on when we add the ability to link directly to posts. We don't need the forum data for now...
|
||||
return buildAlertString(phrases.GetTmplPhrase("alerts.forum_new_topic"), []string{actor.Name, topic.Title}, topic.Link, actor.Avatar, asid), nil
|
||||
return buildAlertString(phrases.GetTmplPhrase("alerts.forum_new_topic"), []string{alert.Actor.Name, topic.Title}, topic.Link, alert.Actor.Avatar, alert.ASID), nil
|
||||
}
|
||||
return buildAlertString(phrases.GetTmplPhrase("alerts.forum_unknown_action"), []string{actor.Name}, "", actor.Avatar, asid), nil
|
||||
return buildAlertString(phrases.GetTmplPhrase("alerts.forum_unknown_action"), []string{alert.Actor.Name}, "", alert.Actor.Avatar, alert.ASID), nil
|
||||
}
|
||||
|
||||
var url, area string
|
||||
var phraseName = "alerts." + elementType
|
||||
switch elementType {
|
||||
var phraseName = "alerts." + alert.ElementType
|
||||
switch alert.ElementType {
|
||||
case "topic":
|
||||
topic, err := Topics.Get(elementID)
|
||||
topic, err := Topics.Get(alert.ElementID)
|
||||
if err != nil {
|
||||
DebugLogf("Unable to find linked topic %d", elementID)
|
||||
DebugLogf("Unable to find linked topic %d", alert.ElementID)
|
||||
return "", errors.New(phrases.GetErrorPhrase("alerts_no_linked_topic"))
|
||||
}
|
||||
url = topic.Link
|
||||
area = topic.Title
|
||||
if targetUserID == user.ID {
|
||||
if alert.TargetUserID == user.ID {
|
||||
phraseName += "_own"
|
||||
}
|
||||
case "user":
|
||||
targetUser, err = Users.Get(elementID)
|
||||
targetUser, err = Users.Get(alert.ElementID)
|
||||
if err != nil {
|
||||
DebugLogf("Unable to find target user %d", elementID)
|
||||
DebugLogf("Unable to find target user %d", alert.ElementID)
|
||||
return "", errors.New(phrases.GetErrorPhrase("alerts_no_target_user"))
|
||||
}
|
||||
area = targetUser.Name
|
||||
url = targetUser.Link
|
||||
if targetUserID == user.ID {
|
||||
if alert.TargetUserID == user.ID {
|
||||
phraseName += "_own"
|
||||
}
|
||||
case "post":
|
||||
topic, err := TopicByReplyID(elementID)
|
||||
topic, err := TopicByReplyID(alert.ElementID)
|
||||
if err != nil {
|
||||
return "", errors.New(phrases.GetErrorPhrase("alerts_no_linked_topic_by_reply"))
|
||||
}
|
||||
url = topic.Link
|
||||
area = topic.Title
|
||||
if targetUserID == user.ID {
|
||||
if alert.TargetUserID == user.ID {
|
||||
phraseName += "_own"
|
||||
}
|
||||
default:
|
||||
return "", errors.New(phrases.GetErrorPhrase("alerts_invalid_elementtype"))
|
||||
}
|
||||
|
||||
switch event {
|
||||
switch alert.Event {
|
||||
case "like":
|
||||
phraseName += "_like"
|
||||
case "mention":
|
||||
|
@ -133,7 +145,7 @@ func BuildAlert(asid int, event string, elementType string, actorID int, targetU
|
|||
phraseName += "_reply"
|
||||
}
|
||||
|
||||
return buildAlertString(phrases.GetTmplPhrase(phraseName), []string{actor.Name, area}, url, actor.Avatar, asid), nil
|
||||
return buildAlertString(phrases.GetTmplPhrase(phraseName), []string{alert.Actor.Name, area}, url, alert.Actor.Avatar, alert.ASID), nil
|
||||
}
|
||||
|
||||
func buildAlertString(msg string, sub []string, path string, avatar string, asid int) string {
|
||||
|
@ -160,22 +172,25 @@ func AddActivityAndNotifyAll(actor int, targetUser int, event string, elementTyp
|
|||
return NotifyWatchers(lastID)
|
||||
}
|
||||
|
||||
func AddActivityAndNotifyTarget(actor int, targetUser int, event string, elementType string, elementID int) error {
|
||||
res, err := alertStmts.addActivity.Exec(actor, targetUser, event, elementType, elementID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
lastID, err := res.LastInsertId()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = NotifyOne(targetUser, lastID)
|
||||
func AddActivityAndNotifyTarget(alert Alert) error {
|
||||
res, err := alertStmts.addActivity.Exec(alert.ActorID, alert.TargetUserID, alert.Event, alert.ElementType, alert.ElementID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
lastID, err := res.LastInsertId()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = NotifyOne(alert.TargetUserID, lastID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
alert.ASID = int(lastID)
|
||||
|
||||
// Live alerts, if the target is online and WebSockets is enabled
|
||||
_ = WsHub.pushAlert(targetUser, int(lastID), event, elementType, actor, targetUser, elementID)
|
||||
_ = WsHub.pushAlert(alert.TargetUserID, alert)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -221,13 +236,12 @@ func notifyWatchers(asid int64) {
|
|||
return
|
||||
}
|
||||
|
||||
var actorID, targetUserID, elementID int
|
||||
var event, elementType string
|
||||
err = alertStmts.getActivityEntry.QueryRow(asid).Scan(&actorID, &targetUserID, &event, &elementType, &elementID)
|
||||
var alert = Alert{ASID: int(asid)}
|
||||
err = alertStmts.getActivityEntry.QueryRow(asid).Scan(&alert.ActorID, &alert.TargetUserID, &alert.Event, &alert.ElementType, &alert.ElementID)
|
||||
if err != nil && err != ErrNoRows {
|
||||
LogError(err)
|
||||
return
|
||||
}
|
||||
|
||||
_ = WsHub.pushAlerts(uids, int(asid), event, elementType, actorID, targetUserID, elementID)
|
||||
_ = WsHub.pushAlerts(uids, alert)
|
||||
}
|
||||
|
|
|
@ -147,6 +147,13 @@ func (list SFileList) JSTmplInit() error {
|
|||
data[braceAt] = ' ' // Blank this one too
|
||||
}
|
||||
})
|
||||
each(" = []byte(", func(index int) {
|
||||
braceAt, hasEndBrace := skipUntilIfExists(data, index, ')')
|
||||
// TODO: Make sure we don't go onto the next line in case someone misplaced a brace
|
||||
if hasEndBrace {
|
||||
data[braceAt] = ' ' // Blank it
|
||||
}
|
||||
})
|
||||
each("w.Write(", func(index int) {
|
||||
braceAt, hasEndBrace := skipUntilIfExists(data, index, ')')
|
||||
// TODO: Make sure we don't go onto the next line in case someone misplaced a brace
|
||||
|
@ -185,6 +192,8 @@ func (list SFileList) JSTmplInit() error {
|
|||
data = replace(data, shortName+"_tmpl_phrase_id = RegisterTmplPhraseNames([]string{", "[")
|
||||
data = replace(data, "var plist = GetTmplPhrasesBytes("+shortName+"_tmpl_phrase_id)", "let plist = tmplPhrases[\""+tmplName+"\"];")
|
||||
//data = replace(data, "var phrases = GetTmplPhrasesBytes("+shortName+"_tmpl_phrase_id)", "let phrases = tmplPhrases[\""+tmplName+"\"];\nconsole.log('tmplName:','"+tmplName+"')\nconsole.log('phrases:', phrases);")
|
||||
data = replace(data, "var cached_var_", "let cached_var_")
|
||||
data = replace(data, " = []byte(", " = ")
|
||||
data = replace(data, "if ", "if(")
|
||||
data = replace(data, "return nil", "return out")
|
||||
data = replace(data, " )", ")")
|
||||
|
|
|
@ -96,9 +96,9 @@ func HandleExpiredScheduledGroups() error {
|
|||
// TODO: Does this even work?
|
||||
func HandleServerSync() error {
|
||||
// We don't want to run any unnecessary queries when there is nothing to synchronise
|
||||
/*if Config.ServerCount > 1 {
|
||||
if Config.ServerCount == 1 {
|
||||
return nil
|
||||
}*/
|
||||
}
|
||||
|
||||
var lastUpdate time.Time
|
||||
err := taskStmts.getSync.QueryRow().Scan(&lastUpdate)
|
||||
|
|
|
@ -4,6 +4,11 @@ import (
|
|||
"reflect"
|
||||
)
|
||||
|
||||
// For use in generated code
|
||||
type FragLite struct {
|
||||
Body string
|
||||
}
|
||||
|
||||
type Fragment struct {
|
||||
Body string
|
||||
TemplateName string
|
||||
|
@ -23,6 +28,7 @@ type CContext struct {
|
|||
VarHolder string
|
||||
HoldReflect reflect.Value
|
||||
TemplateName string
|
||||
LoopDepth int
|
||||
OutBuf *[]OutBufferFrame
|
||||
}
|
||||
|
||||
|
@ -35,3 +41,36 @@ func (con *CContext) PushText(body string, fragIndex int, fragOutIndex int) (ind
|
|||
*con.OutBuf = append(*con.OutBuf, OutBufferFrame{body, "text", con.TemplateName, fragIndex, fragOutIndex})
|
||||
return len(*con.OutBuf) - 1
|
||||
}
|
||||
|
||||
func (con *CContext) PushPhrase(body string, langIndex int) (index int) {
|
||||
*con.OutBuf = append(*con.OutBuf, OutBufferFrame{body, "lang", con.TemplateName, langIndex, nil})
|
||||
return len(*con.OutBuf) - 1
|
||||
}
|
||||
|
||||
func (con *CContext) StartLoop(body string) (index int) {
|
||||
con.LoopDepth++
|
||||
return con.Push("startloop", body)
|
||||
}
|
||||
|
||||
func (con *CContext) EndLoop(body string) (index int) {
|
||||
return con.Push("endloop", body)
|
||||
}
|
||||
|
||||
func (con *CContext) StartTemplate(body string) (index int) {
|
||||
*con.OutBuf = append(*con.OutBuf, OutBufferFrame{body, "starttemplate", con.TemplateName, nil, nil})
|
||||
return len(*con.OutBuf) - 1
|
||||
}
|
||||
|
||||
func (con *CContext) EndTemplate(body string) (index int) {
|
||||
return con.Push("endtemplate", body)
|
||||
}
|
||||
|
||||
func (con *CContext) AttachVars(vars string, index int) {
|
||||
outBuf := *con.OutBuf
|
||||
node := outBuf[index]
|
||||
if node.Type != "starttemplate" && node.Type != "startloop" {
|
||||
panic("not a starttemplate node")
|
||||
}
|
||||
node.Body += vars
|
||||
outBuf[index] = node
|
||||
}
|
||||
|
|
|
@ -189,7 +189,10 @@ func (c *CTemplateSet) Compile(name string, fileDir string, expects string, expe
|
|||
c.TemplateFragmentCount = make(map[string]int)
|
||||
}
|
||||
|
||||
startIndex := con.StartTemplate("")
|
||||
c.rootIterate(c.templateList[fname], con)
|
||||
con.EndTemplate("")
|
||||
c.afterTemplate(con, startIndex)
|
||||
c.TemplateFragmentCount[fname] = c.fragmentCursor[fname] + 1
|
||||
|
||||
_, ok := c.FragOnce[fname]
|
||||
|
@ -280,6 +283,9 @@ func (c *CTemplateSet) Compile(name string, fileDir string, expects string, expe
|
|||
skipBlock.Frags[frame.Extra.(int)] = skipBlock.LastCount
|
||||
}
|
||||
writeTextFrame(frame.TemplateName, frame.Extra.(int)-skip)
|
||||
} else if frame.Type == "varsub" || frame.Type == "cvarsub" {
|
||||
c.detail(frame.Type + " frame")
|
||||
fout += "w.Write(" + frame.Body + ")\n"
|
||||
} else {
|
||||
c.detail(frame.Type + " frame")
|
||||
fout += frame.Body
|
||||
|
@ -425,12 +431,24 @@ func (c *CTemplateSet) compileRangeNode(con CContext, node *parse.RangeNode) {
|
|||
|
||||
var startIf = func(item reflect.Value, useCopy bool) {
|
||||
con.Push("startif", "if len("+expr+") != 0 {\n")
|
||||
con.Push("startloop", "for _, item := range "+expr+" {\n")
|
||||
startIndex := con.StartLoop("for _, item := range " + expr + " {\n")
|
||||
ccon := con
|
||||
ccon.VarHolder = "item"
|
||||
var depth string
|
||||
if ccon.VarHolder == "item" {
|
||||
depth = strings.TrimPrefix(ccon.VarHolder, "item")
|
||||
if depth != "" {
|
||||
idepth, err := strconv.Atoi(depth)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
depth = strconv.Itoa(idepth + 1)
|
||||
}
|
||||
}
|
||||
ccon.VarHolder = "item" + depth
|
||||
ccon.HoldReflect = item
|
||||
c.compileSwitch(ccon, node.List)
|
||||
con.Push("endloop", "}\n")
|
||||
con.EndLoop("}\n")
|
||||
c.afterTemplate(con, startIndex)
|
||||
if node.ElseList != nil {
|
||||
con.Push("endif", "}")
|
||||
con.Push("startelse", " else {\n")
|
||||
|
@ -440,7 +458,7 @@ func (c *CTemplateSet) compileRangeNode(con CContext, node *parse.RangeNode) {
|
|||
c.compileSwitch(ccon, node.ElseList)
|
||||
con.Push("endelse", "}\n")
|
||||
} else {
|
||||
con.Push("endloop", "}\n")
|
||||
con.Push("endif", "}\n")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1098,10 +1116,10 @@ func (c *CTemplateSet) compileVarSub(con CContext, varname string, val reflect.V
|
|||
base = "[]byte(strconv.Itoa(" + varname + "))"
|
||||
case reflect.Bool:
|
||||
con.Push("startif", "if "+varname+" {\n")
|
||||
con.Push("varsub", "w.Write([]byte(\"true\"))")
|
||||
con.Push("varsub", "[]byte(\"true\")")
|
||||
con.Push("endif", "} ")
|
||||
con.Push("startelse", "else {\n")
|
||||
con.Push("varsub", "w.Write([]byte(\"false\"))")
|
||||
con.Push("varsub", "[]byte(\"false\")")
|
||||
con.Push("endelse", "}\n")
|
||||
return
|
||||
case reflect.String:
|
||||
|
@ -1121,7 +1139,6 @@ func (c *CTemplateSet) compileVarSub(con CContext, varname string, val reflect.V
|
|||
fmt.Println("Unknown Type:", val.Type().Name())
|
||||
panic("-- I don't know what this variable's type is o.o\n")
|
||||
}
|
||||
base = "w.Write(" + base + ")\n"
|
||||
c.detail("base: ", base)
|
||||
if assLines == "" {
|
||||
con.Push("varsub", base)
|
||||
|
@ -1179,13 +1196,18 @@ func (c *CTemplateSet) compileSubTemplate(pcon CContext, node *parse.TemplateNod
|
|||
c.templateList[fname] = tree
|
||||
subtree := c.templateList[fname]
|
||||
c.detail("subtree.Root", subtree.Root)
|
||||
|
||||
c.localVars[fname] = make(map[string]VarItemReflect)
|
||||
c.localVars[fname]["."] = VarItemReflect{".", con.VarHolder, con.HoldReflect}
|
||||
c.fragmentCursor[fname] = 0
|
||||
con.Push("starttemplate", "{\n")
|
||||
|
||||
var startBit, endBit string
|
||||
if con.LoopDepth != 0 {
|
||||
startBit = "{\n"
|
||||
endBit = "}\n"
|
||||
}
|
||||
con.StartTemplate(startBit)
|
||||
c.rootIterate(subtree, con)
|
||||
con.Push("endtemplate", "}\n")
|
||||
con.EndTemplate(endBit)
|
||||
c.TemplateFragmentCount[fname] = c.fragmentCursor[fname] + 1
|
||||
|
||||
_, ok := c.FragOnce[fname]
|
||||
|
@ -1194,6 +1216,75 @@ func (c *CTemplateSet) compileSubTemplate(pcon CContext, node *parse.TemplateNod
|
|||
}
|
||||
}
|
||||
|
||||
func (c *CTemplateSet) afterTemplate(con CContext, startIndex int) {
|
||||
c.dumpCall("afterTemplate", con, startIndex)
|
||||
defer c.retCall("afterTemplate")
|
||||
|
||||
var loopDepth = 0
|
||||
var outBuf = *con.OutBuf
|
||||
var varcounts = make(map[string]int)
|
||||
var loopStart = startIndex
|
||||
|
||||
if outBuf[startIndex].Type == "startloop" && (len(outBuf) > startIndex+1) {
|
||||
loopStart++
|
||||
}
|
||||
|
||||
// Exclude varsubs within loops for now
|
||||
for i := loopStart; i < len(outBuf); i++ {
|
||||
item := outBuf[i]
|
||||
c.detail("item:", item)
|
||||
if item.Type == "startloop" {
|
||||
loopDepth++
|
||||
c.detail("loopDepth:", loopDepth)
|
||||
} else if item.Type == "endloop" {
|
||||
loopDepth--
|
||||
c.detail("loopDepth:", loopDepth)
|
||||
if loopDepth == -1 {
|
||||
break
|
||||
}
|
||||
} else if item.Type == "varsub" && loopDepth == 0 {
|
||||
count := varcounts[item.Body]
|
||||
varcounts[item.Body] = count + 1
|
||||
c.detail("count " + strconv.Itoa(count) + " for " + item.Body)
|
||||
c.detail("loopDepth:", loopDepth)
|
||||
}
|
||||
}
|
||||
|
||||
var varstr string
|
||||
var i int
|
||||
var varmap = make(map[string]int)
|
||||
for name, count := range varcounts {
|
||||
if count > 1 {
|
||||
varstr += "var cached_var_" + strconv.Itoa(i) + " = " + name + "\n"
|
||||
varmap[name] = i
|
||||
i++
|
||||
}
|
||||
}
|
||||
|
||||
// Exclude varsubs within loops for now
|
||||
loopDepth = 0
|
||||
for i := loopStart; i < len(outBuf); i++ {
|
||||
item := outBuf[i]
|
||||
if item.Type == "startloop" {
|
||||
loopDepth++
|
||||
} else if item.Type == "endloop" {
|
||||
loopDepth--
|
||||
if loopDepth == -1 {
|
||||
break
|
||||
}
|
||||
} else if item.Type == "varsub" && loopDepth == 0 {
|
||||
index, ok := varmap[item.Body]
|
||||
if ok {
|
||||
item.Body = "cached_var_" + strconv.Itoa(index)
|
||||
item.Type = "cvarsub"
|
||||
outBuf[i] = item
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
con.AttachVars(varstr, startIndex)
|
||||
}
|
||||
|
||||
// TODO: Should we rethink the way the log methods work or their names?
|
||||
|
||||
func (c *CTemplateSet) detail(args ...interface{}) {
|
||||
|
|
|
@ -345,17 +345,18 @@ func TopicByReplyID(rid int) (*Topic, error) {
|
|||
|
||||
// TODO: Refactor the caller to take a Topic and a User rather than a combined TopicUser
|
||||
// TODO: Load LastReplyAt everywhere in here?
|
||||
func GetTopicUser(tid int) (TopicUser, error) {
|
||||
func GetTopicUser(user *User, tid int) (tu TopicUser, err error) {
|
||||
tcache := Topics.GetCache()
|
||||
ucache := Users.GetCache()
|
||||
if tcache != nil && ucache != nil {
|
||||
topic, err := tcache.Get(tid)
|
||||
if err == nil {
|
||||
user, err := Users.Get(topic.CreatedBy)
|
||||
if err != nil {
|
||||
return TopicUser{ID: tid}, err
|
||||
if topic.CreatedBy != user.ID {
|
||||
user, err = Users.Get(topic.CreatedBy)
|
||||
if err != nil {
|
||||
return TopicUser{ID: tid}, err
|
||||
}
|
||||
}
|
||||
|
||||
// We might be better off just passing separate topic and user structs to the caller?
|
||||
return copyTopicToTopicUser(topic, user), nil
|
||||
} else if ucache.Length() < ucache.GetCapacity() {
|
||||
|
@ -363,16 +364,18 @@ func GetTopicUser(tid int) (TopicUser, error) {
|
|||
if err != nil {
|
||||
return TopicUser{ID: tid}, err
|
||||
}
|
||||
user, err := Users.Get(topic.CreatedBy)
|
||||
if err != nil {
|
||||
return TopicUser{ID: tid}, err
|
||||
if topic.CreatedBy != user.ID {
|
||||
user, err = Users.Get(topic.CreatedBy)
|
||||
if err != nil {
|
||||
return TopicUser{ID: tid}, err
|
||||
}
|
||||
}
|
||||
return copyTopicToTopicUser(topic, user), nil
|
||||
}
|
||||
}
|
||||
|
||||
tu := TopicUser{ID: tid}
|
||||
err := topicStmts.getTopicUser.QueryRow(tid).Scan(&tu.Title, &tu.Content, &tu.CreatedBy, &tu.CreatedAt, &tu.IsClosed, &tu.Sticky, &tu.ParentID, &tu.IPAddress, &tu.ViewCount, &tu.PostCount, &tu.LikeCount, &tu.Poll, &tu.CreatedByName, &tu.Avatar, &tu.Group, &tu.URLPrefix, &tu.URLName, &tu.Level)
|
||||
tu = TopicUser{ID: tid}
|
||||
err = topicStmts.getTopicUser.QueryRow(tid).Scan(&tu.Title, &tu.Content, &tu.CreatedBy, &tu.CreatedAt, &tu.IsClosed, &tu.Sticky, &tu.ParentID, &tu.IPAddress, &tu.ViewCount, &tu.PostCount, &tu.LikeCount, &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)
|
||||
|
|
|
@ -340,21 +340,19 @@ func (hub *WsHubImpl) PushMessage(targetUser int, msg string) error {
|
|||
return wsUser.WriteAll(msg)
|
||||
}
|
||||
|
||||
func (hub *WsHubImpl) pushAlert(targetUser int, asid int, event string, elementType string, actorID int, targetUserID int, elementID int) error {
|
||||
func (hub *WsHubImpl) pushAlert(targetUser int, alert Alert) error {
|
||||
wsUser, err := hub.getUser(targetUser)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
alert, err := BuildAlert(asid, event, elementType, actorID, targetUserID, elementID, *wsUser.User)
|
||||
astr, err := BuildAlert(alert, *wsUser.User)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return wsUser.WriteAll(alert)
|
||||
return wsUser.WriteAll(astr)
|
||||
}
|
||||
|
||||
func (hub *WsHubImpl) pushAlerts(users []int, asid int, event string, elementType string, actorID int, targetUserID int, elementID int) error {
|
||||
func (hub *WsHubImpl) pushAlerts(users []int, alert Alert) error {
|
||||
wsUsers, err := hub.getUsers(users)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -365,8 +363,7 @@ func (hub *WsHubImpl) pushAlerts(users []int, asid int, event string, elementTyp
|
|||
if wsUser == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
alert, err := BuildAlert(asid, event, elementType, actorID, targetUserID, elementID, *wsUser.User)
|
||||
alert, err := BuildAlert(alert, *wsUser.User)
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
|
|
12
main.go
12
main.go
|
@ -377,7 +377,7 @@ func main() {
|
|||
go tickLoop(thumbChan, halfSecondTicker, secondTicker, fifteenMinuteTicker, hourTicker)
|
||||
|
||||
// Resource Management Goroutine
|
||||
/*go func() {
|
||||
go func() {
|
||||
ucache := common.Users.GetCache()
|
||||
tcache := common.Topics.GetCache()
|
||||
if ucache == nil && tcache == nil {
|
||||
|
@ -393,17 +393,15 @@ func main() {
|
|||
if ucache != nil {
|
||||
ucap := ucache.GetCapacity()
|
||||
if ucache.Length() <= ucap || common.Users.GlobalCount() <= ucap {
|
||||
countNotDealloc = false
|
||||
couldNotDealloc = false
|
||||
continue
|
||||
}
|
||||
lastEvictedCount = ucache.DeallocOverflow(countNotDealloc)
|
||||
countNotDealloc = (lastEvictedCount == 0)
|
||||
} else {
|
||||
countNotDealloc = false
|
||||
lastEvictedCount = ucache.DeallocOverflow(couldNotDealloc)
|
||||
couldNotDealloc = (lastEvictedCount == 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
}()*/
|
||||
}()
|
||||
|
||||
log.Print("Initialising the router")
|
||||
router, err = NewGenRouter(http.FileServer(http.Dir("./uploads")))
|
||||
|
|
134
misc_test.go
134
misc_test.go
|
@ -1213,137 +1213,3 @@ func TestWordCount(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPreparser(t *testing.T) {
|
||||
var msgList = &METriList{nil}
|
||||
|
||||
// Note: The open tag is evaluated without knowledge of the close tag for efficiency and simplicity, so the parser autofills the associated close tag when it finds an open tag without a partner
|
||||
msgList.Add("", "")
|
||||
msgList.Add(" ", "")
|
||||
msgList.Add(" hi", "hi")
|
||||
msgList.Add("hi ", "hi")
|
||||
msgList.Add("hi", "hi")
|
||||
msgList.Add(":grinning:", "😀")
|
||||
msgList.Add("😀", "😀")
|
||||
msgList.Add(" ", "")
|
||||
msgList.Add("<p>", "")
|
||||
msgList.Add("</p>", "")
|
||||
msgList.Add("<p></p>", "")
|
||||
|
||||
msgList.Add("<", "<")
|
||||
msgList.Add(">", ">")
|
||||
msgList.Add("<meow>", "<meow>")
|
||||
msgList.Add("<", "&lt;")
|
||||
msgList.Add("&", "&")
|
||||
|
||||
// Note: strings.TrimSpace strips newlines, if there's nothing before or after them
|
||||
msgList.Add("<br>", "")
|
||||
msgList.Add("<br />", "")
|
||||
msgList.Add("\\n", "\n", "")
|
||||
msgList.Add("\\n\\n", "\n\n", "")
|
||||
msgList.Add("\\n\\n\\n", "\n\n\n", "")
|
||||
msgList.Add("\\r\\n", "\r\n", "") // Windows style line ending
|
||||
msgList.Add("\\n\\r", "\n\r", "")
|
||||
|
||||
msgList.Add("ho<br>ho", "ho\n\nho")
|
||||
msgList.Add("ho<br />ho", "ho\n\nho")
|
||||
msgList.Add("ho\\nho", "ho\nho", "ho\nho")
|
||||
msgList.Add("ho\\n\\nho", "ho\n\nho", "ho\n\nho")
|
||||
//msgList.Add("ho\\n\\n\\n\\nho", "ho\n\n\n\nho", "ho\n\n\nho")
|
||||
msgList.Add("ho\\r\\nho", "ho\r\nho", "ho\nho") // Windows style line ending
|
||||
msgList.Add("ho\\n\\rho", "ho\n\rho", "ho\nho")
|
||||
|
||||
msgList.Add("<b></b>", "<strong></strong>")
|
||||
msgList.Add("<b>hi</b>", "<strong>hi</strong>")
|
||||
msgList.Add("<s>hi</s>", "<del>hi</del>")
|
||||
msgList.Add("<del>hi</del>", "<del>hi</del>")
|
||||
msgList.Add("<u>hi</u>", "<u>hi</u>")
|
||||
msgList.Add("<em>hi</em>", "<em>hi</em>")
|
||||
msgList.Add("<i>hi</i>", "<em>hi</em>")
|
||||
msgList.Add("<strong>hi</strong>", "<strong>hi</strong>")
|
||||
msgList.Add("<b><i>hi</i></b>", "<strong><em>hi</em></strong>")
|
||||
msgList.Add("<strong><em>hi</em></strong>", "<strong><em>hi</em></strong>")
|
||||
msgList.Add("<b><i><b>hi</b></i></b>", "<strong><em><strong>hi</strong></em></strong>")
|
||||
msgList.Add("<strong><em><strong>hi</strong></em></strong>", "<strong><em><strong>hi</strong></em></strong>")
|
||||
msgList.Add("<div>hi</div>", "<div>hi</div>")
|
||||
msgList.Add("<span>hi</span>", "hi") // This is stripped since the editor (Trumbowyg) likes blasting useless spans
|
||||
msgList.Add("<span >hi</span>", "hi")
|
||||
msgList.Add("<span style='background-color: yellow;'>hi</span>", "hi")
|
||||
msgList.Add("<span style='background-color: yellow;'>>hi</span>", ">hi")
|
||||
msgList.Add("<b>hi", "<strong>hi</strong>")
|
||||
msgList.Add("hi</b>", "hi</b>")
|
||||
msgList.Add("</b>", "</b>")
|
||||
msgList.Add("</del>", "</del>")
|
||||
msgList.Add("</strong>", "</strong>")
|
||||
msgList.Add("<b>", "<strong></strong>")
|
||||
msgList.Add("<span style='background-color: yellow;'>hi", "hi")
|
||||
msgList.Add("hi</span>", "hi")
|
||||
msgList.Add("</span>", "")
|
||||
msgList.Add("<span></span>", "")
|
||||
msgList.Add("<span ></span>", "")
|
||||
msgList.Add("<></>", "<></>")
|
||||
msgList.Add("</><>", "</><>")
|
||||
msgList.Add("<>", "<>")
|
||||
msgList.Add("</>", "</>")
|
||||
msgList.Add("@", "@")
|
||||
msgList.Add("@Admin", "@1")
|
||||
msgList.Add("@Bah", "@Bah")
|
||||
msgList.Add(" @Admin", "@1")
|
||||
msgList.Add("\n@Admin", "@1")
|
||||
msgList.Add("@Admin\n", "@1")
|
||||
msgList.Add("@Admin\ndd", "@1\ndd")
|
||||
msgList.Add("d@Admin", "d@Admin")
|
||||
//msgList.Add("byte 0", string([]byte{0}), "")
|
||||
msgList.Add("byte 'a'", string([]byte{'a'}), "a")
|
||||
//msgList.Add("byte 255", string([]byte{255}), "")
|
||||
//msgList.Add("rune 0", string([]rune{0}), "")
|
||||
// TODO: Do a test with invalid UTF-8 input
|
||||
|
||||
for _, item := range msgList.Items {
|
||||
res := common.PreparseMessage(item.Msg)
|
||||
if res != item.Expects {
|
||||
if item.Name != "" {
|
||||
t.Error("Name: ", item.Name)
|
||||
}
|
||||
t.Error("Testing string '" + item.Msg + "'")
|
||||
t.Error("Bad output:", "'"+res+"'")
|
||||
//t.Error("Ouput in bytes:", []byte(res))
|
||||
t.Error("Expected:", "'"+item.Expects+"'")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestParser(t *testing.T) {
|
||||
var msgList = &METriList{nil}
|
||||
|
||||
msgList.Add("//github.com/Azareal/Gosora", "<a href='//github.com/Azareal/Gosora'>//github.com/Azareal/Gosora</a>")
|
||||
msgList.Add("https://github.com/Azareal/Gosora", "<a href='https://github.com/Azareal/Gosora'>https://github.com/Azareal/Gosora</a>")
|
||||
msgList.Add("http://github.com/Azareal/Gosora", "<a href='http://github.com/Azareal/Gosora'>http://github.com/Azareal/Gosora</a>")
|
||||
msgList.Add("//github.com/Azareal/Gosora\n", "<a href='//github.com/Azareal/Gosora'>//github.com/Azareal/Gosora</a><br>")
|
||||
msgList.Add("\n//github.com/Azareal/Gosora", "<br><a href='//github.com/Azareal/Gosora'>//github.com/Azareal/Gosora</a>")
|
||||
msgList.Add("\n//github.com/Azareal/Gosora\n", "<br><a href='//github.com/Azareal/Gosora'>//github.com/Azareal/Gosora</a><br>")
|
||||
msgList.Add("//github.com/Azareal/Gosora\n//github.com/Azareal/Gosora", "<a href='//github.com/Azareal/Gosora'>//github.com/Azareal/Gosora</a><br><a href='//github.com/Azareal/Gosora'>//github.com/Azareal/Gosora</a>")
|
||||
msgList.Add("//github.com/Azareal/Gosora\n\n//github.com/Azareal/Gosora", "<a href='//github.com/Azareal/Gosora'>//github.com/Azareal/Gosora</a><br><br><a href='//github.com/Azareal/Gosora'>//github.com/Azareal/Gosora</a>")
|
||||
msgList.Add("//"+common.Site.URL, "<a href='//"+common.Site.URL+"'>//"+common.Site.URL+"</a>")
|
||||
msgList.Add("//"+common.Site.URL+"\n", "<a href='//"+common.Site.URL+"'>//"+common.Site.URL+"</a><br>")
|
||||
msgList.Add("//"+common.Site.URL+"\n//"+common.Site.URL, "<a href='//"+common.Site.URL+"'>//"+common.Site.URL+"</a><br><a href='//"+common.Site.URL+"'>//"+common.Site.URL+"</a>")
|
||||
|
||||
msgList.Add("#tid-1", "<a href='/topic/1'>#tid-1</a>")
|
||||
msgList.Add("https://github.com/Azareal/Gosora/#tid-1", "<a href='https://github.com/Azareal/Gosora/#tid-1'>https://github.com/Azareal/Gosora/#tid-1</a>")
|
||||
msgList.Add("#fid-1", "<a href='/forum/1'>#fid-1</a>")
|
||||
msgList.Add("@1", "<a href='/user/admin.1' class='mention'>@Admin</a>")
|
||||
msgList.Add("@0", "<span style='color: red;'>[Invalid Profile]</span>")
|
||||
msgList.Add("@-1", "<span style='color: red;'>[Invalid Profile]</span>1")
|
||||
|
||||
for _, item := range msgList.Items {
|
||||
res := common.ParseMessage(item.Msg, 1, "forums")
|
||||
if res != item.Expects {
|
||||
if item.Name != "" {
|
||||
t.Error("Name: ", item.Name)
|
||||
}
|
||||
t.Error("Testing string '" + item.Msg + "'")
|
||||
t.Error("Bad output:", "'"+res+"'")
|
||||
t.Error("Expected:", "'"+item.Expects+"'")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,142 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/Azareal/Gosora/common"
|
||||
)
|
||||
|
||||
func TestPreparser(t *testing.T) {
|
||||
var msgList = &METriList{nil}
|
||||
|
||||
// Note: The open tag is evaluated without knowledge of the close tag for efficiency and simplicity, so the parser autofills the associated close tag when it finds an open tag without a partner
|
||||
msgList.Add("", "")
|
||||
msgList.Add(" ", "")
|
||||
msgList.Add(" hi", "hi")
|
||||
msgList.Add("hi ", "hi")
|
||||
msgList.Add("hi", "hi")
|
||||
msgList.Add(":grinning:", "😀")
|
||||
msgList.Add("😀", "😀")
|
||||
msgList.Add(" ", "")
|
||||
msgList.Add("<p>", "")
|
||||
msgList.Add("</p>", "")
|
||||
msgList.Add("<p></p>", "")
|
||||
|
||||
msgList.Add("<", "<")
|
||||
msgList.Add(">", ">")
|
||||
msgList.Add("<meow>", "<meow>")
|
||||
msgList.Add("<", "&lt;")
|
||||
msgList.Add("&", "&")
|
||||
|
||||
// Note: strings.TrimSpace strips newlines, if there's nothing before or after them
|
||||
msgList.Add("<br>", "")
|
||||
msgList.Add("<br />", "")
|
||||
msgList.Add("\\n", "\n", "")
|
||||
msgList.Add("\\n\\n", "\n\n", "")
|
||||
msgList.Add("\\n\\n\\n", "\n\n\n", "")
|
||||
msgList.Add("\\r\\n", "\r\n", "") // Windows style line ending
|
||||
msgList.Add("\\n\\r", "\n\r", "")
|
||||
|
||||
msgList.Add("ho<br>ho", "ho\n\nho")
|
||||
msgList.Add("ho<br />ho", "ho\n\nho")
|
||||
msgList.Add("ho\\nho", "ho\nho", "ho\nho")
|
||||
msgList.Add("ho\\n\\nho", "ho\n\nho", "ho\n\nho")
|
||||
//msgList.Add("ho\\n\\n\\n\\nho", "ho\n\n\n\nho", "ho\n\n\nho")
|
||||
msgList.Add("ho\\r\\nho", "ho\r\nho", "ho\nho") // Windows style line ending
|
||||
msgList.Add("ho\\n\\rho", "ho\n\rho", "ho\nho")
|
||||
|
||||
msgList.Add("<b></b>", "<strong></strong>")
|
||||
msgList.Add("<b>hi</b>", "<strong>hi</strong>")
|
||||
msgList.Add("<s>hi</s>", "<del>hi</del>")
|
||||
msgList.Add("<del>hi</del>", "<del>hi</del>")
|
||||
msgList.Add("<u>hi</u>", "<u>hi</u>")
|
||||
msgList.Add("<em>hi</em>", "<em>hi</em>")
|
||||
msgList.Add("<i>hi</i>", "<em>hi</em>")
|
||||
msgList.Add("<strong>hi</strong>", "<strong>hi</strong>")
|
||||
msgList.Add("<b><i>hi</i></b>", "<strong><em>hi</em></strong>")
|
||||
msgList.Add("<strong><em>hi</em></strong>", "<strong><em>hi</em></strong>")
|
||||
msgList.Add("<b><i><b>hi</b></i></b>", "<strong><em><strong>hi</strong></em></strong>")
|
||||
msgList.Add("<strong><em><strong>hi</strong></em></strong>", "<strong><em><strong>hi</strong></em></strong>")
|
||||
msgList.Add("<div>hi</div>", "<div>hi</div>")
|
||||
msgList.Add("<span>hi</span>", "hi") // This is stripped since the editor (Trumbowyg) likes blasting useless spans
|
||||
msgList.Add("<span >hi</span>", "hi")
|
||||
msgList.Add("<span style='background-color: yellow;'>hi</span>", "hi")
|
||||
msgList.Add("<span style='background-color: yellow;'>>hi</span>", ">hi")
|
||||
msgList.Add("<b>hi", "<strong>hi</strong>")
|
||||
msgList.Add("hi</b>", "hi</b>")
|
||||
msgList.Add("</b>", "</b>")
|
||||
msgList.Add("</del>", "</del>")
|
||||
msgList.Add("</strong>", "</strong>")
|
||||
msgList.Add("<b>", "<strong></strong>")
|
||||
msgList.Add("<span style='background-color: yellow;'>hi", "hi")
|
||||
msgList.Add("hi</span>", "hi")
|
||||
msgList.Add("</span>", "")
|
||||
msgList.Add("<span></span>", "")
|
||||
msgList.Add("<span ></span>", "")
|
||||
msgList.Add("<></>", "<></>")
|
||||
msgList.Add("</><>", "</><>")
|
||||
msgList.Add("<>", "<>")
|
||||
msgList.Add("</>", "</>")
|
||||
msgList.Add("@", "@")
|
||||
msgList.Add("@Admin", "@1")
|
||||
msgList.Add("@Bah", "@Bah")
|
||||
msgList.Add(" @Admin", "@1")
|
||||
msgList.Add("\n@Admin", "@1")
|
||||
msgList.Add("@Admin\n", "@1")
|
||||
msgList.Add("@Admin\ndd", "@1\ndd")
|
||||
msgList.Add("d@Admin", "d@Admin")
|
||||
//msgList.Add("byte 0", string([]byte{0}), "")
|
||||
msgList.Add("byte 'a'", string([]byte{'a'}), "a")
|
||||
//msgList.Add("byte 255", string([]byte{255}), "")
|
||||
//msgList.Add("rune 0", string([]rune{0}), "")
|
||||
// TODO: Do a test with invalid UTF-8 input
|
||||
|
||||
for _, item := range msgList.Items {
|
||||
res := common.PreparseMessage(item.Msg)
|
||||
if res != item.Expects {
|
||||
if item.Name != "" {
|
||||
t.Error("Name: ", item.Name)
|
||||
}
|
||||
t.Error("Testing string '" + item.Msg + "'")
|
||||
t.Error("Bad output:", "'"+res+"'")
|
||||
//t.Error("Ouput in bytes:", []byte(res))
|
||||
t.Error("Expected:", "'"+item.Expects+"'")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestParser(t *testing.T) {
|
||||
var msgList = &METriList{nil}
|
||||
|
||||
url := "github.com/Azareal/Gosora"
|
||||
msgList.Add("//"+url, "<a href='//"+url+"'>//"+url+"</a>")
|
||||
msgList.Add("https://"+url, "<a href='https://"+url+"'>https://"+url+"</a>")
|
||||
msgList.Add("http://"+url, "<a href='http://"+url+"'>http://"+url+"</a>")
|
||||
msgList.Add("//"+url+"\n", "<a href='//"+url+"'>//"+url+"</a><br>")
|
||||
msgList.Add("\n//"+url, "<br><a href='//"+url+"'>//"+url+"</a>")
|
||||
msgList.Add("\n//"+url+"\n", "<br><a href='//"+url+"'>//"+url+"</a><br>")
|
||||
msgList.Add("//"+url+"\n//"+url, "<a href='//"+url+"'>//"+url+"</a><br><a href='//"+url+"'>//"+url+"</a>")
|
||||
msgList.Add("//"+url+"\n\n//"+url, "<a href='//"+url+"'>//"+url+"</a><br><br><a href='//"+url+"'>//"+url+"</a>")
|
||||
msgList.Add("//"+common.Site.URL, "<a href='//"+common.Site.URL+"'>//"+common.Site.URL+"</a>")
|
||||
msgList.Add("//"+common.Site.URL+"\n", "<a href='//"+common.Site.URL+"'>//"+common.Site.URL+"</a><br>")
|
||||
msgList.Add("//"+common.Site.URL+"\n//"+common.Site.URL, "<a href='//"+common.Site.URL+"'>//"+common.Site.URL+"</a><br><a href='//"+common.Site.URL+"'>//"+common.Site.URL+"</a>")
|
||||
|
||||
msgList.Add("#tid-1", "<a href='/topic/1'>#tid-1</a>")
|
||||
msgList.Add("https://"+url+"/#tid-1", "<a href='https://"+url+"/#tid-1'>https://"+url+"/#tid-1</a>")
|
||||
msgList.Add("#fid-1", "<a href='/forum/1'>#fid-1</a>")
|
||||
msgList.Add("@1", "<a href='/user/admin.1' class='mention'>@Admin</a>")
|
||||
msgList.Add("@0", "<span style='color: red;'>[Invalid Profile]</span>")
|
||||
msgList.Add("@-1", "<span style='color: red;'>[Invalid Profile]</span>1")
|
||||
|
||||
for _, item := range msgList.Items {
|
||||
res := common.ParseMessage(item.Msg, 1, "forums")
|
||||
if res != item.Expects {
|
||||
if item.Name != "" {
|
||||
t.Error("Name: ", item.Name)
|
||||
}
|
||||
t.Error("Testing string '" + item.Msg + "'")
|
||||
t.Error("Bad output:", "'"+res+"'")
|
||||
t.Error("Expected:", "'"+item.Expects+"'")
|
||||
}
|
||||
}
|
||||
}
|
38
routes.go
38
routes.go
|
@ -10,6 +10,7 @@ import (
|
|||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
@ -65,10 +66,8 @@ func routeAPI(w http.ResponseWriter, r *http.Request, user common.User) common.R
|
|||
return nil
|
||||
}
|
||||
|
||||
var msglist, event, elementType string
|
||||
var asid, actorID, targetUserID, elementID int
|
||||
var msglist string
|
||||
var msgCount int
|
||||
|
||||
err = stmts.getActivityCountByWatcher.QueryRow(user.ID).Scan(&msgCount)
|
||||
if err == ErrNoRows {
|
||||
return common.PreErrorJS("Couldn't find the parent topic", w, r)
|
||||
|
@ -82,22 +81,43 @@ func routeAPI(w http.ResponseWriter, r *http.Request, user common.User) common.R
|
|||
}
|
||||
defer rows.Close()
|
||||
|
||||
var actors []int
|
||||
var alerts []common.Alert
|
||||
for rows.Next() {
|
||||
err = rows.Scan(&asid, &actorID, &targetUserID, &event, &elementType, &elementID)
|
||||
var alert common.Alert
|
||||
err = rows.Scan(&alert.ASID, &alert.ActorID, &alert.TargetUserID, &alert.Event, &alert.ElementType, &alert.ElementID)
|
||||
if err != nil {
|
||||
return common.InternalErrorJS(err, w, r)
|
||||
}
|
||||
res, err := common.BuildAlert(asid, event, elementType, actorID, targetUserID, elementID, user)
|
||||
if err != nil {
|
||||
return common.LocalErrorJS(err.Error(), w, r)
|
||||
}
|
||||
msglist += res + ","
|
||||
alerts = append(alerts, alert)
|
||||
actors = append(actors, alert.ActorID)
|
||||
}
|
||||
err = rows.Err()
|
||||
if err != nil {
|
||||
return common.InternalErrorJS(err, w, r)
|
||||
}
|
||||
|
||||
// Might not want to error here, if the account was deleted properly, we might want to figure out how we should handle deletions in general
|
||||
list, err := common.Users.BulkGetMap(actors)
|
||||
if err != nil {
|
||||
return common.InternalErrorJS(err, w, r)
|
||||
}
|
||||
|
||||
var ok bool
|
||||
for _, alert := range alerts {
|
||||
alert.Actor, ok = list[alert.ActorID]
|
||||
if !ok {
|
||||
return common.InternalErrorJS(errors.New("No such actor"), w, r)
|
||||
}
|
||||
|
||||
res, err := common.BuildAlert(alert, user)
|
||||
if err != nil {
|
||||
return common.LocalErrorJS(err.Error(), w, r)
|
||||
}
|
||||
|
||||
msglist += res + ","
|
||||
}
|
||||
|
||||
if len(msglist) != 0 {
|
||||
msglist = msglist[0 : len(msglist)-1]
|
||||
}
|
||||
|
|
|
@ -328,7 +328,9 @@ func ProfileReplyCreateSubmit(w http.ResponseWriter, r *http.Request, user commo
|
|||
return common.InternalError(err, w, r)
|
||||
}
|
||||
|
||||
err = common.AddActivityAndNotifyTarget(user.ID, profileOwner.ID, "reply", "user", profileOwner.ID)
|
||||
// ! Be careful about leaking per-route permission state with &user
|
||||
alert := common.Alert{0, user.ID, profileOwner.ID, "reply", "user", profileOwner.ID, &user}
|
||||
err = common.AddActivityAndNotifyTarget(alert)
|
||||
if err != nil {
|
||||
return common.InternalError(err, w, r)
|
||||
}
|
||||
|
@ -462,7 +464,9 @@ func ReplyLikeSubmit(w http.ResponseWriter, r *http.Request, user common.User, s
|
|||
return common.InternalErrorJSQ(err, w, r, isJs)
|
||||
}
|
||||
|
||||
err = common.AddActivityAndNotifyTarget(user.ID, reply.CreatedBy, "like", "post", rid)
|
||||
// ! Be careful about leaking per-route permission state with &user
|
||||
alert := common.Alert{0, user.ID, reply.CreatedBy, "like", "post", rid, &user}
|
||||
err = common.AddActivityAndNotifyTarget(alert)
|
||||
if err != nil {
|
||||
return common.InternalErrorJSQ(err, w, r, isJs)
|
||||
}
|
||||
|
|
|
@ -45,7 +45,7 @@ func ViewTopic(w http.ResponseWriter, r *http.Request, user common.User, header
|
|||
}
|
||||
|
||||
// Get the topic...
|
||||
topic, err := common.GetTopicUser(tid)
|
||||
topic, err := common.GetTopicUser(&user, tid)
|
||||
if err == sql.ErrNoRows {
|
||||
return common.NotFound(w, r, nil) // TODO: Can we add a simplified invocation of headerVars here? This is likely to be an extremely common NotFound
|
||||
} else if err != nil {
|
||||
|
@ -822,7 +822,9 @@ func LikeTopicSubmit(w http.ResponseWriter, r *http.Request, user common.User, s
|
|||
return common.InternalErrorJSQ(err, w, r, isJs)
|
||||
}
|
||||
|
||||
err = common.AddActivityAndNotifyTarget(user.ID, topic.CreatedBy, "like", "topic", tid)
|
||||
// ! Be careful about leaking per-route permission state with &user
|
||||
alert := common.Alert{0, user.ID, topic.CreatedBy, "like", "topic", tid, &user}
|
||||
err = common.AddActivityAndNotifyTarget(alert)
|
||||
if err != nil {
|
||||
return common.InternalErrorJSQ(err, w, r, isJs)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue