packages feed

darcsden-1.1: src/DarcsDen/State/Comment.hs

module DarcsDen.State.Comment where

import Control.Monad.Trans
import Data.Time (UTCTime, formatTime)
import Database.CouchDB
import System.Locale (defaultTimeLocale)
import Text.JSON

import DarcsDen.State.Util
import DarcsDen.State.Issue


data IssueChange
    = AddTag String
    | RemoveTag String
    | Summary String String
    | Description String String
    | Closed Bool
    deriving (Eq, Show)

instance JSON IssueChange where
    readJSON js = do
        ctype <- getAttr js "type"
        case ctype of
            "add-tag" -> do
                s <- getAttr js "name"
                return (AddTag s)

            "remove-tag" -> do
                s <- getAttr js "name"
                return (RemoveTag s)

            "summary" -> do
                f <- getAttrOr js "from" ""
                t <- getOneOf js "to" "value"
                return (Summary f t)

            "description" -> do
                f <- getAttrOr js "from" ""
                t <- getOneOf js "to" "value"
                return (Description f t)

            "closed" -> do
                b <- getAttr js "state"
                return (Closed b)

            _ -> fail ("unknown type: " ++ ctype)

    showJSON (AddTag t) = JSObject . toJSObject $
        [ ("type", showJSON "add-tag")
        , ("name", showJSON t)
        ]
    showJSON (RemoveTag t) = JSObject . toJSObject $
        [ ("type", showJSON "remove-tag")
        , ("name", showJSON t)
        ]
    showJSON (Summary f t) = JSObject . toJSObject $
        [ ("type", showJSON "summary")
        , ("from", showJSON f)
        , ("to", showJSON t)
        ]
    showJSON (Description f t) = JSObject . toJSObject $
        [ ("type", showJSON "description")
        , ("from", showJSON f)
        , ("to", showJSON t)
        ]
    showJSON (Closed c) = JSObject . toJSObject $
        [ ("type", showJSON "closed")
        , ("state", showJSON c)
        ]

data Comment =
    Comment
        { cID :: Maybe Doc
        , cRev :: Maybe Rev
        , cBody :: String
        , cChanges :: [IssueChange]
        , cAuthor :: String
        , cCreated :: UTCTime
        , cUpdated :: UTCTime
        , cIssue :: Doc
        }
    deriving (Eq, Show)

instance JSON Comment where
    readJSON o = do
        id' <- getID o
        rev' <- getRev o
        body <- getAttr o "body"
        changes <- getAttr o "changes"
        author <- getAttr o "author"
        created <- getTime o "created"
        updated <- getTime o "updated"
        issue <- getAttr o "issue"
        return Comment
            { cID = Just id'
            , cRev = Just rev'
            , cBody = body
            , cChanges = changes
            , cAuthor = author
            , cCreated = created
            , cUpdated = updated
            , cIssue = issue
            }

    showJSON c = JSObject . toJSObject $
        [ ("body", showJSON (cBody c))
        , ("changes", showJSON (cChanges c))
        , ("author", showJSON (cAuthor c))
        , ("created", showJSON (formatTime defaultTimeLocale "%F %T" (cCreated c)))
        , ("updated", showJSON (formatTime defaultTimeLocale "%F %T" (cUpdated c)))
        , ("issue", showJSON (cIssue c))
        ] ++ id' ++ rev'
      where
        id' =
            case cID c of
                Just id'' -> [("_id", showJSON (show id''))]
                Nothing -> []
        rev' =
            case cRev c of
                Just rev'' -> [("_rev", showJSON (show rev''))]
                Nothing -> []

getComment :: MonadIO m => Doc -> m (Maybe Comment)
getComment key = do
    res <- liftIO $ runDB (getDoc (db "comments") key)
    case res of
        Just (_, _, i) -> return (Just i)
        Nothing -> return Nothing

getComments :: MonadIO m => Issue -> m [Comment]
getComments (Issue { iID = Just issue }) =
    liftIO $ fmap (map snd) (runDB query)
  where
    query = queryView
        (db "comments")
        (doc "comments")
        (doc "by_issue")
        [("key", showJSON issue)]
getComments _ = error "getComments: unsaved issue"

addComment :: MonadIO m => Comment -> m Comment
addComment c = do
    (id', rev') <- liftIO $ runDB (newDoc (db "comments") c)
    return c { cID = Just id', cRev = Just rev' }

updateComment :: MonadIO m => Comment -> m (Maybe Comment)
updateComment c =
    case (cID c, cRev c) of
        (Just id', Just rev') -> do
            update <-
                liftIO . runDB $ updateDoc (db "comments") (id', rev') c
                    { cID = Nothing }

            case update of
                Just (id'', rev'') -> return $ Just c
                    { cID = Just id''
                    , cRev = Just rev''
                    }
                _ -> return Nothing
        _ -> return Nothing