funbot-0.5: src/FunBot/Settings.hs
{- This file is part of funbot.
-
- Written in 2015, 2016 by fr33domlover <fr33domlover@riseup.net>.
-
- ♡ Copying is an act of love. Please copy, reuse and share.
-
- The author(s) have dedicated all copyright and related and neighboring
- rights to this software to the public domain worldwide. This software is
- distributed without any warranty.
-
- You should have received a copy of the CC0 Public Domain Dedication along
- with this software. If not, see
- <http://creativecommons.org/publicdomain/zero/1.0/>.
-}
-- For irc-fun-color StyledString
{-# LANGUAGE OverloadedStrings #-}
module FunBot.Settings
( respondGet'
, respondSet'
, respondReset'
, respondSettingsHelp
)
where
import Control.Applicative
import Control.Monad (liftM, mzero, unless)
import Control.Monad.IO.Class (liftIO)
import Data.Aeson hiding (encode)
import Data.Bool (bool)
import Data.Char (toLower)
import Data.Default.Class (def)
import Data.JsonState
import Data.List (intercalate, intersperse, isSuffixOf, sort)
import Data.Maybe (catMaybes, fromMaybe)
import Data.Monoid
import Data.Settings.Interface
import Data.Settings.Option
import Data.Settings.Route
import Data.Settings.Section (deleteSub, insertSub, memberSub)
import Data.Settings.Types
import Data.Text (Text)
import Data.Time.Units (Second)
import FunBot.Config (stateSaveInterval, configuration, settingsFilename)
import FunBot.Settings.Help
import FunBot.Settings.Instances ()
import FunBot.Types
import FunBot.Util
import Network.IRC.Fun.Bot.Chat
import Network.IRC.Fun.Bot.IrcLog
import Network.IRC.Fun.Bot.MsgCount
import Network.IRC.Fun.Bot.Nicks
import Network.IRC.Fun.Bot.State
import Network.IRC.Fun.Bot.Types (Config (cfgStateRepo))
import Network.IRC.Fun.Color
import Network.IRC.Fun.Types.Base (MsgContent (..))
import Web.Feed.Collect hiding (addFeed)
import qualified Data.HashMap.Lazy as M
import qualified Data.Text as T
import qualified Web.Feed.Collect as F (addFeed)
showError :: SettingsError -> Text
showError (InvalidPath t) = t <> " : Invalid path"
showError (NoSuchNode r) = showRoute r <> " : No such option/section"
showError (NoSuchOption r) = showRoute r <> " : No such option"
showError (NoSuchSection r) = showRoute r <> " : No such section"
showError (InvalidValueForType t) = t <> " : Invalid value for option type"
showError (InvalidValue t) = t <> " : Invalid value"
showOptLine :: Text -> Text -> Text -> Text
showOptLine opt op val =
encode $ Yellow #> plain opt <> Teal #> plain op <> Maroon #> plain val
showGet :: Text -> Text -> Text
showGet opt val = showOptLine opt " = " val
showSec :: OptPath -> [Text] -> [Text] -> Text
showSec path subs opts =
let showSub = ('‣' `T.cons`)
showOpt = ('•' `T.cons`)
showList = T.unwords . sort
pathF = Yellow #> plain path
subsF = Green #> plain (showList $ map showSub subs)
optsF = Purple #> plain (showList $ map showOpt opts)
in encode $ case (null subs, null opts) of
(False, False) -> pathF <> " : " <> subsF <> " | " <> optsF
(False, True) -> pathF <> " : " <> subsF
(True, False) -> pathF <> " : " <> optsF
(True, True) -> pathF <> " : Empty section"
-- Remove user-friendliness parts and determine whether given string refers to
-- a potential section (otherwise it could also be an potential option).
stripPath :: Text -> (Text, Bool)
stripPath opt
| opt == "*" = (T.empty, True)
| ".*" `T.isSuffixOf` opt = (T.dropEnd 2 opt, True)
| otherwise = (opt, False)
respondGet' :: OptPath -> (MsgContent -> BotSession ()) -> BotSession ()
respondGet' opt send = resp path
where
(path, sec) = stripPath opt
resp = if sec then respSec else respAny
respAny path = do
result <- query path
send $ MsgContent $ case result of
Left err -> showError err
Right (Left (subs, opts)) -> showSec path subs opts
Right (Right val) -> showGet path val
respSec path = do
result <- querySection path
send $ MsgContent $ case result of
Left err -> showError err
Right (subs, opts) -> showSec path subs opts
showSet :: Text -> Text -> Text
showSet opt val = showOptLine opt " ← " val
respondSet'
:: OptPath
-> Text
-> (MsgContent -> BotSession ())
-> BotSession ()
respondSet' opt val send = do
merr <- updateOption opt val
case merr of
Just err -> send $ MsgContent $ showError err
Nothing -> send $ MsgContent $ showSet opt val
showReset :: Text -> Text -> Text
showReset opt val = showOptLine opt " ↩ " val
showResetStrange :: Text -> Text
showResetStrange opt = opt <> " : got reset, but I can’t find it now"
respondReset' :: OptPath -> (MsgContent -> BotSession ()) -> BotSession ()
respondReset' opt send = do
merr <- resetOption opt
case merr of
Just err -> send $ MsgContent $ showError err
Nothing -> do
me <- queryOption opt
send $ MsgContent $ case me of
Left _ -> showResetStrange opt
Right val -> showReset opt val
respondSettingsHelp
:: OptPath
-> (MsgContent -> BotSession ())
-> BotSession Bool
respondSettingsHelp path send =
let p = fst $ stripPath path
in case parseRoute p of
Just r -> do
send $ MsgContent $ p <> " : " <> help r
return True
Nothing -> return False