Hi,
I finally got the authentication for my app set up and the next task is now to check inside Leaf templates whether the user is authenticated or not. I figured that, in the templates, I could do something like
#if(user):
<p>Hello, #(user.username)</p>
#endif
but to do this I would need to pass the user object in every... single... view... which I am not a fan of. I therefor went through the source code and found ViewRenderer
. I'm now wondering if a solution could be to extend this protocol
struct Context: Encodable {
var user: User?
}
extension ViewRenderer {
func myRender(req: Request, name: String) async throws -> View {
var context = Context()
if let user = req.auth.get(User.self) {
context.user = user
}
return try await self.render(name, context).get()
}
// func myRender<E>(req: Request, _ name: String, _ context: E) async throws -> View where E: Encodable
}
or is there a better way of achieving this?
Edit:
I came up with this solution
import Vapor
struct ViewContext: Encodable {
let valueEncoder: (Encoder) throws -> Void
init<T: Encodable>(user: User.Read, ctx: T) {
self.valueEncoder = {
var container = $0.container(keyedBy: CodingKeys.self)
try container.encode(user, forKey: .user)
try container.encode(ctx, forKey: .ctx)
}
}
enum CodingKeys: String, CodingKey {
case user, ctx
}
func encode(to encoder: Encoder) throws {
try valueEncoder(encoder)
}
}
extension User {
struct Read: Content {
var id: UUID
var username: String
var email: String
}
}
extension ViewRenderer {
func customRender<E>(_ req: Request, _ name: String, _ context: E) async throws -> View where E: Encodable {
guard let user = req.auth.get(User.self) else {
return try await self.render(name, context).get()
}
let userDTO = User.Read(
id: user.id!,
username: user.username,
email: user.email
)
return try await self.render(name, ViewContext(user: userDTO, ctx: context)).get()
}
func customRender(_ req: Request, _ name: String) async throws -> View {
guard let user = req.auth.get(User.self) else {
return try await self.render(name).get()
}
return try await self.render(name, ["user": user]).get()
}
}