Implements mention highlighting in posts.

This commit is contained in:
Dominik Picheta 2018-05-14 14:41:12 +01:00
commit eeda927085
2 changed files with 90 additions and 36 deletions

View file

@ -281,9 +281,6 @@ proc validThreadId(c: TForumData): bool =
result = getValue(db, sql"select id from thread where id = ?",
$c.threadId).len > 0
const
SecureChars = {'A'..'Z', 'a'..'z', '0'..'9', '_', '\128'..'\255'}
proc setError(c: TForumData, field, msg: string): bool {.inline.} =
c.invalidField = field
c.errorMsg = "Error: " & msg
@ -292,7 +289,7 @@ proc setError(c: TForumData, field, msg: string): bool {.inline.} =
proc register(c: TForumData, name, pass, antibot, userIp,
email: string): Future[bool] {.async.} =
# Username validation:
if name.len == 0 or not allCharsInSet(name, SecureChars):
if name.len == 0 or not allCharsInSet(name, UsernameIdent):
return setError(c, "name", "Invalid username!")
if getValue(db, sql"select name from person where name = ?", name).len > 0:
return setError(c, "name", "Username already exists!")

121
utils.nim
View file

@ -2,6 +2,12 @@ import asyncdispatch, smtp, strutils, json, os, rst, rstgen, xmltree, strtabs,
htmlparser, streams, parseutils, options
from times import getTime, getGMTime, format
# Used to be:
# {'A'..'Z', 'a'..'z', '0'..'9', '_', '\128'..'\255'}
let
UsernameIdent* = IdentChars # TODO: Double check that everyone follows this.
proc parseInt*(s: string, value: var int, validRange: Slice[int]) {.
noSideEffect.} =
## parses `s` into an integer in the range `validRange`. If successful,
@ -80,46 +86,97 @@ proc blockquoteFinish(currentBlockquote, newNode: var XmlNode, n: XmlNode) =
currentBlockquote = newElement("blockquote")
newNode.add(n)
proc processQuotes(node: XmlNode): XmlNode =
# Bolt on quotes.
# TODO: Yes, this is ugly. I wrote it quickly. PRs welcome ;)
result = newElement("div")
var currentBlockquote = newElement("blockquote")
for n in items(node):
case n.kind
of xnElement:
case n.tag
of "p":
let (nesting, contentNode, _) = processGT(n, "p")
if nesting > 0:
var bq = currentBlockquote
for i in 1 ..< nesting:
var newBq = bq.child("blockquote")
if newBq.isNil:
newBq = newElement("blockquote")
bq.add(newBq)
bq = newBq
bq.insert(contentNode, if bq.len == 0: 0 else: bq.len)
else:
blockquoteFinish(currentBlockquote, result, n)
else:
blockquoteFinish(currentBlockquote, result, n)
of xnText:
if n.text[0] == '\10':
result.add(n)
else:
blockquoteFinish(currentBlockquote, result, n)
else:
blockquoteFinish(currentBlockquote, result, n)
proc replaceMentions(node: XmlNode): seq[XmlNode] =
assert node.kind == xnText
result = @[]
var current = ""
var i = 0
while i < len(node.text):
i += parseUntil(node.text, current, {'@'}, i)
if i >= len(node.text): break
if node.text[i] == '@':
i.inc # Skip @
var username = ""
i += parseWhile(node.text, username, UsernameIdent, i)
let el = <>span(
class="user-mention",
data-username=username,
newText("@" & username)
)
result.add(newText(current))
current = ""
result.add(el)
result.add(newText(current))
proc processMentions(node: XmlNode): XmlNode =
case node.kind
of xnText:
result = newElement("span")
for child in replaceMentions(node):
result.add(child)
of xnElement:
case node.tag
of "pre", "code", "tt":
return node
else:
result = newElement(node.tag)
for n in items(node):
result.add(processMentions(n))
else:
return node
proc rstToHtml*(content: string): string =
result = rstgen.rstToHtml(content, {roSupportMarkdown},
docConfig)
# Bolt on quotes.
# TODO: Yes, this is ugly. I wrote it quickly. PRs welcome ;)
try:
var node = parseHtml(newStringStream(result))
var newNode = newElement("div")
if node.kind == xnElement:
var currentBlockquote = newElement("blockquote")
for n in items(node):
case n.kind
of xnElement:
case n.tag
of "p":
let (nesting, contentNode, tag) = processGT(n, "p")
if nesting > 0:
var bq = currentBlockquote
for i in 1 .. <nesting:
var newBq = bq.child("blockquote")
if newBq.isNil:
newBq = newElement("blockquote")
bq.add(newBq)
bq = newBq
bq.insert(contentNode, if bq.len == 0: 0 else: bq.len)
else:
blockquoteFinish(currentBlockquote, newNode, n)
else:
blockquoteFinish(currentBlockquote, newNode, n)
of xnText:
if n.text[0] == '\10':
newNode.add(n)
else:
blockquoteFinish(currentBlockquote, newNode, n)
else:
blockquoteFinish(currentBlockquote, newNode, n)
let quotedNode = processQuotes(node)
let mentionedNode = processMentions(quotedNode)
result = ""
add(result, newNode, indWidth=0, addNewLines=false)
add(result, mentionedNode, indWidth=0, addNewLines=false)
except:
echo("[WARNING] Could not parse rst html.")
raise
# echo("[WARNING] Could not parse rst html.")
proc sendMail(config: Config, subject, message, recipient: string, from_addr = "forum@nim-lang.org", otherHeaders:seq[(string, string)] = @[]) {.async.} =
if config.smtpAddress.len == 0: