mb21
mb21

Reputation: 39229

Basic email/password auth with Yesod 1.4

I'm trying to integrate Yesod.Auth.Email into the default scaffolding of Yesod 1.4 (what you get with stack exec -- yesod init --bare && stack init). So I copied the relevant parts from the authentication and authorization example from the Yesod book to my Foundation.hs and started adjusting it to the new Yesod version:

instance YesodAuthEmail App where
    type AuthEmailId App = UserId

    afterPasswordRoute _ = HomeR

    addUnverified email verkey = do
        userId <- runDB $ insert $ User email Nothing
        runDB $ insert $ Email email (Just userId) (Just verkey)
        return userId

    sendVerifyEmail email _ verurl =
        liftIO $ renderSendMail (emptyMail $ Address Nothing "noreply")
            { mailTo = [Address Nothing email]
            , mailHeaders =
                [ ("Subject", "Verify your email address")
                ]
            , mailParts = [[textPart, htmlPart]]
            }
      where
        textPart = Part
            { partType = "text/plain; charset=utf-8"
            , partEncoding = None
            , partFilename = Nothing
            , partContent = Data.Text.Lazy.Encoding.encodeUtf8
                [stext|
                    Please confirm your email address by clicking on the link below.

                    #{verurl}

                    Thank you
                |]
            , partHeaders = []
            }
        htmlPart = Part
            { partType = "text/html; charset=utf-8"
            , partEncoding = None
            , partFilename = Nothing
            , partContent = withUrlRenderer
                [shamlet|
                    <p>Please confirm your email address by clicking on the link below.
                    <p>
                        <a href=#{verurl}>#{verurl}
                    <p>Thank you
                |]
            , partHeaders = []
            }
    getVerifyKey = runDB . fmap (join . fmap emailVerkey) . getBy
    setVerifyKey uid key = runDB $ update uid [EmailVerkey =. Just key]
    verifyAccount uid = runDB $ do
        mu <- get uid
        case mu of
            Nothing -> return Nothing
            Just u -> do
                update uid [EmailVerkey =. Nothing]
                return $ Just uid
    getPassword = runDB . fmap (join . fmap userPassword) . get
    setPassword uid pass = runDB $ update uid [UserPassword =. Just pass]
    getEmailCreds email = runDB $ do
        mu <- getBy $ UniqueUser email
        case mu of
            Nothing -> return Nothing
            Just (Entity uid u) -> return $ Just EmailCreds
                { emailCredsId = uid
                , emailCredsAuthId = Just uid
                , emailCredsStatus = isJust $ userPassword u
                , emailCredsVerkey = emailVerkey u
                , emailCredsEmail = email
                }
    getEmail = runDB . fmap (fmap emailEmail) . get

The config/models is unchanged from the yesod init scaffolding:

User
    ident Text
    password Text Maybe
    UniqueUser ident
    deriving Typeable
Email
    email Text
    user UserId Maybe
    verkey Text Maybe
    UniqueEmail email

I get a bunch of type errors, mostly because the functions (e.g. getVerifyKey) are supposed to take/return Users, not Emails.

Why did they change to using a separate Email table instead of keeping the verkey and email columns in the User table anyway? I'm fairly certain my users will never need to register multiple email addresses. Do you recommend keeping it this way so it plays well with the different auth plugins?

Upvotes: 2

Views: 333

Answers (1)

kjl
kjl

Reputation: 41

It looks like you could switch UserId for EmailId in type AuthEmailId App = UserId and it might work without issue.

I think the scaffolded table is there for illustrative purposes (unique columns, joins) and demonstrates a nice conceptual separation between users and emails, but is not strictly necessary.

Upvotes: 2

Related Questions