{-# LANGUAGE CPP #-} #if __GLASGOW_HASKELL__ < 710 {-# LANGUAGE DeriveDataTypeable #-} #endif {-# LANGUAGE GADTs #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE QuasiQuotes #-} {-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE TypeFamilies #-} module TestSite ( User(..), migrateAll, App(..), Route(..), Handler, runDB ) where #if __GLASGOW_HASKELL__ < 710 import Control.Applicative ((<$>)) import Data.Typeable (Typeable) #endif import Control.Monad (when) import Data.Text import Database.Persist.Sqlite import Network.HTTP.Client.Conduit (Manager) import Yesod import Yesod.Auth import Yesod.Auth.HashDB (HashDBUser(..), authHashDB, submitRouteHashDB) import Yesod.Auth.Message (AuthMessage (InvalidLogin)) #if ! MIN_VERSION_yesod_auth(1,4,9) import Yesod.Auth.Message (AuthMessage (LoginTitle)) defaultLoginHandler :: AuthHandler master Html defaultLoginHandler = do tp <- getRouteToParent lift $ authLayout $ do setTitleI LoginTitle master <- getYesod mapM_ (flip apLogin tp) (authPlugins master) #endif -- Trivial example site needing authentication -- share [mkPersist sqlSettings, mkMigrate "migrateAll"] [persistLowerCase| User name Text password Text Maybe UniqueUser name deriving Show #if __GLASGOW_HASKELL__ < 710 deriving Typeable #endif |] instance HashDBUser User where userPasswordHash = userPassword setPasswordHash h u = u { userPassword = Just h } data App = App { appHttpManager :: Manager , appDBConnection :: SqlBackend } mkYesod "App" [parseRoutes| / HomeR GET /prot ProtectedR GET /auth AuthR Auth getAuth |] instance Yesod App where approot = ApprootStatic "http://localhost:3000" authRoute _ = Just $ AuthR LoginR isAuthorized ProtectedR _ = do mu <- maybeAuthId return $ case mu of Nothing -> AuthenticationRequired Just _ -> Authorized -- Other pages (HomeR and AuthR _) do not require login isAuthorized _ _ = return Authorized #if MIN_VERSION_yesod_core(1,4,19) || (MIN_VERSION_yesod_core(1,4,14) && MIN_VERSION_yesod_test(1,4,4)) -- CSRF middleware requires yesod-core-1.4.14, but only include it if tests -- can get at the token (see IntegrationTest.hs for additional comment). yesodMiddleware = defaultCsrfMiddleware . defaultYesodMiddleware #endif instance YesodPersist App where type YesodPersistBackend App = SqlBackend runDB action = do master <- getYesod runSqlConn action $ appDBConnection master instance YesodAuth App where type AuthId App = UserId loginDest _ = HomeR logoutDest _ = HomeR authenticate creds = runDB $ do x <- getBy $ UniqueUser $ credsIdent creds case x of Just (Entity uid _) -> return $ Authenticated uid Nothing -> return $ UserError InvalidLogin authPlugins _ = [ authHashDB (Just . UniqueUser) ] authHttpManager = appHttpManager loginHandler = do submission <- submitRouteHashDB render <- lift getUrlRender typedContent@(TypedContent ct _) <- selectRep $ do provideRepType typeHtml $ return emptyContent -- Dummy: the real Html version is at the end provideJson $ object [("loginUrl", toJSON $ render submission)] when (ct == typeJson) $ sendResponse typedContent -- Short-circuit JSON response defaultLoginHandler -- Html response instance YesodAuthPersist App instance RenderMessage App FormMessage where renderMessage _ _ = defaultFormMessage getHomeR :: Handler Html getHomeR = do mauth <- maybeAuth let mname = userName . entityVal <$> mauth defaultLayout [whamlet|

Your current auth ID: #{show mname} $maybe _ <- mname

Logout $nothing

Go to the login page

Go to protected page |] -- This page requires a valid login getProtectedR :: Handler Html getProtectedR = defaultLayout [whamlet|

OK, you are logged in so you are allowed to see this!

Go to home page |]