Add route to send recovery email

This commit is contained in:
Christoph Hagen 2022-10-12 19:30:11 +02:00
parent 26adcc2868
commit 4e9675c284
2 changed files with 46 additions and 3 deletions

View File

@ -54,11 +54,35 @@ final class SQLiteDatabase {
self.playerNameForToken[token] = name
return token
}
/**
Send a password reset email.
Possible errors:
- `404`: Player name or email not found.
*/
func sendPasswordResetEmailIfPossible(name: PlayerName, in database: Database) async throws {
guard let user = try await User.query(on: database).filter(\.$name == name).first() else {
throw Abort(.notFound)
}
guard let email = user.recoveryEmail else {
throw Abort(.notFound)
}
try await user.$resetRequest.load(on: database)
if let request = user.resetRequest {
request.renew()
try await request.save(on: database)
self.sendEmail(name: name, email: email, token: request.resetToken)
} else {
let reset = PasswordReset()
try await user.$resetRequest.create(reset, on: database)
self.sendEmail(name: name, email: email, token: reset.resetToken)
}
}
private func sendEmail(name: PlayerName, email: String, token: String) {
let recipient = Mail.User(name: name, email: email)
let url = "\(mailConfiguration.serverDomain)/player/reset?token=\(token)"
let url = "\(mailConfiguration.serverDomain)/recovery.html?token=\(token)"
let mail = Mail(
from: mailSender,
to: [recipient],
@ -70,7 +94,7 @@ final class SQLiteDatabase {
a reset of your account password has been requested for the Schafkopf Server at \(mailConfiguration.serverDomain).
To choose a new password, click the following link:
<a href="\(url)">\(url)</a>
\(url)
The link will expire in \(mailConfiguration.tokenExpiryDuration) minutes. If you didn't request the password reset, you don't have to do anything.
@ -80,7 +104,7 @@ final class SQLiteDatabase {
"""
)
self.smtp.send(mail) { (error) in
smtp.send(mail) { (error) in
if let error = error {
print("Failed to send recovery email to \(email): \(error)")
}

View File

@ -64,6 +64,25 @@ func registerPlayer(_ app: Application) {
return try await server.registerPlayer(named: name, hash: hash, email: mail, in: request.db)
}
}
/**
Request an email to reset the password of a player.
Headers:
- `name`: The player name
Possible responses:
- `200`: Success, email will be sent
- `400`: Missing name header
- `404`: Player name not found or no email registered
*/
func requestPlayerPasswordReset(_ app: Application) {
app.post("player", "password", "reset") { request async throws -> HTTPResponseStatus in
let name = try request.header(.name) // Error: 400
try await server.sendPasswordResetEmailIfPossible(name: name, in: request.db)
return .ok
}
}
/**
Delete a player.