use string builder for alert api

This commit is contained in:
Azareal 2020-03-04 14:31:11 +10:00
parent 24107aaef1
commit 28daeee702
2 changed files with 192 additions and 65 deletions

View File

@ -62,114 +62,237 @@ func escapeTextInJson(in string) string {
return strings.Replace(in, "/", "\\/", -1) return strings.Replace(in, "/", "\\/", -1)
} }
func BuildAlert(alert Alert, user User /* The current user */) (out string, err error) { func BuildAlert(a Alert, user User /* The current user */) (out string, err error) {
var targetUser *User var targetUser *User
if alert.Actor == nil { if a.Actor == nil {
alert.Actor, err = Users.Get(alert.ActorID) a.Actor, err = Users.Get(a.ActorID)
if err != nil { if err != nil {
return "", errors.New(phrases.GetErrorPhrase("alerts_no_actor")) return "", errors.New(phrases.GetErrorPhrase("alerts_no_actor"))
} }
} }
/*if alert.ElementType != "forum" { /*if a.ElementType != "forum" {
targetUser, err = users.Get(alert.TargetUserID) targetUser, err = users.Get(a.TargetUserID)
if err != nil { if err != nil {
LocalErrorJS("Unable to find the target user",w,r) LocalErrorJS("Unable to find the target user",w,r)
return return
} }
}*/ }*/
if alert.Event == "friend_invite" { if a.Event == "friend_invite" {
return buildAlertString(".new_friend_invite", []string{alert.Actor.Name}, alert.Actor.Link, alert.Actor.Avatar, alert.ASID), nil return buildAlertString(".new_friend_invite", []string{a.Actor.Name}, a.Actor.Link, a.Actor.Avatar, a.ASID), nil
} }
// Not that many events for us to handle in a forum // Not that many events for us to handle in a forum
if alert.ElementType == "forum" { if a.ElementType == "forum" {
if alert.Event == "reply" { if a.Event == "reply" {
topic, err := Topics.Get(alert.ElementID) topic, err := Topics.Get(a.ElementID)
if err != nil { if err != nil {
DebugLogf("Unable to find linked topic %d", alert.ElementID) DebugLogf("Unable to find linked topic %d", a.ElementID)
return "", errors.New(phrases.GetErrorPhrase("alerts_no_linked_topic")) 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 // 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... // 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(".forum_new_topic", []string{alert.Actor.Name, topic.Title}, topic.Link, alert.Actor.Avatar, alert.ASID), nil return buildAlertString(".forum_new_topic", []string{a.Actor.Name, topic.Title}, topic.Link, a.Actor.Avatar, a.ASID), nil
} }
return buildAlertString(".forum_unknown_action", []string{alert.Actor.Name}, "", alert.Actor.Avatar, alert.ASID), nil return buildAlertString(".forum_unknown_action", []string{a.Actor.Name}, "", a.Actor.Avatar, a.ASID), nil
} }
var url, area string var url, area, phraseName string
phraseName := "." + alert.ElementType own := false
switch alert.ElementType { switch a.ElementType {
case "convo": case "convo":
convo, err := Convos.Get(alert.ElementID) convo, err := Convos.Get(a.ElementID)
if err != nil { if err != nil {
DebugLogf("Unable to find linked convo %d", alert.ElementID) DebugLogf("Unable to find linked convo %d", a.ElementID)
return "", errors.New(phrases.GetErrorPhrase("alerts_no_linked_convo")) return "", errors.New(phrases.GetErrorPhrase("alerts_no_linked_convo"))
} }
url = convo.Link url = convo.Link
area = ""
case "topic": case "topic":
topic, err := Topics.Get(alert.ElementID) topic, err := Topics.Get(a.ElementID)
if err != nil { if err != nil {
DebugLogf("Unable to find linked topic %d", alert.ElementID) DebugLogf("Unable to find linked topic %d", a.ElementID)
return "", errors.New(phrases.GetErrorPhrase("alerts_no_linked_topic")) return "", errors.New(phrases.GetErrorPhrase("alerts_no_linked_topic"))
} }
url = topic.Link url = topic.Link
area = topic.Title area = topic.Title
if alert.TargetUserID == user.ID { own = a.TargetUserID == user.ID
phraseName += "_own"
}
case "user": case "user":
targetUser, err = Users.Get(alert.ElementID) targetUser, err = Users.Get(a.ElementID)
if err != nil { if err != nil {
DebugLogf("Unable to find target user %d", alert.ElementID) DebugLogf("Unable to find target user %d", a.ElementID)
return "", errors.New(phrases.GetErrorPhrase("alerts_no_target_user")) return "", errors.New(phrases.GetErrorPhrase("alerts_no_target_user"))
} }
area = targetUser.Name area = targetUser.Name
url = targetUser.Link url = targetUser.Link
if alert.TargetUserID == user.ID { own = a.TargetUserID == user.ID
phraseName += "_own"
}
case "post": case "post":
topic, err := TopicByReplyID(alert.ElementID) topic, err := TopicByReplyID(a.ElementID)
if err != nil { if err != nil {
DebugLogf("Unable to find linked topic by reply ID %d", alert.ElementID) DebugLogf("Unable to find linked topic by reply ID %d", a.ElementID)
return "", errors.New(phrases.GetErrorPhrase("alerts_no_linked_topic_by_reply")) return "", errors.New(phrases.GetErrorPhrase("alerts_no_linked_topic_by_reply"))
} }
url = topic.Link url = topic.Link
area = topic.Title area = topic.Title
if alert.TargetUserID == user.ID { own = a.TargetUserID == user.ID
phraseName += "_own"
}
default: default:
return "", errors.New(phrases.GetErrorPhrase("alerts_invalid_elementtype")) return "", errors.New(phrases.GetErrorPhrase("alerts_invalid_elementtype"))
} }
switch alert.Event { badEv := false
case "create": switch a.Event {
phraseName += "_create" case "create", "like", "mention", "reply":
case "like": // skip
phraseName += "_like" default:
case "mention": badEv = true
phraseName += "_mention"
case "reply":
phraseName += "_reply"
} }
return buildAlertString(phraseName, []string{alert.Actor.Name, area}, url, alert.Actor.Avatar, alert.ASID), nil if own && !badEv {
phraseName = "." + a.ElementType + "_own_" + a.Event
} else if !badEv {
phraseName = "." + a.ElementType + "_" + a.Event
} else if own {
phraseName = "." + a.ElementType + "_own"
} else {
phraseName = "." + a.ElementType
}
return buildAlertString(phraseName, []string{a.Actor.Name, area}, url, a.Actor.Avatar, a.ASID), nil
}
func buildAlertString(msg string, sub []string, path, avatar string, asid int) string {
var sb strings.Builder
buildAlertSb(&sb, msg, sub, path, avatar, asid)
return sb.String()
} }
// TODO: Use a string builder? // TODO: Use a string builder?
func buildAlertString(msg string, sub []string, path, avatar string, asid int) string { func buildAlertSb(sb *strings.Builder, msg string, sub []string, path, avatar string, asid int) {
var subString string sb.WriteString(`{"msg":"`)
for _, item := range sub { sb.WriteString(escapeTextInJson(msg))
subString += "\"" + escapeTextInJson(item) + "\"," sb.WriteString(`","sub":[`)
for i, it := range sub {
if i != 0 {
sb.WriteString(",\"")
} else {
sb.WriteString("\"")
}
sb.WriteString(escapeTextInJson(it))
sb.WriteString("\"")
} }
if len(subString) > 0 { sb.WriteString(`],"path":"`)
subString = subString[:len(subString)-1] sb.WriteString(escapeTextInJson(path))
sb.WriteString(`","avatar":"`)
sb.WriteString(escapeTextInJson(avatar))
sb.WriteString(`","id":`)
sb.WriteString(strconv.Itoa(asid))
sb.WriteRune('}')
}
func BuildAlertSb(sb *strings.Builder, a Alert, user User /* The current user */) (err error) {
var targetUser *User
if a.Actor == nil {
a.Actor, err = Users.Get(a.ActorID)
if err != nil {
return errors.New(phrases.GetErrorPhrase("alerts_no_actor"))
}
} }
return `{"msg":"` + escapeTextInJson(msg) + `","sub":[` + subString + `],"path":"` + escapeTextInJson(path) + `","avatar":"` + escapeTextInJson(avatar) + `","id":` + strconv.Itoa(asid) + `}` /*if a.ElementType != "forum" {
targetUser, err = users.Get(a.TargetUserID)
if err != nil {
LocalErrorJS("Unable to find the target user",w,r)
return
}
}*/
if a.Event == "friend_invite" {
buildAlertSb(sb, ".new_friend_invite", []string{a.Actor.Name}, a.Actor.Link, a.Actor.Avatar, a.ASID)
return nil
}
// Not that many events for us to handle in a forum
if a.ElementType == "forum" {
if a.Event == "reply" {
topic, err := Topics.Get(a.ElementID)
if err != nil {
DebugLogf("Unable to find linked topic %d", a.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...
buildAlertSb(sb, ".forum_new_topic", []string{a.Actor.Name, topic.Title}, topic.Link, a.Actor.Avatar, a.ASID)
return nil
}
buildAlertSb(sb, ".forum_unknown_action", []string{a.Actor.Name}, "", a.Actor.Avatar, a.ASID)
return nil
}
var url, area string
own := false
switch a.ElementType {
case "convo":
convo, err := Convos.Get(a.ElementID)
if err != nil {
DebugLogf("Unable to find linked convo %d", a.ElementID)
return errors.New(phrases.GetErrorPhrase("alerts_no_linked_convo"))
}
url = convo.Link
case "topic":
topic, err := Topics.Get(a.ElementID)
if err != nil {
DebugLogf("Unable to find linked topic %d", a.ElementID)
return errors.New(phrases.GetErrorPhrase("alerts_no_linked_topic"))
}
url = topic.Link
area = topic.Title
own = a.TargetUserID == user.ID
case "user":
targetUser, err = Users.Get(a.ElementID)
if err != nil {
DebugLogf("Unable to find target user %d", a.ElementID)
return errors.New(phrases.GetErrorPhrase("alerts_no_target_user"))
}
area = targetUser.Name
url = targetUser.Link
own = a.TargetUserID == user.ID
case "post":
topic, err := TopicByReplyID(a.ElementID)
if err != nil {
DebugLogf("Unable to find linked topic by reply ID %d", a.ElementID)
return errors.New(phrases.GetErrorPhrase("alerts_no_linked_topic_by_reply"))
}
url = topic.Link
area = topic.Title
own = a.TargetUserID == user.ID
default:
return errors.New(phrases.GetErrorPhrase("alerts_invalid_elementtype"))
}
sb.WriteString(`{"msg":"`)
sb.WriteRune('.')
sb.WriteString(a.ElementType)
if own {
sb.WriteString("_own_")
} else {
sb.WriteRune('_')
}
switch a.Event {
case "create", "like", "mention", "reply":
sb.WriteString(a.Event)
}
sb.WriteString(`","sub":["`)
sb.WriteString(escapeTextInJson(a.Actor.Name))
sb.WriteString("\",\"")
sb.WriteString(escapeTextInJson(area))
sb.WriteString(`"],"path":"`)
sb.WriteString(escapeTextInJson(url))
sb.WriteString(`","avatar":"`)
sb.WriteString(escapeTextInJson(a.Actor.Avatar))
sb.WriteString(`","id":`)
sb.WriteString(strconv.Itoa(a.ASID))
sb.WriteRune('}')
return nil
} }
func AddActivityAndNotifyAll(a Alert) error { func AddActivityAndNotifyAll(a Alert) error {

View File

@ -144,30 +144,34 @@ func routeAPI(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError
return c.InternalErrorJS(err, w, r) return c.InternalErrorJS(err, w, r)
} }
var msglist string if count == 0 || len(alerts) == 0 || (rCreatedAt != 0 && rCreatedAt >= topCreatedAt && count == rCount) {
//var sb strings.Builder _, _ = io.WriteString(w, `{}`)
return nil
}
var ok bool var ok bool
for _, alert := range alerts { var sb strings.Builder
sb.WriteString(`{"msgs":[`)
for i, alert := range alerts {
if i != 0 {
sb.WriteRune(',')
}
alert.Actor, ok = list[alert.ActorID] alert.Actor, ok = list[alert.ActorID]
if !ok { if !ok {
return c.InternalErrorJS(errors.New("No such actor"), w, r) return c.InternalErrorJS(errors.New("No such actor"), w, r)
} }
res, err := c.BuildAlert(alert, user) err := c.BuildAlertSb(&sb, alert, user)
if err != nil { if err != nil {
return c.LocalErrorJS(err.Error(), w, r) return c.LocalErrorJS(err.Error(), w, r)
} }
//sb.Write(res)
msglist += res + ","
}
if len(msglist) != 0 {
msglist = msglist[0 : len(msglist)-1]
} }
sb.WriteString(`],"count":`)
sb.WriteString(strconv.Itoa(count))
sb.WriteString(`,"tc":`)
sb.WriteString(strconv.Itoa(int(topCreatedAt)))
sb.WriteRune('}')
if count == 0 || msglist == "" || (rCreatedAt != 0 && rCreatedAt >= topCreatedAt && count == rCount) { _, _ = io.WriteString(w, sb.String())
_, _ = io.WriteString(w, `{}`)
} else {
_, _ = io.WriteString(w, `{"msgs":[`+msglist+`],"count":`+strconv.Itoa(count)+`,"tc":`+strconv.Itoa(int(topCreatedAt))+`}`)
}
default: default:
return c.PreErrorJS("Invalid Module", w, r) return c.PreErrorJS("Invalid Module", w, r)
} }