calamity-0.5.0.0: Calamity/Commands/Context.hs
{-# LANGUAGE TemplateHaskell #-}
-- | Command invokation context
module Calamity.Commands.Context (
CalamityCommandContext (..),
FullContext (..),
useFullContext,
LightContext (..),
useLightContext,
) where
import Calamity.Cache.Eff
import Calamity.Commands.Types
import Calamity.Internal.Utils
import Calamity.Types.Model.Channel
import Calamity.Types.Model.Guild
import Calamity.Types.Model.User
import Calamity.Types.Snowflake
import Calamity.Types.Tellable
import qualified CalamityCommands.Context as CC
import Control.Applicative
import Control.Monad
import qualified Data.Text as T
import Optics
import qualified Polysemy as P
import qualified Polysemy.Fail as P
import qualified TextShow
class CommandContext c => CalamityCommandContext c where
-- | The id of the channel that invoked this command
ctxChannelID :: c -> Snowflake Channel
-- | The id of the guild the command was invoked in, if in a guild
ctxGuildID :: c -> Maybe (Snowflake Guild)
-- | The id of the user that invoked this command
ctxUserID :: c -> Snowflake User
-- | The message that triggered this command
ctxMessage :: c -> Message
-- | Invokation context for commands
data FullContext = FullContext
{ -- | The message that the command was invoked from
message :: Message
, -- | If the command was sent in a guild, this will be present
guild :: Maybe Guild
, -- | The member that invoked the command, if in a guild
--
-- Note: If discord sent a member with the message, this is used; otherwise
-- we try to fetch the member from the cache.
member :: Maybe Member
, -- | The channel the command was invoked from
channel :: Channel
, -- | The user that invoked the command
user :: User
, -- | The command that was invoked
command :: Command FullContext
, -- | The prefix that was used to invoke the command
prefix :: T.Text
, -- | The message remaining after consuming the prefix
unparsedParams :: T.Text
}
deriving (Show)
deriving (TextShow.TextShow) via TextShow.FromStringShow FullContext
deriving (HasID Channel) via HasIDField "channel" FullContext
deriving (HasID Message) via HasIDField "message" FullContext
deriving (HasID User) via HasIDField "user" FullContext
$(makeFieldLabelsNoPrefix ''FullContext)
instance CC.CommandContext IO FullContext () where
ctxPrefix = (^. #prefix)
ctxCommand = (^. #command)
ctxUnparsedParams = (^. #unparsedParams)
instance CalamityCommandContext FullContext where
ctxChannelID = getID . (^. #channel)
ctxGuildID c = getID <$> c ^. #guild
ctxUserID = getID . (^. #user)
ctxMessage = (^. #message)
instance Tellable FullContext where
getChannel = pure . ctxChannelID
useFullContext :: P.Member CacheEff r => P.Sem (CC.ConstructContext (Message, User, Maybe Member) FullContext IO () ': r) a -> P.Sem r a
useFullContext =
P.interpret
( \case
CC.ConstructContext (pre, cmd, up) (msg, usr, mem) -> buildContext msg usr mem pre cmd up
)
buildContext :: P.Member CacheEff r => Message -> User -> Maybe Member -> T.Text -> Command FullContext -> T.Text -> P.Sem r (Maybe FullContext)
buildContext msg usr mem prefix command unparsed = (rightToMaybe <$>) . P.runFail $ do
guild <- join <$> getGuild `traverse` (msg ^. #guildID)
let member = mem <|> guild ^? _Just % #members % ix (coerceSnowflake $ getID @User msg)
let gchan = guild ^? _Just % #channels % ix (coerceSnowflake $ getID @Channel msg)
Just channel <- case gchan of
Just chan -> pure . pure $ GuildChannel' chan
Nothing -> DMChannel' <<$>> getDM (coerceSnowflake $ getID @Channel msg)
pure $ FullContext msg guild member channel usr command prefix unparsed
-- | A lightweight context that doesn't need any cache information
data LightContext = LightContext
{ -- | The message that the command was invoked from
message :: Message
, -- | If the command was sent in a guild, this will be present
guildID :: Maybe (Snowflake Guild)
, -- | The channel the command was invoked from
channelID :: Snowflake Channel
, -- | The user that invoked the command
user :: User
, -- | The member that triggered the command.
--
-- Note: Only sent if discord sent the member object with the message.
member :: Maybe Member
, -- | The command that was invoked
command :: Command LightContext
, -- | The prefix that was used to invoke the command
prefix :: T.Text
, -- | The message remaining after consuming the prefix
unparsedParams :: T.Text
}
deriving (Show)
deriving (TextShow.TextShow) via TextShow.FromStringShow LightContext
deriving (HasID Channel) via HasIDField "channelID" LightContext
deriving (HasID Message) via HasIDField "message" LightContext
deriving (HasID User) via HasIDField "user" LightContext
$(makeFieldLabelsNoPrefix ''LightContext)
instance CC.CommandContext IO LightContext () where
ctxPrefix = (^. #prefix)
ctxCommand = (^. #command)
ctxUnparsedParams = (^. #unparsedParams)
instance CalamityCommandContext LightContext where
ctxChannelID = (^. #channelID)
ctxGuildID = (^. #guildID)
ctxUserID = (^. #user % #id)
ctxMessage = (^. #message)
instance Tellable LightContext where
getChannel = pure . ctxChannelID
useLightContext :: P.Sem (CC.ConstructContext (Message, User, Maybe Member) LightContext IO () ': r) a -> P.Sem r a
useLightContext =
P.interpret
( \case
CC.ConstructContext (pre, cmd, up) (msg, usr, mem) ->
pure . Just $ LightContext msg (msg ^. #guildID) (msg ^. #channelID) usr mem cmd pre up
)