Take deleted accounts into account.
This commit is contained in:
parent
aa9f24e1d7
commit
2fbebfa3f9
8 changed files with 57 additions and 37 deletions
|
|
@ -888,20 +888,26 @@ template createTFD() =
|
||||||
#[ DB functions. TODO: Move to another module? ]#
|
#[ DB functions. TODO: Move to another module? ]#
|
||||||
|
|
||||||
proc selectUser(userRow: seq[string], avatarSize: int=80): User =
|
proc selectUser(userRow: seq[string], avatarSize: int=80): User =
|
||||||
return User(
|
result = User(
|
||||||
name: userRow[0],
|
name: userRow[0],
|
||||||
avatarUrl: userRow[1].getGravatarUrl(avatarSize),
|
avatarUrl: userRow[1].getGravatarUrl(avatarSize),
|
||||||
lastOnline: userRow[2].parseInt,
|
lastOnline: userRow[2].parseInt,
|
||||||
rank: parseEnum[Rank](userRow[3])
|
rank: parseEnum[Rank](userRow[3]),
|
||||||
|
isDeleted: userRow[4] == "1"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Don't give data about a deleted user.
|
||||||
|
if result.isDeleted:
|
||||||
|
result.name = "DeletedUser"
|
||||||
|
result.avatarUrl = getGravatarUrl(result.name & userRow[1], avatarSize)
|
||||||
|
|
||||||
proc selectPost(postRow: seq[string], skippedPosts: seq[int],
|
proc selectPost(postRow: seq[string], skippedPosts: seq[int],
|
||||||
replyingTo: Option[PostLink], history: seq[PostInfo],
|
replyingTo: Option[PostLink], history: seq[PostInfo],
|
||||||
likes: seq[User]): Post =
|
likes: seq[User]): Post =
|
||||||
return Post(
|
return Post(
|
||||||
id: postRow[0].parseInt,
|
id: postRow[0].parseInt,
|
||||||
replyingTo: replyingTo,
|
replyingTo: replyingTo,
|
||||||
author: selectUser(@[postRow[5], postRow[6], postRow[7], postRow[8]]),
|
author: selectUser(postRow[5..9]),
|
||||||
likes: likes,
|
likes: likes,
|
||||||
seen: false, # TODO:
|
seen: false, # TODO:
|
||||||
history: history,
|
history: history,
|
||||||
|
|
@ -918,6 +924,7 @@ proc selectReplyingTo(replyingTo: string): Option[PostLink] =
|
||||||
const replyingToQuery = sql"""
|
const replyingToQuery = sql"""
|
||||||
select p.id, strftime('%s', p.creation), p.thread,
|
select p.id, strftime('%s', p.creation), p.thread,
|
||||||
u.name, u.email, strftime('%s', u.lastOnline), u.status,
|
u.name, u.email, strftime('%s', u.lastOnline), u.status,
|
||||||
|
u.isDeleted,
|
||||||
t.name
|
t.name
|
||||||
from post p, person u, thread t
|
from post p, person u, thread t
|
||||||
where p.thread = t.id and p.author = u.id and p.id = ? and p.isDeleted = 0;
|
where p.thread = t.id and p.author = u.id and p.id = ? and p.isDeleted = 0;
|
||||||
|
|
@ -931,7 +938,7 @@ proc selectReplyingTo(replyingTo: string): Option[PostLink] =
|
||||||
topic: row[^1],
|
topic: row[^1],
|
||||||
threadId: row[2].parseInt(),
|
threadId: row[2].parseInt(),
|
||||||
postId: row[0].parseInt(),
|
postId: row[0].parseInt(),
|
||||||
author: some(selectUser(@[row[3], row[4], row[5], row[6]]))
|
author: some(selectUser(row[3..7]))
|
||||||
))
|
))
|
||||||
|
|
||||||
proc selectHistory(postId: int): seq[PostInfo] =
|
proc selectHistory(postId: int): seq[PostInfo] =
|
||||||
|
|
@ -950,7 +957,8 @@ proc selectHistory(postId: int): seq[PostInfo] =
|
||||||
|
|
||||||
proc selectLikes(postId: int): seq[User] =
|
proc selectLikes(postId: int): seq[User] =
|
||||||
const likeQuery = sql"""
|
const likeQuery = sql"""
|
||||||
select u.name, u.email, strftime('%s', u.lastOnline), u.status
|
select u.name, u.email, strftime('%s', u.lastOnline), u.status,
|
||||||
|
u.isDeleted
|
||||||
from like h, person u
|
from like h, person u
|
||||||
where h.post = ? and h.author = u.id
|
where h.post = ? and h.author = u.id
|
||||||
order by h.creation asc;
|
order by h.creation asc;
|
||||||
|
|
@ -963,7 +971,7 @@ proc selectLikes(postId: int): seq[User] =
|
||||||
proc selectThreadAuthor(threadId: int): User =
|
proc selectThreadAuthor(threadId: int): User =
|
||||||
const authorQuery =
|
const authorQuery =
|
||||||
sql"""
|
sql"""
|
||||||
select name, email, strftime('%s', lastOnline), status
|
select name, email, strftime('%s', lastOnline), status, isDeleted
|
||||||
from person where id in (
|
from person where id in (
|
||||||
select author from post
|
select author from post
|
||||||
where thread = ?
|
where thread = ?
|
||||||
|
|
@ -981,7 +989,8 @@ proc selectThread(threadRow: seq[string]): Thread =
|
||||||
order by creation asc limit 1;"""
|
order by creation asc limit 1;"""
|
||||||
const usersListQuery =
|
const usersListQuery =
|
||||||
sql"""
|
sql"""
|
||||||
select name, email, strftime('%s', lastOnline), status, count(*)
|
select name, email, strftime('%s', lastOnline), status, u.isDeleted,
|
||||||
|
count(*)
|
||||||
from person u, post p where p.author = u.id and p.thread = ?
|
from person u, post p where p.author = u.id and p.thread = ?
|
||||||
group by name order by count(*) desc limit 5;
|
group by name order by count(*) desc limit 5;
|
||||||
"""
|
"""
|
||||||
|
|
@ -1142,7 +1151,7 @@ proc executeLogin(c: TForumData, username, password: string): string =
|
||||||
const query =
|
const query =
|
||||||
sql"""
|
sql"""
|
||||||
select id, name, password, email, salt
|
select id, name, password, email, salt
|
||||||
from person where name = ? or email = ?
|
from person where (name = ? or email = ?) and isDeleted = 0
|
||||||
"""
|
"""
|
||||||
if username.len == 0:
|
if username.len == 0:
|
||||||
raise newForumError("Username cannot be empty", @["username"])
|
raise newForumError("Username cannot be empty", @["username"])
|
||||||
|
|
@ -1280,6 +1289,8 @@ proc executeDeleteUser(c: TForumData, username: string) =
|
||||||
# Set the `isDeleted` flag.
|
# Set the `isDeleted` flag.
|
||||||
exec(db, sql"update person set isDeleted = 1 where name = ?;", username)
|
exec(db, sql"update person set isDeleted = 1 where name = ?;", username)
|
||||||
|
|
||||||
|
logout(c)
|
||||||
|
|
||||||
proc updateProfile(
|
proc updateProfile(
|
||||||
c: TForumData, username, email: string, rank: Rank
|
c: TForumData, username, email: string, rank: Rank
|
||||||
) {.async.} =
|
) {.async.} =
|
||||||
|
|
@ -1367,7 +1378,8 @@ routes:
|
||||||
sql(
|
sql(
|
||||||
"""select p.id, p.content, strftime('%s', p.creation), p.author,
|
"""select p.id, p.content, strftime('%s', p.creation), p.author,
|
||||||
p.replyingTo,
|
p.replyingTo,
|
||||||
u.name, u.email, strftime('%s', u.lastOnline), u.status
|
u.name, u.email, strftime('%s', u.lastOnline), u.status,
|
||||||
|
u.isDeleted
|
||||||
from post p, person u
|
from post p, person u
|
||||||
where u.id = p.author and p.thread = ? and p.isDeleted = 0
|
where u.id = p.author and p.thread = ? and p.isDeleted = 0
|
||||||
order by p.id"""
|
order by p.id"""
|
||||||
|
|
@ -1410,7 +1422,8 @@ routes:
|
||||||
let postsQuery = sql("""
|
let postsQuery = sql("""
|
||||||
select p.id, p.content, strftime('%s', p.creation), p.author,
|
select p.id, p.content, strftime('%s', p.creation), p.author,
|
||||||
p.replyingTo,
|
p.replyingTo,
|
||||||
u.name, u.email, strftime('%s', u.lastOnline), u.status
|
u.name, u.email, strftime('%s', u.lastOnline), u.status,
|
||||||
|
u.isDeleted
|
||||||
from post p, person u
|
from post p, person u
|
||||||
where u.id = p.author and p.id in ($#)
|
where u.id = p.author and p.id in ($#)
|
||||||
order by p.id;
|
order by p.id;
|
||||||
|
|
@ -1477,10 +1490,10 @@ routes:
|
||||||
""" % postsFrom)
|
""" % postsFrom)
|
||||||
|
|
||||||
let userQuery = sql("""
|
let userQuery = sql("""
|
||||||
select name, email, strftime('%s', lastOnline), status,
|
select name, email, strftime('%s', lastOnline), status, isDeleted,
|
||||||
strftime('%s', creation), id
|
strftime('%s', creation), id
|
||||||
from person
|
from person
|
||||||
where name = ?
|
where name = ? and isDeleted = 0
|
||||||
""")
|
""")
|
||||||
|
|
||||||
var profile = Profile(
|
var profile = Profile(
|
||||||
|
|
@ -1491,8 +1504,11 @@ routes:
|
||||||
let userRow = db.getRow(userQuery, username)
|
let userRow = db.getRow(userQuery, username)
|
||||||
|
|
||||||
let userID = userRow[^1]
|
let userID = userRow[^1]
|
||||||
|
if userID.len == 0:
|
||||||
|
halt()
|
||||||
|
|
||||||
profile.user = selectUser(userRow, avatarSize=200)
|
profile.user = selectUser(userRow, avatarSize=200)
|
||||||
profile.joinTime = userRow[4].parseInt()
|
profile.joinTime = userRow[^2].parseInt()
|
||||||
profile.postCount =
|
profile.postCount =
|
||||||
getValue(db, sql("select count(*) " & postsFrom), username).parseInt()
|
getValue(db, sql("select count(*) " & postsFrom), username).parseInt()
|
||||||
profile.threadCount =
|
profile.threadCount =
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,7 @@ when defined(js):
|
||||||
|
|
||||||
proc render*(state: EditBox, post: Post): VNode =
|
proc render*(state: EditBox, post: Post): VNode =
|
||||||
if state.status != Http200:
|
if state.status != Http200:
|
||||||
return renderError("Couldn't retrieve raw post")
|
return renderError("Couldn't retrieve raw post", state.status)
|
||||||
|
|
||||||
if state.rawContent.isNone() or state.post.id != post.id:
|
if state.rawContent.isNone() or state.post.id != post.id:
|
||||||
state.post = post
|
state.post = post
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import options
|
import options, httpcore
|
||||||
type
|
type
|
||||||
PostError* = object
|
PostError* = object
|
||||||
errorFields*: seq[string] ## IDs of the fields with an error.
|
errorFields*: seq[string] ## IDs of the fields with an error.
|
||||||
|
|
@ -11,7 +11,25 @@ when defined(js):
|
||||||
|
|
||||||
import karaxutils
|
import karaxutils
|
||||||
|
|
||||||
proc renderError*(message: string): VNode =
|
proc render404*(): VNode =
|
||||||
|
result = buildHtml():
|
||||||
|
tdiv(class="empty error"):
|
||||||
|
tdiv(class="empty icon"):
|
||||||
|
italic(class="fas fa-bug fa-5x")
|
||||||
|
p(class="empty-title h5"):
|
||||||
|
text "404 Not Found"
|
||||||
|
p(class="empty-subtitle"):
|
||||||
|
text "Cannot find what you are looking for, it might have been " &
|
||||||
|
"deleted. Sorry!"
|
||||||
|
tdiv(class="empty-action"):
|
||||||
|
a(href="/", onClick=anchorCB):
|
||||||
|
button(class="btn btn-primary"):
|
||||||
|
text "Go back home"
|
||||||
|
|
||||||
|
proc renderError*(message: string, status: HttpCode): VNode =
|
||||||
|
if status == Http404:
|
||||||
|
return render404()
|
||||||
|
|
||||||
result = buildHtml():
|
result = buildHtml():
|
||||||
tdiv(class="empty error"):
|
tdiv(class="empty error"):
|
||||||
tdiv(class="empty icon"):
|
tdiv(class="empty icon"):
|
||||||
|
|
@ -62,18 +80,3 @@ when defined(js):
|
||||||
errorFields: @[],
|
errorFields: @[],
|
||||||
message: "Unknown error occurred."
|
message: "Unknown error occurred."
|
||||||
))
|
))
|
||||||
|
|
||||||
proc render404*(): VNode =
|
|
||||||
result = buildHtml():
|
|
||||||
tdiv(class="empty error"):
|
|
||||||
tdiv(class="empty icon"):
|
|
||||||
italic(class="fas fa-bug fa-5x")
|
|
||||||
p(class="empty-title h5"):
|
|
||||||
text "404 Not Found"
|
|
||||||
p(class="empty-subtitle"):
|
|
||||||
text "Cannot find what you are looking for, it might have been " &
|
|
||||||
"deleted. Sorry!"
|
|
||||||
tdiv(class="empty-action"):
|
|
||||||
a(href="/", onClick=anchorCB):
|
|
||||||
button(class="btn btn-primary"):
|
|
||||||
text "Go back home"
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import strformat, times, options, json, tables, sugar
|
import strformat, times, options, json, tables, sugar, httpcore
|
||||||
from dom import window, Location
|
from dom import window, Location
|
||||||
|
|
||||||
include karax/prelude
|
include karax/prelude
|
||||||
|
|
@ -46,7 +46,7 @@ proc route(routes: openarray[Route]): VNode =
|
||||||
if matched:
|
if matched:
|
||||||
return route.p(params)
|
return route.p(params)
|
||||||
|
|
||||||
return renderError("Unmatched route: " & path)
|
return renderError("Unmatched route: " & path, Http500)
|
||||||
|
|
||||||
proc render(): VNode =
|
proc render(): VNode =
|
||||||
result = buildHtml(tdiv()):
|
result = buildHtml(tdiv()):
|
||||||
|
|
|
||||||
|
|
@ -308,7 +308,7 @@ when defined(js):
|
||||||
proc renderPostList*(threadId: int, postId: Option[int],
|
proc renderPostList*(threadId: int, postId: Option[int],
|
||||||
currentUser: Option[User]): VNode =
|
currentUser: Option[User]): VNode =
|
||||||
if state.status != Http200:
|
if state.status != Http200:
|
||||||
return renderError("Couldn't retrieve posts.")
|
return renderError("Couldn't retrieve posts.", state.status)
|
||||||
|
|
||||||
if state.list.isNone or state.list.get().thread.id != threadId:
|
if state.list.isNone or state.list.get().thread.id != threadId:
|
||||||
var params = @[("id", $threadId)]
|
var params = @[("id", $threadId)]
|
||||||
|
|
|
||||||
|
|
@ -58,7 +58,7 @@ when defined(js):
|
||||||
currentUser: Option[User]
|
currentUser: Option[User]
|
||||||
): VNode =
|
): VNode =
|
||||||
if state.status != Http200:
|
if state.status != Http200:
|
||||||
return renderError("Couldn't retrieve profile.")
|
return renderError("Couldn't retrieve profile.", state.status)
|
||||||
|
|
||||||
if state.profile.isNone or state.profile.get().user.name != username:
|
if state.profile.isNone or state.profile.get().user.name != username:
|
||||||
let uri = makeUri("profile.json", ("username", username))
|
let uri = makeUri("profile.json", ("username", username))
|
||||||
|
|
|
||||||
|
|
@ -161,7 +161,7 @@ when defined(js):
|
||||||
|
|
||||||
proc genThreadList(currentUser: Option[User]): VNode =
|
proc genThreadList(currentUser: Option[User]): VNode =
|
||||||
if state.status != Http200:
|
if state.status != Http200:
|
||||||
return renderError("Couldn't retrieve threads.")
|
return renderError("Couldn't retrieve threads.", state.status)
|
||||||
|
|
||||||
if state.list.isNone:
|
if state.list.isNone:
|
||||||
if not state.loading:
|
if not state.loading:
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ type
|
||||||
avatarUrl*: string
|
avatarUrl*: string
|
||||||
lastOnline*: int64
|
lastOnline*: int64
|
||||||
rank*: Rank
|
rank*: Rank
|
||||||
|
isDeleted*: bool
|
||||||
|
|
||||||
proc isOnline*(user: User): bool =
|
proc isOnline*(user: User): bool =
|
||||||
return getTime().toUnix() - user.lastOnline < (60*5)
|
return getTime().toUnix() - user.lastOnline < (60*5)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue