Added the AddHashLinkType function so that plugins can add custom hash link types in an efficient manner.

Moved the hashLinkMap, etc. out of ParseMessage so that we can make them more pluggable.
The first word in usernames can no longer be purely numeric.
Added some ID mention tests.
This commit is contained in:
Azareal 2018-09-20 14:36:50 +10:00
parent f6b889b53b
commit 47d1010a53
3 changed files with 75 additions and 46 deletions

View File

@ -398,6 +398,62 @@ func peekMatch(cur int, phrase string, runes []rune) bool {
return true
}
// ! Not concurrency safe
func AddHashLinkType(prefix string, handler func(*strings.Builder, string, *int)) {
// There can only be one hash link type starting with a specific character at the moment
hashType := hashLinkTypes[prefix[0]]
if hashType != "" {
return
}
hashLinkMap[prefix] = handler
hashLinkTypes[prefix[0]] = prefix
}
func writeURL(sb *strings.Builder, url string, label string) {
sb.Write(URLOpen)
sb.WriteString(url)
sb.Write(URLOpen2)
sb.WriteString(label)
sb.Write(URLClose)
}
var hashLinkTypes = []string{'t': "tid-", 'r': "rid-", 'f': "fid-"}
var hashLinkMap = map[string]func(*strings.Builder, string, *int){
"tid-": func(sb *strings.Builder, msg string, i *int) {
tid, intLen := CoerceIntString(msg[*i:])
*i += intLen
topic, err := Topics.Get(tid)
if err != nil || !Forums.Exists(topic.ParentID) {
sb.Write(InvalidTopic)
return
}
writeURL(sb, BuildTopicURL("", tid), "#tid-"+strconv.Itoa(tid))
},
"rid-": func(sb *strings.Builder, msg string, i *int) {
rid, intLen := CoerceIntString(msg[*i:])
*i += intLen
topic, err := TopicByReplyID(rid)
if err != nil || !Forums.Exists(topic.ParentID) {
sb.Write(InvalidTopic)
return
}
writeURL(sb, BuildTopicURL("", topic.ID), "#rid-"+strconv.Itoa(rid))
},
"fid-": func(sb *strings.Builder, msg string, i *int) {
fid, intLen := CoerceIntString(msg[*i:])
*i += intLen
if !Forums.Exists(fid) {
sb.Write(InvalidForum)
return
}
writeURL(sb, BuildForumURL("", fid), "#fid-"+strconv.Itoa(fid))
},
// TODO: Forum Shortcode Link
}
// TODO: Write a test for this
// TODO: We need a lot more hooks here. E.g. To add custom media types and handlers.
// TODO: Use templates to reduce the amount of boilerplate?
@ -427,51 +483,6 @@ func ParseMessage(msg string, sectionID int, sectionType string /*, user User*/)
var sb strings.Builder
var lastItem = 0
var i = 0
var writeURL = func(url string, label string) {
sb.Write(URLOpen)
sb.WriteString(url)
sb.Write(URLOpen2)
sb.WriteString(label)
sb.Write(URLClose)
}
var hashLinkTypes = []string{'t': "tid-", 'r': "rid-", 'f': "fid-"}
var hashLinkMap = map[string]func(){
"tid-": func() {
tid, intLen := CoerceIntString(msg[i:])
i += intLen
topic, err := Topics.Get(tid)
if err != nil || !Forums.Exists(topic.ParentID) {
sb.Write(InvalidTopic)
return
}
writeURL(BuildTopicURL("", tid), "#tid-"+strconv.Itoa(tid))
},
"rid-": func() {
rid, intLen := CoerceIntString(msg[i:])
i += intLen
topic, err := TopicByReplyID(rid)
if err != nil || !Forums.Exists(topic.ParentID) {
sb.Write(InvalidTopic)
return
}
writeURL(BuildTopicURL("", topic.ID), "#rid-"+strconv.Itoa(rid))
},
"fid-": func() {
fid, intLen := CoerceIntString(msg[i:])
i += intLen
if !Forums.Exists(fid) {
sb.Write(InvalidForum)
return
}
writeURL(BuildForumURL("", fid), "#fid-"+strconv.Itoa(fid))
},
// TODO: Forum Shortcode Link
}
for ; len(msg) > (i + 1); i++ {
if (i == 0 && (msg[0] > 32)) || ((msg[i] < 33) && (msg[i+1] > 32)) {
if (i != 0) || msg[i] < 33 {
@ -485,7 +496,7 @@ func ParseMessage(msg string, sectionID int, sectionType string /*, user User*/)
if msg[i+1:len(hashType)+1] == hashType {
sb.WriteString(msg[lastItem:i])
i += len(hashType) + 1
hashLinkMap[hashType]()
hashLinkMap[hashType](&sb, msg, &i)
lastItem = i
}
} else if msg[i] == '@' {

View File

@ -1262,6 +1262,9 @@ func TestParser(t *testing.T) {
msgList = addMETri(msgList, "#tid-1", "<a href='/topic/1'>#tid-1</a>")
msgList = addMETri(msgList, "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 = addMETri(msgList, "#fid-1", "<a href='/forum/1'>#fid-1</a>")
msgList = addMETri(msgList, "@1", "<a href='/user/admin.1' class='mention'>@Admin</a>")
msgList = addMETri(msgList, "@0", "<span style='color: red;'>[Invalid Profile]</span>")
msgList = addMETri(msgList, "@-1", "<span style='color: red;'>[Invalid Profile]</span>1")
for _, item := range msgList {
res = common.ParseMessage(item.Msg, 1, "forums")

View File

@ -212,6 +212,15 @@ func AccountRegister(w http.ResponseWriter, r *http.Request, user common.User) c
return nil
}
func isNumeric(data string) (numeric bool) {
for _, char := range data {
if char < 48 || char > 57 {
return false
}
}
return true
}
func AccountRegisterSubmit(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError {
headerLite, _ := common.SimpleUserCheck(w, r, &user)
@ -247,6 +256,12 @@ func AccountRegisterSubmit(w http.ResponseWriter, r *http.Request, user common.U
regError("You didn't put in an email.", "no-email")
}
// This is so a numeric name won't interfere with mentioning a user by ID, there might be a better way of doing this like perhaps !@ to mean IDs and @ to mean usernames in the pre-parser
usernameBits := strings.Split(username, " ")
if isNumeric(usernameBits[0]) {
regError("The first word of your name may not be purely numeric", "numeric-name")
}
ok := common.HasSuspiciousEmail(email)
if ok {
regError("Your email address is suspicious.", "suspicious-email")