packages feed

doc-review-0.7: src/State/Types.hs

{-# LANGUAGE OverloadedStrings #-}
module State.Types
    ( Comment(..)

    , ChapterId
    , chapterId
    , mkChapterId

    , CommentId
    , commentId
    , mkCommentId

    , State(..)
    , SessionId(..)
    , SessionInfo(..)
    )
where

import Control.Applicative ( (<$>), (<*>) )
import qualified Data.Text as T
import qualified Data.Text.Encoding as E
import Data.Binary ( Binary(..), Get )
import Data.Time.Clock.POSIX ( POSIXTime )
import qualified Data.ByteString as B
import Network.URI ( URI )

newtype CommentId = CommentId { commentId :: T.Text } deriving (Ord, Eq, Show)
instance Binary CommentId where
    get = CommentId . E.decodeUtf8 <$> get
    put = put . E.encodeUtf8 . commentId

newtype ChapterId = ChapterId { chapterId :: T.Text } deriving (Ord, Eq, Show)
instance Binary ChapterId where
    get = ChapterId . E.decodeUtf8 <$> get
    put = put . E.encodeUtf8 . chapterId

data SessionInfo = SessionInfo { siName :: !T.Text
                               , siEmail :: !(Maybe T.Text)
                               } deriving (Eq, Show)

data State =
    State
    { findComments       :: CommentId -> IO [Comment]
    , getCounts          :: Maybe ChapterId -> IO [(CommentId, Int)]
    , getLastInfo        :: SessionId -> IO (Maybe SessionInfo)
    , getChapterComments :: ChapterId -> IO [(CommentId, Comment)]
    , getChapterURI      :: ChapterId -> IO (Maybe URI)

    , addComment         :: CommentId -> Maybe ChapterId -> Comment -> IO ()
    , addChapter         :: ChapterId -> [CommentId] -> Maybe URI -> IO ()
    }

data Comment =
    Comment
    { cName    :: !T.Text
    , cComment :: !T.Text
    , cEmail   :: Maybe T.Text
    , cDate    :: !POSIXTime
    , cSession :: !SessionId
    } deriving (Show, Eq)

newtype SessionId =
    SessionId { sidBS :: B.ByteString }
    deriving ( Eq, Show, Ord )

instance Binary Comment where
    put (Comment name comment email date sid) =
        do putU8 name
           putU8 comment
           put (E.encodeUtf8 <$> email)
           put (realToFrac date :: Double)
           put $ sidBS sid
        where putU8 = put . E.encodeUtf8

    get = Comment
          <$> getU8
          <*> getU8
          <*> (fmap E.decodeUtf8 <$> get)
          <*> fmap realToFrac (get :: Get Double)
          <*> fmap SessionId get
        where getU8 = E.decodeUtf8 <$> get

-- These functions allow any text content as comment and chapter ids,
-- but we may want to be able to restrict these to allow only things
-- that could appear in the wild (or at least some length
-- restrictions).
mkCommentId :: T.Text -> Maybe CommentId
mkCommentId = Just . CommentId

mkChapterId :: T.Text -> Maybe ChapterId
mkChapterId = Just . ChapterId