packages feed

github-app-token-0.0.2.0: src/GitHub/App/Token/Permissions.hs

-- | Type-safe implementation for requesting 'AccessToken' permissions
--
-- <https://docs.github.com/en/rest/apps/apps?apiVersion=2022-11-28#create-an-installation-access-token-for-an-app>
--
-- Usage:
--
-- 1. Use a constructor function for a specific permission, each of which only
--    accepts appropriate values (e.g. you can't ask for @admin@ on a permission
--    that only allows @read@ or @write@).
-- 2. Combine these using 'Permissions' 'Semigroup' instance.
--
-- For example:
--
-- @
-- let permissions = 'actions' 'Read' <> 'checks' 'Write'
--
-- 'generateInstallationTokenScoped' mempty {permissions} creds installationId
-- @
--
-- Supplying the same permission more than once will take the higher:
--
-- @
-- 'checks' 'Read' <> 'checks' 'Write' == 'checks' 'Write'
-- @
module GitHub.App.Token.Permissions
  ( Permissions
  , Read (..)
  , Write (..)
  , Admin (..)
  , actions
  , administration
  , checks
  , codespaces
  , contents
  , dependabot_secrets
  , deployments
  , environments
  , issues
  , metadata
  , packages
  , pages
  , pull_requests
  , repository_custom_properties
  , repository_hooks
  , repository_projects
  , secret_scanning_alerts
  , secrets
  , security_events
  , single_file
  , statuses
  , vulnerability_alerts
  , workflows
  , members
  , organization_administration
  , organization_custom_roles
  , organization_custom_org_roles
  , organization_custom_properties
  , organization_copilot_seat_management
  , organization_announcement_banners
  , organization_events
  , organization_hooks
  , organization_personal_access_tokens
  , organization_personal_access_token_requests
  , organization_plan
  , organization_projects
  , organization_packages
  , organization_secrets
  , organization_self_hosted_runners
  , organization_user_blocking
  , team_discussions
  , email_addresses
  , followers
  , git_ssh_keys
  , gpg_keys
  , interaction_limits
  , profile
  , starring
  ) where

import GitHub.App.Token.Prelude hiding (Read)

import Data.Aeson (ToJSON (..))
import Data.Map.Monoidal.Strict (MonoidalMap)
import Data.Map.Monoidal.Strict qualified as MonoidalMap
import Data.Semigroup (Max (..))

