You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

184 lines
7.7 KiB

{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Main where
import Commands ( edtCommand
, edtResponse
, groupCommand
, groupResponse
, helpCommand
, helpResponse
, pingCommand
, pingResponse
, remindCommand
, remindResponse
)
import Commands.EDT ( getEdt )
import Commands.Reminds ( Remind(..)
, scheduleRemind
, setupRemindDb
)
import Conf ( Config(..)
, Group(..)
, readConfig
)
import qualified Control.Concurrent
import qualified Control.Event as E
import Control.Monad ( void
, when
)
import Control.Monad.IO.Unlift ( liftIO
, toIO
, withRunInIO
)
import qualified Data.Map.Strict as Map
import qualified Data.Text as T
import qualified Data.Text.IO as TIO
import Data.Time ( getCurrentTime )
import qualified Database.HDBC as DB
import qualified Database.HDBC.Sqlite3 as DB.SQ3
import Discord ( DiscordHandler
, RunDiscordOpts(..)
, def
, restCall
, runDiscord
, sendCommand
)
import Discord.Interactions ( Interaction(..)
, ApplicationCommandData(..)
, interactionResponseBasic
)
import qualified Discord.Requests as R
import Discord.Types ( Activity(..)
, ActivityType(..)
, Event(..)
, GatewaySendable(..)
, PartialApplication(..)
, Snowflake(Snowflake)
, UpdateStatusOpts(..)
, UpdateStatusType(..)
)
import qualified System.Cron.Schedule as Cron
import UnliftIO.Directory ( doesFileExist
, removeFile
)
import System.Environment (setEnv)
main :: IO ()
main = do
tok <- TIO.readFile "./auth.secret"
conf <- readConfig "./conf.yaml"
eventSystem <- E.initEventSystem
setEnv "TZ" "Europe/Paris" -- The bot needs to run on the french timezone for edt to work properly
err <- Discord.runDiscord $ Discord.def
{ discordToken = tok
, discordOnStart = onDiscordStart conf eventSystem
, discordOnEnd = liftIO $ putStrLn "Ended"
, discordOnEvent = onDiscordEvent conf eventSystem
, discordOnLog = \s -> TIO.putStrLn s >> TIO.putStrLn ""
}
TIO.putStrLn err
onDiscordStart :: Config -> E.EventSystem -> Discord.DiscordHandler ()
onDiscordStart conf@Config {..} eventSystem = do
let activity :: Activity
activity = Discord.def { activityName = "Doing stuff"
, activityType = ActivityTypeGame
, activityUrl = Nothing
}
opts :: UpdateStatusOpts
opts = UpdateStatusOpts { updateStatusOptsSince = Nothing
, updateStatusOptsGame = Just activity
, updateStatusOptsNewStatus = UpdateStatusOnline
, updateStatusOptsAFK = False
}
Discord.sendCommand (UpdateStatus opts)
let glist = Map.toList configGroups
withRunInIO $ \runInIO -> Cron.execSchedule $ do
Cron.addJob (runInIO $ pushgroupedt conf "tomorrow" glist)
configAutoEDTCronDay
Cron.addJob (runInIO $ pushgroupedt conf "week" glist) configAutoEDTCronWeek
-- Ensure the database is setup
liftIO setupRemindDb
-- Get the reminders out of the database
conn <- liftIO $ DB.SQ3.connectSqlite3 "db.sqlite3"
query <- liftIO $ DB.prepare
conn
"SELECT user, channel, message, dt \
\FROM reminds \
\WHERE (datetime(dt) > datetime('now'));"
liftIO $ DB.execute query []
reminds <- liftIO $ DB.fetchAllRows' query
mapM_
(\[u, c, m, d] -> do
liftIO $ print [u, c, m, d]
scheduleRemind
eventSystem
Remind { rmdUser = fromInteger $ DB.fromSql u
, rmdChannel = fromInteger $ DB.fromSql c
, rmdMessage = DB.fromSql m
, rmdDatetime = DB.fromSql d
}
)
reminds
liftIO $ putStrLn "Started"
onDiscordEvent :: Config -> E.EventSystem -> Event -> Discord.DiscordHandler ()
onDiscordEvent conf@Config {..} eventSystem (Ready _ _ _ _ _ _ (PartialApplication i _))
= do
liftIO $ putStrLn "onready"
mapM_
(maybe
(return ())
(void . Discord.restCall . R.CreateGuildApplicationCommand i configServer)
)
[ pingCommand
-- , edtCommand conf
, remindCommand
-- , groupCommand conf
, helpCommand
]
onDiscordEvent conf@Config {..} eventSystem (InteractionCreate InteractionApplicationCommand { applicationCommandData = ApplicationCommandDataChatInput { applicationCommandDataName = name, optionsData = opts, ..}, interactionChannelId = Just channel, interactionGuildId = Just guild, interactionUser = user, ..})
= do
response <- responseIO
void $ Discord.restCall
(R.CreateInteractionResponse interactionId interactionToken response)
where
responseIO = case name of
"ping" -> liftIO $ pingResponse conf
"edt" -> liftIO $ edtResponse conf opts
"remind" -> remindResponse opts eventSystem channel user
"group" -> groupResponse conf user guild opts
"help" -> liftIO helpResponse
_ ->
return $ interactionResponseBasic $ "Unhandled Command: " `T.append` name
onDiscordEvent _ _ _ = return ()
pushgroupedt :: Config -> T.Text -> [(T.Text, Group)] -> Discord.DiscordHandler ()
pushgroupedt conf@Config {..} day glist = do
mapM_
(\(gn, Group { groupChannel = gc }) -> do
edt <- liftIO $ getEdt conf $ Map.fromList [("group", gn), ("day", day)]
liftIO
$ TIO.putStrLn
$ "Putting out time table for group "
<> gn
<> " in "
<> T.pack (show gc)
<> ":\n"
<> edt
Discord.restCall $ R.CreateMessage gc edt
return ()
)
glist