{-# LANGUAGE FlexibleContexts, FlexibleInstances, MultiParamTypeClasses, RecordWildCards, TypeFamilies, TypeSynonymInstances #-} module Clckwrks.Redirect.Monad where import Control.Applicative ((<$>)) import Control.Monad (foldM) import Control.Monad.Fail (MonadFail(fail)) import Control.Monad.Reader (MonadReader(ask,local), ReaderT(runReaderT)) import Control.Monad.State (StateT, put, get, modify) import Control.Monad.Trans (MonadIO(liftIO)) import qualified Data.Text.Lazy as LT import Clckwrks.Acid (GetAcidState(..)) import Clckwrks.Monad (Content(..), ClckT(..), ClckFormT, ClckState(..), ClckPluginsSt(..), mapClckT, runClckT, withRouteClckT, getPreProcessors) import Clckwrks.URL (ClckURL) import Clckwrks.Redirect.Acid (RedirectState(..)) import Clckwrks.Redirect.Types () import Clckwrks.Redirect.URL (RedirectURL(..), RedirectAdminURL(..)) import Clckwrks.Redirect.Types () import Clckwrks.Plugin (clckPlugin) import Control.Monad.Trans (lift) import Data.Acid (AcidState) import Data.Data (Typeable) import qualified Data.Text as T import qualified Data.Text.Lazy as TL import Happstack.Server (Happstack, Input, ServerPartT) import HSP.XMLGenerator import HSP.XML import Text.Reform (CommonFormError, FormError(..)) import Web.Plugins.Core (Plugin(..), getConfig, getPluginsSt, getPluginRouteFn) import Web.Routes (RouteT(..), showURL, withRouteT) data RedirectConfig = RedirectConfig { redirectState :: AcidState RedirectState , redirectClckURL :: ClckURL -> [(T.Text, Maybe T.Text)] -> T.Text } type RedirectT m = ClckT RedirectURL (ReaderT RedirectConfig m) type RedirectT' url m = ClckT url (ReaderT RedirectConfig m) type RedirectM = ClckT RedirectURL (ReaderT RedirectConfig (ServerPartT IO)) type RedirectAdminM = ClckT RedirectAdminURL (ReaderT RedirectConfig (ServerPartT IO)) runRedirectT :: RedirectConfig -> RedirectT m a -> ClckT RedirectURL m a runRedirectT mc m = mapClckT f m where f r = runReaderT r mc runRedirectT'' :: Monad m => (RedirectURL -> [(T.Text, Maybe T.Text)] -> T.Text) -> RedirectConfig -> RedirectT m a -> ClckT url m a runRedirectT'' showRedirectURL stripeConfig m = ClckT $ withRouteT flattenURL $ unClckT $ runRedirectT stripeConfig $ m where flattenURL :: ((url' -> [(T.Text, Maybe T.Text)] -> T.Text) -> (RedirectURL -> [(T.Text, Maybe T.Text)] -> T.Text)) flattenURL _ u p = showRedirectURL u p -- withRouteClckT ? flattenURLClckT :: (url1 -> [(T.Text, Maybe T.Text)] -> T.Text) -> ClckT url1 m a -> ClckT url2 m a flattenURLClckT showClckURL m = ClckT $ withRouteT flattenURL $ unClckT m where flattenURL _ = \u p -> showClckURL u p clckT2RedirectT :: (Functor m, MonadIO m, MonadFail m, Typeable url1) => ClckT url1 m a -> RedirectT m a clckT2RedirectT m = do p <- plugins <$> get (Just clckShowFn) <- getPluginRouteFn p (pluginName clckPlugin) flattenURLClckT clckShowFn $ mapClckT addReaderT m where addReaderT :: (Monad m) => m (a, ClckState) -> ReaderT RedirectConfig m (a, ClckState) addReaderT m = do (a, cs) <- lift m return (a, cs) data RedirectFormError = RedirectCFE (CommonFormError [Input]) | RedirectErrorInternal deriving Show instance FormError RedirectFormError where type ErrorInputType RedirectFormError = [Input] commonFormError = RedirectCFE instance (Functor m, Monad m) => EmbedAsChild (RedirectT m) RedirectFormError where asChild e = asChild (show e) type RedirectForm = ClckFormT RedirectFormError RedirectM instance (Monad m) => MonadReader RedirectConfig (RedirectT' url m) where ask = ClckT $ ask local f (ClckT m) = ClckT $ local f m instance (Functor m, Monad m) => GetAcidState (RedirectT' url m) RedirectState where getAcidState = redirectState <$> ask instance (IsName n TL.Text) => EmbedAsAttr RedirectM (Attr n RedirectURL) where asAttr (n := u) = do url <- showURL u asAttr $ MkAttr (toName n, pAttrVal (TL.fromStrict url)) instance (IsName n TL.Text) => EmbedAsAttr RedirectM (Attr n ClckURL) where asAttr (n := url) = do showFn <- redirectClckURL <$> ask asAttr $ MkAttr (toName n, pAttrVal (TL.fromStrict $ showFn url [])) {- -- | convert 'Markup' to 'Content' that can be embedded. Generally by running the pre-processors needed. -- markupToContent :: (Functor m, MonadIO m, Happstack m) => Markup -> ClckT url m Content markupToContent :: (Functor m, MonadIO m, Happstack m) => Markup -> ClckT url m Content markupToContent Markup{..} = do clckState <- get transformers <- getPreProcessors (plugins clckState) (Just clckRouteFn) <- getPluginRouteFn (plugins clckState) (pluginName clckPlugin) (markup', clckState') <- liftIO $ runClckT clckRouteFn clckState (foldM (\txt pp -> pp txt) (TL.fromStrict markup) transformers) put clckState' e <- liftIO $ runPreProcessors preProcessors trust (TL.toStrict markup') case e of (Left err) -> return (PlainText err) (Right html) -> return (TrustedHtml html) {- -- | update the 'currentRedirect' field of 'ClckState' setCurrentRedirect :: (MonadIO m) => RedirectId -> RedirectT m () setCurrentRedirect pid = modify $ \s -> s { pageCurrent = pid } -} -}