{-# ANN module ("HLint: ignore Use camelCase" :: String) #-}

newtype Permissions = Permissions
  { _unwrap :: MonoidalMap Text Permission
  }
  deriving stock (Eq, Show)
  deriving newtype (Semigroup, Monoid, ToJSON)

data Permission
  = PermissionRead
  | PermissionWrite
  | PermissionAdmin
  deriving stock (Eq, Ord, Show)
  deriving (Semigroup) via (Max Permission)

instance ToJSON Permission where
  toJSON =
    toJSON @Text . \case
      PermissionRead -> "read"
      PermissionWrite -> "write"
      PermissionAdmin -> "admin"

class AsReadWrite a where
  toReadWritePermission :: a -> Permission

class AsReadWriteAdmin a where
  toReadWriteAdminPermission :: a -> Permission

data Read = Read

instance AsReadWrite Read where
  toReadWritePermission _ = PermissionRead

instance AsReadWriteAdmin Read where
  toReadWriteAdminPermission _ = PermissionRead

data Write = Write

instance AsReadWrite Write where
  toReadWritePermission _ = PermissionWrite

instance AsReadWriteAdmin Write where
  toReadWriteAdminPermission _ = PermissionWrite

data Admin = Admin

instance AsReadWriteAdmin Admin where
  toReadWriteAdminPermission _ = PermissionAdmin

actions :: AsReadWrite a => a -> Permissions
actions = mkReadWrite "actions"

administration :: AsReadWrite a => a -> Permissions
administration = mkReadWrite "administration"

checks :: AsReadWrite a => a -> Permissions
checks = mkReadWrite "checks"

codespaces :: AsReadWrite a => a -> Permissions
codespaces = mkReadWrite "codespaces"

contents :: AsReadWrite a => a -> Permissions
contents = mkReadWrite "contents"

dependabot_secrets :: AsReadWrite a => a -> Permissions
dependabot_secrets = mkReadWrite "dependabot_secrets"

deployments :: AsReadWrite a => a -> Permissions
deployments = mkReadWrite "deployments"

environments :: AsReadWrite a => a -> Permissions
environments = mkReadWrite "environments"

issues :: AsReadWrite a => a -> Permissions
issues = mkReadWrite "issues"

metadata :: AsReadWrite a => a -> Permissions
metadata = mkReadWrite "metadata"

packages :: AsReadWrite a => a -> Permissions
packages = mkReadWrite "packages"

pages :: AsReadWrite a => a -> Permissions
pages = mkReadWrite "pages"

pull_requests :: AsReadWrite a => a -> Permissions
pull_requests = mkReadWrite "pull_requests"

repository_custom_properties :: AsReadWrite a => a -> Permissions
repository_custom_properties = mkReadWrite "repository_custom_properties"

repository_hooks :: AsReadWrite a => a -> Permissions
repository_hooks = mkReadWrite "repository_hooks"

repository_projects :: AsReadWriteAdmin a => a -> Permissions
repository_projects = mkReadWriteAdmin "repository_projects"

secret_scanning_alerts :: AsReadWrite p => p -> Permissions
secret_scanning_alerts = mkReadWrite "secret_scanning_alerts"

secrets :: AsReadWrite p => p -> Permissions
secrets = mkReadWrite "secrets"

security_events :: AsReadWrite p => p -> Permissions
security_events = mkReadWrite "security_events"

single_file :: AsReadWrite p => p -> Permissions
single_file = mkReadWrite "single_file"

statuses :: AsReadWrite p => p -> Permissions
statuses = mkReadWrite "statuses"

vulnerability_alerts :: AsReadWrite p => p -> Permissions
vulnerability_alerts = mkReadWrite "vulnerability_alerts"

-- | Only supported permission is 'Write'
workflows :: Permissions
workflows = mkWrite "workflows"

members :: AsReadWrite p => p -> Permissions
members = mkReadWrite "members"

organization_administration :: AsReadWrite p => p -> Permissions
organization_administration = mkReadWrite "organization_administration"

organization_custom_roles :: AsReadWrite p => p -> Permissions
organization_custom_roles = mkReadWrite "organization_custom_roles"

organization_custom_org_roles :: AsReadWrite p => p -> Permissions
organization_custom_org_roles = mkReadWrite "organization_custom_org_roles"

organization_custom_properties :: AsReadWriteAdmin p => p -> Permissions
organization_custom_properties = mkReadWriteAdmin "organization_custom_properties"

-- | Only supported permission is 'Write'
organization_copilot_seat_management :: Permissions
organization_copilot_seat_management = mkWrite "organization_copilot_seat_management"

organization_announcement_banners :: AsReadWrite p => p -> Permissions
organization_announcement_banners = mkReadWrite "organization_announcement_banners"

-- | Only supported permission is 'Read'
organization_events :: Permissions
organization_events = mkRead "organization_events"

organization_hooks :: AsReadWrite p => p -> Permissions
organization_hooks = mkReadWrite "organization_hooks"

organization_personal_access_tokens :: AsReadWrite p => p -> Permissions
organization_personal_access_tokens = mkReadWrite "organization_personal_access_tokens"

organization_personal_access_token_requests :: AsReadWrite p => p -> Permissions
organization_personal_access_token_requests = mkReadWrite "organization_personal_access_token_requests"

-- | Only supported permission is 'Read'
organization_plan :: Permissions
organization_plan = mkRead "organization_plan"

organization_projects :: AsReadWriteAdmin p => p -> Permissions
organization_projects = mkReadWriteAdmin "organization_projects"

organization_packages :: AsReadWrite p => p -> Permissions
organization_packages = mkReadWrite "organization_packages"

organization_secrets :: AsReadWrite p => p -> Permissions
organization_secrets = mkReadWrite "organization_secrets"

organization_self_hosted_runners :: AsReadWrite p => p -> Permissions
organization_self_hosted_runners = mkReadWrite "organization_self_hosted_runners"

organization_user_blocking :: AsReadWrite p => p -> Permissions
organization_user_blocking = mkReadWrite "organization_user_blocking"

team_discussions :: AsReadWrite p => p -> Permissions
team_discussions = mkReadWrite "team_discussions"

email_addresses :: AsReadWrite p => p -> Permissions
email_addresses = mkReadWrite "email_addresses"

followers :: AsReadWrite p => p -> Permissions
followers = mkReadWrite "followers"

git_ssh_keys :: AsReadWrite p => p -> Permissions
git_ssh_keys = mkReadWrite "git_ssh_keys"

gpg_keys :: AsReadWrite p => p -> Permissions
gpg_keys = mkReadWrite "gpg_keys"

interaction_limits :: AsReadWrite p => p -> Permissions
interaction_limits = mkReadWrite "interaction_limits"

-- | Only supported permission is 'Write'
profile :: Permissions
profile = mkWrite "profile"

starring :: AsReadWrite p => p -> Permissions
starring = mkReadWrite "starring"

mkRead :: Text -> Permissions
mkRead name = Permissions $ MonoidalMap.singleton name PermissionRead

mkWrite :: Text -> Permissions
mkWrite name = Permissions $ MonoidalMap.singleton name PermissionWrite

mkReadWrite :: AsReadWrite p => Text -> p -> Permissions
mkReadWrite name =
  Permissions
    . MonoidalMap.singleton name
    . toReadWritePermission

mkReadWriteAdmin :: AsReadWriteAdmin p => Text -> p -> Permissions
mkReadWriteAdmin name =
  Permissions
    . MonoidalMap.singleton name
    . toReadWriteAdminPermission