Implement user bans and deactivations. Fix registration issues.
This commit is contained in:
parent
72f8126d01
commit
57ee631735
2 changed files with 128 additions and 4 deletions
|
|
@ -42,6 +42,11 @@ create table if not exists person(
|
||||||
);""" % [TUserName, TPassword, TEmail]), [])
|
);""" % [TUserName, TPassword, TEmail]), [])
|
||||||
# echo "person table already exists"
|
# echo "person table already exists"
|
||||||
|
|
||||||
|
db.exec(sql("""
|
||||||
|
alter table person
|
||||||
|
add ban varchar(128) not null default ''
|
||||||
|
"""))
|
||||||
|
|
||||||
db.exec(sql"""
|
db.exec(sql"""
|
||||||
create unique index if not exists UserNameIx on person (name);
|
create unique index if not exists UserNameIx on person (name);
|
||||||
""", [])
|
""", [])
|
||||||
|
|
|
||||||
127
forum.nim
127
forum.nim
|
|
@ -24,6 +24,7 @@ const
|
||||||
MaxPagesFromCurrent = 8
|
MaxPagesFromCurrent = 8
|
||||||
noPageNums = ["/login", "/register", "/dologin", "/doregister", "/profile"]
|
noPageNums = ["/login", "/register", "/dologin", "/doregister", "/profile"]
|
||||||
noHomeBtn = ["/", "/login", "/register", "/dologin", "/doregister", "/profile"]
|
noHomeBtn = ["/", "/login", "/register", "/dologin", "/doregister", "/profile"]
|
||||||
|
banReasonDeactivated = "DEACTIVATED"
|
||||||
|
|
||||||
type
|
type
|
||||||
TCrud = enum crCreate, crRead, crUpdate, crDelete
|
TCrud = enum crCreate, crRead, crUpdate, crDelete
|
||||||
|
|
@ -65,6 +66,7 @@ type
|
||||||
threads: int
|
threads: int
|
||||||
lastOnline: int
|
lastOnline: int
|
||||||
email: string
|
email: string
|
||||||
|
ban: string
|
||||||
|
|
||||||
var
|
var
|
||||||
db: TDbConn
|
db: TDbConn
|
||||||
|
|
@ -223,11 +225,19 @@ proc devRandomSalt(): string =
|
||||||
|
|
||||||
proc makeSalt(): string =
|
proc makeSalt(): string =
|
||||||
## Creates a salt using a cryptographically secure random number generator.
|
## Creates a salt using a cryptographically secure random number generator.
|
||||||
|
##
|
||||||
|
## Ensures that the resulting salt contains no ``\0``.
|
||||||
try:
|
try:
|
||||||
result = devRandomSalt()
|
result = devRandomSalt()
|
||||||
except IOError:
|
except IOError:
|
||||||
result = randomSalt()
|
result = randomSalt()
|
||||||
|
|
||||||
|
var newResult = ""
|
||||||
|
for i in 0 .. <result.len:
|
||||||
|
if result[i] != '\0':
|
||||||
|
newResult.add result[i]
|
||||||
|
return newResult
|
||||||
|
|
||||||
proc makePassword(password, salt: string, comparingTo = ""): string =
|
proc makePassword(password, salt: string, comparingTo = ""): string =
|
||||||
## Creates an MD5 hash by combining password and salt.
|
## Creates an MD5 hash by combining password and salt.
|
||||||
when defined(windows):
|
when defined(windows):
|
||||||
|
|
@ -287,8 +297,9 @@ 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, lastOnline) " &
|
exec(db,
|
||||||
"VALUES (?, ?, ?, ?, 'user', DATETIME('now'))"), name,
|
sql("INSERT INTO person(name, password, email, salt, status, lastOnline, " &
|
||||||
|
"ban) 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
|
||||||
|
|
@ -480,12 +491,18 @@ proc newThread(c: var TForumData): bool =
|
||||||
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 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.")
|
||||||
var success = false
|
var success = false
|
||||||
for row in fastRows(db, query, name):
|
for row in fastRows(db, query, name):
|
||||||
if row[2] == makePassword(pass, row[4], row[2]):
|
if row[2] == makePassword(pass, row[4], row[2]):
|
||||||
|
case row[6]
|
||||||
|
of "": discard
|
||||||
|
of banReasonDeactivated:
|
||||||
|
return c.setError("name", "Your account has been deactivated.")
|
||||||
|
else:
|
||||||
|
return c.setError("name", "You have been banned: " & row[6])
|
||||||
c.userid = row[0]
|
c.userid = row[0]
|
||||||
c.username = row[1]
|
c.username = row[1]
|
||||||
c.userpass = row[2]
|
c.userpass = row[2]
|
||||||
|
|
@ -495,13 +512,18 @@ proc login(c: var TForumData, name, pass: string): bool =
|
||||||
break
|
break
|
||||||
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:
|
||||||
return c.setError("password", "Login failed!")
|
return c.setError("password", "Login failed!")
|
||||||
|
|
||||||
|
proc setBan(c: var TForumData, nick, reason: string): bool =
|
||||||
|
const query =
|
||||||
|
sql("update person set ban = ? where name = ?")
|
||||||
|
return tryExec(db, query, reason, 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"
|
||||||
|
|
@ -687,6 +709,10 @@ proc gatherUserInfo(c: var TForumData, nick: string, ui: var TUserInfo): bool =
|
||||||
let lastOnlineDBVal = getValue(db, lastOnlineQuery, uid)
|
let lastOnlineDBVal = getValue(db, lastOnlineQuery, uid)
|
||||||
ui.lastOnline = if lastOnlineDBVal != "": lastOnlineDBVal.parseInt else: -1
|
ui.lastOnline = if lastOnlineDBVal != "": lastOnlineDBVal.parseInt else: -1
|
||||||
ui.email = getValue(db, sql"select email from person where id = ?", uid)
|
ui.email = getValue(db, sql"select email from person where id = ?", uid)
|
||||||
|
ui.ban = getValue(db, sql"select ban from person where id = ?", uid)
|
||||||
|
|
||||||
|
proc genSetUserStatusUrl(c: var TForumData, nick: string, typ: string): string =
|
||||||
|
c.req.makeUri("/setUserStatus?nick=$1&type=$2" % [nick, typ])
|
||||||
|
|
||||||
proc genProfile(c: var TForumData, ui: TUserInfo): string =
|
proc genProfile(c: var TForumData, ui: TUserInfo): string =
|
||||||
result = ""
|
result = ""
|
||||||
|
|
@ -724,6 +750,41 @@ proc genProfile(c: var TForumData, ui: TUserInfo): string =
|
||||||
th("Last Online"),
|
th("Last Online"),
|
||||||
td(if ui.lastOnline != -1: t2.format("dd/MM/yy HH':'mm 'UTC'")
|
td(if ui.lastOnline != -1: t2.format("dd/MM/yy HH':'mm 'UTC'")
|
||||||
else: "Never")
|
else: "Never")
|
||||||
|
),
|
||||||
|
tr(
|
||||||
|
th("Status"),
|
||||||
|
td(case ui.ban
|
||||||
|
of banReasonDeactivated:
|
||||||
|
"Deactivated"
|
||||||
|
of "":
|
||||||
|
"Active"
|
||||||
|
else:
|
||||||
|
"Banned: " & ui.ban
|
||||||
|
)
|
||||||
|
),
|
||||||
|
tr(
|
||||||
|
th(""),
|
||||||
|
td(if c.isAdmin and ui.ban != banReasonDeactivated:
|
||||||
|
if ui.ban == "":
|
||||||
|
htmlgen.a(
|
||||||
|
href=c.genSetUserStatusUrl(ui.nick, "ban"),
|
||||||
|
"Ban user")
|
||||||
|
else:
|
||||||
|
htmlgen.a(href=c.genSetUserStatusUrl(ui.nick, "unban"),
|
||||||
|
"Unban user")
|
||||||
|
else: "")
|
||||||
|
),
|
||||||
|
tr(
|
||||||
|
th(""),
|
||||||
|
td(if c.userName == ui.nick or c.isAdmin:
|
||||||
|
if ui.ban == "":
|
||||||
|
htmlgen.a(href=c.genSetUserStatusUrl(ui.nick, "deactivate"),
|
||||||
|
"Deactivate user")
|
||||||
|
elif ui.ban == banReasonDeactivated:
|
||||||
|
htmlgen.a(href=c.genSetUserStatusUrl(ui.nick, "activate"),
|
||||||
|
"Activate user")
|
||||||
|
else: ""
|
||||||
|
else: "")
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
))
|
))
|
||||||
|
|
@ -923,6 +984,64 @@ routes:
|
||||||
resp genMain(c, genFormPost(c, "donewthread", "New thread", "", "", false),
|
resp genMain(c, genFormPost(c, "donewthread", "New thread", "", "", false),
|
||||||
"New Thread - Nimrod Forum")
|
"New Thread - Nimrod Forum")
|
||||||
|
|
||||||
|
get "/setUserStatus/?":
|
||||||
|
createTFD()
|
||||||
|
cond (@"nick" != "")
|
||||||
|
cond (@"type" != "")
|
||||||
|
var formBody = "<input type=\"hidden\" name=\"nick\" value=\"" &
|
||||||
|
@"nick" & "\">"
|
||||||
|
var del = false
|
||||||
|
var content = ""
|
||||||
|
echo("Got type: ", @"type")
|
||||||
|
case @"type"
|
||||||
|
of "ban":
|
||||||
|
formBody.add "<input type='text' name='reason' />" &
|
||||||
|
"<input type='submit' name='banBtn' value='Ban' />"
|
||||||
|
content =
|
||||||
|
htmlgen.p("Please enter a reason for banning this user:")
|
||||||
|
of "unban":
|
||||||
|
formBody.add "<input type='submit' name='unbanBtn' value='Unban' />"
|
||||||
|
content =
|
||||||
|
htmlgen.p("Are you sure you wish to unban ", htmlgen.b(@"nick"),
|
||||||
|
"?")
|
||||||
|
del = true
|
||||||
|
of "deactivate":
|
||||||
|
formBody.add "<input type='hidden' name='reason' value='" &
|
||||||
|
banReasonDeactivated & "' />" &
|
||||||
|
"<input type='submit' name='actBtn' value='Deactivate' />"
|
||||||
|
content =
|
||||||
|
htmlgen.p("Are you sure you wish to deactivate ", htmlgen.b(@"nick"),
|
||||||
|
"?")
|
||||||
|
of "activate":
|
||||||
|
formBody.add "<input type='submit' name='actBtn' value='Activate' />"
|
||||||
|
content =
|
||||||
|
htmlgen.p("Are you sure you wish to activate ", htmlgen.b(@"nick"),
|
||||||
|
"?")
|
||||||
|
del = true
|
||||||
|
formBody.add "<input type='hidden' name='del' value='" & $del & "'/>"
|
||||||
|
content = htmlgen.form(action = c.req.makeUri("/dosetban"),
|
||||||
|
`method` = "POST", formBody) & content
|
||||||
|
resp genMain(c, content, "Set user status - Nim Forum")
|
||||||
|
|
||||||
|
post "/dosetban":
|
||||||
|
createTFD()
|
||||||
|
cond (@"nick" != "")
|
||||||
|
if not c.isAdmin and @"nick" != c.userName:
|
||||||
|
resp genMain(c, "You cannot ban this user.", "Error - Nim Forum")
|
||||||
|
if @"reason" == "" and @"del" != "true":
|
||||||
|
resp genMain(c, "Invalid ban reason.", "Error - Nim Forum")
|
||||||
|
let result =
|
||||||
|
if @"del" == "true":
|
||||||
|
# Remove the ban.
|
||||||
|
setBan(c, @"nick", "")
|
||||||
|
else:
|
||||||
|
setBan(c, @"nick", @"reason")
|
||||||
|
if result:
|
||||||
|
redirect(c.req.makeUri("/profile/" & @"nick"))
|
||||||
|
else:
|
||||||
|
resp genMain(c, "Failed to change the ban status of user.",
|
||||||
|
"Error - Nim Forum")
|
||||||
|
|
||||||
const licenseRst = slurp("static/license.rst")
|
const licenseRst = slurp("static/license.rst")
|
||||||
get "/license":
|
get "/license":
|
||||||
createTFD()
|
createTFD()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue