-- Hoogle documentation, generated by Haddock
-- See Hoogle, http://www.haskell.org/hoogle/


-- | An account authentication plugin for Yesod
--   
--   An auth plugin for accounts. Each account consists of a username,
--   email, and password. The plugin provides new account, email
--   verification, and password reset pages that can be customized to
--   enhance the user experience.
@package yesod-auth-account
@version 1.4.3

module Yesod.Auth.Account.Message

-- | Messages specific to yesod-auth-account. We also use messages from
--   <a>Yesod.Auth.Message</a>.
data AccountMsg
MsgUsername :: AccountMsg
MsgForgotPassword :: AccountMsg
MsgInvalidUsername :: AccountMsg
MsgUsernameExists :: Text -> AccountMsg
MsgResendVerifyEmail :: AccountMsg
MsgResetPwdEmailSent :: AccountMsg
MsgEmailVerified :: AccountMsg
MsgEmailUnverified :: AccountMsg

-- | Defaults to <a>englishAccountMsg</a>
defaultAccountMsg :: AccountMsg -> Text
englishAccountMsg :: AccountMsg -> Text


-- | An auth plugin for accounts. Each account consists of a username,
--   email, and password.
--   
--   This module is designed so that you can use the default pages for
--   login, account creation, change password, etc. But the module also
--   exports some forms which you can embed into your own pages,
--   customizing the account process. The minimal requirements to use this
--   module are:
--   
--   <ul>
--   <li>If you are not using persistent or just want more control over the
--   user data, you can use any datatype for user information and make it
--   an instance of <a>UserCredentials</a>. You must also create an
--   instance of <a>AccountDB</a>.</li>
--   <li>You may use a user datatype created by persistent, in which case
--   you can make the datatype an instance of <a>PersistUserCredentials</a>
--   instead of <a>UserCredentials</a>. In this case,
--   <a>AccountPersistDB</a> from this module already implements the
--   <a>AccountDB</a> interface for you.</li>
--   <li>Make your master site an instance of <a>AccountSendEmail</a>. By
--   default, this class just logs a message so during development this
--   class requires no implementation.</li>
--   <li>Make your master site and database an instance of
--   <a>YesodAuthAccount</a>. There is only one required function which
--   must be implemented (<a>runAccountDB</a>) although there are several
--   functions you can override in this class to customize the behavior of
--   this module.</li>
--   <li>Include <a>accountPlugin</a> in the list of plugins in your
--   instance of <a>YesodAuth</a>.</li>
--   </ul>
module Yesod.Auth.Account

-- | Each user is uniquely identified by a username.
type Username = Text

-- | Route for the default new account page.
--   
--   See the New Account section below for customizing the new account
--   process.
newAccountR :: AuthRoute

-- | Route for the reset password page.
--   
--   This page allows the user to reset their password by requesting an
--   email with a reset URL be sent to them. See the Password Reset section
--   below for customization.
resetPasswordR :: AuthRoute

