{-# LANGUAGE DeriveDataTypeable, FlexibleContexts, FlexibleInstances, MultiParamTypeClasses, RankNTypes, TypeFamilies, TypeSynonymInstances, UndecidableInstances, OverloadedStrings #-} module Clckwrks.MailingList.Monad where import Clckwrks (Clck, ClckT(..), ClckFormT, ClckState(..), ClckURL(..), mapClckT, withRouteT) import Clckwrks.Acid import Clckwrks.IOThread (IOThread(..), startIOThread, killIOThread) import Clckwrks.MailingList.Acid import Clckwrks.MailingList.Types import Clckwrks.MailingList.URL import Control.Applicative ((<$>)) import Control.Exception (bracket) import Control.Monad.Reader (ReaderT(..), MonadReader(..)) import Control.Monad.State (get) import Control.Monad.Trans (MonadIO, lift) import Clckwrks.Plugin (clckPlugin) import Data.Acid (AcidState) import Data.Acid.Local (createCheckpointAndClose, openLocalStateFrom) import Data.Typeable (Typeable) import qualified Data.Map as Map import Data.Maybe (fromMaybe) import qualified Data.Text as T import qualified Data.Text.Lazy as TL import Happstack.Server import Happstack.Server.Internal.Monads (FilterFun) import HSP (Attr((:=)), Attribute(MkAttr), EmbedAsAttr(..), EmbedAsChild(..), IsName(toName), XMLGenT, XML, pAttrVal) import System.Directory (createDirectoryIfMissing) import System.FilePath (()) import Text.Reform (CommonFormError, FormError(..)) import Web.Plugins.Core (Plugin(..), getConfig, getPluginsSt, getPluginRouteFn) import Web.Routes (URL, MonadRoute, showURL) data MailingListConfig = MailingListConfig { mailingListState :: AcidState MailingListState , mailingListClckURL :: ClckURL -> [(T.Text, Maybe T.Text)] -> T.Text } deriving Typeable type MailingListT m = ClckT MailingListURL (ReaderT MailingListConfig m) type MailingListM = ClckT MailingListURL (ReaderT MailingListConfig (ServerPartT IO)) data MailingListFormError = MailingListCFE (CommonFormError [Input]) | InvalidEmail | MissingLink | MissingSubject | SendmailNotFound deriving Show instance FormError MailingListFormError where type ErrorInputType MailingListFormError = [Input] commonFormError = MailingListCFE instance (Functor m, Monad m) => EmbedAsChild (MailingListT m) MailingListFormError where asChild InvalidEmail = asChild ("This is definitely not a valid email address." :: T.Text) asChild e = asChild (show e) type MailingListForm = ClckFormT MailingListFormError MailingListM instance (IsName n TL.Text) => EmbedAsAttr MailingListM (Attr n MailingListURL) where asAttr (n := u) = do url <- showURL u asAttr $ MkAttr (toName n, pAttrVal (TL.fromStrict url)) instance (IsName n TL.Text) => EmbedAsAttr MailingListM (Attr n ClckURL) where asAttr (n := url) = do showFn <- mailingListClckURL <$> ask asAttr $ MkAttr (toName n, pAttrVal (TL.fromStrict $ showFn url [])) runMailingListT :: MailingListConfig -> MailingListT m a -> ClckT MailingListURL m a runMailingListT mc m = mapClckT f m where f r = runReaderT r mc runMailingListT'' :: Monad m => (MailingListURL -> [(T.Text, Maybe T.Text)] -> T.Text) -> MailingListConfig -> MailingListT m a -> ClckT url m a runMailingListT'' showMailingListURL stripeConfig m = ClckT $ withRouteT flattenURL $ unClckT $ runMailingListT stripeConfig $ m where flattenURL :: ((url' -> [(T.Text, Maybe T.Text)] -> T.Text) -> (MailingListURL -> [(T.Text, Maybe T.Text)] -> T.Text)) flattenURL _ u p = showMailingListURL u p instance (Monad m) => MonadReader MailingListConfig (MailingListT m) where ask = ClckT $ ask local f (ClckT m) = ClckT $ local f m instance (Functor m, Monad m) => GetAcidState (MailingListT m) MailingListState where getAcidState = mailingListState <$> ask 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 clckT2MailingListT :: (Functor m, MonadIO m, Typeable url1) => ClckT url1 m a -> MailingListT m a clckT2MailingListT m = do p <- plugins <$> get (Just clckShowFn) <- getPluginRouteFn p (pluginName clckPlugin) flattenURLClckT clckShowFn $ mapClckT addReaderT m where addReaderT :: (Monad m) => m (a, ClckState) -> ReaderT MailingListConfig m (a, ClckState) addReaderT m = do (a, cs) <- lift m return (a, cs)