205 lines
6.9 KiB
Haskell
205 lines
6.9 KiB
Haskell
{-# LANGUAGE UndecidableInstances #-} -- for `MonadCrypto` and `MonadSecretBox`
|
|
{-# OPTIONS_GHC -fno-warn-orphans #-}
|
|
|
|
module Foundation.Instances
|
|
( ButtonClass(..), YesodPersistBackend, AuthId, MonadCryptoKey
|
|
, unsafeHandler
|
|
) where
|
|
|
|
import Import.NoFoundation
|
|
|
|
import qualified Data.Text as Text
|
|
import qualified Data.List as List
|
|
import Data.List (inits)
|
|
|
|
import qualified Yesod.Core.Unsafe as Unsafe
|
|
import qualified Yesod.Auth.Message as Auth
|
|
|
|
import Utils.Form
|
|
import Auth.LDAP
|
|
import Auth.PWHash
|
|
import Auth.Dummy
|
|
|
|
import qualified Foundation.Yesod.Session as UniWorX
|
|
import qualified Foundation.Yesod.Middleware as UniWorX
|
|
import qualified Foundation.Yesod.ErrorHandler as UniWorX
|
|
import qualified Foundation.Yesod.StaticContent as UniWorX
|
|
import qualified Foundation.Yesod.Persist as UniWorX
|
|
import qualified Foundation.Yesod.Auth as UniWorX
|
|
|
|
import Foundation.SiteLayout
|
|
import Foundation.Type
|
|
import Foundation.I18n
|
|
import Foundation.Authorization
|
|
import Foundation.Yesod.Auth hiding (authenticate)
|
|
import Foundation.Routes
|
|
import Foundation.DB
|
|
|
|
import Network.Wai.Parse (lbsBackEnd)
|
|
|
|
import Control.Monad.Writer.Class (MonadWriter(..))
|
|
import UnliftIO.Pool (withResource)
|
|
|
|
|
|
data instance ButtonClass UniWorX
|
|
= BCIsButton
|
|
| BCDefault
|
|
| BCPrimary
|
|
| BCSuccess
|
|
| BCInfo
|
|
| BCWarning
|
|
| BCDanger
|
|
| BCLink
|
|
| BCMassInputAdd | BCMassInputDelete
|
|
| BCScheduleView | BCScheduleOffset
|
|
deriving (Enum, Eq, Ord, Bounded, Read, Show, Generic, Typeable)
|
|
deriving anyclass (Universe, Finite)
|
|
|
|
instance PathPiece (ButtonClass UniWorX) where
|
|
toPathPiece BCIsButton = "btn"
|
|
toPathPiece bClass = ("btn-" <>) . camelToPathPiece' 1 $ tshow bClass
|
|
fromPathPiece = flip List.lookup $ map (toPathPiece &&& id) universeF
|
|
|
|
instance Button UniWorX ButtonSubmit where
|
|
btnClasses BtnSubmit = [BCIsButton, BCPrimary]
|
|
|
|
|
|
|
|
-- Please see the documentation for the Yesod typeclass. There are a number
|
|
-- of settings which can be configured by overriding methods here.
|
|
instance Yesod UniWorX where
|
|
-- Controls the base of generated URLs. For more information on modifying,
|
|
-- see: https://github.com/yesodweb/yesod/wiki/Overriding-approot
|
|
approot = ApprootRequest $ \app req ->
|
|
case app ^. _appRoot of
|
|
Nothing -> getApprootText guessApproot app req
|
|
Just root -> root
|
|
|
|
makeSessionBackend = UniWorX.makeSessionBackend
|
|
|
|
maximumContentLength app _ = app ^. _appMaximumContentLength
|
|
|
|
-- Yesod Middleware allows you to run code before and after each handler function.
|
|
-- The defaultYesodMiddleware adds the response header "Vary: Accept, Accept-Language" and performs authorization checks.
|
|
-- Some users may also want to add the defaultCsrfMiddleware, which:
|
|
-- a) Sets a cookie with a CSRF token in it.
|
|
-- b) Validates that incoming write requests include that token in either a header or POST parameter.
|
|
-- To add it, chain it together with the defaultMiddleware: yesodMiddleware = defaultYesodMiddleware . defaultCsrfMiddleware
|
|
-- For details, see the CSRF documentation in the Yesod.Core.Handler module of the yesod-core package.
|
|
yesodMiddleware = UniWorX.yesodMiddleware
|
|
|
|
-- Since we implement `errorHandler` ourselves we don't need `defaultMessageWidget`
|
|
defaultMessageWidget _title _body = error "defaultMessageWidget: undefined"
|
|
|
|
errorHandler = UniWorX.errorHandler
|
|
|
|
defaultLayout = siteLayout' Nothing
|
|
|
|
-- The page to be redirected to when authentication is required.
|
|
authRoute _ = Just $ AuthR LoginR
|
|
|
|
isAuthorized = evalAccess
|
|
|
|
addStaticContent = UniWorX.addStaticContent
|
|
|
|
fileUpload _site _length = FileUploadMemory lbsBackEnd
|
|
|
|
-- What messages should be logged. The following includes all messages when
|
|
-- in development, and warnings and errors in production.
|
|
shouldLogIO app _source level = do
|
|
LogSettings{..} <- readTVarIO $ appLogSettings app
|
|
return $ logAll || level >= logMinimumLevel
|
|
|
|
makeLogger = readTVarIO . snd . appLogger
|
|
|
|
unsafeHandler :: UniWorX -> HandlerFor UniWorX a -> IO a
|
|
unsafeHandler f h = do
|
|
logger <- makeLogger f
|
|
Unsafe.fakeHandlerGetLogger (const logger) f h
|
|
|
|
|
|
-- How to run database actions.
|
|
instance YesodPersist UniWorX where
|
|
type YesodPersistBackend UniWorX = SqlBackend
|
|
runDB = UniWorX.runDB
|
|
|
|
instance YesodPersistRunner UniWorX where
|
|
getDBRunner = UniWorX.getDBRunner
|
|
|
|
|
|
instance YesodAuth UniWorX where
|
|
type AuthId UniWorX = UserId
|
|
|
|
-- Where to send a user after successful login
|
|
loginDest _ = NewsR
|
|
-- Where to send a user after logout
|
|
logoutDest _ = NewsR
|
|
-- Override the above two destinations when a Referer: header is present
|
|
redirectToReferer _ = True
|
|
|
|
loginHandler = do
|
|
toParent <- getRouteToParent
|
|
liftHandler . defaultLayout $ do
|
|
plugins <- getsYesod authPlugins
|
|
$logDebugS "Auth" $ "Enabled plugins: " <> Text.intercalate ", " (map apName plugins)
|
|
|
|
setTitleI MsgLoginTitle
|
|
$(widgetFile "login")
|
|
|
|
authenticate = UniWorX.authenticate
|
|
|
|
authPlugins UniWorX{ appSettings' = AppSettings{..}, appLdapPool } = catMaybes
|
|
[ flip campusLogin campusUserFailoverMode <$> appLdapPool
|
|
, Just . hashLogin $ pwHashAlgorithm appAuthPWHash
|
|
, dummyLogin <$ guard appAuthDummyLogin
|
|
]
|
|
|
|
authHttpManager = getsYesod appHttpManager
|
|
|
|
onLogin = liftHandler $ do
|
|
mlang <- runDB $ updateUserLanguage Nothing
|
|
app <- getYesod
|
|
let mr | Just lang <- mlang = renderMessage app . map (Text.intercalate "-") . reverse . inits $ Text.splitOn "-" lang
|
|
| otherwise = renderMessage app []
|
|
addMessage Success . toHtml $ mr Auth.NowLoggedIn
|
|
|
|
onErrorHtml dest msg = do
|
|
addMessage Error $ toHtml msg
|
|
redirect dest
|
|
|
|
renderAuthMessage _ ls = case lang of
|
|
("en" : _) -> Auth.englishMessage
|
|
_other -> Auth.germanMessage
|
|
where lang = Text.splitOn "-" $ selectLanguage' appLanguages ls
|
|
|
|
instance YesodAuthPersist UniWorX where
|
|
getAuthEntity = liftHandler . runDBRead . get
|
|
|
|
|
|
instance YesodMail UniWorX where
|
|
defaultFromAddress = getsYesod $ view _appMailFrom
|
|
mailObjectIdDomain = getsYesod $ view _appMailObjectDomain
|
|
mailVerp = getsYesod $ view _appMailVerp
|
|
mailDateTZ = return appTZ
|
|
mailSmtp act = do
|
|
pool <- maybe (throwM MailNotAvailable) return =<< getsYesod appSmtpPool
|
|
withResource pool act
|
|
mailT ctx mail = defMailT ctx $ do
|
|
void setMailObjectIdRandom
|
|
setDateCurrent
|
|
replaceMailHeader "Sender" . Just =<< getsYesod (view $ _appMailFrom . _addressEmail)
|
|
|
|
(mRes, smtpData) <- listen mail
|
|
unless (view _MailSmtpDataSet smtpData)
|
|
setMailSmtpData
|
|
|
|
return mRes
|
|
|
|
|
|
instance (MonadThrow m, MonadHandler m, HandlerSite m ~ UniWorX) => MonadCrypto m where
|
|
type MonadCryptoKey m = CryptoIDKey
|
|
cryptoIDKey f = getsYesod appCryptoIDKey >>= f
|
|
|
|
instance {-# OVERLAPPING #-} (Monad m, MonadHandler m, HandlerSite m ~ UniWorX) => MonadSecretBox m where
|
|
secretBoxKey = getsYesod appSecretBoxKey
|