{-# 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