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.

228 lines
8.9 KiB

3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
  1. {-# LANGUAGE OverloadedStrings #-}
  2. {-# LANGUAGE RecordWildCards #-}
  3. module Commands where
  4. import Commands.EDT ( getEdt )
  5. import Commands.Reminds ( Remind(..)
  6. , registerRemind
  7. , scheduleRemind
  8. )
  9. import Conf ( Config(..)
  10. , Group(..)
  11. )
  12. import Control.Event ( EventSystem
  13. , addEvent
  14. )
  15. import Control.Monad ( when )
  16. import Control.Monad.IO.Class ( liftIO )
  17. import qualified Data.Map.Strict as Map
  18. import Data.Maybe ( fromMaybe )
  19. import qualified Data.Text as T
  20. import Data.Time ( addUTCTime
  21. , getCurrentTime
  22. )
  23. import Discord ( DiscordHandler
  24. , restCall
  25. )
  26. import Discord.Interactions ( OptionValue(..)
  27. , Options(..)
  28. , Choice(..)
  29. , CreateApplicationCommand(..)
  30. , OptionDataValue(..)
  31. , OptionsData(..)
  32. , InteractionResponse
  33. , MemberOrUser(..)
  34. , LocalizedText(..)
  35. , createChatInput
  36. , interactionResponseBasic
  37. )
  38. import Discord.Requests ( ChannelRequest(..)
  39. , GuildRequest(..)
  40. )
  41. import Discord.Types ( ChannelId
  42. , GuildId
  43. , GuildMember(..)
  44. , Snowflake
  45. , UTCTime
  46. , User(..)
  47. , RoleId(..)
  48. , DiscordId,
  49. )
  50. import UnliftIO ( withRunInIO )
  51. groupNames :: Config -> [T.Text]
  52. groupNames Config {..} = map fst $ Map.toList configGroups
  53. pingCommand :: Maybe CreateApplicationCommand
  54. pingCommand = createChatInput "ping" "pong"
  55. pingResponse :: Config -> IO InteractionResponse
  56. pingResponse _ = return $ interactionResponseBasic "Pong"
  57. edtCommand :: Config -> Maybe CreateApplicationCommand
  58. edtCommand c =
  59. createChatInput "edt" "Gets the planning for a group"
  60. >>= \cac -> return $ cac
  61. { createOptions =
  62. Just $ OptionsValues
  63. [ OptionValueString
  64. "group"
  65. Nothing
  66. "The group for which the planning is requested"
  67. Nothing
  68. True
  69. (Right $ map (\x -> Choice x Nothing x) $ groupNames c)
  70. Nothing Nothing
  71. , OptionValueString
  72. "day"
  73. Nothing
  74. "The day(s) for which the planning is requested (today, tomorrow, week or DD/MM/YYYY)"
  75. Nothing
  76. False
  77. (Left False)
  78. Nothing Nothing
  79. ]
  80. }
  81. parseOpt :: OptionDataValue -> (T.Text, T.Text)
  82. parseOpt OptionDataValueString { optionDataValueName = name, optionDataValueString = Right val, ..}
  83. = (name, val)
  84. parseOpt _ = ("INVALID Option", "INVALID type")
  85. edtResponse
  86. :: Config
  87. -> Maybe OptionsData
  88. -> IO InteractionResponse
  89. edtResponse conf@Config {..} (Just (OptionsDataValues opts))
  90. = do
  91. planning <- getEdt conf parsedOpts
  92. return $ interactionResponseBasic planning
  93. where
  94. parsedOpts :: Map.Map T.Text T.Text
  95. parsedOpts = Map.fromList $ map parseOpt opts
  96. edtResponse _ _ = return $ interactionResponseBasic
  97. "The edt command has mandatory params yet you managed not to give any, WOW"
  98. remindCommand :: Maybe CreateApplicationCommand
  99. remindCommand =
  100. createChatInput "remind" "reminds you of something later on"
  101. >>= \cac -> return $ cac
  102. { createOptions =
  103. Just $ OptionsValues
  104. [ OptionValueString "delay" Nothing "delay" Nothing True (Left False) Nothing Nothing
  105. , OptionValueString "message" Nothing "message" Nothing True (Left False) Nothing Nothing
  106. ]
  107. }
  108. remindResponse
  109. :: Maybe OptionsData
  110. -> EventSystem
  111. -> Discord.Types.ChannelId
  112. -> MemberOrUser
  113. -> DiscordHandler InteractionResponse
  114. remindResponse (Just (OptionsDataValues opts)) evts ch mou
  115. = do
  116. let
  117. userid = case mou of
  118. MemberOrUser (Left Discord.Types.GuildMember { memberUser = Just Discord.Types.User { userId = uid } })
  119. -> uid
  120. MemberOrUser (Right Discord.Types.User { userId = uid }) -> uid
  121. _ -> error "Couldnt get user id"
  122. let d = delay'
  123. now <- liftIO getCurrentTime
  124. let
  125. remindDateTime = case T.last d of
  126. 's' -> addUTCTime (fromInteger $ read $ init $ T.unpack d) now
  127. 'm' -> addUTCTime ((* 60) $ fromInteger $ read $ init $ T.unpack d) now
  128. 'h' ->
  129. addUTCTime ((* 3600) $ fromInteger $ read $ init $ T.unpack d) now
  130. 'd' ->
  131. addUTCTime ((* 86400) $ fromInteger $ read $ init $ T.unpack d) now
  132. _ -> now
  133. if remindDateTime /= now
  134. then do
  135. let rmd = Remind { rmdUser = userid
  136. , rmdChannel = ch
  137. , rmdMessage = message
  138. , rmdDatetime = remindDateTime
  139. }
  140. scheduleRemind evts rmd
  141. liftIO $ registerRemind rmd
  142. return
  143. $ interactionResponseBasic
  144. $ "Reminder registered sucessfully for "
  145. `T.append` T.pack (show remindDateTime)
  146. else return $ interactionResponseBasic "couldn't parse your delay :/"
  147. where
  148. parsedOpts = Map.fromList $ map parseOpt opts
  149. delay' =
  150. fromMaybe (error "delay must exist wtf") $ Map.lookup "delay" parsedOpts
  151. message = fromMaybe (error "message must exist, wtf")
  152. $ Map.lookup "message" parsedOpts
  153. remindResponse _ _ _ _ =
  154. return
  155. $ interactionResponseBasic
  156. "The remind command has mandatory params, yet you managed not to give any, WOW"
  157. groupCommand :: Config -> Maybe CreateApplicationCommand
  158. groupCommand c =
  159. createChatInput "group" "grab your group" >>= \cac ->
  160. return $ cac
  161. { createOptions = Just $ OptionsValues
  162. [ OptionValueString
  163. "group" Nothing
  164. "Your group" Nothing
  165. True
  166. (Right $ map (\x -> Choice x Nothing x) $ groupNames c)
  167. Nothing Nothing
  168. ]
  169. }
  170. groupResponse
  171. :: Config
  172. -> MemberOrUser
  173. -> Discord.Types.GuildId
  174. -> Maybe OptionsData
  175. -> DiscordHandler InteractionResponse
  176. groupResponse c mou gid (Just (OptionsDataValues opts))
  177. = do
  178. let
  179. uid = case mou of
  180. MemberOrUser (Left Discord.Types.GuildMember { memberUser = Just Discord.Types.User { userId = uid } })
  181. -> uid
  182. MemberOrUser (Right Discord.Types.User { userId = uid }) -> uid
  183. _ -> -1
  184. let rid =
  185. groupRole
  186. $ fromMaybe (error "group must exist")
  187. $ Map.lookup group
  188. $ configGroups c
  189. restCall $ AddGuildMemberRole gid uid rid
  190. return
  191. $ interactionResponseBasic
  192. $ "You are now part of group "
  193. `T.append` group
  194. where
  195. group =
  196. fromMaybe (error "required option")
  197. $ Map.lookup "group"
  198. $ Map.fromList
  199. $ map parseOpt opts
  200. groupResponse _ _ _ _ =
  201. return
  202. $ interactionResponseBasic
  203. "the group command has mandatory params, yet you managed not to give any, WOW"
  204. helpCommand :: Maybe CreateApplicationCommand
  205. helpCommand = createChatInput "help" "help"
  206. helpResponse :: IO InteractionResponse
  207. helpResponse =
  208. return
  209. . interactionResponseBasic
  210. $ "**__Help for Bot IUT__**\n\n"
  211. `T.append` "`/help` shows this help message\n"
  212. `T.append` "`/group <group>` join a group\n"
  213. `T.append` "`/remind <time><s|m|h|d> <message>` reminds you of something in the future\n"
  214. `T.append` "`/edt <group> [week|today|tomorrow|dd/mm/yyyy]` get the planning for group `group` on `day` (`day` defaults to `week`)"