The time a user was last online is now tracked and the main page displays the "online" users as well as some other stats.
This commit is contained in:
parent
5e79d2191b
commit
753e946817
5 changed files with 126 additions and 8 deletions
11
editdb.nim
Normal file
11
editdb.nim
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
|
||||||
|
import strutils, db_sqlite
|
||||||
|
|
||||||
|
var db = Open(connection="nimforum.db", user="postgres", password="",
|
||||||
|
database="nimforum")
|
||||||
|
|
||||||
|
db.exec(sql"""ALTER TABLE person add column
|
||||||
|
lastOnline timestamp
|
||||||
|
""", [])
|
||||||
|
|
||||||
|
close(db)
|
||||||
31
forms.tmpl
31
forms.tmpl
|
|
@ -186,4 +186,33 @@
|
||||||
# else:
|
# else:
|
||||||
<span style="color:red">You're already logged in!</span>
|
<span style="color:red">You're already logged in!</span>
|
||||||
# end if
|
# end if
|
||||||
#end proc
|
#end proc
|
||||||
|
#
|
||||||
|
#
|
||||||
|
#proc genListOnline(c: var TForumData): string =
|
||||||
|
# result = ""
|
||||||
|
# let stats = c.getStats()
|
||||||
|
<div id="whoisonline">
|
||||||
|
<div class="wioHeader">
|
||||||
|
<span>Who is online?<span>
|
||||||
|
</div>
|
||||||
|
<div class="content">
|
||||||
|
<span>Out of ${stats.totalUsers} users ${stats.activeUsers.len} are online:
|
||||||
|
#for index, usr in stats.activeUsers:
|
||||||
|
# if usr.isAdmin:
|
||||||
|
#if index != 0: result.add ','
|
||||||
|
#end if
|
||||||
|
<span class="user admin">${usr.nick}</span>
|
||||||
|
# else:
|
||||||
|
#if index != 0: result.add ','
|
||||||
|
#end if
|
||||||
|
<span class="user">${usr.nick}</span>
|
||||||
|
# end if
|
||||||
|
#end for
|
||||||
|
</span>
|
||||||
|
<hr/>
|
||||||
|
<span>Total threads: ${stats.totalThreads} | Total posts: ${stats.totalPosts} | Newest member: ${stats.newestMember.nick}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
#end proc
|
||||||
|
|
|
||||||
42
forum.nim
42
forum.nim
|
|
@ -37,6 +37,13 @@ type
|
||||||
|
|
||||||
TStyledButton = tuple[text: string, link: string]
|
TStyledButton = tuple[text: string, link: string]
|
||||||
|
|
||||||
|
TForumStats = object
|
||||||
|
totalUsers: int
|
||||||
|
totalPosts: int
|
||||||
|
totalThreads: int
|
||||||
|
newestMember: tuple[nick: string, id: int, isAdmin: bool]
|
||||||
|
activeUsers: seq[tuple[nick: string, id: int, isAdmin: bool]]
|
||||||
|
|
||||||
var
|
var
|
||||||
db: TDbConn
|
db: TDbConn
|
||||||
docConfig: PStringTable
|
docConfig: PStringTable
|
||||||
|
|
@ -211,8 +218,8 @@ proc register(c: var TForumData, name, pass, antibot, email: string): bool =
|
||||||
|
|
||||||
# perform registration:
|
# perform registration:
|
||||||
var salt = makeSalt()
|
var salt = makeSalt()
|
||||||
Exec(db, sql("INSERT INTO person(name, password, email, salt, status) " &
|
Exec(db, sql("INSERT INTO person(name, password, email, salt, status, lastOnline) " &
|
||||||
"VALUES (?, ?, ?, ?, 'user')"), name,
|
"VALUES (?, ?, ?, ?, 'user', DATETIME('now'))"), name,
|
||||||
makePassword(pass, salt), email, salt)
|
makePassword(pass, salt), email, salt)
|
||||||
# return setError(c, "", "Could not create your account!")
|
# return setError(c, "", "Could not create your account!")
|
||||||
return true
|
return true
|
||||||
|
|
@ -234,6 +241,10 @@ proc checkLoggedIn(c: var TForumData) =
|
||||||
c.username = ||row[0]
|
c.username = ||row[0]
|
||||||
c.email = ||row[1]
|
c.email = ||row[1]
|
||||||
c.isAdmin = parseBool(||row[2])
|
c.isAdmin = parseBool(||row[2])
|
||||||
|
# Update lastOnline
|
||||||
|
db.exec(sql"update person set lastOnline = DATETIME('now') where id = ?",
|
||||||
|
c.userid)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
echo("SID not found in sessions. Assuming logged out.")
|
echo("SID not found in sessions. Assuming logged out.")
|
||||||
|
|
||||||
|
|
@ -405,6 +416,29 @@ proc genActionMenu(c: var TForumData): string =
|
||||||
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): TForumStats =
|
||||||
|
const totalUsersQuery =
|
||||||
|
sql"select count(*) from person"
|
||||||
|
result.totalUsers = getValue(db, totalUsersQuery).parseInt
|
||||||
|
const totalPostsQuery =
|
||||||
|
sql"select count(*) from post"
|
||||||
|
result.totalPosts = getValue(db, totalPostsQuery).parseInt
|
||||||
|
const totalThreadsQuery =
|
||||||
|
sql"select count(*) from thread"
|
||||||
|
result.totalThreads = getValue(db, totalThreadsQuery).parseInt
|
||||||
|
|
||||||
|
var newestMemberCreation = 0
|
||||||
|
result.activeUsers = @[]
|
||||||
|
const getUsersQuery =
|
||||||
|
sql"select id, name, admin, strftime('%s', lastOnline), strftime('%s', creation) from person"
|
||||||
|
for row in fastRows(db, getUsersQuery):
|
||||||
|
let lastOnlineSeconds = getTime() - TTime(row[3].parseInt)
|
||||||
|
if lastOnlineSeconds < (60 * 5): # 5 minutes
|
||||||
|
result.activeUsers.add((row[1], row[0].parseInt, row[2].parseBool))
|
||||||
|
if row[4].parseInt > newestMemberCreation:
|
||||||
|
result.newestMember = (row[1], row[0].parseInt, row[2].parseBool)
|
||||||
|
newestMemberCreation = row[4].parseInt
|
||||||
|
|
||||||
include "forms.tmpl"
|
include "forms.tmpl"
|
||||||
include "main.tmpl"
|
include "main.tmpl"
|
||||||
|
|
||||||
|
|
@ -424,7 +458,7 @@ template createTFD(): stmt =
|
||||||
|
|
||||||
get "/":
|
get "/":
|
||||||
createTFD()
|
createTFD()
|
||||||
resp genMain(c, genThreadsList(c))
|
resp genMain(c, genThreadsList(c), true)
|
||||||
|
|
||||||
get "/t/@threadid/?":
|
get "/t/@threadid/?":
|
||||||
createTFD()
|
createTFD()
|
||||||
|
|
@ -541,6 +575,6 @@ when isMainModule:
|
||||||
if paramCount() > 0:
|
if paramCount() > 0:
|
||||||
if paramStr(1) == "scgi":
|
if paramStr(1) == "scgi":
|
||||||
http = false
|
http = false
|
||||||
run(websiteLoc, port = TPort(9001), http = http)
|
run(websiteLoc, port = TPort(9000), http = http)
|
||||||
db.close()
|
db.close()
|
||||||
|
|
||||||
|
|
|
||||||
11
main.tmpl
11
main.tmpl
|
|
@ -1,5 +1,5 @@
|
||||||
#! stdtmpl
|
#! stdtmpl
|
||||||
#proc genMain(c: var TForumData, content: string): string =
|
#proc genMain(c: var TForumData, content: string, mainPage = false): string =
|
||||||
# result = ""
|
# result = ""
|
||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
|
|
@ -38,9 +38,16 @@
|
||||||
<div id="topbar">
|
<div id="topbar">
|
||||||
${c.genActionMenu}
|
${c.genActionMenu}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
#if mainPage:
|
||||||
|
${c.genListOnline}
|
||||||
|
#end if
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div id="footer">
|
<div id="footer">
|
||||||
<p>Written in Nimrod. Generated in ${int((epochTime()-c.startTime)*1000.0)}ms.</p>
|
<span>Written in <a href="http://nimrod-code.org/">Nimrod</a> using <a href="https://github.com/dom96/jester">Jester</a></span>
|
||||||
|
<span> | <a href="https://github.com/nimrod-code/nimforum">Fork on Github</a></span>
|
||||||
|
<span style="float:right;">Generated in ${int((epochTime()-c.startTime)*1000.0)}ms</span>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
||||||
|
|
@ -122,13 +122,50 @@ div#header a:hover, #nimbtn a:hover {
|
||||||
width: 15%;
|
width: 15%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#whoisonline {
|
||||||
|
margin: 5pt;
|
||||||
|
font-size: 9pt;
|
||||||
|
}
|
||||||
|
|
||||||
|
#whoisonline .wioHeader {
|
||||||
|
background-color: #5D5D5D;
|
||||||
|
background: -moz-linear-gradient(top, #5D5D5D, #4D4D4D);
|
||||||
|
background: -webkit-linear-gradient(top, #5D5D5D, #4d4d4d);
|
||||||
|
background: -o-linear-gradient(top, #5D5D5D, #4d4d4d);
|
||||||
|
color: #ffffff;
|
||||||
|
border-bottom: #2d2d2d solid 1px;
|
||||||
|
padding: 3px;
|
||||||
|
padding-left: 5pt;
|
||||||
|
}
|
||||||
|
|
||||||
|
#whoisonline .content {
|
||||||
|
border: #9d9d9d solid 1px;
|
||||||
|
border-top: #2D2D2D solid 1px;
|
||||||
|
padding: 5pt;
|
||||||
|
}
|
||||||
|
|
||||||
|
#whoisonline .content hr {
|
||||||
|
margin-top: 5pt;
|
||||||
|
margin-bottom: 5pt;
|
||||||
|
}
|
||||||
|
|
||||||
#footer {
|
#footer {
|
||||||
background-color: #5D5D5D;
|
background-color: #5D5D5D;
|
||||||
background: -moz-linear-gradient(top, #5D5D5D, #4D4D4D);
|
background: -moz-linear-gradient(top, #5D5D5D, #4D4D4D);
|
||||||
background: -webkit-linear-gradient(top, #5D5D5D, #4d4d4d);
|
background: -webkit-linear-gradient(top, #5D5D5D, #4d4d4d);
|
||||||
background: -o-linear-gradient(top, #5D5D5D, #4d4d4d);
|
background: -o-linear-gradient(top, #5D5D5D, #4d4d4d);
|
||||||
color: #ffffff;
|
color: #ffffff;
|
||||||
text-align: center;
|
|
||||||
|
padding-left: 5px;
|
||||||
|
padding-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#footer a:link, #footer a:visited {
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
#footer a:hover {
|
||||||
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
#topbar {
|
#topbar {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue