Chapter 20: Logout only shown on index page

So, I’ve added the Web Authentication and realised that the logout button is only shown on the index page, when switching to the create acronym page the register menu item appears again, even tho you cannot get to the page unauthenticated.

I’ve tried to find how it’s getting checked, but I’m just starting to learn swift and vapor.
Can someone help me out on this? Thanks :grinning_face_with_smiling_eyes:

The reason for this is the indexHandler is the only place that passes in the userLoggedIn to the context. You will also have to pass that in on other pages as well or use a custom middleware :wink:

Ah, that kinda makes sense now.
Will try to get that working tomorrow after work.
Thanks mate.

1 Like

Yes unfortunately Leaf doesn’t make this particularly easy yet, which is why it wasn’t included in the book. What I do is wrap the render call with my own function that populates a PageContext that has both the context passed into it and a set of global properties, like the currently logged in user etc.

I’m working on adding something similar to Leaf to make it easier

1 Like

@0xtim I’m not sure if I follow you on that.

But I got it fixed by plainly adding
let userLoggedIn = req.auth.has(User.self) and userLoggedIn: userLoggedIn, to the needed contexts

@0xtim Could you give me an example how to create those global properties?

I’ve been trying to get access to the logged in user, but I’m not sure how to do that.
I do get the User with let user = req.auth.get(User.self) but it’s an optional and I cannot get it to work :frowning:
Can you help?

So I have a custom context that looks like:

struct PageContext<InnerContext: Encodable>: Encodable {
    let pageData: InnerContext
    let loggedInUser: User?
    // ...
}

Then a custom render call that looks like:

extension Request {
    func render<Context: Encodable>(_ template: String, _ context: Context) -> EventLoopFuture<View> {
        let user = self.auth.get(User.self)

        return someFutureThing.flatMap { somethingElse in
            let pageContext = PageContext(pageData: context, loggedInUser: user, ...)
            return self.view.render(template, pageContext)
        }
    }
}

Then in my code, instead of doing req.view.render("template", context) I call req.render("template", context). That passes the user to every page. Then in the template I can do #if(loggedInUser): etc and all the regular context stuff is #(pageData.acronyms) etc

3 Likes