Allow moderators to edit profiles, but don't show them the emails.
This commit is contained in:
parent
93ae21cee6
commit
f8a9909278
4 changed files with 70 additions and 48 deletions
|
|
@ -126,8 +126,11 @@ proc resetPassword(
|
||||||
) {.async.} =
|
) {.async.} =
|
||||||
# Gather some extra information to determine ident hash.
|
# Gather some extra information to determine ident hash.
|
||||||
let row = db.getRow(
|
let row = db.getRow(
|
||||||
sql"select name, password, email, salt from person where email = ?",
|
sql"""
|
||||||
email
|
select name, password, email, salt from person
|
||||||
|
where email = ? or name = ?
|
||||||
|
""",
|
||||||
|
email, email
|
||||||
)
|
)
|
||||||
if row[0] == "":
|
if row[0] == "":
|
||||||
raise newForumError("Email not found", @["email"])
|
raise newForumError("Email not found", @["email"])
|
||||||
|
|
@ -559,18 +562,22 @@ proc executeLogin(c: TForumData, username, password: string): string =
|
||||||
|
|
||||||
raise newForumError("Invalid username or password")
|
raise newForumError("Invalid username or password")
|
||||||
|
|
||||||
|
proc validateEmail(email: string, checkDuplicated: bool) =
|
||||||
|
if not ('@' in email and '.' in email):
|
||||||
|
raise newForumError("Invalid email", @["email"])
|
||||||
|
if checkDuplicated:
|
||||||
|
if getValue(
|
||||||
|
db, sql"select email from person where email = ?", email
|
||||||
|
).len > 0:
|
||||||
|
raise newForumError("Email already exists", @["email"])
|
||||||
|
|
||||||
proc executeRegister(c: TForumData, name, pass, antibot, userIp,
|
proc executeRegister(c: TForumData, name, pass, antibot, userIp,
|
||||||
email: string): Future[string] {.async.} =
|
email: string): Future[string] {.async.} =
|
||||||
## Registers a new user and returns a new session key for that user's
|
## Registers a new user and returns a new session key for that user's
|
||||||
## session if registration was successful. Exceptions are raised otherwise.
|
## session if registration was successful. Exceptions are raised otherwise.
|
||||||
|
|
||||||
# email validation
|
# email validation
|
||||||
if not ('@' in email and '.' in email):
|
validateEmail(email, checkDuplicated=true)
|
||||||
raise newForumError("Invalid email", @["email"])
|
|
||||||
if getValue(
|
|
||||||
db, sql"select email from person where email = ?", email
|
|
||||||
).len > 0:
|
|
||||||
raise newForumError("Email already exists", @["email"])
|
|
||||||
|
|
||||||
# Username validation:
|
# Username validation:
|
||||||
if name.len == 0 or not allCharsInSet(name, UsernameIdent) or name.len > 20:
|
if name.len == 0 or not allCharsInSet(name, UsernameIdent) or name.len > 20:
|
||||||
|
|
@ -681,20 +688,31 @@ proc updateProfile(
|
||||||
if c.username != username and c.rank < Moderator:
|
if c.username != username and c.rank < Moderator:
|
||||||
raise newForumError("You can't change this profile.")
|
raise newForumError("You can't change this profile.")
|
||||||
|
|
||||||
# Make sure the rank is set to EmailUnconfirmed when the email changes.
|
# Check if we are only setting the rank.
|
||||||
if c.rank < Moderator:
|
if email.len == 0:
|
||||||
let row = getRow(
|
exec(
|
||||||
db,
|
db,
|
||||||
sql"select name, password, email, salt from person where name = ?",
|
sql"update person set status = ? where name = ?;",
|
||||||
username
|
$rank, username
|
||||||
)
|
)
|
||||||
if row[2] != email:
|
return
|
||||||
if rank != EmailUnconfirmed:
|
|
||||||
raise newForumError("Rank needs a change when setting new email.")
|
|
||||||
|
|
||||||
await sendSecureEmail(
|
# Make sure the rank is set to EmailUnconfirmed when the email changes.
|
||||||
mailer, ActivateEmail, c.req, row[0], row[1], row[2], row[3]
|
let row = getRow(
|
||||||
)
|
db,
|
||||||
|
sql"select name, password, email, salt from person where name = ?",
|
||||||
|
username
|
||||||
|
)
|
||||||
|
let wasEmailChanged = row[2] != email
|
||||||
|
if c.rank < Moderator and wasEmailChanged:
|
||||||
|
if rank != EmailUnconfirmed:
|
||||||
|
raise newForumError("Rank needs a change when setting new email.")
|
||||||
|
|
||||||
|
await sendSecureEmail(
|
||||||
|
mailer, ActivateEmail, c.req, row[0], row[1], row[2], row[3]
|
||||||
|
)
|
||||||
|
|
||||||
|
validateEmail(email, checkDuplicated=wasEmailChanged)
|
||||||
|
|
||||||
exec(
|
exec(
|
||||||
db,
|
db,
|
||||||
|
|
|
||||||
|
|
@ -27,9 +27,9 @@ when defined(js):
|
||||||
icon: icon
|
icon: icon
|
||||||
)
|
)
|
||||||
|
|
||||||
proc newResetPasswordButton*(email: string): PostButton =
|
proc newResetPasswordButton*(username: string): PostButton =
|
||||||
var formData = newFormData()
|
var formData = newFormData()
|
||||||
formData.append("email", email)
|
formData.append("email", username)
|
||||||
result = newPostButton(
|
result = newPostButton(
|
||||||
makeUri("/sendResetPassword"),
|
makeUri("/sendResetPassword"),
|
||||||
formData,
|
formData,
|
||||||
|
|
|
||||||
|
|
@ -35,8 +35,7 @@ when defined(js):
|
||||||
let profile = to(parsed, Profile)
|
let profile = to(parsed, Profile)
|
||||||
|
|
||||||
state.profile = some(profile)
|
state.profile = some(profile)
|
||||||
if profile.email.isSome():
|
state.settings = some(newProfileSettings(profile))
|
||||||
state.settings = some(newProfileSettings(profile))
|
|
||||||
|
|
||||||
proc genPostLink(link: PostLink): VNode =
|
proc genPostLink(link: PostLink): VNode =
|
||||||
let url = renderPostUrl(link)
|
let url = renderPostUrl(link)
|
||||||
|
|
@ -106,7 +105,7 @@ when defined(js):
|
||||||
|
|
||||||
if currentUser.isSome():
|
if currentUser.isSome():
|
||||||
let user = currentUser.get()
|
let user = currentUser.get()
|
||||||
if user.name == profile.user.name or user.rank == Admin:
|
if user.name == profile.user.name or user.rank >= Moderator:
|
||||||
ul(class="tab"):
|
ul(class="tab"):
|
||||||
li(class=class(
|
li(class=class(
|
||||||
{"active": state.currentTab == Overview},
|
{"active": state.currentTab == Overview},
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,9 @@ when defined(js):
|
||||||
let profile = state.profile
|
let profile = state.profile
|
||||||
if profile.email.isSome():
|
if profile.email.isSome():
|
||||||
state.email = profile.email.get()
|
state.email = profile.email.get()
|
||||||
state.rank = profile.user.rank
|
else:
|
||||||
|
state.email = ""
|
||||||
|
state.rank = profile.user.rank
|
||||||
|
|
||||||
state.error = none[PostError]()
|
state.error = none[PostError]()
|
||||||
|
|
||||||
|
|
@ -32,7 +34,7 @@ when defined(js):
|
||||||
result = ProfileSettings(
|
result = ProfileSettings(
|
||||||
status: Http200,
|
status: Http200,
|
||||||
deleteModal: newDeleteModal(nil, nil, onUserDelete),
|
deleteModal: newDeleteModal(nil, nil, onUserDelete),
|
||||||
resetPassword: newResetPasswordButton(profile.email.get()),
|
resetPassword: newResetPasswordButton(profile.user.name),
|
||||||
profile: profile
|
profile: profile
|
||||||
)
|
)
|
||||||
resetSettings(result)
|
resetSettings(result)
|
||||||
|
|
@ -70,23 +72,25 @@ when defined(js):
|
||||||
(s: int, r: kstring) => onProfilePost(s, r, state))
|
(s: int, r: kstring) => onProfilePost(s, r, state))
|
||||||
|
|
||||||
proc needsSave(state: ProfileSettings): bool =
|
proc needsSave(state: ProfileSettings): bool =
|
||||||
state.email != state.profile.email.get() or
|
if state.profile.email.isSome():
|
||||||
state.rank != state.profile.user.rank
|
result = state.email != state.profile.email.get()
|
||||||
|
result = result or state.rank != state.profile.user.rank
|
||||||
|
|
||||||
proc render*(state: ProfileSettings,
|
proc render*(state: ProfileSettings,
|
||||||
currentUser: Option[User]): VNode =
|
currentUser: Option[User]): VNode =
|
||||||
let isAdmin = currentUser.isSome() and currentUser.get().rank == Admin
|
let canEditRank = currentUser.isSome() and
|
||||||
|
currentUser.get().rank > state.profile.user.rank
|
||||||
let canResetPassword = state.profile.user.rank > EmailUnconfirmed
|
let canResetPassword = state.profile.user.rank > EmailUnconfirmed
|
||||||
|
|
||||||
let rankSelect = buildHtml(tdiv()):
|
let rankSelect = buildHtml(tdiv()):
|
||||||
if isAdmin:
|
if canEditRank:
|
||||||
select(id="rank-field",
|
select(id="rank-field",
|
||||||
class="form-select", value = $state.rank,
|
class="form-select", value = $state.rank,
|
||||||
onchange=(e: Event, n: VNode) => onRankChange(e, n, state)):
|
onchange=(e: Event, n: VNode) => onRankChange(e, n, state)):
|
||||||
for r in Rank:
|
for r in Rank:
|
||||||
option(text $r)
|
option(text $r)
|
||||||
p(class="form-input-hint text-warning"):
|
p(class="form-input-hint text-warning"):
|
||||||
text "As an admin you can modify anyone's rank. Remember: with " &
|
text "You can modify anyone's rank. Remember: with " &
|
||||||
"great power comes great responsibility."
|
"great power comes great responsibility."
|
||||||
else:
|
else:
|
||||||
input(id="rank-field", class="form-input",
|
input(id="rank-field", class="form-input",
|
||||||
|
|
@ -125,23 +129,24 @@ when defined(js):
|
||||||
p(class="form-input-hint"):
|
p(class="form-input-hint"):
|
||||||
text fmt("Users can refer to you by writing" &
|
text fmt("Users can refer to you by writing" &
|
||||||
" @{state.profile.user.name} in their posts.")
|
" @{state.profile.user.name} in their posts.")
|
||||||
tdiv(class="form-group"):
|
if state.profile.email.isSome():
|
||||||
tdiv(class="col-3 col-sm-12"):
|
tdiv(class="form-group"):
|
||||||
label(class="form-label"):
|
tdiv(class="col-3 col-sm-12"):
|
||||||
text "Email"
|
label(class="form-label"):
|
||||||
tdiv(class="col-9 col-sm-12"):
|
text "Email"
|
||||||
input(id="email-input", class="form-input",
|
tdiv(class="col-9 col-sm-12"):
|
||||||
`type`="text", value=state.email,
|
input(id="email-input", class="form-input",
|
||||||
oninput=(e: Event, n: VNode) =>
|
`type`="text", value=state.email,
|
||||||
onEmailChange(e, n, state)
|
oninput=(e: Event, n: VNode) =>
|
||||||
)
|
onEmailChange(e, n, state)
|
||||||
p(class="form-input-hint"):
|
)
|
||||||
text "Your avatar is linked to this email and can be " &
|
p(class="form-input-hint"):
|
||||||
"changed at "
|
text "Your avatar is linked to this email and can be " &
|
||||||
a(href="https://gravatar.com/emails"):
|
"changed at "
|
||||||
text "gravatar.com"
|
a(href="https://gravatar.com/emails"):
|
||||||
text ". Note that any changes to your email will " &
|
text "gravatar.com"
|
||||||
"require email verification."
|
text ". Note that any changes to your email will " &
|
||||||
|
"require email verification."
|
||||||
tdiv(class="form-group"):
|
tdiv(class="form-group"):
|
||||||
tdiv(class="col-3 col-sm-12"):
|
tdiv(class="col-3 col-sm-12"):
|
||||||
label(class="form-label"):
|
label(class="form-label"):
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue