diff --git a/.swiftpm/xcode/package.xcworkspace/xcuserdata/michielcarman.xcuserdatad/UserInterfaceState.xcuserstate b/.swiftpm/xcode/package.xcworkspace/xcuserdata/michielcarman.xcuserdatad/UserInterfaceState.xcuserstate
index 4e71f86..3aed83f 100644
Binary files a/.swiftpm/xcode/package.xcworkspace/xcuserdata/michielcarman.xcuserdatad/UserInterfaceState.xcuserstate and b/.swiftpm/xcode/package.xcworkspace/xcuserdata/michielcarman.xcuserdatad/UserInterfaceState.xcuserstate differ
diff --git a/.swiftpm/xcode/xcuserdata/michielcarman.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/.swiftpm/xcode/xcuserdata/michielcarman.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist
index 75f58b2..b4117e8 100644
--- a/.swiftpm/xcode/xcuserdata/michielcarman.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist
+++ b/.swiftpm/xcode/xcuserdata/michielcarman.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist
@@ -3,4 +3,22 @@
uuid = "D3C706B5-9CBD-4F91-8A68-CF08562866B5"
type = "1"
version = "2.0">
+
+
+
+
+
+
diff --git a/Sources/App/Controllers/FuelEntryV2Controller.swift b/Sources/App/Controllers/FuelEntryV2Controller.swift
index 4267d0f..b97c86f 100644
--- a/Sources/App/Controllers/FuelEntryV2Controller.swift
+++ b/Sources/App/Controllers/FuelEntryV2Controller.swift
@@ -11,14 +11,18 @@ import FluentKit
struct FuelEntryV2Controller: RouteCollection {
func boot(routes: RoutesBuilder) throws {
let fuelEntries = routes.grouped("fuel_entries")
- fuelEntries.get(use: index)
- fuelEntries.get("test", use: filtered)
+ let tokenAuthMiddleware = Token.authenticator()
+ let guardMiddleware = User.guardMiddleware()
+ let tokenAuthGroup = fuelEntries.grouped(tokenAuthMiddleware, guardMiddleware)
+ tokenAuthGroup.get(use: index)
+ tokenAuthGroup.get("test", use: filtered)
// fuelEntries.get("with-images", use: getAllEntriesWithImages)
- fuelEntries.post(use: create)
+ tokenAuthGroup.post(use: create)
// fuelEntries.post("upload-image", use: uploadImage)
- fuelEntries.group(":fuelEntryID") { fuelEntry in
+ tokenAuthGroup.group(":fuelEntryID") { fuelEntry in
fuelEntry.delete(use: delete)
}
+
}
func index(req: Request) async throws -> [FuelEntry] {
diff --git a/Sources/App/Controllers/UserController.swift b/Sources/App/Controllers/UserController.swift
index 1ede7b2..29cf9bf 100644
--- a/Sources/App/Controllers/UserController.swift
+++ b/Sources/App/Controllers/UserController.swift
@@ -26,57 +26,17 @@ extension UserSignup: Validatable {
}
struct UserController: RouteCollection {
- func boot(routes: RoutesBuilder) throws {
- let usersRoute = routes.grouped("users")
- usersRoute.post("signup", use: create)
-
- let tokenProtected = usersRoute.grouped(Token.authenticator())
- tokenProtected.get("me", use: getMyOwnUser)
-
- let passwordProtected = usersRoute.grouped(User.authenticator())
- passwordProtected.post("login", use: login)
- }
-
- fileprivate func create(req: Request) throws -> EventLoopFuture {
- try UserSignup.validate(content: req)
- let userSignup = try req.content.decode(UserSignup.self)
- let user = try User.create(from: userSignup)
- var token: Token!
-
- return checkIfUserExists(userSignup.username, req: req).flatMap { exists in
- guard !exists else {
- return req.eventLoop.future(error: UserError.usernameTaken)
- }
-
- return user.save(on: req.db)
- }.flatMap {
- guard let newToken = try? user.createToken(source: .signup) else {
- return req.eventLoop.future(error: Abort(.internalServerError))
- }
- token = newToken
- return token.save(on: req.db)
- }.flatMapThrowing {
- NewSession(token: token.value, user: try user.asPublic())
+ func boot(routes: any RoutesBuilder) throws {
+ let users = routes.grouped("users")
+ users.post(use: create)
}
- }
-
- fileprivate func login(req: Request) throws -> EventLoopFuture {
- let user = try req.auth.require(User.self)
- let token = try user.createToken(source: .login)
-
- return token.save(on: req.db).flatMapThrowing {
- NewSession(token: token.value, user: try user.asPublic())
+ @Sendable
+ func create(req: Request) async throws -> Response{
+ let user = try req.content.decode(User.self)
+ user.passwordHash = try Bcrypt.hash(user.passwordHash)
+ try await user.save(on: req.db)
+ let token = try Token.generate(for: user)
+ try await token.save(on: req.db)
+ return try await token.encodeResponse(for: req)
}
- }
-
- func getMyOwnUser(req: Request) throws -> User.Public {
- try req.auth.require(User.self).asPublic()
- }
-
- private func checkIfUserExists(_ username: String, req: Request) -> EventLoopFuture {
- User.query(on: req.db)
- .filter(\.$username == username)
- .first()
- .map { $0 != nil }
- }
}
diff --git a/Sources/App/Migrations/CreateToken.swift b/Sources/App/Migrations/CreateToken.swift
index 3f7228f..13c7a22 100644
--- a/Sources/App/Migrations/CreateToken.swift
+++ b/Sources/App/Migrations/CreateToken.swift
@@ -29,3 +29,23 @@ struct CreateTokens: Migration {
database.schema(Token.schema).delete()
}
}
+struct UpdateTokens1: Migration {
+ func prepare(on database: Database) -> EventLoopFuture {
+ // 2
+ database.schema(Token.schema)
+ // 3
+ .deleteField("source")
+ .deleteField("created_at")
+ .deleteField("expires_at")
+ .update()
+ }
+
+ // 5
+ func revert(on database: Database) -> EventLoopFuture {
+ database.schema(Token.schema)
+ .field("source", .int, .required)
+ .field("created_at", .datetime, .required)
+ .field("expires_at", .datetime)
+ .update()
+ }
+}
diff --git a/Sources/App/Migrations/CreateUser.swift b/Sources/App/Migrations/CreateUser.swift
index bd3990b..b718bc2 100644
--- a/Sources/App/Migrations/CreateUser.swift
+++ b/Sources/App/Migrations/CreateUser.swift
@@ -25,3 +25,45 @@ struct CreateUser: AsyncMigration {
try await database.schema(User.schema).delete()
}
}
+
+struct UpdateUser1: AsyncMigration{
+ func prepare(on database: Database) async throws {
+ try await database.schema(User.schema)
+ .deleteField("created_at")
+ .deleteField("updated_at")
+ .update()
+ }
+
+ func revert(on database: Database) async throws {
+ try await database.schema(User.schema)
+ .field("created_at", .datetime, .required)
+ .field("updated_at", .datetime, .required)
+ .update()
+ }
+}
+struct UpdateUser2_AddTokenfield: AsyncMigration {
+ func prepare(on database: Database) async throws {
+ try await database.schema(User.schema)
+ .field("token", .string)
+ .update()
+ }
+
+ func revert(on database: Database) async throws {
+ try await database.schema(User.schema)
+ .deleteField("token")
+ .update()
+ }
+}
+struct UpdateUser3_RemoveTokenfield: AsyncMigration {
+ func prepare(on database: Database) async throws {
+ try await database.schema(User.schema)
+ .deleteField("token")
+ .update()
+ }
+
+ func revert(on database: Database) async throws {
+ try await database.schema(User.schema)
+ .field("token", .string)
+ .update()
+ }
+}
diff --git a/Sources/App/Models/Token.swift b/Sources/App/Models/Token.swift
index 8b7e109..6b8ce82 100644
--- a/Sources/App/Models/Token.swift
+++ b/Sources/App/Models/Token.swift
@@ -8,12 +8,9 @@
import Vapor
import Fluent
-enum SessionSource: Int, Content {
- case signup
- case login
-}
-final class Token: Model {
+
+final class Token: Model, Content, @unchecked Sendable {
static let schema = "token"
@ID()
@@ -25,36 +22,29 @@ final class Token: Model {
@Field(key: "value")
var value: String
- @Field(key: "source")
- var source: SessionSource
-
- @Field(key: "expires_at")
- var expiresAt: Date?
-
- @Timestamp(key: "created_at", on: .create)
- var createdAt: Date?
init() {}
- init(id: UUID? = nil, userId: User.IDValue, token: String,
- source: SessionSource, expiresAt: Date?) {
+ init(id: UUID? = nil, userId: User.IDValue, token: String) {
self.id = id
self.$user.id = userId
self.value = token
- self.source = source
- self.expiresAt = expiresAt
}
}
-extension Token: ModelTokenAuthenticatable {
- static let valueKey = \Token.$value
- static let userKey = \Token.$user
-
- var isValid: Bool {
- guard let expiryDate = expiresAt else {
- return true
+extension Token {
+ static func generate(for user: User) throws -> Token {
+ let random = [UInt8].random(count: 32).base64
+ return try Token( userId: user.requireID(), token: random)
}
+}
+
+extension Token: ModelTokenAuthenticatable {
+ typealias User = App.User
+ static let valueKey = \Token.$value
+ static let userKey = \Token.$user
- return expiryDate > Date()
- }
+ var isValid: Bool {
+ true
+ }
}
diff --git a/Sources/App/Models/User.swift b/Sources/App/Models/User.swift
index be1cbf2..5452f8d 100644
--- a/Sources/App/Models/User.swift
+++ b/Sources/App/Models/User.swift
@@ -8,16 +8,17 @@
import Fluent
import Vapor
-final class User: Model {
- struct Public: Content {
- let username: String
- let id: UUID
- let createdAt: Date?
- let updatedAt: Date?
- }
-
+final class User: Model, Content {
static let schema = "user"
-
+ final class Public: Content {
+ var id: UUID?
+ var username: String
+
+ init(id: UUID?, username: String) {
+ self.id = id
+ self.username = username
+ }
+ }
@ID()
var id: UUID?
@@ -26,12 +27,13 @@ final class User: Model {
@Field(key: "password_hash")
var passwordHash: String
+
- @Timestamp(key: "created_at", on: .create)
- var createdAt: Date?
-
- @Timestamp(key: "updated_at", on: .update)
- var updatedAt: Date?
+// @Timestamp(key: "created_at", on: .create)
+// var createdAt: Date?
+//
+// @Timestamp(key: "updated_at", on: .update)
+// var updatedAt: Date?
init() {}
@@ -41,27 +43,11 @@ final class User: Model {
self.passwordHash = passwordHash
}
}
-
extension User {
- static func create(from userSignup: UserSignup) throws -> User {
- User(username: userSignup.username, passwordHash: try Bcrypt.hash(userSignup.password))
- }
-
- func createToken(source: SessionSource) throws -> Token {
- let calendar = Calendar(identifier: .gregorian)
- let expiryDate = calendar.date(byAdding: .year, value: 1, to: Date())
- return try Token(userId: requireID(),
- token: [UInt8].random(count: 16).base64, source: source, expiresAt: expiryDate)
- }
-
- func asPublic() throws -> Public {
- Public(username: username,
- id: try requireID(),
- createdAt: createdAt,
- updatedAt: updatedAt)
- }
+ func convertToPublic() -> User.Public {
+ return User.Public(id: id, username: username)
+ }
}
-
extension User: ModelAuthenticatable {
static let usernameKey = \User.$username
static let passwordHashKey = \User.$passwordHash
@@ -70,3 +56,8 @@ extension User: ModelAuthenticatable {
try Bcrypt.verify(password, created: self.passwordHash)
}
}
+
+
+
+
+
diff --git a/Sources/App/configure.swift b/Sources/App/configure.swift
index 177900a..fdf81e7 100755
--- a/Sources/App/configure.swift
+++ b/Sources/App/configure.swift
@@ -19,6 +19,10 @@ public func configure(_ app: Application) async throws {
app.migrations.add(AddDownloadedBool())
app.migrations.add(CreateUser())
app.migrations.add(CreateTokens())
+ app.migrations.add(UpdateUser1())
+ app.migrations.add(UpdateTokens1())
+ app.migrations.add(UpdateUser2_AddTokenfield())
+ app.migrations.add(UpdateUser3_RemoveTokenfield())
try await app.autoMigrate().get()
// register routes