Added a way for admins to reset passwords.
This commit is contained in:
parent
5742a1d33d
commit
b7584de440
1 changed files with 85 additions and 67 deletions
152
forum.nim
152
forum.nim
|
|
@ -50,7 +50,7 @@ type
|
||||||
totalPosts: int
|
totalPosts: int
|
||||||
search: string
|
search: string
|
||||||
noPagenumumNav: bool
|
noPagenumumNav: bool
|
||||||
|
|
||||||
TStyledButton = tuple[text: string, link: string]
|
TStyledButton = tuple[text: string, link: string]
|
||||||
|
|
||||||
TForumStats = object
|
TForumStats = object
|
||||||
|
|
@ -72,23 +72,23 @@ var
|
||||||
db: TDbConn
|
db: TDbConn
|
||||||
docConfig: StringTableRef
|
docConfig: StringTableRef
|
||||||
isFTSAvailable: bool
|
isFTSAvailable: bool
|
||||||
|
|
||||||
proc init(c: var TForumData) =
|
proc init(c: var TForumData) =
|
||||||
c.userPass = ""
|
c.userPass = ""
|
||||||
c.userName = ""
|
c.userName = ""
|
||||||
c.threadId = unselectedThread
|
c.threadId = unselectedThread
|
||||||
c.postId = -1
|
c.postId = -1
|
||||||
|
|
||||||
c.userid = ""
|
c.userid = ""
|
||||||
c.actionContent = ""
|
c.actionContent = ""
|
||||||
c.errorMsg = ""
|
c.errorMsg = ""
|
||||||
c.loginErrorMsg = ""
|
c.loginErrorMsg = ""
|
||||||
c.invalidField = ""
|
c.invalidField = ""
|
||||||
c.currentPost = (subject: "", content: "")
|
c.currentPost = (subject: "", content: "")
|
||||||
|
|
||||||
c.search = ""
|
c.search = ""
|
||||||
|
|
||||||
proc loggedIn(c: TForumData): bool =
|
proc loggedIn(c: TForumData): bool =
|
||||||
result = c.userName.len > 0
|
result = c.userName.len > 0
|
||||||
|
|
||||||
# --------------- HTML widgets ------------------------------------------------
|
# --------------- HTML widgets ------------------------------------------------
|
||||||
|
|
@ -98,7 +98,7 @@ proc loggedIn(c: TForumData): bool =
|
||||||
const
|
const
|
||||||
reuseText = "\1"
|
reuseText = "\1"
|
||||||
|
|
||||||
proc TextWidget(c: TForumData, name, defaultText: string,
|
proc TextWidget(c: TForumData, name, defaultText: string,
|
||||||
maxlength = 30, size = -1): string =
|
maxlength = 30, size = -1): string =
|
||||||
let x = if defaultText != reuseText: defaultText
|
let x = if defaultText != reuseText: defaultText
|
||||||
else: xmlEncode(c.req.params[name])
|
else: xmlEncode(c.req.params[name])
|
||||||
|
|
@ -116,8 +116,8 @@ proc TextAreaWidget(c: TForumData, name, defaultText: string): string =
|
||||||
return """<textarea name="$1">$2</textarea>""" % [
|
return """<textarea name="$1">$2</textarea>""" % [
|
||||||
name, x]
|
name, x]
|
||||||
|
|
||||||
proc FieldValid(c: TForumData, name, text: string): string =
|
proc FieldValid(c: TForumData, name, text: string): string =
|
||||||
if name == c.invalidField:
|
if name == c.invalidField:
|
||||||
result = """<span style="color:red">$1</span>""" % text
|
result = """<span style="color:red">$1</span>""" % text
|
||||||
else:
|
else:
|
||||||
result = text
|
result = text
|
||||||
|
|
@ -146,14 +146,14 @@ proc UrlButton(c: var TForumData, text, url: string): string =
|
||||||
proc genButtons(c: var TForumData, btns: seq[TStyledButton]): string =
|
proc genButtons(c: var TForumData, btns: seq[TStyledButton]): string =
|
||||||
if btns.len == 1:
|
if btns.len == 1:
|
||||||
var anchor = ""
|
var anchor = ""
|
||||||
|
|
||||||
result = ("""<a class="active button" href="$1$3">$2</a>""") % [
|
result = ("""<a class="active button" href="$1$3">$2</a>""") % [
|
||||||
btns[0].link, btns[0].text, anchor]
|
btns[0].link, btns[0].text, anchor]
|
||||||
else:
|
else:
|
||||||
result = ""
|
result = ""
|
||||||
for i, btn in pairs(btns):
|
for i, btn in pairs(btns):
|
||||||
var anchor = ""
|
var anchor = ""
|
||||||
|
|
||||||
var class = ""
|
var class = ""
|
||||||
if i == 0: class = "left "
|
if i == 0: class = "left "
|
||||||
elif i == btns.len()-1: class = "right "
|
elif i == btns.len()-1: class = "right "
|
||||||
|
|
@ -200,7 +200,7 @@ proc getGravatarUrl(email: string, size = 80): string =
|
||||||
"&d=identicon")
|
"&d=identicon")
|
||||||
|
|
||||||
proc genGravatar(email: string, size: int = 80): string =
|
proc genGravatar(email: string, size: int = 80): string =
|
||||||
result = "<img width=\"$1\" height=\"$2\" src=\"$3\" />" %
|
result = "<img width=\"$1\" height=\"$2\" src=\"$3\" />" %
|
||||||
[$size, $size, getGravatarUrl(email, size)]
|
[$size, $size, getGravatarUrl(email, size)]
|
||||||
|
|
||||||
proc randomSalt(): string =
|
proc randomSalt(): string =
|
||||||
|
|
@ -250,17 +250,17 @@ proc makePassword(password, salt: string, comparingTo = ""): string =
|
||||||
template `||`(x: expr): expr = (if not isNil(x): x else: "")
|
template `||`(x: expr): expr = (if not isNil(x): x else: "")
|
||||||
|
|
||||||
proc validThreadId(c: TForumData): bool =
|
proc validThreadId(c: TForumData): bool =
|
||||||
result = getValue(db, sql"select id from thread where id = ?",
|
result = getValue(db, sql"select id from thread where id = ?",
|
||||||
$c.threadId).len > 0
|
$c.threadId).len > 0
|
||||||
|
|
||||||
proc antibot(c: var TForumData): string =
|
proc antibot(c: var TForumData): string =
|
||||||
let a = math.random(10)+1
|
let a = math.random(10)+1
|
||||||
let b = math.random(1000)+1
|
let b = math.random(1000)+1
|
||||||
let answer = $(a+b)
|
let answer = $(a+b)
|
||||||
|
|
||||||
exec(db, sql"delete from antibot where ip = ?", c.req.ip)
|
exec(db, sql"delete from antibot where ip = ?", c.req.ip)
|
||||||
let captchaId = tryInsertID(db,
|
let captchaId = tryInsertID(db,
|
||||||
sql"insert into antibot(ip, answer) values (?, ?)", c.req.ip,
|
sql"insert into antibot(ip, answer) values (?, ?)", c.req.ip,
|
||||||
answer).int mod 10_000
|
answer).int mod 10_000
|
||||||
let captchaFile = getCaptchaFilename(captchaId)
|
let captchaFile = getCaptchaFilename(captchaId)
|
||||||
createCaptcha(captchaFile, $a & "+" & $b)
|
createCaptcha(captchaFile, $a & "+" & $b)
|
||||||
|
|
@ -274,27 +274,27 @@ proc setError(c: var TForumData, field, msg: string): bool {.inline.} =
|
||||||
c.errorMsg = "Error: " & msg
|
c.errorMsg = "Error: " & msg
|
||||||
return false
|
return false
|
||||||
|
|
||||||
proc register(c: var TForumData, name, pass, antibot, email: string): bool =
|
proc register(c: var TForumData, name, pass, antibot, email: string): bool =
|
||||||
# Username validation:
|
# Username validation:
|
||||||
if name.len == 0 or not allCharsInSet(name, SecureChars):
|
if name.len == 0 or not allCharsInSet(name, SecureChars):
|
||||||
return setError(c, "name", "Invalid username!")
|
return setError(c, "name", "Invalid username!")
|
||||||
if getValue(db, sql"select name from person where name = ?", name).len > 0:
|
if getValue(db, sql"select name from person where name = ?", name).len > 0:
|
||||||
return setError(c, "name", "Username already exists!")
|
return setError(c, "name", "Username already exists!")
|
||||||
|
|
||||||
# Password validation:
|
# Password validation:
|
||||||
if pass.len < 4:
|
if pass.len < 4:
|
||||||
return setError(c, "new_password", "Invalid password!")
|
return setError(c, "new_password", "Invalid password!")
|
||||||
|
|
||||||
# antibot validation:
|
# antibot validation:
|
||||||
let correctRes = getValue(db,
|
let correctRes = getValue(db,
|
||||||
sql"select answer from antibot where ip = ?", c.req.ip)
|
sql"select answer from antibot where ip = ?", c.req.ip)
|
||||||
if antibot != correctRes:
|
if antibot != correctRes:
|
||||||
return setError(c, "antibot", "You seem to be a bot!")
|
return setError(c, "antibot", "You seem to be a bot!")
|
||||||
|
|
||||||
# email validation
|
# email validation
|
||||||
if not validEmailAddress(email):
|
if not validEmailAddress(email):
|
||||||
return setError(c, "email", "Invalid email address")
|
return setError(c, "email", "Invalid email address")
|
||||||
|
|
||||||
# perform registration:
|
# perform registration:
|
||||||
var salt = makeSalt()
|
var salt = makeSalt()
|
||||||
exec(db,
|
exec(db,
|
||||||
|
|
@ -304,18 +304,18 @@ proc register(c: var TForumData, name, pass, antibot, email: string): bool =
|
||||||
# return setError(c, "", "Could not create your account!")
|
# return setError(c, "", "Could not create your account!")
|
||||||
return true
|
return true
|
||||||
|
|
||||||
proc checkLoggedIn(c: var TForumData) =
|
proc checkLoggedIn(c: var TForumData) =
|
||||||
let pass = c.req.cookies["sid"]
|
let pass = c.req.cookies["sid"]
|
||||||
if pass.len == 0: return
|
if pass.len == 0: return
|
||||||
if execAffectedRows(db,
|
if execAffectedRows(db,
|
||||||
sql("update session set lastModified = DATETIME('now') " &
|
sql("update session set lastModified = DATETIME('now') " &
|
||||||
"where ip = ? and password = ?"),
|
"where ip = ? and password = ?"),
|
||||||
c.req.ip, pass) > 0:
|
c.req.ip, pass) > 0:
|
||||||
c.userpass = pass
|
c.userpass = pass
|
||||||
c.userid = getValue(db,
|
c.userid = getValue(db,
|
||||||
sql"select userid from session where ip = ? and password = ?",
|
sql"select userid from session where ip = ? and password = ?",
|
||||||
c.req.ip, pass)
|
c.req.ip, pass)
|
||||||
|
|
||||||
let row = getRow(db,
|
let row = getRow(db,
|
||||||
sql"select name, email, admin from person where id = ?", c.userid)
|
sql"select name, email, admin from person where id = ?", c.userid)
|
||||||
c.username = ||row[0]
|
c.username = ||row[0]
|
||||||
|
|
@ -324,7 +324,7 @@ proc checkLoggedIn(c: var TForumData) =
|
||||||
# Update lastOnline
|
# Update lastOnline
|
||||||
db.exec(sql"update person set lastOnline = DATETIME('now') where id = ?",
|
db.exec(sql"update person set lastOnline = DATETIME('now') where id = ?",
|
||||||
c.userid)
|
c.userid)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
echo("SID not found in sessions. Assuming logged out.")
|
echo("SID not found in sessions. Assuming logged out.")
|
||||||
|
|
||||||
|
|
@ -334,7 +334,7 @@ proc logout(c: var TForumData) =
|
||||||
c.userpass = ""
|
c.userpass = ""
|
||||||
exec(db, query, c.req.ip, c.req.cookies["sid"])
|
exec(db, query, c.req.ip, c.req.cookies["sid"])
|
||||||
|
|
||||||
proc incrementViews(c: var TForumData) =
|
proc incrementViews(c: var TForumData) =
|
||||||
const query = sql"update thread set views = views + 1 where id = ?"
|
const query = sql"update thread set views = views + 1 where id = ?"
|
||||||
exec(db, query, $c.threadId)
|
exec(db, query, $c.threadId)
|
||||||
|
|
||||||
|
|
@ -345,7 +345,7 @@ proc isDelete(c: TForumData): bool =
|
||||||
result = c.req.params["delete"].len > 0
|
result = c.req.params["delete"].len > 0
|
||||||
|
|
||||||
proc rstToHtml(content: string): string =
|
proc rstToHtml(content: string): string =
|
||||||
result = rstgen.rstToHtml(content, {roSupportSmilies, roSupportMarkdown},
|
result = rstgen.rstToHtml(content, {roSupportSmilies, roSupportMarkdown},
|
||||||
docConfig)
|
docConfig)
|
||||||
|
|
||||||
proc validateRst(c: var TForumData, content: string): bool =
|
proc validateRst(c: var TForumData, content: string): bool =
|
||||||
|
|
@ -358,10 +358,10 @@ proc validateRst(c: var TForumData, content: string): bool =
|
||||||
proc crud(c: TCrud, table: string, data: varargs[string]): TSqlQuery =
|
proc crud(c: TCrud, table: string, data: varargs[string]): TSqlQuery =
|
||||||
case c
|
case c
|
||||||
of crCreate:
|
of crCreate:
|
||||||
var fields = "insert into " & table & "("
|
var fields = "insert into " & table & "("
|
||||||
var vals = ""
|
var vals = ""
|
||||||
for i, d in data:
|
for i, d in data:
|
||||||
if i > 0:
|
if i > 0:
|
||||||
fields.add(", ")
|
fields.add(", ")
|
||||||
vals.add(", ")
|
vals.add(", ")
|
||||||
fields.add(d)
|
fields.add(d)
|
||||||
|
|
@ -403,7 +403,7 @@ template checkLogin(c: expr) =
|
||||||
|
|
||||||
template checkOwnership(c, postId: expr) =
|
template checkOwnership(c, postId: expr) =
|
||||||
if not c.isAdmin:
|
if not c.isAdmin:
|
||||||
let x = getValue(db, sql"select author from post where id = ?",
|
let x = getValue(db, sql"select author from post where id = ?",
|
||||||
postId)
|
postId)
|
||||||
if x != c.userId:
|
if x != c.userId:
|
||||||
return setError(c, "", "You are not the owner of this post")
|
return setError(c, "", "You are not the owner of this post")
|
||||||
|
|
@ -421,7 +421,7 @@ template writeToDb(c, cr, setPostId: expr) =
|
||||||
c.postId = retID.int
|
c.postId = retID.int
|
||||||
|
|
||||||
proc edit(c: var TForumData, postId: int): bool =
|
proc edit(c: var TForumData, postId: int): bool =
|
||||||
checkLogin(c)
|
checkLogin(c)
|
||||||
if c.isPreview:
|
if c.isPreview:
|
||||||
retrPost(c)
|
retrPost(c)
|
||||||
setPreviewData(c)
|
setPreviewData(c)
|
||||||
|
|
@ -458,19 +458,19 @@ proc edit(c: var TForumData, postId: int): bool =
|
||||||
if rows[0][0] == $postId:
|
if rows[0][0] == $postId:
|
||||||
exec(db, crud(crUpdate, "thread", "name"), subject, $c.threadId)
|
exec(db, crud(crUpdate, "thread", "name"), subject, $c.threadId)
|
||||||
result = true
|
result = true
|
||||||
|
|
||||||
proc reply(c: var TForumData): bool =
|
proc reply(c: var TForumData): bool =
|
||||||
checkLogin(c)
|
checkLogin(c)
|
||||||
retrPost(c)
|
retrPost(c)
|
||||||
if c.isPreview:
|
if c.isPreview:
|
||||||
setPreviewData(c)
|
setPreviewData(c)
|
||||||
else:
|
else:
|
||||||
writeToDb(c, crCreate, true)
|
writeToDb(c, crCreate, true)
|
||||||
|
|
||||||
exec(db, sql"update thread set modified = DATETIME('now') where id = ?",
|
exec(db, sql"update thread set modified = DATETIME('now') where id = ?",
|
||||||
$c.threadId)
|
$c.threadId)
|
||||||
result = true
|
result = true
|
||||||
|
|
||||||
proc newThread(c: var TForumData): bool =
|
proc newThread(c: var TForumData): bool =
|
||||||
const query = sql"insert into thread(name, views, modified) values (?, 0, DATETIME('now'))"
|
const query = sql"insert into thread(name, views, modified) values (?, 0, DATETIME('now'))"
|
||||||
checkLogin(c)
|
checkLogin(c)
|
||||||
|
|
@ -488,9 +488,9 @@ proc newThread(c: var TForumData): bool =
|
||||||
discard tryExec(db, sql"insert into post_fts(thread_fts) values('optimize')")
|
discard tryExec(db, sql"insert into post_fts(thread_fts) values('optimize')")
|
||||||
result = true
|
result = true
|
||||||
|
|
||||||
proc login(c: var TForumData, name, pass: string): bool =
|
proc login(c: var TForumData, name, pass: string): bool =
|
||||||
# get form data:
|
# get form data:
|
||||||
const query =
|
const query =
|
||||||
sql"select id, name, password, email, salt, admin, ban from person where name = ?"
|
sql"select id, name, password, email, salt, admin, ban from person where name = ?"
|
||||||
if name.len == 0:
|
if name.len == 0:
|
||||||
return c.setError("name", "Username cannot be nil.")
|
return c.setError("name", "Username cannot be nil.")
|
||||||
|
|
@ -513,7 +513,7 @@ proc login(c: var TForumData, name, pass: string): bool =
|
||||||
if success:
|
if success:
|
||||||
# create session:
|
# create session:
|
||||||
exec(db,
|
exec(db,
|
||||||
sql"insert into session (ip, password, userid) values (?, ?, ?)",
|
sql"insert into session (ip, password, userid) values (?, ?, ?)",
|
||||||
c.req.ip, c.userpass, c.userid)
|
c.req.ip, c.userpass, c.userid)
|
||||||
return true
|
return true
|
||||||
else:
|
else:
|
||||||
|
|
@ -524,6 +524,12 @@ proc setBan(c: var TForumData, nick, reason: string): bool =
|
||||||
sql("update person set ban = ? where name = ?")
|
sql("update person set ban = ? where name = ?")
|
||||||
return tryExec(db, query, reason, nick)
|
return tryExec(db, query, reason, nick)
|
||||||
|
|
||||||
|
proc setPassword(c: var TForumData, nick, pass: string): bool =
|
||||||
|
const query =
|
||||||
|
sql("update person set password = ?, salt = ? where name = ?")
|
||||||
|
var salt = makeSalt()
|
||||||
|
result = tryExec(db, query, makePassword(pass, salt), salt, nick)
|
||||||
|
|
||||||
proc hasReplyBtn(c: var TForumData): bool =
|
proc hasReplyBtn(c: var TForumData): bool =
|
||||||
result = c.req.pathInfo != "/donewthread" and c.req.pathInfo != "/doreply"
|
result = c.req.pathInfo != "/donewthread" and c.req.pathInfo != "/doreply"
|
||||||
result = result and c.req.params["action"] != "reply"
|
result = result and c.req.params["action"] != "reply"
|
||||||
|
|
@ -543,14 +549,14 @@ proc genActionMenu(c: var TForumData): string =
|
||||||
if c.loggedIn:
|
if c.loggedIn:
|
||||||
let hasReplyBtn = c.req.pathInfo != "/donewthread" and c.req.pathInfo != "/doreply"
|
let hasReplyBtn = c.req.pathInfo != "/donewthread" and c.req.pathInfo != "/doreply"
|
||||||
if c.threadId >= 0 and hasReplyBtn:
|
if c.threadId >= 0 and hasReplyBtn:
|
||||||
let replyUrl = c.genThreadUrl(action = "reply",
|
let replyUrl = c.genThreadUrl(action = "reply",
|
||||||
pageNum = $(ceil(c.totalPosts / PostsPerPage).int)) & "#reply"
|
pageNum = $(ceil(c.totalPosts / PostsPerPage).int)) & "#reply"
|
||||||
btns.add(("Reply", replyUrl))
|
btns.add(("Reply", replyUrl))
|
||||||
btns.add(("New Thread", c.req.makeUri("/newthread", false)))
|
btns.add(("New Thread", c.req.makeUri("/newthread", false)))
|
||||||
result = c.genButtons(btns)
|
result = c.genButtons(btns)
|
||||||
|
|
||||||
proc getStats(c: var TForumData, simple: bool): TForumStats =
|
proc getStats(c: var TForumData, simple: bool): TForumStats =
|
||||||
const totalUsersQuery =
|
const totalUsersQuery =
|
||||||
sql"select count(*) from person"
|
sql"select count(*) from person"
|
||||||
result.totalUsers = getValue(db, totalUsersQuery).parseInt
|
result.totalUsers = getValue(db, totalUsersQuery).parseInt
|
||||||
const totalPostsQuery =
|
const totalPostsQuery =
|
||||||
|
|
@ -576,13 +582,13 @@ proc getStats(c: var TForumData, simple: bool): TForumStats =
|
||||||
|
|
||||||
proc genPagenumNav(c: var TForumData, stats: TForumStats): string =
|
proc genPagenumNav(c: var TForumData, stats: TForumStats): string =
|
||||||
result = ""
|
result = ""
|
||||||
var
|
var
|
||||||
firstUrl = ""
|
firstUrl = ""
|
||||||
prevUrl = ""
|
prevUrl = ""
|
||||||
totalPages = 0
|
totalPages = 0
|
||||||
lastUrl = ""
|
lastUrl = ""
|
||||||
nextUrl = ""
|
nextUrl = ""
|
||||||
|
|
||||||
if c.isThreadsList:
|
if c.isThreadsList:
|
||||||
firstUrl = c.req.makeUri("/")
|
firstUrl = c.req.makeUri("/")
|
||||||
prevUrl = c.req.makeUri(if c.pageNum == 1: "/" else: "/page/" & $(c.pageNum-1))
|
prevUrl = c.req.makeUri(if c.pageNum == 1: "/" else: "/page/" & $(c.pageNum-1))
|
||||||
|
|
@ -593,15 +599,15 @@ proc genPagenumNav(c: var TForumData, stats: TForumStats): string =
|
||||||
firstUrl = c.req.makeUri("/t/" & $c.threadId)
|
firstUrl = c.req.makeUri("/t/" & $c.threadId)
|
||||||
if c.pageNum == 1:
|
if c.pageNum == 1:
|
||||||
prevUrl = firstUrl
|
prevUrl = firstUrl
|
||||||
else:
|
else:
|
||||||
prevUrl = c.req.makeUri(firstUrl & "/" & $(c.pageNum-1))
|
prevUrl = c.req.makeUri(firstUrl & "/" & $(c.pageNum-1))
|
||||||
totalPages = ceil(c.totalPosts / PostsPerPage).int
|
totalPages = ceil(c.totalPosts / PostsPerPage).int
|
||||||
lastUrl = c.req.makeUri(firstUrl & "/" & $(totalPages))
|
lastUrl = c.req.makeUri(firstUrl & "/" & $(totalPages))
|
||||||
nextUrl = c.req.makeUri(firstUrl & "/" & $(c.pageNum+1))
|
nextUrl = c.req.makeUri(firstUrl & "/" & $(c.pageNum+1))
|
||||||
|
|
||||||
if totalPages <= 1:
|
if totalPages <= 1:
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
var firstTag = ""
|
var firstTag = ""
|
||||||
var prevTag = ""
|
var prevTag = ""
|
||||||
if c.pageNum == 1:
|
if c.pageNum == 1:
|
||||||
|
|
@ -613,7 +619,7 @@ proc genPagenumNav(c: var TForumData, stats: TForumStats): string =
|
||||||
prevTag.add(htmlgen.link(rel="previous", href=prevUrl))
|
prevTag.add(htmlgen.link(rel="previous", href=prevUrl))
|
||||||
result.add(firstTag)
|
result.add(firstTag)
|
||||||
result.add(prevTag)
|
result.add(prevTag)
|
||||||
|
|
||||||
# Numbers
|
# Numbers
|
||||||
var pages = "" # Tags
|
var pages = "" # Tags
|
||||||
# cutting numbers to the left and to the right tp MaxPagesFromCurrent
|
# cutting numbers to the left and to the right tp MaxPagesFromCurrent
|
||||||
|
|
@ -629,7 +635,7 @@ proc genPagenumNav(c: var TForumData, stats: TForumStats): string =
|
||||||
pageUrl = c.req.makeUri("/page/" & $(i))
|
pageUrl = c.req.makeUri("/page/" & $(i))
|
||||||
else:
|
else:
|
||||||
pageUrl = c.req.makeUri(firstUrl & "/" & $(i))
|
pageUrl = c.req.makeUri(firstUrl & "/" & $(i))
|
||||||
|
|
||||||
pages.add(htmlgen.a(href = pageUrl, $(i)))
|
pages.add(htmlgen.a(href = pageUrl, $(i)))
|
||||||
if lastToShow < totalPages: pages.add(span("..."))
|
if lastToShow < totalPages: pages.add(span("..."))
|
||||||
result.add(pages)
|
result.add(pages)
|
||||||
|
|
@ -702,7 +708,7 @@ proc gatherUserInfo(c: var TForumData, nick: string, ui: var TUserInfo): bool =
|
||||||
const totalThreadsQuery =
|
const totalThreadsQuery =
|
||||||
sql("select count(*) from thread where id in (select thread from post where" &
|
sql("select count(*) from thread where id in (select thread from post where" &
|
||||||
" author = ? and post.id in (select min(id) from post group by thread))")
|
" author = ? and post.id in (select min(id) from post group by thread))")
|
||||||
|
|
||||||
ui.threads = getValue(db, totalThreadsQuery, uid).parseInt
|
ui.threads = getValue(db, totalThreadsQuery, uid).parseInt
|
||||||
const lastOnlineQuery =
|
const lastOnlineQuery =
|
||||||
sql"select strftime('%s', lastOnline) from person where id = ?"
|
sql"select strftime('%s', lastOnline) from person where id = ?"
|
||||||
|
|
@ -729,10 +735,10 @@ proc genProfile(c: var TForumData, ui: TUserInfo): string =
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
result.add(htmlgen.`div`(id = "avatar", genGravatar(ui.email, 250)))
|
result.add(htmlgen.`div`(id = "avatar", genGravatar(ui.email, 250)))
|
||||||
let t2 = if ui.lastOnline != -1: getGMTime(Time(ui.lastOnline))
|
let t2 = if ui.lastOnline != -1: getGMTime(Time(ui.lastOnline))
|
||||||
else: getGMTime(getTime())
|
else: getGMTime(getTime())
|
||||||
|
|
||||||
result.add(htmlgen.`div`(id = "info",
|
result.add(htmlgen.`div`(id = "info",
|
||||||
htmlgen.table(
|
htmlgen.table(
|
||||||
tr(
|
tr(
|
||||||
th("Nickname"),
|
th("Nickname"),
|
||||||
|
|
@ -788,7 +794,7 @@ proc genProfile(c: var TForumData, ui: TUserInfo): string =
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
))
|
))
|
||||||
|
|
||||||
result = htmlgen.`div`(id = "profile",
|
result = htmlgen.`div`(id = "profile",
|
||||||
htmlgen.`div`(id = "left", result))
|
htmlgen.`div`(id = "left", result))
|
||||||
|
|
||||||
|
|
@ -797,7 +803,7 @@ include "main.tmpl"
|
||||||
|
|
||||||
proc prependRe(s: string): string =
|
proc prependRe(s: string): string =
|
||||||
result = if s.len == 0:
|
result = if s.len == 0:
|
||||||
""
|
""
|
||||||
elif s.startswith("Re:"): s
|
elif s.startswith("Re:"): s
|
||||||
else: "Re: " & s
|
else: "Re: " & s
|
||||||
|
|
||||||
|
|
@ -852,7 +858,7 @@ routes:
|
||||||
case @"action"
|
case @"action"
|
||||||
of "reply":
|
of "reply":
|
||||||
let subject = getValue(db,
|
let subject = getValue(db,
|
||||||
sql"select header from post where id = (select max(id) from post where thread = ?)",
|
sql"select header from post where id = (select max(id) from post where thread = ?)",
|
||||||
$c.threadId).prependRe
|
$c.threadId).prependRe
|
||||||
body = genPostsList(c, $c.threadId, count)
|
body = genPostsList(c, $c.threadId, count)
|
||||||
cond count != 0
|
cond count != 0
|
||||||
|
|
@ -917,16 +923,16 @@ routes:
|
||||||
if (@"postid").len > 0:
|
if (@"postid").len > 0:
|
||||||
parseInt(@"postid", c.postId, -1..1000_000)
|
parseInt(@"postid", c.postId, -1..1000_000)
|
||||||
|
|
||||||
template finishLogin(): stmt =
|
template finishLogin(): stmt =
|
||||||
setCookie("sid", c.userpass, daysForward(7))
|
setCookie("sid", c.userpass, daysForward(7))
|
||||||
redirect(uri("/"))
|
redirect(uri("/"))
|
||||||
|
|
||||||
template handleError(action: string, topText: string, isEdit: bool): stmt =
|
template handleError(action: string, topText: string, isEdit: bool): stmt =
|
||||||
if c.isPreview:
|
if c.isPreview:
|
||||||
body.add genPostPreview(c, @"subject", @"content",
|
body.add genPostPreview(c, @"subject", @"content",
|
||||||
c.userName, $getGMTime(getTime()))
|
c.userName, $getGMTime(getTime()))
|
||||||
body.add genFormPost(c, action, topText, reuseText, reuseText, isEdit)
|
body.add genFormPost(c, action, topText, reuseText, reuseText, isEdit)
|
||||||
resp genMain(c, body(), "Nim Forum - " &
|
resp genMain(c, body(), "Nim Forum - " &
|
||||||
(if c.isPreview: "Preview" else: "Error"))
|
(if c.isPreview: "Preview" else: "Error"))
|
||||||
|
|
||||||
post "/dologin":
|
post "/dologin":
|
||||||
|
|
@ -1042,6 +1048,18 @@ routes:
|
||||||
resp genMain(c, "Failed to change the ban status of user.",
|
resp genMain(c, "Failed to change the ban status of user.",
|
||||||
"Error - Nim Forum")
|
"Error - Nim Forum")
|
||||||
|
|
||||||
|
get "/setpassword/?":
|
||||||
|
createTFD()
|
||||||
|
cond (@"nick" != "")
|
||||||
|
cond (@"pass" != "")
|
||||||
|
if not c.isAdmin:
|
||||||
|
resp genMain(c, "You cannot change this user's pass.", "Error - Nim Forum")
|
||||||
|
let res = setPassword(c, @"nick", @"pass")
|
||||||
|
if res:
|
||||||
|
resp genMain(c, "Success", "Nim Forum")
|
||||||
|
else:
|
||||||
|
resp genMain(c, "Failure", "Nim Forum")
|
||||||
|
|
||||||
const licenseRst = slurp("static/license.rst")
|
const licenseRst = slurp("static/license.rst")
|
||||||
get "/license":
|
get "/license":
|
||||||
createTFD()
|
createTFD()
|
||||||
|
|
@ -1078,7 +1096,7 @@ routes:
|
||||||
if existsFile(path):
|
if existsFile(path):
|
||||||
page = readFile(path)
|
page = readFile(path)
|
||||||
else:
|
else:
|
||||||
let basePath =
|
let basePath =
|
||||||
if path[path.high] == '/': path & "index"
|
if path[path.high] == '/': path & "index"
|
||||||
elif path.endsWith(".html"): path[-5 .. -1]
|
elif path.endsWith(".html"): path[-5 .. -1]
|
||||||
else: path
|
else: path
|
||||||
|
|
@ -1095,7 +1113,7 @@ when isMainModule:
|
||||||
docConfig = rstgen.defaultConfig()
|
docConfig = rstgen.defaultConfig()
|
||||||
docConfig["doc.smiley_format"] = "/images/smilieys/$1.png"
|
docConfig["doc.smiley_format"] = "/images/smilieys/$1.png"
|
||||||
math.randomize()
|
math.randomize()
|
||||||
db = open(connection="nimforum.db", user="postgres", password="",
|
db = open(connection="nimforum.db", user="postgres", password="",
|
||||||
database="nimforum")
|
database="nimforum")
|
||||||
isFTSAvailable = db.getAllRows(sql("SELECT name FROM sqlite_master WHERE " &
|
isFTSAvailable = db.getAllRows(sql("SELECT name FROM sqlite_master WHERE " &
|
||||||
"type='table' AND name='post_fts'")).len == 1
|
"type='table' AND name='post_fts'")).len == 1
|
||||||
|
|
@ -1103,9 +1121,9 @@ when isMainModule:
|
||||||
if paramCount() > 0:
|
if paramCount() > 0:
|
||||||
if paramStr(1) == "scgi":
|
if paramStr(1) == "scgi":
|
||||||
http = false
|
http = false
|
||||||
|
|
||||||
#run("", port = TPort(9000), http = http)
|
#run("", port = TPort(9000), http = http)
|
||||||
|
|
||||||
runForever()
|
runForever()
|
||||||
db.close()
|
db.close()
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue