Skip to content

Instantly share code, notes, and snippets.

@v0d1ch
Forked from stla/authaccountcustom.hs
Created April 15, 2017 14:36
Show Gist options
  • Save v0d1ch/beb39263e11346975d4edd573cf4889b to your computer and use it in GitHub Desktop.
Save v0d1ch/beb39263e11346975d4edd573cf4889b to your computer and use it in GitHub Desktop.
Yesod Auth Account custom login page
{-# LANGUAGE QuasiQuotes, TypeFamilies, GeneralizedNewtypeDeriving #-}
{-# LANGUAGE FlexibleContexts, FlexibleInstances, TemplateHaskell, OverloadedStrings #-}
{-# LANGUAGE GADTs, MultiParamTypeClasses, TypeSynonymInstances #-}
import Data.Text (Text)
import Data.ByteString (ByteString)
import Database.Persist.Sqlite
import Control.Monad.Logger (runStderrLoggingT)
import Yesod
import Yesod.Auth
import Yesod.Auth.Account
share [mkPersist sqlSettings, mkMigrate "migrateAll"] [persistUpperCase|
User
username Text
UniqueUsername username
password ByteString
emailAddress Text
verified Bool
verifyKey Text
resetPasswordKey Text
deriving Show
|]
instance PersistUserCredentials User where
userUsernameF = UserUsername
userPasswordHashF = UserPassword
userEmailF = UserEmailAddress
userEmailVerifiedF = UserVerified
userEmailVerifyKeyF = UserVerifyKey
userResetPwdKeyF = UserResetPasswordKey
uniqueUsername = UniqueUsername
userCreate name email key pwd = User name pwd email False key ""
data MyApp = MyApp ConnectionPool
mkYesod "MyApp" [parseRoutes|
/ HomeR GET
/auth AuthR Auth getAuth
|]
instance Yesod MyApp
instance RenderMessage MyApp FormMessage where
renderMessage _ _ = defaultFormMessage
instance YesodPersist MyApp where
type YesodPersistBackend MyApp = SqlBackend
runDB action = do
MyApp pool <- getYesod
runSqlPool action pool
instance YesodAuth MyApp where
type AuthId MyApp = Username
getAuthId = return . Just . credsIdent
loginDest _ = HomeR
logoutDest _ = HomeR
authPlugins _ = [accountPluginCustom]
authHttpManager _ = error "No manager needed"
onLogin = return ()
maybeAuthId = lookupSession credsKey
accountPluginCustom :: YesodAuthAccount db master => AuthPlugin master
accountPluginCustom = AuthPlugin "account" (apDispatch accountPlugin) myLoginWidget
myLoginWidget :: YesodAuthAccount db master => (Route Auth -> Route master) -> WidgetT master IO ()
myLoginWidget tm = do
toWidget loginStyle
[whamlet|
<div .loginDiv>
<form method=post enctype="application/x-www-form-urlencoded" action=@{tm loginFormPostTargetR}>
<h1>
Login
<input type="text" #username placeholder="Username" required="required" name="f1">
<input type="password" #password placeholder="Password" required="required" name="f2">
<button type="submit" .btn .btn-primary .btn-block .btn-large>
Let me in.
<p>
<a href="@{tm newAccountR}">Register a new account
<a href="@{tm resetPasswordR}">Forgot password?
|]
loginStyle = [lucius|
@import url(http://fonts.googleapis.com/css?family=Open+Sans);
.btn { display: inline-block; *display: inline; *zoom: 1; padding: 4px 10px 4px; margin-bottom: 0; font-size: 13px; line-height: 18px; color: #333333; text-align: center;text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75); vertical-align: middle; background-color: #f5f5f5; background-image: -moz-linear-gradient(top, #ffffff, #e6e6e6); background-image: -ms-linear-gradient(top, #ffffff, #e6e6e6); background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6)); background-image: -webkit-linear-gradient(top, #ffffff, #e6e6e6); background-image: -o-linear-gradient(top, #ffffff, #e6e6e6); background-image: linear-gradient(top, #ffffff, #e6e6e6); background-repeat: repeat-x; filter: progid:dximagetransform.microsoft.gradient(startColorstr=#ffffff, endColorstr=#e6e6e6, GradientType=0); border-color: #e6e6e6 #e6e6e6 #e6e6e6; border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); border: 1px solid #e6e6e6; -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); cursor: pointer; *margin-left: .3em; }
.btn:hover, .btn:active, .btn.active, .btn.disabled, .btn[disabled] { background-color: #e6e6e6; }
.btn-large { padding: 9px 14px; font-size: 15px; line-height: normal; -webkit-border-radius: 5px; -moz-border-radius: 5px; border-radius: 5px; }
.btn:hover { color: #333333; text-decoration: none; background-color: #e6e6e6; background-position: 0 -15px; -webkit-transition: background-position 0.1s linear; -moz-transition: background-position 0.1s linear; -ms-transition: background-position 0.1s linear; -o-transition: background-position 0.1s linear; transition: background-position 0.1s linear; }
.btn-primary, .btn-primary:hover { text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); color: #ffffff; }
.btn-primary.active { color: rgba(255, 255, 255, 0.75); }
.btn-primary { background-color: #4a77d4; background-image: -moz-linear-gradient(top, #6eb6de, #4a77d4); background-image: -ms-linear-gradient(top, #6eb6de, #4a77d4); background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#6eb6de), to(#4a77d4)); background-image: -webkit-linear-gradient(top, #6eb6de, #4a77d4); background-image: -o-linear-gradient(top, #6eb6de, #4a77d4); background-image: linear-gradient(top, #6eb6de, #4a77d4); background-repeat: repeat-x; filter: progid:dximagetransform.microsoft.gradient(startColorstr=#6eb6de, endColorstr=#4a77d4, GradientType=0); border: 1px solid #3762bc; text-shadow: 1px 1px 1px rgba(0,0,0,0.4); box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.5); }
.btn-primary:hover, .btn-primary:active, .btn-primary.active, .btn-primary.disabled, .btn-primary[disabled] { filter: none; background-color: #4a77d4; }
.btn-block { width: 60%; display:block; text-align:center; margin-left:auto; margin-right:auto;}
* { -webkit-box-sizing:border-box; -moz-box-sizing:border-box; -ms-box-sizing:border-box; -o-box-sizing:border-box; box-sizing:border-box; }
.loginDiv {
height: 100%;
font-family: 'Open Sans', sans-serif;
background: #092756;
background: -moz-radial-gradient(0% 100%, ellipse cover, rgba(104,128,138,.4) 10%,rgba(138,114,76,0) 40%),-moz-linear-gradient(top, rgba(57,173,219,.25) 0%, rgba(42,60,87,.4) 100%), -moz-linear-gradient(-45deg, #670d10 0%, #092756 100%);
background: -webkit-radial-gradient(0% 100%, ellipse cover, rgba(104,128,138,.4) 10%,rgba(138,114,76,0) 40%), -webkit-linear-gradient(top, rgba(57,173,219,.25) 0%,rgba(42,60,87,.4) 100%), -webkit-linear-gradient(-45deg, #670d10 0%,#092756 100%);
background: -o-radial-gradient(0% 100%, ellipse cover, rgba(104,128,138,.4) 10%,rgba(138,114,76,0) 40%), -o-linear-gradient(top, rgba(57,173,219,.25) 0%,rgba(42,60,87,.4) 100%), -o-linear-gradient(-45deg, #670d10 0%,#092756 100%);
background: -ms-radial-gradient(0% 100%, ellipse cover, rgba(104,128,138,.4) 10%,rgba(138,114,76,0) 40%), -ms-linear-gradient(top, rgba(57,173,219,.25) 0%,rgba(42,60,87,.4) 100%), -ms-linear-gradient(-45deg, #670d10 0%,#092756 100%);
background: -webkit-radial-gradient(0% 100%, ellipse cover, rgba(104,128,138,.4) 10%,rgba(138,114,76,0) 40%), linear-gradient(to bottom, rgba(57,173,219,.25) 0%,rgba(42,60,87,.4) 100%), linear-gradient(135deg, #670d10 0%,#092756 100%);
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#3E1D6D', endColorstr='#092756',GradientType=1 );
position: fixed;
top: 0;
left: 0;
bottom: 0;
right:0;
margin: 0;
}
h1 { color: #fff; text-shadow: 0 0 10px rgba(0,0,0,0.3); letter-spacing:1px; text-align:center; }
form {
display: block;
position: relative;
top: 20%;
width: 30%;
text-align: center;
margin-left: auto;
margin-right: auto;
}
input {
width: 60%;
margin-bottom: 10px;
background: rgba(0,0,0,0.3);
border: none;
outline: none;
padding: 10px;
font-size: 13px;
color: #fff;
text-shadow: 1px 1px 1px rgba(0,0,0,0.3);
border: 1px solid rgba(0,0,0,0.3);
border-radius: 4px;
box-shadow: inset 0 -5px 45px rgba(100,100,100,0.2), 0 1px 1px rgba(255,255,255,0.2);
-webkit-transition: box-shadow .5s ease;
-moz-transition: box-shadow .5s ease;
-o-transition: box-shadow .5s ease;
-ms-transition: box-shadow .5s ease;
transition: box-shadow .5s ease;
}
input:focus { box-shadow: inset 0 -5px 45px rgba(100,100,100,0.4), 0 1px 1px rgba(255,255,255,0.2); }
.message {
position: fixed;
z-index: 1000;
color: #fff;
}
a {
color: #fb660a;
}
|]
instance AccountSendEmail MyApp
instance YesodAuthAccount (AccountPersistDB MyApp User) MyApp where
runAccountDB = runAccountPersistDB
getHomeR :: Handler Html
getHomeR = do
maid <- maybeAuthId
case maid of
Nothing -> redirect $ AuthR LoginR
Just u -> defaultLayout $ [whamlet|
<p>You are logged in as #{u}
<p><a href="@{AuthR LogoutR}">Logout</a>
|]
main :: IO ()
main = runStderrLoggingT $ withSqlitePool "users.db3" 10 $ \pool -> do
runSqlPool (runMigration migrateAll) pool
liftIO $ warp 3000 $ MyApp pool
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment