{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE OverloadedStrings #-}
module Web.Tracker.Story where
import Data.Aeson
import Data.Aeson.Casing
import Data.String
import Data.Text (Text)
import qualified Data.Text as T
import Data.Time.Clock
import GHC.Generics
import Servant.API
import Text.Read
data StoryId
= StoryId Integer
deriving (Show, Eq, Ord)
instance FromJSON StoryId where
parseJSON = fmap StoryId . parseJSON
instance Read StoryId where
readPrec = fmap StoryId readPrec
instance ToJSON StoryId where
toJSON (StoryId t) = toJSON t
instance ToHttpApiData StoryId where
toUrlPiece (StoryId t) = toUrlPiece t
data ProjectId
= ProjectId Int
deriving (Show, Eq, Ord)
instance FromJSON ProjectId where
parseJSON = fmap ProjectId . parseJSON
instance Read ProjectId where
readPrec = fmap ProjectId readPrec
instance ToHttpApiData ProjectId where
toUrlPiece (ProjectId t) = toUrlPiece t
data UserId
= UserId Int
deriving (Show, Eq, Ord)
instance FromJSON UserId where
parseJSON = fmap UserId . parseJSON
data StoryState
= Accepted | Delivered | Finished | Started
| Rejected | Planned | Unstarted | Unscheduled
deriving (Show, Eq, Ord, Enum, Bounded)
instance FromJSON StoryState where
parseJSON = withText "StoryState" $ \case
"accepted" -> return Accepted
"delivered" -> return Delivered
"finished" -> return Finished
"started" -> return Started
"rejected" -> return Rejected
"planned" -> return Planned
"unstarted" -> return Unstarted
"unscheduled" -> return Unscheduled
other -> fail $ "Invalid story state: " ++ T.unpack other
instance ToJSON StoryState where
toJSON = toJSON . toUrlPiece
instance ToHttpApiData StoryState where
toUrlPiece = \case
Accepted -> "accepted"
Delivered -> "delivered"
Finished -> "finished"
Started -> "started"
Rejected -> "rejected"
Planned -> "planned"
Unstarted -> "unstarted"
Unscheduled -> "unscheduled"
data StoryType
= Feature | Bug | Chore | Release
deriving (Show, Eq, Ord)
instance FromJSON StoryType where
parseJSON = withText "StoryType" $ \case
"feature" -> return Feature
"bug" -> return Bug
"chore" -> return Chore
"release" -> return Release
other -> fail $ "Invalid StoryType: " ++ T.unpack other
data UpdateStory
= SetStoryState StoryState
instance ToJSON UpdateStory where
toJSON (SetStoryState state)
= object [ "current_state" .= state ]
data Story = Story
{ sId :: StoryId
, sProjectId :: ProjectId
, sName :: Text
, sDescription :: Maybe Text
, sStoryType :: StoryType
, sCurrentState :: StoryState
, sEstimate :: Maybe Double
, sAcceptedAt :: Maybe UTCTime
, sRequestedById :: UserId
, sOwnerIds :: [UserId]
, sCreatedAt :: UTCTime
, sUpdatedAt :: UTCTime
, sUrl :: Text
} deriving (Show, Generic)
instance FromJSON Story where
parseJSON = genericParseJSON $ aesonPrefix snakeCase