First of all, thank you for all your effort. I am using a mysql server on my private nas for testing. The password is stored as a hash in the database. Here the code for the user modell and user controller. Should be the same as in the book or similar.
Here first the code for the user model:
// model code`
import Vapor
import FluentMySQL
import Authentication
final class User: Codable {
var id : Int?
var name: String
var username: String
var password: String
init(name: String, username: String, password: String){
self.name = name
self.username = username
self.password = password
}
final class Public: Codable {
var id: Int?
var name: String
var username: String
init(id: Int?, name: String, username: String){
self.id = id
self.name = name
self.username = username
}
}
}
extension User: MySQLModel{}
extension User: Parameter{}
extension User.Public: Content{}
extension User: Migration{}
extension User: Content{}
extension User {
var acronyms: Children<User, Acronym>{
return children(.userID)
}
func convertToPublic() → User.Public {
return User.Public(id: id, name: name, username: username)
}
}
extension Future where T: User {
func convertToPublic()->Future<User.Public> {
return self.map(to: User.Public.self) { user in
return user.convertToPublic()
}
}
}
extension User: BasicAuthenticatable {
static let usernameKey: UsernameKey = \User.username
static let passwordKey: PasswordKey = \User.password
}
Here the code for the controller:
import Vapor
import Crypto
struct UsersController: RouteCollection {
func boot(router: Router) throws {
let usersRoute = router.grouped(“api”,“users”)
//usersRoute.post(User.self, use: createHandler)
usersRoute.get(use:getAllHandler)
usersRoute.get(User.parameter, use: getHandler)
usersRoute.delete(User.parameter, use:deleteHandler)
usersRoute.get(User.parameter, "acronyms", use: getAcronymsHandler)
usersRoute.post(User.self, use: createHandler)
usersRoute.put(User.parameter, use: updateHandler)
let basicAuthMiddleware = User.basicAuthMiddleware(using: BCryptDigest())
let basicAuthGroup = usersRoute.grouped(basicAuthMiddleware)
basicAuthGroup.post("login", use: loginHandler)
}
func createHandler(_ req: Request, user: User) throws -> Future<User.Public> {
user.password = try BCrypt.hash(user.password)
return user.save(on: req).convertToPublic()
}
func getAllHandler(_ req: Request) throws -> Future<[User.Public]>{
return User.query(on: req).decode(data:User.Public.self).all()
}
func getHandler (_ req: Request) throws -> Future<User.Public> {
return try req.parameters.next(User.self).convertToPublic()
}
func deleteHandler (_ req: Request) throws -> Future<HTTPStatus> {
return try req
.parameters
.next(User.self)
.delete(on: req)
.transform(to: HTTPStatus.noContent)
}
func getAcronymsHandler(_ req: Request) throws -> Future <[Acronym]> {
return try req
.parameters.next (User.self)
.flatMap(to: [Acronym].self){ user in
try user.acronyms.query(on: req).all()
}
}
func updateHandler(_ req: Request) throws -> Future<User.Public> {
return try flatMap(
to: User.Public.self,
req.parameters.next(User.self),
req.content.decode(User.self)
){ user, updatedUser in
user.name = updatedUser.name
user.username = updatedUser.username
user.password = try BCrypt.hash(updatedUser.password)
return user.save(on:req).convertToPublic()
}
}
func loginHandler(_ req: Request) throws -> Future<Token> {
let user = try req.requireAuthenticated(User.self)
let token = try Token.generate(for: user)
return token.save (on: req)
}
}
And here finally a screenshot of the table of my db:
thanks a lot
Arnold