Added support for simple named mentions.
Added a GetByName method to the UserStore. Added eight mention tests. Added the tryStepBackward function, might get removed. Removed some superfluous commented debug statements.
This commit is contained in:
parent
47d1010a53
commit
e9645c07bd
|
@ -180,10 +180,16 @@ func tryStepForward(i int, step int, runes []rune) (int, bool) {
|
||||||
return i - step, false
|
return i - step, false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Write a test for this
|
||||||
|
func tryStepBackward(i int, step int, runes []rune) (int, bool) {
|
||||||
|
if i == 0 {
|
||||||
|
return i, false
|
||||||
|
}
|
||||||
|
return i - 1, true
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Preparse Markdown and normalize it into HTML?
|
// TODO: Preparse Markdown and normalize it into HTML?
|
||||||
func PreparseMessage(msg string) string {
|
func PreparseMessage(msg string) string {
|
||||||
//fmt.Println("initial msg: ", msg)
|
|
||||||
//fmt.Println("initial []byte(msg): ", []byte(msg))
|
|
||||||
// TODO: Kick this check down a level into SanitiseBody?
|
// TODO: Kick this check down a level into SanitiseBody?
|
||||||
if !utf8.ValidString(msg) {
|
if !utf8.ValidString(msg) {
|
||||||
return ""
|
return ""
|
||||||
|
@ -201,8 +207,6 @@ func PreparseMessage(msg string) string {
|
||||||
// There are a few useful cases for having spaces, but I'd like to stop the WYSIWYG from inserting random lines here and there
|
// There are a few useful cases for having spaces, but I'd like to stop the WYSIWYG from inserting random lines here and there
|
||||||
msg = SanitiseBody(msg)
|
msg = SanitiseBody(msg)
|
||||||
|
|
||||||
//fmt.Println("before msg: ", msg)
|
|
||||||
//fmt.Println("before []byte(msg): ", []byte(msg))
|
|
||||||
var runes = []rune(msg)
|
var runes = []rune(msg)
|
||||||
msg = ""
|
msg = ""
|
||||||
|
|
||||||
|
@ -263,7 +267,6 @@ func PreparseMessage(msg string) string {
|
||||||
for i := 0; i < len(runes); i++ {
|
for i := 0; i < len(runes); i++ {
|
||||||
char := runes[i]
|
char := runes[i]
|
||||||
if char == '&' && peekMatch(i, "lt;", runes) {
|
if char == '&' && peekMatch(i, "lt;", runes) {
|
||||||
//fmt.Println("found less than")
|
|
||||||
var ok bool
|
var ok bool
|
||||||
i, ok = tryStepForward(i, 4, runes)
|
i, ok = tryStepForward(i, 4, runes)
|
||||||
if !ok {
|
if !ok {
|
||||||
|
@ -271,8 +274,6 @@ func PreparseMessage(msg string) string {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
char := runes[i]
|
char := runes[i]
|
||||||
//fmt.Println("char: ", char)
|
|
||||||
//fmt.Println("string(char): ", string(char))
|
|
||||||
if int(char) >= len(allowedTags) {
|
if int(char) >= len(allowedTags) {
|
||||||
//fmt.Println("sentinel char out of bounds")
|
//fmt.Println("sentinel char out of bounds")
|
||||||
msg += "&"
|
msg += "&"
|
||||||
|
@ -311,29 +312,19 @@ func PreparseMessage(msg string) string {
|
||||||
var newI = -1
|
var newI = -1
|
||||||
var out string
|
var out string
|
||||||
toActionList := tagToAction[char]
|
toActionList := tagToAction[char]
|
||||||
//fmt.Println("toActionList: ", toActionList)
|
|
||||||
for _, toAction := range toActionList {
|
for _, toAction := range toActionList {
|
||||||
//fmt.Printf("toAction: %+v\n", toAction)
|
|
||||||
// TODO: Optimise this, maybe with goto or a function call to avoid scanning the text twice?
|
// TODO: Optimise this, maybe with goto or a function call to avoid scanning the text twice?
|
||||||
if (toAction.PartialMode && !closeTag && peekMatch(i, toAction.Suffix, runes)) || peekMatch(i, toAction.Suffix+">", runes) {
|
if (toAction.PartialMode && !closeTag && peekMatch(i, toAction.Suffix, runes)) || peekMatch(i, toAction.Suffix+">", runes) {
|
||||||
//fmt.Println("peekMatched")
|
|
||||||
newI, out = toAction.Do(toAction, !closeTag, i, runes)
|
newI, out = toAction.Do(toAction, !closeTag, i, runes)
|
||||||
//fmt.Println("newI: ", newI)
|
|
||||||
//fmt.Println("i: ", i)
|
|
||||||
//fmt.Println("string(runes[i]): ", string(runes[i]))
|
|
||||||
if newI != -1 {
|
if newI != -1 {
|
||||||
i = newI
|
i = newI
|
||||||
} else if out != "" {
|
} else if out != "" {
|
||||||
i += len(toAction.Suffix + ">")
|
i += len(toAction.Suffix + ">")
|
||||||
}
|
}
|
||||||
//fmt.Println("i: ", i)
|
|
||||||
//fmt.Println("string(runes[i]): ", string(runes[i]))
|
|
||||||
//fmt.Println("out: ", out)
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if out == "" {
|
if out == "" {
|
||||||
//fmt.Println("no out")
|
|
||||||
msg += "&"
|
msg += "&"
|
||||||
if closeTag {
|
if closeTag {
|
||||||
i -= 5
|
i -= 5
|
||||||
|
@ -343,24 +334,54 @@ func PreparseMessage(msg string) string {
|
||||||
} else if out != " " {
|
} else if out != " " {
|
||||||
msg += out
|
msg += out
|
||||||
}
|
}
|
||||||
|
} else if char == '@' && (i == 0 || runes[i-1] < 33) {
|
||||||
|
// TODO: Handle usernames containing spaces, maybe in the front-end with AJAX
|
||||||
|
// Do not mention-ify ridiculously long things
|
||||||
|
var ok bool
|
||||||
|
i, ok = tryStepForward(i, 1, runes)
|
||||||
|
if !ok {
|
||||||
|
msg += "@"
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
start := i
|
||||||
|
|
||||||
|
for j := 0; i < len(runes) && j < Config.MaxUsernameLength; j++ {
|
||||||
|
cchar := runes[i]
|
||||||
|
if cchar < 33 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
|
||||||
|
username := string(runes[start:i])
|
||||||
|
if username == "" {
|
||||||
|
msg += "@"
|
||||||
|
i = start - 1
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
//fmt.Printf("username: %+v\n", username)
|
||||||
|
user, err := Users.GetByName(username)
|
||||||
|
if err != nil {
|
||||||
|
if err != ErrNoRows {
|
||||||
|
LogError(err)
|
||||||
|
}
|
||||||
|
msg += "@"
|
||||||
|
i = start - 1
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
msg += "@" + strconv.Itoa(user.ID)
|
||||||
|
i--
|
||||||
} else {
|
} else {
|
||||||
msg += string(char)
|
msg += string(char)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//fmt.Println("running autoclosers")
|
|
||||||
//fmt.Println("msg: ", msg)
|
|
||||||
for _, actionList := range tagToAction {
|
for _, actionList := range tagToAction {
|
||||||
//if len(actionList) > 0 {
|
|
||||||
// fmt.Println("actionList: ", actionList)
|
|
||||||
//}
|
|
||||||
for _, toAction := range actionList {
|
for _, toAction := range actionList {
|
||||||
//fmt.Printf("toAction: %+v\n", toAction)
|
|
||||||
if toAction.Depth > 0 {
|
if toAction.Depth > 0 {
|
||||||
//fmt.Println("autoclosing")
|
|
||||||
for ; toAction.Depth > 0; toAction.Depth-- {
|
for ; toAction.Depth > 0; toAction.Depth-- {
|
||||||
_, out := toAction.Do(toAction, false, len(runes), runes)
|
_, out := toAction.Do(toAction, false, len(runes), runes)
|
||||||
//fmt.Println("out: ", out)
|
|
||||||
if out != "" {
|
if out != "" {
|
||||||
msg += out
|
msg += out
|
||||||
}
|
}
|
||||||
|
@ -368,8 +389,6 @@ func PreparseMessage(msg string) string {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//fmt.Println("msg: ", msg)
|
|
||||||
|
|
||||||
return strings.TrimSpace(shortcodeToUnicode(msg))
|
return strings.TrimSpace(shortcodeToUnicode(msg))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@ var ErrLongUsername = errors.New("this username is too long")
|
||||||
type UserStore interface {
|
type UserStore interface {
|
||||||
DirtyGet(id int) *User
|
DirtyGet(id int) *User
|
||||||
Get(id int) (*User, error)
|
Get(id int) (*User, error)
|
||||||
|
GetByName(name string) (*User, error)
|
||||||
Exists(id int) bool
|
Exists(id int) bool
|
||||||
GetOffset(offset int, perPage int) (users []*User, err error)
|
GetOffset(offset int, perPage int) (users []*User, err error)
|
||||||
//BulkGet(ids []int) ([]*User, error)
|
//BulkGet(ids []int) ([]*User, error)
|
||||||
|
@ -36,6 +37,7 @@ type DefaultUserStore struct {
|
||||||
cache UserCache
|
cache UserCache
|
||||||
|
|
||||||
get *sql.Stmt
|
get *sql.Stmt
|
||||||
|
getByName *sql.Stmt
|
||||||
getOffset *sql.Stmt
|
getOffset *sql.Stmt
|
||||||
exists *sql.Stmt
|
exists *sql.Stmt
|
||||||
register *sql.Stmt
|
register *sql.Stmt
|
||||||
|
@ -53,6 +55,7 @@ func NewDefaultUserStore(cache UserCache) (*DefaultUserStore, error) {
|
||||||
return &DefaultUserStore{
|
return &DefaultUserStore{
|
||||||
cache: cache,
|
cache: cache,
|
||||||
get: acc.SimpleSelect("users", "name, group, active, is_super_admin, session, email, avatar, message, url_prefix, url_name, level, score, liked, last_ip, temp_group", "uid = ?", "", ""),
|
get: acc.SimpleSelect("users", "name, group, active, is_super_admin, session, email, avatar, message, url_prefix, url_name, level, score, liked, last_ip, temp_group", "uid = ?", "", ""),
|
||||||
|
getByName: acc.Select("users").Columns("uid, name, group, active, is_super_admin, session, email, avatar, message, url_prefix, url_name, level, score, liked, last_ip, temp_group").Where("name = ?").Prepare(),
|
||||||
getOffset: acc.Select("users").Columns("uid, name, group, active, is_super_admin, session, email, avatar, message, url_prefix, url_name, level, score, liked, last_ip, temp_group").Orderby("uid ASC").Limit("?,?").Prepare(),
|
getOffset: acc.Select("users").Columns("uid, name, group, active, is_super_admin, session, email, avatar, message, url_prefix, url_name, level, score, liked, last_ip, temp_group").Orderby("uid ASC").Limit("?,?").Prepare(),
|
||||||
exists: acc.SimpleSelect("users", "uid", "uid = ?", "", ""),
|
exists: acc.SimpleSelect("users", "uid", "uid = ?", "", ""),
|
||||||
register: acc.SimpleInsert("users", "name, email, password, salt, group, is_super_admin, session, active, message, createdAt, lastActiveAt", "?,?,?,?,?,0,'',?,'',UTC_TIMESTAMP(),UTC_TIMESTAMP()"), // TODO: Implement user_count on users_groups here
|
register: acc.SimpleInsert("users", "name, email, password, salt, group, is_super_admin, session, active, message, createdAt, lastActiveAt", "?,?,?,?,?,0,'',?,'',UTC_TIMESTAMP(),UTC_TIMESTAMP()"), // TODO: Implement user_count on users_groups here
|
||||||
|
@ -98,6 +101,19 @@ func (mus *DefaultUserStore) Get(id int) (*User, error) {
|
||||||
return user, err
|
return user, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Log weird cache errors? Not just here but in every *Cache?
|
||||||
|
// ! This bypasses the cache, use frugally
|
||||||
|
func (mus *DefaultUserStore) GetByName(name string) (*User, error) {
|
||||||
|
user := &User{Loggedin: true}
|
||||||
|
err := mus.getByName.QueryRow(name).Scan(&user.ID, &user.Name, &user.Group, &user.Active, &user.IsSuperAdmin, &user.Session, &user.Email, &user.RawAvatar, &user.Message, &user.URLPrefix, &user.URLName, &user.Level, &user.Score, &user.Liked, &user.LastIP, &user.TempGroup)
|
||||||
|
|
||||||
|
user.Init()
|
||||||
|
if err == nil {
|
||||||
|
mus.cache.Set(user)
|
||||||
|
}
|
||||||
|
return user, err
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Optimise this, so we don't wind up hitting the database every-time for small gaps
|
// TODO: Optimise this, so we don't wind up hitting the database every-time for small gaps
|
||||||
// TODO: Make this a little more consistent with DefaultGroupStore's GetRange method
|
// TODO: Make this a little more consistent with DefaultGroupStore's GetRange method
|
||||||
func (store *DefaultUserStore) GetOffset(offset int, perPage int) (users []*User, err error) {
|
func (store *DefaultUserStore) GetOffset(offset int, perPage int) (users []*User, err error) {
|
||||||
|
|
|
@ -1223,6 +1223,14 @@ func TestPreparser(t *testing.T) {
|
||||||
msgList = addMETri(msgList, "</><>", "</><>")
|
msgList = addMETri(msgList, "</><>", "</><>")
|
||||||
msgList = addMETri(msgList, "<>", "<>")
|
msgList = addMETri(msgList, "<>", "<>")
|
||||||
msgList = addMETri(msgList, "</>", "</>")
|
msgList = addMETri(msgList, "</>", "</>")
|
||||||
|
msgList = addMETri(msgList, "@", "@")
|
||||||
|
msgList = addMETri(msgList, "@Admin", "@1")
|
||||||
|
msgList = addMETri(msgList, "@Bah", "@Bah")
|
||||||
|
msgList = addMETri(msgList, " @Admin", "@1")
|
||||||
|
msgList = addMETri(msgList, "\n@Admin", "@1")
|
||||||
|
msgList = addMETri(msgList, "@Admin\n", "@1")
|
||||||
|
msgList = addMETri(msgList, "@Admin\ndd", "@1\ndd")
|
||||||
|
msgList = addMETri(msgList, "d@Admin", "d@Admin")
|
||||||
//msgList = addMETri(msgList, "byte 0", string([]byte{0}), "")
|
//msgList = addMETri(msgList, "byte 0", string([]byte{0}), "")
|
||||||
msgList = addMETri(msgList, "byte 'a'", string([]byte{'a'}), "a")
|
msgList = addMETri(msgList, "byte 'a'", string([]byte{'a'}), "a")
|
||||||
//msgList = addMETri(msgList, "byte 255", string([]byte{255}), "")
|
//msgList = addMETri(msgList, "byte 255", string([]byte{255}), "")
|
||||||
|
|
Loading…
Reference in New Issue