ggarcia.jr
ggarcia.jr

Reputation: 33

Custom registration form with Yesod.Auth.Email

I have a question regarding why Yesod.Auth was done the way it was. I was trying to create a custom register form - i.e: more fields other than just email - and here are the issues I've encoutered along the way:

  1. I tried to create customized versions of functions defined in the Email module to render customized templates: defaultEmailLoginHandler, defaultRegisterHandler, defaultForgotPasswordHandler.

And it kept me wondering: why we can't simply provide a custom hamlet file and be done with it? Why do I have to create custom versions of those functions?

  1. After the template part was done I moved to processing the forms, and here I hit the wall. I tried to create a custom version of the registerHelper function but, that is not a visible member of the Yesod.Auth.Email class so, creating a custom registerHelper won't work. Then I thought I could provide a custom route to process the form by rewriting postRegisterR and again I was out of luck.

Why those functions, particularly registerHelper, were not created as visible members of Yesod.Auth.Email?

  1. My third attempt would be to "fork" the whole Email.hs module, but again I failed to meet some requirements to make this possible. In this case was the Yesod.PasswordStore that is not an exposed module, so I cannot import it into my custom Yesod.Auth.Email.

Why Yesod.PasswordStore was not exposed?

Given I don't want to go deeper into the rabbit hole and rewrite fork the PasswordStore, I just came to realize that it is not possible to have a custom registration form using Yesod.Auth.Email.

Am I missing something here or I got this right? Why Yesod.Auth.Email was built in that way?

Upvotes: 3

Views: 241

Answers (1)

Sibi
Sibi

Reputation: 48654

I'm not exactly aware of the design decisions made by Michael Snoyman on this, but my reasoning was that "email" is the minimal information required to register an account. Once you have registered your email, a registration link email is sent to your account through which you can verify your account. It is on this password reset page, where I define all my custom fields along with setting new password. I define my own handler for setting new password. The code usually goes something like this:

  if (jpNewPassword profile == jpConfirmPassword profile)
    then do
      newPass <- liftIO $ saltPass (jpNewPassword profile)
      lift $
        runDB $
        do user <- getUser maid
           update maid [UserPassword =. (Just newPass)]

The above is a code from one of my personal projects.

why we can't simply provide a custom hamlet file and be done with it?

Well you can still provide a custom hamlet file. This is how my setPasswordHandler is defined in the instance of YesodAuthEmail:

  setPasswordHandler _ =
    selectRep $
    do provideRep $ return $(shamletFile "./templates/password.shamlet")

Why Yesod.PasswordStore was not exposed?

As explained above, you can still update the password without Yesod.PasswordStore being exposed. The relevant functions are in Yesod.Auth.Email module.

That being said, I can understand your concern. This is why I implemented JSON endpoints for all of the endpoints in Yesod.Auth.Email module so that validation and other stuffs can be easily done at client side itself. Those endpoints have been documented in the above linked Haddock page. But if you want to have custom fields in the registration page, I think it may involve some code change in Yesod.Auth.Email module. I would suggest you to open a issue in github (brownie points if you can also send a PR!) and give us the feedback there. We are very open to change!

Upvotes: 2

Related Questions