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
|
||||
}
|
||||
|
||||
// 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?
|
||||
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?
|
||||
if !utf8.ValidString(msg) {
|
||||
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
|
||||
msg = SanitiseBody(msg)
|
||||
|
||||
//fmt.Println("before msg: ", msg)
|
||||
//fmt.Println("before []byte(msg): ", []byte(msg))
|
||||
var runes = []rune(msg)
|
||||
msg = ""
|
||||
|
||||
|
@ -263,7 +267,6 @@ func PreparseMessage(msg string) string {
|
|||
for i := 0; i < len(runes); i++ {
|
||||
char := runes[i]
|
||||
if char == '&' && peekMatch(i, "lt;", runes) {
|
||||
//fmt.Println("found less than")
|
||||
var ok bool
|
||||
i, ok = tryStepForward(i, 4, runes)
|
||||
if !ok {
|
||||
|
@ -271,8 +274,6 @@ func PreparseMessage(msg string) string {
|
|||
break
|
||||
}
|
||||
char := runes[i]
|
||||
//fmt.Println("char: ", char)
|
||||
//fmt.Println("string(char): ", string(char))
|
||||
if int(char) >= len(allowedTags) {
|
||||
//fmt.Println("sentinel char out of bounds")
|
||||
msg += "&"
|
||||
|
@ -311,29 +312,19 @@ func PreparseMessage(msg string) string {
|
|||
var newI = -1
|
||||
var out string
|
||||
toActionList := tagToAction[char]
|
||||
//fmt.Println("toActionList: ", 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?
|
||||
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)
|
||||
//fmt.Println("newI: ", newI)
|
||||
//fmt.Println("i: ", i)
|
||||
//fmt.Println("string(runes[i]): ", string(runes[i]))
|
||||
if newI != -1 {
|
||||
i = newI
|
||||
} else if out != "" {
|
||||
i += len(toAction.Suffix + ">")
|
||||
}
|
||||
//fmt.Println("i: ", i)
|
||||
//fmt.Println("string(runes[i]): ", string(runes[i]))
|
||||
//fmt.Println("out: ", out)
|
||||
break
|
||||
}
|
||||
}
|
||||
if out == "" {
|
||||
//fmt.Println("no out")
|
||||
msg += "&"
|
||||
if closeTag {
|
||||
i -= 5
|
||||
|
@ -343,24 +334,54 @@ func PreparseMessage(msg string) string {
|
|||
} else if 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 {
|
||||
msg += string(char)
|
||||
}
|
||||
}
|
||||
|
||||
//fmt.Println("running autoclosers")
|
||||
//fmt.Println("msg: ", msg)
|
||||
for _, actionList := range tagToAction {
|
||||
//if len(actionList) > 0 {
|
||||
// fmt.Println("actionList: ", actionList)
|
||||
//}
|
||||
for _, toAction := range actionList {
|
||||
//fmt.Printf("toAction: %+v\n", toAction)
|
||||
if toAction.Depth > 0 {
|
||||
//fmt.Println("autoclosing")
|
||||
for ; toAction.Depth > 0; toAction.Depth-- {
|
||||
_, out := toAction.Do(toAction, false, len(runes), runes)
|
||||
//fmt.Println("out: ", out)
|
||||
if out != "" {
|
||||
msg += out
|
||||
}
|
||||
|
@ -368,8 +389,6 @@ func PreparseMessage(msg string) string {
|
|||
}
|
||||
}
|
||||
}
|
||||
//fmt.Println("msg: ", msg)
|
||||
|
||||
return strings.TrimSpace(shortcodeToUnicode(msg))
|
||||
}
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@ var ErrLongUsername = errors.New("this username is too long")
|
|||
type UserStore interface {
|
||||
DirtyGet(id int) *User
|
||||
Get(id int) (*User, error)
|
||||
GetByName(name string) (*User, error)
|
||||
Exists(id int) bool
|
||||
GetOffset(offset int, perPage int) (users []*User, err error)
|
||||
//BulkGet(ids []int) ([]*User, error)
|
||||
|
@ -36,6 +37,7 @@ type DefaultUserStore struct {
|
|||
cache UserCache
|
||||
|
||||
get *sql.Stmt
|
||||
getByName *sql.Stmt
|
||||
getOffset *sql.Stmt
|
||||
exists *sql.Stmt
|
||||
register *sql.Stmt
|
||||
|
@ -53,6 +55,7 @@ func NewDefaultUserStore(cache UserCache) (*DefaultUserStore, error) {
|
|||
return &DefaultUserStore{
|
||||
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 = ?", "", ""),
|
||||
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(),
|
||||
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
|
||||
|
@ -98,6 +101,19 @@ func (mus *DefaultUserStore) Get(id int) (*User, error) {
|
|||
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: Make this a little more consistent with DefaultGroupStore's GetRange method
|
||||
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, "@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 'a'", string([]byte{'a'}), "a")
|
||||
//msgList = addMETri(msgList, "byte 255", string([]byte{255}), "")
|
||||
|
|
Loading…
Reference in New Issue