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? ]#
|
||||
|
||||
proc selectUser(userRow: seq[string], avatarSize: int=80): User =
|
||||
return User(
|
||||
result = User(
|
||||
name: userRow[0],
|
||||
avatarUrl: userRow[1].getGravatarUrl(avatarSize),
|
||||
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],
|
||||
replyingTo: Option[PostLink], history: seq[PostInfo],
|
||||
likes: seq[User]): Post =
|
||||
return Post(
|
||||
id: postRow[0].parseInt,
|
||||
replyingTo: replyingTo,
|
||||
author: selectUser(@[postRow[5], postRow[6], postRow[7], postRow[8]]),
|
||||
author: selectUser(postRow[5..9]),
|
||||
likes: likes,
|
||||
seen: false, # TODO:
|
||||
history: history,
|
||||
|
|
@ -918,6 +924,7 @@ proc selectReplyingTo(replyingTo: string): Option[PostLink] =
|
|||
const replyingToQuery = sql"""
|
||||
select p.id, strftime('%s', p.creation), p.thread,
|
||||
u.name, u.email, strftime('%s', u.lastOnline), u.status,
|
||||
u.isDeleted,
|
||||
t.name
|
||||
from post p, person u, thread t
|
||||
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],
|
||||
threadId: row[2].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] =
|
||||
|
|
@ -950,7 +957,8 @@ proc selectHistory(postId: int): seq[PostInfo] =
|
|||
|
||||
proc selectLikes(postId: int): seq[User] =
|
||||
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
|
||||
where h.post = ? and h.author = u.id
|
||||
order by h.creation asc;
|
||||
|
|
@ -963,7 +971,7 @@ proc selectLikes(postId: int): seq[User] =
|
|||
proc selectThreadAuthor(threadId: int): User =
|
||||
const authorQuery =
|
||||
sql"""
|
||||
select name, email, strftime('%s', lastOnline), status
|
||||
select name, email, strftime('%s', lastOnline), status, isDeleted
|
||||
from person where id in (
|
||||
select author from post
|
||||
where thread = ?
|
||||
|
|
@ -981,7 +989,8 @@ proc selectThread(threadRow: seq[string]): Thread =
|
|||
order by creation asc limit 1;"""
|
||||
const usersListQuery =
|
||||
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 = ?
|
||||
group by name order by count(*) desc limit 5;
|
||||
"""
|
||||
|
|
@ -1142,7 +1151,7 @@ proc executeLogin(c: TForumData, username, password: string): string =
|
|||
const query =
|
||||
sql"""
|
||||
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:
|
||||
raise newForumError("Username cannot be empty", @["username"])
|
||||
|
|
@ -1280,6 +1289,8 @@ proc executeDeleteUser(c: TForumData, username: string) =
|
|||
# Set the `isDeleted` flag.
|
||||
exec(db, sql"update person set isDeleted = 1 where name = ?;", username)
|
||||
|
||||
logout(c)
|
||||
|
||||
proc updateProfile(
|
||||
c: TForumData, username, email: string, rank: Rank
|
||||
) {.async.} =
|
||||
|
|
@ -1367,7 +1378,8 @@ routes:
|
|||
sql(
|
||||
"""select p.id, p.content, strftime('%s', p.creation), p.author,
|
||||
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
|
||||
where u.id = p.author and p.thread = ? and p.isDeleted = 0
|
||||
order by p.id"""
|
||||
|
|
@ -1410,7 +1422,8 @@ routes:
|
|||
let postsQuery = sql("""
|
||||
select p.id, p.content, strftime('%s', p.creation), p.author,
|
||||
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
|
||||
where u.id = p.author and p.id in ($#)
|
||||
order by p.id;
|
||||
|
|
@ -1477,10 +1490,10 @@ routes:
|
|||
""" % postsFrom)
|
||||
|
||||
let userQuery = sql("""
|
||||
select name, email, strftime('%s', lastOnline), status,
|
||||
select name, email, strftime('%s', lastOnline), status, isDeleted,
|
||||
strftime('%s', creation), id
|
||||
from person
|
||||
where name = ?
|
||||
where name = ? and isDeleted = 0
|
||||
""")
|
||||
|
||||
var profile = Profile(
|
||||
|
|
@ -1491,8 +1504,11 @@ routes:
|
|||
let userRow = db.getRow(userQuery, username)
|
||||
|
||||
let userID = userRow[^1]
|
||||
if userID.len == 0:
|
||||
halt()
|
||||
|
||||
profile.user = selectUser(userRow, avatarSize=200)
|
||||
profile.joinTime = userRow[4].parseInt()
|
||||
profile.joinTime = userRow[^2].parseInt()
|
||||
profile.postCount =
|
||||
getValue(db, sql("select count(*) " & postsFrom), username).parseInt()
|
||||
profile.threadCount =
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ when defined(js):
|
|||
|
||||
proc render*(state: EditBox, post: Post): VNode =
|
||||
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:
|
||||
state.post = post
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import options
|
||||
import options, httpcore
|
||||
type
|
||||
PostError* = object
|
||||
errorFields*: seq[string] ## IDs of the fields with an error.
|
||||
|
|
@ -11,7 +11,25 @@ when defined(js):
|
|||
|
||||
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():
|
||||
tdiv(class="empty error"):
|
||||
tdiv(class="empty icon"):
|
||||
|
|
@ -61,19 +79,4 @@ when defined(js):
|
|||
state.error = some(PostError(
|
||||
errorFields: @[],
|
||||
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
|
||||
|
||||
include karax/prelude
|
||||
|
|
@ -46,7 +46,7 @@ proc route(routes: openarray[Route]): VNode =
|
|||
if matched:
|
||||
return route.p(params)
|
||||
|
||||
return renderError("Unmatched route: " & path)
|
||||
return renderError("Unmatched route: " & path, Http500)
|
||||
|
||||
proc render(): VNode =
|
||||
result = buildHtml(tdiv()):
|
||||
|
|
|
|||
|
|
@ -308,7 +308,7 @@ when defined(js):
|
|||
proc renderPostList*(threadId: int, postId: Option[int],
|
||||
currentUser: Option[User]): VNode =
|
||||
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:
|
||||
var params = @[("id", $threadId)]
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ when defined(js):
|
|||
currentUser: Option[User]
|
||||
): VNode =
|
||||
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:
|
||||
let uri = makeUri("profile.json", ("username", username))
|
||||
|
|
|
|||
|
|
@ -161,7 +161,7 @@ when defined(js):
|
|||
|
||||
proc genThreadList(currentUser: Option[User]): VNode =
|
||||
if state.status != Http200:
|
||||
return renderError("Couldn't retrieve threads.")
|
||||
return renderError("Couldn't retrieve threads.", state.status)
|
||||
|
||||
if state.list.isNone:
|
||||
if not state.loading:
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ type
|
|||
avatarUrl*: string
|
||||
lastOnline*: int64
|
||||
rank*: Rank
|
||||
isDeleted*: bool
|
||||
|
||||
proc isOnline*(user: User): bool =
|
||||
return getTime().toUnix() - user.lastOnline < (60*5)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue