hoggl-0.2.0.1: main/Main.hs
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE OverloadedStrings #-}
module Main where
import Control.Monad (when)
import Control.Monad.IO.Class (liftIO)
import Data.Foldable (for_)
import Data.Function (on)
import Data.List (groupBy,sortOn)
import Data.Monoid ((<>))
import qualified Data.Text as T
import qualified Data.Text.IO as T
import Data.Time.Calendar (Day, fromGregorian, toGregorian)
import Data.Time.Calendar.WeekDate (toWeekDate, fromWeekDate)
import Data.Time.Clock (UTCTime(..), getCurrentTime)
import Data.Time.Format (formatTime, defaultTimeLocale, parseTimeM)
import Formatting (sformat, (%))
import qualified Formatting as F
import qualified Formatting.Time as F
import GHC.IO.Handle.FD (stderr)
import Network.HTTP.Client (newManager)
import Network.HTTP.Client.TLS (tlsManagerSettings)
import Options.Applicative
import Servant.Client
import System.Exit (exitFailure, exitFailure)
import System.IO (hPutStrLn)
import Network.Hoggl
import Network.Hoggl.Types
import Network.Hoggl.Pretty
main :: IO ()
main = execParser opts >>= run
where opts = info (helper <*> hoggleArgsParser)
(fullDesc
<> progDesc "Haskell client for Toggl."
<> header "hoggl - the Haskell Toggl client.")
run :: HoggleArgs -> IO ()
run (HoggleArgs auth _ TimeToday) = do
manager <- newManager tlsManagerSettings
let clientEnv = mkClientEnv manager togglBaseUrl
e <- runClientM (timeEntriesToday auth) clientEnv
case e of
Left _ -> die "There was an error."
Right ts -> do
ds <- traverse calcDuration ts
T.putStrLn (pretty (sum ds))
run (HoggleArgs auth _ TimeWeek) = do
day <- utctDay <$> getCurrentTime
let (year,weekNr,dow) = toWeekDate day
doReport auth (fromWeekDate year weekNr 1) (fromWeekDate year weekNr dow)
run (HoggleArgs auth _ TimeMonth) = do
day <- utctDay <$> getCurrentTime
let (year,month,dom) = toGregorian day
doReport auth (fromGregorian year month 1) (fromGregorian year month dom)
run (HoggleArgs auth _ StartTimer) = do
e <- tryStartDefault auth
case e of
Left _ -> die "Failed to start timer."
Right _ -> return ()
run (HoggleArgs auth _ StopTimer) = do
e <- tryStopRunning auth
case e of
Left _ -> die "Failed to stop timer."
Right _ -> return ()
run (HoggleArgs auth _ Info) = do
manager <- newManager tlsManagerSettings
let clientEnv = mkClientEnv manager togglBaseUrl
e <- runClientM (listWorkspaces auth) clientEnv
case e of
Left _ -> die "Failed to get workspaces."
Right ws -> do
putStrLn "Workspaces:"
for_ ws (putStrLn . ("- " <>) . workspacePretty)
run (HoggleArgs auth workHours HowLong) = do
manager <- newManager tlsManagerSettings
let clientEnv = mkClientEnv manager togglBaseUrl
start <- utctDay <$> getCurrentTime
eCurLogged <- runClientM (timeEntriesFromTillNow auth start) clientEnv
case eCurLogged of
Left _ -> die "Failed to get time entries."
Right ts -> do
worked <- sum <$> traverse calcDuration ts
let diff = (fromIntegral workHours * 60 * 60) - worked
T.putStrLn (sformat ("Target of " % F.int % " hours reached: " % F.diff True) workHours diff)
run (HoggleArgs auth _ (Report rSince rUntil)) = do
tSince <- parseTimeM True defaultTimeLocale dateFormat rSince
tUntil <- case rUntil of
Just rUntil' -> parseTimeM True defaultTimeLocale dateFormat rUntil'
Nothing -> utctDay <$> getCurrentTime
doReport auth tSince tUntil
doReport :: Token -> Day -> Day -> IO ()
doReport auth tSince tUntil = do
manager <- newManager tlsManagerSettings
let clientEnv = mkClientEnv manager togglBaseUrl
eResult <- runClientM (do
ws <- listWorkspaces auth
when (length ws /= 1) (liftIO $ die "Ambiguous workspace")
detailedReport auth
(wsId (head ws))
(ISO6801Date tSince)
(ISO6801Date tUntil)
"hoggl") clientEnv
case eResult of
Left e -> do
print e
die "Failed to get report."
Right report -> do
for_ (groupBy ((==) `on` (utctDay . unpack . teStart)) . sortOn teStart . drData $ report) $ \tesPerDay -> do
durations <- traverse calcDuration tesPerDay
T.putStrLn (T.pack (formatTime defaultTimeLocale dateFormat (unpack (teStart (head tesPerDay))))
<> ": "
<> pretty (sum durations))
T.putStrLn ("Total: " <> pretty @Double (fromIntegral (drTotalGrand report)))
where unpack (ISO6801 x) = x
data HoggleArgs = HoggleArgs Token Integer HoggleCmd
data HoggleCmd = TimeToday
| TimeWeek
| TimeMonth
| StartTimer
| StopTimer
| HowLong
| Info
| Report {reportSince :: String
,reportUntil :: Maybe String
}
token :: Parser Token
token = Api <$> strOption (long "token" <> help "API Token")
workHoursOpt :: Parser Integer
workHoursOpt = option auto (long "hours"
<> value 8
<> showDefault
<> help "Number of hours to work per day.")
todayCmd :: Mod CommandFields HoggleCmd
todayCmd = command "today" (info (pure TimeToday) (progDesc "List today's time."))
weekCmd :: Mod CommandFields HoggleCmd
weekCmd = command "week" (info (pure TimeWeek) (progDesc "List this week's time."))
monthCmd :: Mod CommandFields HoggleCmd
monthCmd = command "month" (info (pure TimeMonth) (progDesc "List this month's time."))
startTimerCmd :: Mod CommandFields HoggleCmd
startTimerCmd = command "start" (info (pure StartTimer) (progDesc "Start a timer."))
stopTimerCmd :: Mod CommandFields HoggleCmd
stopTimerCmd = command "stop" (info (pure StopTimer) (progDesc "Stop the current timer."))
howLongCmd :: Mod CommandFields HoggleCmd
howLongCmd = command "howlong" (info (pure HowLong) (progDesc "How long until 8h reached."))
reportCmd :: Mod CommandFields HoggleCmd
reportCmd = command "report" (info (Report <$> strArgument (metavar "SINCE")
<*> optional (strArgument (metavar "UNTIL")))
(progDesc "Request a report for the specified time range."))
infoCmd :: Mod CommandFields HoggleCmd
infoCmd = command "info" (info (pure Info) (progDesc "Display workspaces, clients and projects"))
hoggleArgsParser :: Parser HoggleArgs
hoggleArgsParser = HoggleArgs
<$> token
<*> workHoursOpt
<*> subparser (todayCmd
<> weekCmd
<> monthCmd
<> startTimerCmd
<> stopTimerCmd
<> howLongCmd
<> reportCmd
<> infoCmd)
die :: String -> IO ()
die msg = hPutStrLn stderr msg >> exitFailure
dateFormat :: String
dateFormat = "%Y-%m-%d"