add fourmolu config; reformat using fourmolu
This commit is contained in:
parent
dfe275eedf
commit
74f96dc563
191
app/Main.hs
191
app/Main.hs
|
@ -2,11 +2,12 @@ module Main where
|
||||||
|
|
||||||
import Data.Text as T
|
import Data.Text as T
|
||||||
import Data.Text.IO as T
|
import Data.Text.IO as T
|
||||||
|
|
||||||
-- import Data.Time.Clock
|
-- import Data.Time.Clock
|
||||||
import Data.Time.LocalTime
|
import Data.Time.LocalTime
|
||||||
|
import NCDeck
|
||||||
import Options.Applicative
|
import Options.Applicative
|
||||||
import System.IO
|
import System.IO
|
||||||
import NCDeck
|
|
||||||
|
|
||||||
data Options = Options
|
data Options = Options
|
||||||
{ hostname :: Text
|
{ hostname :: Text
|
||||||
|
@ -17,20 +18,20 @@ data Options = Options
|
||||||
data Command
|
data Command
|
||||||
= ListBoards
|
= ListBoards
|
||||||
| ListStacks
|
| ListStacks
|
||||||
{ boardId :: Word
|
{ boardId :: Word
|
||||||
}
|
}
|
||||||
| ListCards
|
| ListCards
|
||||||
{ boardId :: Word
|
{ boardId :: Word
|
||||||
, stackId :: Word
|
, stackId :: Word
|
||||||
}
|
}
|
||||||
| CreateCard
|
| CreateCard
|
||||||
{ boardId :: Word
|
{ boardId :: Word
|
||||||
, stackId :: Word
|
, stackId :: Word
|
||||||
, title :: Text
|
, title :: Text
|
||||||
, description :: Text
|
, description :: Text
|
||||||
, date :: LocalTime
|
, date :: LocalTime
|
||||||
, weeklyRepeats :: Word
|
, weeklyRepeats :: Word
|
||||||
}
|
}
|
||||||
|
|
||||||
run :: Options -> IO ()
|
run :: Options -> IO ()
|
||||||
run (Options {..}) = do
|
run (Options {..}) = do
|
||||||
|
@ -51,103 +52,113 @@ run (Options {..}) = do
|
||||||
mapM_ print cards
|
mapM_ print cards
|
||||||
CreateCard {..} -> do
|
CreateCard {..} -> do
|
||||||
createCard hostname username password boardId stackId title description date weeklyRepeats
|
createCard hostname username password boardId stackId title description date weeklyRepeats
|
||||||
|
|
||||||
parseListStacks :: Parser Command
|
parseListStacks :: Parser Command
|
||||||
parseListStacks =
|
parseListStacks =
|
||||||
ListStacks
|
ListStacks
|
||||||
<$> option auto
|
<$> option
|
||||||
( long "board-id"
|
auto
|
||||||
<> short 'b'
|
( long "board-id"
|
||||||
<> metavar "BOARD_ID"
|
<> short 'b'
|
||||||
<> help "the id of the kanban board"
|
<> metavar "BOARD_ID"
|
||||||
)
|
<> help "the id of the kanban board"
|
||||||
|
)
|
||||||
|
|
||||||
parseListCards :: Parser Command
|
parseListCards :: Parser Command
|
||||||
parseListCards =
|
parseListCards =
|
||||||
ListCards
|
ListCards
|
||||||
<$> option auto
|
<$> option
|
||||||
( long "board-id"
|
auto
|
||||||
<> short 'b'
|
( long "board-id"
|
||||||
<> metavar "BOARD_ID"
|
<> short 'b'
|
||||||
<> help "the id of the kanban board"
|
<> metavar "BOARD_ID"
|
||||||
)
|
<> help "the id of the kanban board"
|
||||||
<*> option auto
|
)
|
||||||
( long "stack-id"
|
<*> option
|
||||||
<> short 's'
|
auto
|
||||||
<> metavar "STACK_ID"
|
( long "stack-id"
|
||||||
<> help "the id of the kanban stack"
|
<> short 's'
|
||||||
)
|
<> metavar "STACK_ID"
|
||||||
|
<> help "the id of the kanban stack"
|
||||||
|
)
|
||||||
|
|
||||||
parseCreateCard :: Parser Command
|
parseCreateCard :: Parser Command
|
||||||
parseCreateCard =
|
parseCreateCard =
|
||||||
CreateCard
|
CreateCard
|
||||||
<$> option auto
|
<$> option
|
||||||
( long "board-id"
|
auto
|
||||||
<> short 'b'
|
( long "board-id"
|
||||||
<> metavar "BOARD_ID"
|
<> short 'b'
|
||||||
<> help "the id of the kanban board"
|
<> metavar "BOARD_ID"
|
||||||
)
|
<> help "the id of the kanban board"
|
||||||
<*> option auto
|
)
|
||||||
( long "stack-id"
|
<*> option
|
||||||
<> short 's'
|
auto
|
||||||
<> metavar "STACK_ID"
|
( long "stack-id"
|
||||||
<> help "the id of the kanban stack"
|
<> short 's'
|
||||||
)
|
<> metavar "STACK_ID"
|
||||||
|
<> help "the id of the kanban stack"
|
||||||
|
)
|
||||||
<*> strOption
|
<*> strOption
|
||||||
( long "title"
|
( long "title"
|
||||||
<> short 't'
|
<> short 't'
|
||||||
<> metavar "TITLE"
|
<> metavar "TITLE"
|
||||||
<> help "the card's title; the card's date can be included using the placeholders %YY, %MM and %DD"
|
<> help "the card's title; the card's date can be included using the placeholders %YY, %MM and %DD"
|
||||||
)
|
)
|
||||||
<*> strOption
|
<*> strOption
|
||||||
( long "description"
|
( long "description"
|
||||||
<> short 'd'
|
<> short 'd'
|
||||||
<> metavar "DESC"
|
<> metavar "DESC"
|
||||||
<> value ""
|
<> value ""
|
||||||
<> showDefault
|
<> showDefault
|
||||||
<> help "the card's description"
|
<> help "the card's description"
|
||||||
)
|
)
|
||||||
<*> option auto
|
<*> option
|
||||||
( long "date" -- FIXME: make this optional?
|
auto
|
||||||
<> short 'e'
|
( long "date" -- FIXME: make this optional?
|
||||||
<> metavar "DATE"
|
<> short 'e'
|
||||||
<> help "the card's date, format: YYYY-MM-DD hh:mm:ss"
|
<> metavar "DATE"
|
||||||
)
|
<> help "the card's date, format: YYYY-MM-DD hh:mm:ss"
|
||||||
<*> option auto
|
)
|
||||||
( long "weekly-repeats"
|
<*> option
|
||||||
<> short 'w'
|
auto
|
||||||
<> metavar "COUNT"
|
( long "weekly-repeats"
|
||||||
<> value 0
|
<> short 'w'
|
||||||
<> showDefault
|
<> metavar "COUNT"
|
||||||
<> help "repeat the card weekly COUNT times")
|
<> value 0
|
||||||
|
<> showDefault
|
||||||
|
<> help "repeat the card weekly COUNT times"
|
||||||
|
)
|
||||||
|
|
||||||
parseOptions :: Parser Options
|
parseOptions :: Parser Options
|
||||||
parseOptions =
|
parseOptions =
|
||||||
Options
|
Options
|
||||||
<$> strOption
|
<$> strOption
|
||||||
( long "hostname"
|
( long "hostname"
|
||||||
<> short 'o'
|
<> short 'o'
|
||||||
<> metavar "HOSTNAME"
|
<> metavar "HOSTNAME"
|
||||||
<> help "the hostname of the Nextcloud instance"
|
<> help "the hostname of the Nextcloud instance"
|
||||||
)
|
)
|
||||||
<*> strOption
|
<*> strOption
|
||||||
( long "username"
|
( long "username"
|
||||||
<> short 'u'
|
<> short 'u'
|
||||||
<> metavar "USERNAME"
|
<> metavar "USERNAME"
|
||||||
<> help "the Nextcloud username"
|
<> help "the Nextcloud username"
|
||||||
)
|
)
|
||||||
<*> hsubparser
|
<*> hsubparser
|
||||||
( command "list-boards" (info (pure ListBoards) (progDesc "list all stacks"))
|
( command "list-boards" (info (pure ListBoards) (progDesc "list all stacks"))
|
||||||
<> command "list-stacks" (info parseListStacks (progDesc "list all stacks"))
|
<> command "list-stacks" (info parseListStacks (progDesc "list all stacks"))
|
||||||
<> command "list-cards" (info parseListCards (progDesc "list all cards"))
|
<> command "list-cards" (info parseListCards (progDesc "list all cards"))
|
||||||
<> command "create-card" (info parseCreateCard (progDesc "create a new card"))
|
<> command "create-card" (info parseCreateCard (progDesc "create a new card"))
|
||||||
)
|
)
|
||||||
|
|
||||||
main :: IO ()
|
main :: IO ()
|
||||||
main = run =<< execParser opts
|
main = run =<< execParser opts
|
||||||
where
|
where
|
||||||
opts = info (parseOptions <**> helper)
|
opts =
|
||||||
( fullDesc
|
info
|
||||||
<> progDesc "Manage a Nextcloud Deck"
|
(parseOptions <**> helper)
|
||||||
<> header "ncdeck - Manage a Nextcloud Deck"
|
( fullDesc
|
||||||
)
|
<> progDesc "Manage a Nextcloud Deck"
|
||||||
|
<> header "ncdeck - Manage a Nextcloud Deck"
|
||||||
|
)
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
indentation: 2
|
||||||
|
column-limit: none
|
||||||
|
function-arrows: leading
|
||||||
|
comma-style: leading
|
||||||
|
import-export-style: leading
|
||||||
|
indent-wheres: true
|
||||||
|
record-brace-space: true
|
||||||
|
newline-between-decls: true
|
||||||
|
haddock-style: multi-line
|
||||||
|
haddock-style-module: null
|
||||||
|
let-style: newline
|
||||||
|
in-style: left-align
|
||||||
|
single-constraint-parens: always
|
||||||
|
single-deriving-parens: always
|
||||||
|
unicode: never
|
||||||
|
respectful: true
|
137
src/NCDeck.hs
137
src/NCDeck.hs
|
@ -8,21 +8,23 @@ module NCDeck
|
||||||
, createCard
|
, createCard
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Prelude hiding (id)
|
|
||||||
import Data.Aeson
|
import Data.Aeson
|
||||||
import Data.Maybe (fromMaybe)
|
import Data.Maybe (fromMaybe)
|
||||||
import Data.Text (Text)
|
import Data.Text (Text)
|
||||||
import qualified Data.Text as T
|
import Data.Text qualified as T
|
||||||
import qualified Data.Text.Encoding as T
|
import Data.Text.Encoding qualified as T
|
||||||
|
import Prelude hiding (id)
|
||||||
|
|
||||||
-- import Data.Time.Clock
|
-- import Data.Time.Clock
|
||||||
import Data.Time.LocalTime
|
|
||||||
|
import Control.Monad
|
||||||
|
import Control.Monad.IO.Class
|
||||||
import Data.Time.Calendar
|
import Data.Time.Calendar
|
||||||
import Data.Time.Calendar.OrdinalDate
|
import Data.Time.Calendar.OrdinalDate
|
||||||
import Data.Time.Clock.POSIX (POSIXTime)
|
import Data.Time.Clock.POSIX (POSIXTime)
|
||||||
|
import Data.Time.LocalTime
|
||||||
import GHC.Generics
|
import GHC.Generics
|
||||||
import Network.HTTP.Req
|
import Network.HTTP.Req
|
||||||
import Control.Monad
|
|
||||||
import Control.Monad.IO.Class
|
|
||||||
|
|
||||||
data Board = Board
|
data Board = Board
|
||||||
{ id :: Int
|
{ id :: Int
|
||||||
|
@ -30,7 +32,8 @@ data Board = Board
|
||||||
, deletedAt :: POSIXTime
|
, deletedAt :: POSIXTime
|
||||||
, lastModified :: POSIXTime
|
, lastModified :: POSIXTime
|
||||||
, archived :: Bool
|
, archived :: Bool
|
||||||
} deriving Generic
|
}
|
||||||
|
deriving (Generic)
|
||||||
|
|
||||||
data Stack = Stack
|
data Stack = Stack
|
||||||
{ id :: Int
|
{ id :: Int
|
||||||
|
@ -39,38 +42,58 @@ data Stack = Stack
|
||||||
, deletedAt :: POSIXTime
|
, deletedAt :: POSIXTime
|
||||||
, lastModified :: POSIXTime
|
, lastModified :: POSIXTime
|
||||||
, cards :: Maybe [Card]
|
, cards :: Maybe [Card]
|
||||||
} deriving Generic
|
}
|
||||||
|
deriving (Generic)
|
||||||
|
|
||||||
data Card = Card
|
data Card = Card
|
||||||
{ id :: Int
|
{ id :: Int
|
||||||
, title :: Text
|
, title :: Text
|
||||||
, description :: Text
|
, description :: Text
|
||||||
, duedate :: Maybe LocalTime
|
, duedate :: Maybe LocalTime
|
||||||
} deriving Generic
|
}
|
||||||
|
deriving (Generic)
|
||||||
|
|
||||||
instance FromJSON Board
|
instance FromJSON Board
|
||||||
|
|
||||||
instance Show Board where
|
instance Show Board where
|
||||||
show :: Board -> String
|
show :: Board -> String
|
||||||
show (Board {..}) =
|
show (Board {..}) =
|
||||||
T.unpack title <> "\n" <>
|
T.unpack title
|
||||||
"------------------------------------------------------\n" <>
|
<> "\n"
|
||||||
"id:\t\t" <> show id <> "\n" <>
|
<> "------------------------------------------------------\n"
|
||||||
"last modified:\t" <> show lastModified <> "\n" <>
|
<> "id:\t\t"
|
||||||
"deleted at:\t" <> show deletedAt <> "\n" <>
|
<> show id
|
||||||
"archived: \t" <> show archived <> "\n"
|
<> "\n"
|
||||||
|
<> "last modified:\t"
|
||||||
|
<> show lastModified
|
||||||
|
<> "\n"
|
||||||
|
<> "deleted at:\t"
|
||||||
|
<> show deletedAt
|
||||||
|
<> "\n"
|
||||||
|
<> "archived: \t"
|
||||||
|
<> show archived
|
||||||
|
<> "\n"
|
||||||
|
|
||||||
instance FromJSON Stack
|
instance FromJSON Stack
|
||||||
|
|
||||||
instance Show Stack where
|
instance Show Stack where
|
||||||
show :: Stack -> String
|
show :: Stack -> String
|
||||||
show (Stack {..}) =
|
show (Stack {..}) =
|
||||||
T.unpack title <> "\n" <>
|
T.unpack title
|
||||||
"------------------------------------------------------\n" <>
|
<> "\n"
|
||||||
"id:\t\t" <> show id <> "\n" <>
|
<> "------------------------------------------------------\n"
|
||||||
"last modified:\t" <> show lastModified <> "\n" <>
|
<> "id:\t\t"
|
||||||
"deleted at:\t" <> show deletedAt <> "\n" <>
|
<> show id
|
||||||
"#cards: \t" <> show (length cards) <> "\n"
|
<> "\n"
|
||||||
|
<> "last modified:\t"
|
||||||
|
<> show lastModified
|
||||||
|
<> "\n"
|
||||||
|
<> "deleted at:\t"
|
||||||
|
<> show deletedAt
|
||||||
|
<> "\n"
|
||||||
|
<> "#cards: \t"
|
||||||
|
<> show (length cards)
|
||||||
|
<> "\n"
|
||||||
|
|
||||||
instance FromJSON Card
|
instance FromJSON Card
|
||||||
|
|
||||||
|
@ -81,26 +104,35 @@ instance Show Card where
|
||||||
desc = T.unpack $ truncateDesc description
|
desc = T.unpack $ truncateDesc description
|
||||||
dd = maybe "None" show duedate
|
dd = maybe "None" show duedate
|
||||||
in
|
in
|
||||||
T.unpack title <> "\n" <>
|
T.unpack title
|
||||||
"----------------------------------------------------\n" <>
|
<> "\n"
|
||||||
"id:\t\t" <> show id <> "\n" <>
|
<> "----------------------------------------------------\n"
|
||||||
"description: \t" <> desc <> "\n" <>
|
<> "id:\t\t"
|
||||||
"due date: \t" <> dd <> "\n"
|
<> show id
|
||||||
|
<> "\n"
|
||||||
|
<> "description: \t"
|
||||||
|
<> desc
|
||||||
|
<> "\n"
|
||||||
|
<> "due date: \t"
|
||||||
|
<> dd
|
||||||
|
<> "\n"
|
||||||
where
|
where
|
||||||
truncateDesc :: Text -> Text
|
truncateDesc :: Text -> Text
|
||||||
truncateDesc input =
|
truncateDesc input =
|
||||||
let (fstLine, _) = T.break (== '\n') input
|
let
|
||||||
|
(fstLine, _) = T.break (== '\n') input
|
||||||
in
|
in
|
||||||
if T.length fstLine > 30
|
if T.length fstLine > 30
|
||||||
then T.take 30 fstLine <> "..."
|
then T.take 30 fstLine <> "..."
|
||||||
else fstLine
|
else fstLine
|
||||||
|
|
||||||
authHeaders :: Text -> Text -> Option Https
|
authHeaders :: Text -> Text -> Option Https
|
||||||
authHeaders username password =
|
authHeaders username password =
|
||||||
let
|
let
|
||||||
usernameBS = T.encodeUtf8 username
|
usernameBS = T.encodeUtf8 username
|
||||||
passwordBS = T.encodeUtf8 password
|
passwordBS = T.encodeUtf8 password
|
||||||
in header "OCS-APIRequest" "true" <> basicAuth usernameBS passwordBS
|
in
|
||||||
|
header "OCS-APIRequest" "true" <> basicAuth usernameBS passwordBS
|
||||||
|
|
||||||
baseUrl :: Text -> Url Https
|
baseUrl :: Text -> Url Https
|
||||||
baseUrl hostname =
|
baseUrl hostname =
|
||||||
|
@ -111,28 +143,32 @@ listBoards hostname username password =
|
||||||
let
|
let
|
||||||
headers = authHeaders username password
|
headers = authHeaders username password
|
||||||
url = baseUrl hostname /: "boards"
|
url = baseUrl hostname /: "boards"
|
||||||
in runReq defaultHttpConfig $ do
|
in
|
||||||
response <- req GET url NoReqBody jsonResponse headers
|
runReq defaultHttpConfig $ do
|
||||||
return $ responseBody response
|
response <- req GET url NoReqBody jsonResponse headers
|
||||||
|
return $ responseBody response
|
||||||
|
|
||||||
listStacks :: Text -> Text -> Text -> Word -> IO [Stack]
|
listStacks :: Text -> Text -> Text -> Word -> IO [Stack]
|
||||||
listStacks hostname username password boardId =
|
listStacks hostname username password boardId =
|
||||||
let
|
let
|
||||||
headers = authHeaders username password
|
headers = authHeaders username password
|
||||||
url = baseUrl hostname /: "boards" /: T.pack (show boardId) /: "stacks"
|
url = baseUrl hostname /: "boards" /: T.pack (show boardId) /: "stacks"
|
||||||
in runReq defaultHttpConfig $ do
|
in
|
||||||
response <- req GET url NoReqBody jsonResponse headers
|
runReq defaultHttpConfig $ do
|
||||||
return $ responseBody response
|
response <- req GET url NoReqBody jsonResponse headers
|
||||||
|
return $ responseBody response
|
||||||
|
|
||||||
listCards :: Text -> Text -> Text -> Word -> Word -> IO [Card]
|
listCards :: Text -> Text -> Text -> Word -> Word -> IO [Card]
|
||||||
listCards hostname username password boardId stackId =
|
listCards hostname username password boardId stackId =
|
||||||
let
|
let
|
||||||
headers = authHeaders username password
|
headers = authHeaders username password
|
||||||
url = baseUrl hostname /: "boards" /: T.pack (show boardId) /: "stacks" /: T.pack (show stackId)
|
url = baseUrl hostname /: "boards" /: T.pack (show boardId) /: "stacks" /: T.pack (show stackId)
|
||||||
in runReq defaultHttpConfig $ do
|
in
|
||||||
response <- req GET url NoReqBody jsonResponse headers
|
runReq defaultHttpConfig $ do
|
||||||
let stack :: Stack = responseBody response
|
response <- req GET url NoReqBody jsonResponse headers
|
||||||
return $ fromMaybe [] stack.cards
|
let
|
||||||
|
stack :: Stack = responseBody response
|
||||||
|
return $ fromMaybe [] stack.cards
|
||||||
|
|
||||||
createCard :: Text -> Text -> Text -> Word -> Word -> Text -> Text -> LocalTime -> Word -> IO ()
|
createCard :: Text -> Text -> Text -> Word -> Word -> Text -> Text -> LocalTime -> Word -> IO ()
|
||||||
createCard hostname username password boardId stackId title description date weeklyRepeats = do
|
createCard hostname username password boardId stackId title description date weeklyRepeats = do
|
||||||
|
@ -143,16 +179,17 @@ createCard hostname username password boardId stackId title description date wee
|
||||||
(_, dayOfYear) = toOrdinalDate date.localDay
|
(_, dayOfYear) = toOrdinalDate date.localDay
|
||||||
(year, month, day) = toGregorian date.localDay
|
(year, month, day) = toGregorian date.localDay
|
||||||
expandedTitle =
|
expandedTitle =
|
||||||
T.replace "%YY" (T.pack $ show year) $
|
T.replace "%YY" (T.pack $ show year)
|
||||||
T.replace "%MM" (T.pack $ show month) $
|
$ T.replace "%MM" (T.pack $ show month)
|
||||||
T.replace "%DD" (T.pack $ show day) title
|
$ T.replace "%DD" (T.pack $ show day) title
|
||||||
body = object
|
body =
|
||||||
[ "title" .= expandedTitle
|
object
|
||||||
, "type" .= ("plain" :: Text)
|
[ "title" .= expandedTitle
|
||||||
, "order" .= dayOfYear
|
, "type" .= ("plain" :: Text)
|
||||||
, "description" .= description
|
, "order" .= dayOfYear
|
||||||
, "duedate" .= localTimeToUTC timezone date
|
, "description" .= description
|
||||||
]
|
, "duedate" .= localTimeToUTC timezone date
|
||||||
|
]
|
||||||
runReq defaultHttpConfig $ do
|
runReq defaultHttpConfig $ do
|
||||||
_ <- req POST url (ReqBodyJson body) ignoreResponse headers
|
_ <- req POST url (ReqBodyJson body) ignoreResponse headers
|
||||||
when (weeklyRepeats > 0) $ do
|
when (weeklyRepeats > 0) $ do
|
||||||
|
|
Loading…
Reference in New Issue