-- | The account authentication plugin. Here is a complete example using
--   persistent 2.1 and yesod 1.4.
--   
--   <pre>
--   {-# 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 &lt;- getYesod
--           runSqlPool action pool
--   
--   instance YesodAuth MyApp where
--       type AuthId MyApp = Username
--       getAuthId = return . Just . credsIdent
--       loginDest _ = HomeR
--       logoutDest _ = HomeR
--       authPlugins _ = [accountPlugin]
--       authHttpManager _ = error "No manager needed"
--       onLogin = return ()
--       maybeAuthId = lookupSession credsKey
--   
--   instance AccountSendEmail MyApp
--   
--   instance YesodAuthAccount (AccountPersistDB MyApp User) MyApp where
--       runAccountDB = runAccountPersistDB
--   
--   getHomeR :: Handler Html
--   getHomeR = do
--       maid &lt;- maybeAuthId
--       case maid of
--           Nothing -&gt; defaultLayout $ [whamlet|
--   &lt;p&gt;Please visit the &lt;a href="@{AuthR LoginR}"&gt;Login page&lt;/a&gt;
--   |]
--           Just u -&gt; defaultLayout $ [whamlet|
--   &lt;p&gt;You are logged in as #{u}
--   &lt;p&gt;&lt;a href="@{AuthR LogoutR}"&gt;Logout&lt;/a&gt;
--   |]
--   
--   main :: IO ()
--   main = runStderrLoggingT $ withSqlitePool "test.db3" 10 $ \pool -&gt; do
--       runSqlPool (runMigration migrateAll) pool
--       liftIO $ warp 3000 $ MyApp pool
--   </pre>
accountPlugin :: YesodAuthAccount db master => AuthPlugin master

-- | The data collected in the login form.
data LoginData
LoginData :: Text -> Text -> LoginData
[loginUsername] :: LoginData -> Text
[loginPassword] :: LoginData -> Text

-- | The login form.
--   
--   You can embed this form into your own pages if you want a custom
--   rendering of this form or to include a login form on your own pages.
--   The form submission should be posted to <a>loginFormPostTargetR</a>.
loginForm :: (MonadHandler m, YesodAuthAccount db master, HandlerSite m ~ master) => AForm m LoginData

-- | The POST target for the <a>loginForm</a>.
loginFormPostTargetR :: AuthRoute

-- | A default rendering of <a>loginForm</a> using renderDivs.
--   
--   This is the widget used in the default implementation of
--   <a>loginHandler</a>. The widget also includes links to the new account
--   and reset password pages.
loginWidget :: YesodAuthAccount db master => (Route Auth -> Route master) -> WidgetT master IO ()

-- | The URL sent in an email for email verification
verifyR :: Username -> Text -> AuthRoute

-- | The data collected in the new account form.
data NewAccountData
NewAccountData :: Username -> Text -> Text -> Text -> NewAccountData
[newAccountUsername] :: NewAccountData -> Username
[newAccountEmail] :: NewAccountData -> Text
[newAccountPassword1] :: NewAccountData -> Text
[newAccountPassword2] :: NewAccountData -> Text

-- | The new account form.
--   
--   You can embed this form into your own pages or into
--   <a>getNewAccountR</a>. The form submission should be posted to
--   <a>newAccountR</a>. Alternatively, you could embed this form into a
--   larger form where you prompt for more information during account
--   creation. In this case, the NewAccountData should be passed to
--   <a>createNewAccount</a> from inside <a>postNewAccountR</a>.
newAccountForm :: (YesodAuthAccount db master, MonadHandler m, HandlerSite m ~ master) => AForm m NewAccountData

-- | A default rendering of the <a>newAccountForm</a> using renderDivs.
newAccountWidget :: YesodAuthAccount db master => (Route Auth -> Route master) -> WidgetT master IO ()

-- | An action to create a new account.
--   
--   You can use this action inside your own implementation of
--   <a>postNewAccountR</a> if you add additional fields to the new account
--   creation. This action assumes the user has not yet been created in the
--   database and will create the user, so this action should be run first
--   in your handler. Note that this action does not check if the passwords
--   are equal. If an error occurs (username exists, etc.) this will set a
--   message and redirect to <a>newAccountR</a>.
createNewAccount :: YesodAuthAccount db master => NewAccountData -> (Route Auth -> Route master) -> HandlerT master IO (UserAccount db)

-- | A form to allow the user to request the email validation be resent.
--   
--   Intended for use in <a>unregisteredLogin</a>. The result should be
--   posted to <a>resendVerifyR</a>.
resendVerifyEmailForm :: (RenderMessage master FormMessage, MonadHandler m, HandlerSite m ~ master) => Username -> AForm m Username

-- | The POST target for resending a verification email
resendVerifyR :: AuthRoute

-- | A default rendering of <a>resendVerifyEmailForm</a>
resendVerifyEmailWidget :: YesodAuthAccount db master => Username -> (Route Auth -> Route master) -> WidgetT master IO ()

-- | The URL sent in an email when the user requests to reset their
--   password
newPasswordR :: Username -> Text -> AuthRoute

-- | A form for the user to request that an email be sent to them to allow
--   them to reset their password. This form contains a field for the
--   username (plus the CSRF token). The form should be posted to
--   <a>resetPasswordR</a>.
resetPasswordForm :: (YesodAuthAccount db master, MonadHandler m, HandlerSite m ~ master) => AForm m Username

-- | A default rendering of <a>resetPasswordForm</a>.
resetPasswordWidget :: YesodAuthAccount db master => (Route Auth -> Route master) -> WidgetT master IO ()

-- | The data for setting a new password.
data NewPasswordData
NewPasswordData :: Username -> Text -> Text -> Text -> NewPasswordData
[newPasswordUser] :: NewPasswordData -> Username
[newPasswordKey] :: NewPasswordData -> Text
[newPasswordPwd1] :: NewPasswordData -> Text
[newPasswordPwd2] :: NewPasswordData -> Text

-- | The form for setting a new password. It contains hidden fields for the
--   username and key and prompts for the passwords. This form should be
--   posted to <a>setPasswordR</a>.
newPasswordForm :: (YesodAuth master, RenderMessage master FormMessage, MonadHandler m, HandlerSite m ~ master) => Username -> Text -> AForm m NewPasswordData

-- | The POST target for reseting the password
setPasswordR :: AuthRoute

-- | A default rendering of <a>newPasswordForm</a>.
newPasswordWidget :: YesodAuthAccount db master => UserAccount db -> (Route Auth -> Route master) -> WidgetT master IO ()

-- | Interface for the data type which stores the user info when not using
--   persistent.
--   
--   You must make a data type that is either an instance of this class or
--   of <a>PersistUserCredentials</a>, depending on if you are using
--   persistent or not.
--   
--   Users are uniquely identified by their username, and for each user we
--   must store the email, the verify status, a hashed user password, and a
--   reset password key. The format for the hashed password is the format
--   from <a>Crypto.PasswordStore</a>. If the email has been verified and
--   no password reset is in progress, the relevent keys should be the
--   empty string.
class UserCredentials u
username :: UserCredentials u => u -> Username
userPasswordHash :: UserCredentials u => u -> ByteString
userEmail :: UserCredentials u => u -> Text
userEmailVerified :: UserCredentials u => u -> Bool
userEmailVerifyKey :: UserCredentials u => u -> Text
userResetPwdKey :: UserCredentials u => u -> Text

-- | Interface for the data type which stores the user info when using
--   persistent.
--   
--   You must make a data type that is either an instance of this class or
--   of <a>UserCredentials</a>, depending on if you are using persistent or
--   not.
class PersistUserCredentials u
userUsernameF :: PersistUserCredentials u => EntityField u Username
userPasswordHashF :: PersistUserCredentials u => EntityField u ByteString
userEmailF :: PersistUserCredentials u => EntityField u Text
userEmailVerifiedF :: PersistUserCredentials u => EntityField u Bool
userEmailVerifyKeyF :: PersistUserCredentials u => EntityField u Text
userResetPwdKeyF :: PersistUserCredentials u => EntityField u Text
uniqueUsername :: PersistUserCredentials u => Text -> Unique u

-- | Creates a new user for use during <a>addNewUser</a>. The starting
--   reset password key should be the empty string.
userCreate :: PersistUserCredentials u => Username -> Text -> Text -> ByteString -> u

-- | These are the database operations to load and update user data.
--   
--   Persistent users can use <a>AccountPersistDB</a> and don't need to
--   create their own instance. If you are not using persistent or are
--   using persistent but want to customize the database activity, you must
--   manually make a monad an instance of this class. You can use any monad
--   for which you can write <a>runAccountDB</a>, but typically the monad
--   will be a newtype of HandlerT. For example,
--   
--   <pre>
--   newtype MyAccountDB a = MyAccountDB {runMyAccountDB :: HandlerT MyApp IO a}
--      deriving (Monad, MonadIO)
--   instance AccountDB MyAccountDB where
--       ....
--   </pre>
class AccountDB m where type UserAccount m where {
    type family UserAccount m;
}

-- | Load a user by username
loadUser :: AccountDB m => Username -> m (Maybe (UserAccount m))

-- | Create new account. The password reset key should be added as an empty
--   string. The creation can fail with an error message, in which case the
--   error is set in a message and the post handler redirects to
--   <a>newAccountR</a>.
addNewUser :: AccountDB m => Username -> Text -> Text -> ByteString -> m (Either Text (UserAccount m))

-- | Mark the account as successfully verified. This should reset the email
--   validation key to the empty string.
verifyAccount :: AccountDB m => UserAccount m -> m ()

-- | Change/set the users email verification key.
setVerifyKey :: AccountDB m => UserAccount m -> Text -> m ()

-- | Change/set the users password reset key.
setNewPasswordKey :: AccountDB m => UserAccount m -> Text -> m ()

-- | Set a new hashed password. This should also set the password reset key
--   to the empty string.
setNewPassword :: AccountDB m => UserAccount m -> ByteString -> m ()

-- | A class to send email.
--   
--   Both of the methods are implemented by default to just log a message,
--   so during development there are no required methods. For production, I
--   recommend <a>http://hackage.haskell.org/package/mime-mail</a>.
class AccountSendEmail master where sendVerifyEmail uname email url = (((monadLoggerLog (Loc "Yesod/Auth/Account.hs" "yesod-auth-account-1.4.3-1fFhAuqU9D9CZTZybrhlCc" "Yesod.Auth.Account" (744, 11) (744, 18)) (pack "") LevelInfo) . (id :: Text -> Text))) $ concat ["Verification email for ", uname, " (", email, "): ", url] sendNewPasswordEmail uname email url = (((monadLoggerLog (Loc "Yesod/Auth/Account.hs" "yesod-auth-account-1.4.3-1fFhAuqU9D9CZTZybrhlCc" "Yesod.Auth.Account" (755, 11) (755, 18)) (pack "") LevelInfo) . (id :: Text -> Text))) $ concat ["Reset password email for ", uname, " (", email, "): ", url]
sendVerifyEmail :: AccountSendEmail master => Username -> Text -> Text -> HandlerT master IO ()
sendNewPasswordEmail :: AccountSendEmail master => Username -> Text -> Text -> HandlerT master IO ()

-- | A newtype which when using persistent is an instance of
--   <a>AccountDB</a>.
data AccountPersistDB master user a

-- | Use this for <a>runAccountDB</a> if you are using
--   <a>AccountPersistDB</a> as your database type.
runAccountPersistDB :: (Yesod master, YesodPersist master, PersistEntity user, PersistUserCredentials user, b ~ YesodPersistBackend master, b ~ PersistEntityBackend user, PersistUnique b, b ~ BaseBackend b, YesodAuthAccount db master, db ~ AccountPersistDB master user) => AccountPersistDB master user a -> HandlerT master IO a

-- | The main class controlling the account plugin.
--   
--   You must make your database instance of <a>AccountDB</a> and your
--   master site an instance of this class. The only required method is
--   <a>runAccountDB</a>, although this class contains many other methods
--   to customize the behavior of the account plugin.
--   
--   Continuing the example from the manual creation of <a>AccountDB</a>, a
--   minimal instance is
--   
--   <pre>
--   instance YesodAuthAccount MyAccountDB MyApp where
--       runAccountDB = runMyAccountDB
--   </pre>
--   
--   If instead you are using persistent and have made an instance of
--   <a>PersistUserCredentials</a>, a minimal instance is
--   
--   <pre>
--   instance YesodAuthAccount (AccountPersistDB MyApp User) MyApp where
--      runAccountDB = runAccountPersistDB
--   </pre>
class (YesodAuth master, AccountSendEmail master, AccountDB db, UserCredentials (UserAccount db), RenderMessage master FormMessage) => YesodAuthAccount db master | master -> db where checkValidUsername u | all isAlphaNum u = return $ Right u checkValidUsername _ = do { mr <- getMessageRender; return $ Left $ mr MsgInvalidUsername } unregisteredLogin u = do { tm <- getRouteToParent; lift $ defaultLayout $ do { setTitleI MsgEmailUnverified; (do { (asWidgetT . toWidget) ((preEscapedText . pack) "<p>"); ((fmap (toHtml .) getMessageRender) >>= (\ urender_asPx -> (asWidgetT . toWidget) (urender_asPx MsgEmailUnverified))); (asWidgetT . toWidget) ((preEscapedText . pack) "</p>\n"); (asWidgetT . toWidget) (resendVerifyEmailWidget (username u) tm) }) } } getNewAccountR = do { tm <- getRouteToParent; lift $ defaultLayout $ do { setTitleI RegisterLong; newAccountWidget tm } } postNewAccountR = do { tm <- getRouteToParent; mr <- lift getMessageRender; ((result, _), _) <- lift $ runFormPost $ renderDivs newAccountForm; mdata <- case result of { FormMissing -> invalidArgs ["Form is missing"] FormFailure msg -> return $ Left msg FormSuccess d -> return $ if newAccountPassword1 d == newAccountPassword2 d then Right d else Left [mr PassMismatch] }; case mdata of { Left errs -> do { setMessage $ toHtml $ concat errs; redirect newAccountR } Right d -> do { void $ lift $ createNewAccount d tm; redirect LoginR } } } allowPasswordReset _ = True getResetPasswordR = do { tm <- getRouteToParent; lift $ defaultLayout $ do { setTitleI PasswordResetTitle; resetPasswordWidget tm } } setPasswordHandler u = do { tm <- getRouteToParent; lift $ defaultLayout $ do { setTitleI SetPassTitle; newPasswordWidget u tm } } renderAccountMessage _ _ = defaultAccountMsg

-- | Run a database action. This is the only required method.
runAccountDB :: YesodAuthAccount db master => db a -> HandlerT master IO a

-- | A form validator for valid usernames during new account creation.
--   
--   By default this allows usernames made up of <a>isAlphaNum</a>. You can
--   also ignore this validation and instead validate in <a>addNewUser</a>,
--   but validating here allows the validation to occur before database
--   activity (checking existing username) and before random salt creation
--   (requires IO).
checkValidUsername :: (YesodAuthAccount db master, MonadHandler m, HandlerSite m ~ master) => Username -> m (Either Text Username)

-- | What to do when the user logs in and the email has not yet been
--   verified.
--   
--   By default, this displays a message and contains
--   <a>resendVerifyEmailForm</a>, allowing the user to resend the
--   verification email. The handler is run inside the post handler for
--   login, so you can call <a>setCreds</a> to preform a successful login.
unregisteredLogin :: YesodAuthAccount db master => UserAccount db -> HandlerT Auth (HandlerT master IO) Html

-- | The new account page.
--   
--   This is the page which is displayed on a GET to <a>newAccountR</a>,
--   and defaults to an embedding of <a>newAccountWidget</a>.
getNewAccountR :: YesodAuthAccount db master => HandlerT Auth (HandlerT master IO) Html

-- | Handles new account creation.
--   
--   By default, this processes <a>newAccountForm</a>, calls
--   <a>createNewAccount</a>, sets a message and redirects to LoginR. If an
--   error occurs, a message is set and the user is redirected to
--   <a>newAccountR</a>.
postNewAccountR :: YesodAuthAccount db master => HandlerT Auth (HandlerT master IO) Html

-- | Should the password reset inside this plugin be allowed? Defaults to
--   True
allowPasswordReset :: YesodAuthAccount db master => master -> Bool

-- | The page which prompts for a username and sends an email allowing
--   password reset. By default, it embeds <a>resetPasswordWidget</a>.
getResetPasswordR :: YesodAuthAccount db master => HandlerT Auth (HandlerT master IO) Html

-- | The page which allows the user to set a new password.
--   
--   This is called only when the email key has been verified as correct.
--   By default, it embeds <a>newPasswordWidget</a>.
setPasswordHandler :: YesodAuthAccount db master => UserAccount db -> HandlerT Auth (HandlerT master IO) Html

-- | Used for i18n of <a>AccountMsg</a>, defaults to
--   <a>defaultAccountMsg</a>. To support multiple languages, you can
--   implement this method using the various translations from
--   <a>Yesod.Auth.Account.Message</a>.
renderAccountMessage :: YesodAuthAccount db master => master -> [Text] -> AccountMsg -> Text

-- | Salt and hash a password.
hashPassword :: MonadIO m => Text -> m ByteString

-- | Verify a password
verifyPassword :: Text -> ByteString -> Bool

-- | Randomly create a new verification key.
newVerifyKey :: MonadIO m => m Text
instance GHC.Base.Applicative (Yesod.Auth.Account.AccountPersistDB master user)
instance GHC.Base.Functor (Yesod.Auth.Account.AccountPersistDB master user)
instance Control.Monad.IO.Class.MonadIO (Yesod.Auth.Account.AccountPersistDB master user)
instance GHC.Base.Monad (Yesod.Auth.Account.AccountPersistDB master user)
instance GHC.Show.Show Yesod.Auth.Account.NewPasswordData
instance GHC.Show.Show Yesod.Auth.Account.NewAccountData
instance GHC.Show.Show Yesod.Auth.Account.LoginData
instance Yesod.Auth.Account.YesodAuthAccount db master => Text.Shakespeare.I18N.RenderMessage master Yesod.Auth.Account.Message.AccountMsg
instance (Database.Persist.Class.PersistEntity.PersistEntity u, Yesod.Auth.Account.PersistUserCredentials u) => Yesod.Auth.Account.UserCredentials (Database.Persist.Class.PersistEntity.Entity u)
instance (Yesod.Core.Class.Yesod.Yesod master, Yesod.Auth.Account.PersistUserCredentials user) => Yesod.Auth.Account.AccountDB (Yesod.Auth.Account.AccountPersistDB master user)
