packages feed

calamity-0.1.10.1: src/Calamity/Utils/Permissions.hs

-- | Permission utilities
module Calamity.Utils.Permissions
    ( PermissionsIn(..)
    , PermissionsIn'(..)
    , basePermissions
    , applyOverwrites ) where

import           Calamity.Client.Types
import           Calamity.Types.Model.Channel.Guild
import           Calamity.Types.Model.Guild.Guild
import           Calamity.Types.Model.Guild.Member
import           Calamity.Types.Model.Guild.Overwrite
import           Calamity.Types.Model.Guild.Permissions
import           Calamity.Types.Snowflake
import           Calamity.Types.Upgradeable

import           Control.Lens

import           Data.Flags
import qualified Data.Vector.Unboxed                    as V

import qualified Polysemy                               as P

basePermissions :: Guild -> Member -> Permissions
basePermissions g m
  | (g ^. #ownerID == getID m) = allFlags
  | otherwise = let everyoneRole  = g ^. #roles . at (coerceSnowflake $ getID @Guild g)
                    permsEveryone = maybe noFlags (^. #permissions) everyoneRole
                    rolePerms     = g ^.. #roles . foldMap ix (V.toList $ m ^. #roles) . #permissions
                    perms         = foldl andFlags noFlags (permsEveryone:rolePerms)
                in if perms .<=. administrator
                   then allFlags
                   else perms

applyOverwrites :: GuildChannel -> Member -> Permissions -> Permissions
applyOverwrites c m p
  | p .<=. administrator = allFlags
  | otherwise =
    let everyoneOverwrite = c ^. #permissionOverwrites . at (coerceSnowflake $ getID @Guild c)
        everyoneAllow     = maybe noFlags (^. #allow) everyoneOverwrite
        everyoneDeny      = maybe noFlags (^. #deny) everyoneOverwrite
        p'                = p .-. everyoneDeny .+. everyoneAllow
        roleOverwrites    = c ^.. #permissionOverwrites . foldMap ix
          (map (coerceSnowflake @_ @Overwrite) . V.toList $ m ^. #roles)
        roleAllow         = foldl andFlags noFlags (roleOverwrites ^.. traverse . #allow)
        roleDeny          = foldl andFlags noFlags (roleOverwrites ^.. traverse . #deny)
        p''               = p' .-. roleDeny .+. roleAllow
        memberOverwrite   = c ^. #permissionOverwrites . at (coerceSnowflake @_ @Overwrite $ getID @Member m)
        memberAllow       = maybe noFlags (^. #allow) memberOverwrite
        memberDeny        = maybe noFlags (^. #deny) memberOverwrite
        p'''              = p'' .-. memberDeny .+. memberAllow
    in p'''

class PermissionsIn a where
  permissionsIn :: a -> Member -> Permissions

instance PermissionsIn (Guild, GuildChannel) where
  permissionsIn (g, c) m = applyOverwrites c m $ basePermissions g m

instance PermissionsIn Guild where
  permissionsIn g m = basePermissions g m

class PermissionsIn' a where
  permissionsIn' :: BotC r => a -> Member -> P.Sem r Permissions

instance PermissionsIn' GuildChannel where
  permissionsIn' c m = do
    g <- upgrade (getID @Guild c)
    case g of
      Just g' -> pure $ permissionsIn (g', c) m
      Nothing -> pure noFlags

instance PermissionsIn' Guild where
  permissionsIn' g m = pure $ permissionsIn g m

instance PermissionsIn' (Snowflake GuildChannel) where
  permissionsIn' cid m = do
    c <- upgrade cid
    case c of
      Just c' -> permissionsIn' c' m
      Nothing -> pure noFlags

instance PermissionsIn' (Snowflake Guild) where
  permissionsIn' gid m = do
    g <- upgrade gid
    case g of
      Just g' -> permissionsIn' g' m
      Nothing -> pure noFlags