Add email sending functionality and configuration
This commit is contained in:
parent
3a76c924ca
commit
067d7ffb7a
@ -3,6 +3,26 @@ import Foundation
|
||||
struct Configuration {
|
||||
|
||||
let serverPort: Int
|
||||
|
||||
let mail: EMail
|
||||
|
||||
struct EMail {
|
||||
|
||||
/// The url to the root of the server
|
||||
let serverDomain: String
|
||||
|
||||
/// SMTP server address
|
||||
let emailHostname: String
|
||||
|
||||
/// username to login
|
||||
let email: String
|
||||
|
||||
/// password to login
|
||||
let password: String
|
||||
|
||||
/// The number of minutes until a password reset token is no longer valid
|
||||
let tokenExpiryDuration: Int
|
||||
}
|
||||
}
|
||||
|
||||
extension Configuration {
|
||||
@ -27,6 +47,11 @@ extension Configuration {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension Configuration.EMail: Codable {
|
||||
|
||||
}
|
||||
|
||||
extension Configuration: Codable {
|
||||
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
import Foundation
|
||||
import Fluent
|
||||
import Vapor
|
||||
import SwiftSMTP
|
||||
|
||||
typealias PasswordHash = String
|
||||
typealias SessionToken = String
|
||||
@ -15,8 +16,20 @@ final class SQLiteDatabase {
|
||||
|
||||
private let tables: TableManagement
|
||||
|
||||
init(db: Database) throws {
|
||||
private let mailConfiguration: Configuration.EMail
|
||||
|
||||
private let smtp: SMTP
|
||||
|
||||
private let mailSender: Mail.User
|
||||
|
||||
init(db: Database, mail: Configuration.EMail) throws {
|
||||
self.tables = try TableManagement(db: db)
|
||||
self.smtp = SMTP(
|
||||
hostname: mail.emailHostname,
|
||||
email: mail.email,
|
||||
password: mail.password)
|
||||
self.mailSender = Mail.User(name: "Schafkopf Server", email: mail.email)
|
||||
self.mailConfiguration = mail
|
||||
}
|
||||
|
||||
func registerPlayer(named name: PlayerName, hash: PasswordHash, in database: Database) -> EventLoopFuture<SessionToken> {
|
||||
@ -33,6 +46,37 @@ final class SQLiteDatabase {
|
||||
}
|
||||
}
|
||||
|
||||
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 mail = Mail(
|
||||
from: mailSender,
|
||||
to: [recipient],
|
||||
subject: "Schafkopf Server Password Reset",
|
||||
text:
|
||||
"""
|
||||
Hello \(name),
|
||||
|
||||
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>
|
||||
|
||||
The link will expire in \(mailConfiguration.tokenExpiryDuration) minutes. If you didn't request the password reset, you don't have to do anything.
|
||||
|
||||
Regards,
|
||||
|
||||
The Schafkopf Server Team
|
||||
"""
|
||||
)
|
||||
|
||||
self.smtp.send(mail) { (error) in
|
||||
if let error = error {
|
||||
print("Failed to send recovery email to \(email): \(error)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func passwordHashForExistingPlayer(named name: PlayerName, in database: Database) -> EventLoopFuture<PasswordHash> {
|
||||
User.query(on: database).filter(\.$name == name).first()
|
||||
.unwrap(or: Abort(.forbidden)).map { $0.passwordHash }
|
||||
|
@ -36,7 +36,7 @@ public func configure(_ app: Application) throws {
|
||||
app.middleware.use(FileMiddleware(publicDirectory: app.directory.publicDirectory))
|
||||
|
||||
let db = app.databases.database(.sqlite, logger: .init(label: "Init"), on: app.databases.eventLoopGroup.next())!
|
||||
server = try SQLiteDatabase(db: db)
|
||||
server = try SQLiteDatabase(db: db, mail: configuration.mail)
|
||||
|
||||
// Gracefully shut down by closing potentially open socket
|
||||
DispatchQueue.global(qos: .utility).asyncAfter(deadline: .now() + .seconds(5)) {
|
||||
|
Loading…
Reference in New Issue
Block a user