{-# LANGUAGE TemplateHaskell #-}

-- | Type definitions for the Slack files APIs.
-- See <https://api.slack.com/messaging/files>.
--
-- @since 1.6.0.0
module Web.Slack.Files.Types where

import Control.Monad.Fail (MonadFail (..))
import Data.Aeson ((.!=))
import Data.Aeson qualified as A
import Data.Aeson.KeyMap qualified as KM
import Web.Slack.AesonUtils (UnixTimestamp, snakeCaseOptions)
import Web.Slack.Prelude

-- | ID for a file, which looks something like @F2147483862@.
newtype FileId = FileId {FileId -> Text
unFileId :: Text}
  deriving stock (Int -> FileId -> ShowS
[FileId] -> ShowS
FileId -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [FileId] -> ShowS
$cshowList :: [FileId] -> ShowS
show :: FileId -> String
$cshow :: FileId -> String
showsPrec :: Int -> FileId -> ShowS
$cshowsPrec :: Int -> FileId -> ShowS
Show, FileId -> FileId -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: FileId -> FileId -> Bool
$c/= :: FileId -> FileId -> Bool
== :: FileId -> FileId -> Bool
$c== :: FileId -> FileId -> Bool
Eq)
  deriving newtype (Value -> Parser [FileId]
Value -> Parser FileId
forall a.
(Value -> Parser a) -> (Value -> Parser [a]) -> FromJSON a
parseJSONList :: Value -> Parser [FileId]
$cparseJSONList :: Value -> Parser [FileId]
parseJSON :: Value -> Parser FileId
$cparseJSON :: Value -> Parser FileId
FromJSON, [FileId] -> Encoding
[FileId] -> Value
FileId -> Encoding
FileId -> Value
forall a.
(a -> Value)
-> (a -> Encoding)
-> ([a] -> Value)
-> ([a] -> Encoding)
-> ToJSON a
toEncodingList :: [FileId] -> Encoding
$ctoEncodingList :: [FileId] -> Encoding
toJSONList :: [FileId] -> Value
$ctoJSONList :: [FileId] -> Value
toEncoding :: FileId -> Encoding
$ctoEncoding :: FileId -> Encoding
toJSON :: FileId -> Value
$ctoJSON :: FileId -> Value
ToJSON)

data FileMode
  = Hosted
  | External
  | Snippet
  | Post
  | FileAccess
  | -- | <https://slack.com/help/articles/206819278-Send-emails-to-Slack>
    --
    -- @since 1.6.1.0
    Email
  | -- | Other file modes.
    --
    --   @since 1.6.1.0
    Other Text
  deriving stock (Int -> FileMode -> ShowS
[FileMode] -> ShowS
FileMode -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [FileMode] -> ShowS
$cshowList :: [FileMode] -> ShowS
show :: FileMode -> String
$cshow :: FileMode -> String
showsPrec :: Int -> FileMode -> ShowS
$cshowsPrec :: Int -> FileMode -> ShowS
Show, FileMode -> FileMode -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: FileMode -> FileMode -> Bool
$c/= :: FileMode -> FileMode -> Bool
== :: FileMode -> FileMode -> Bool
$c== :: FileMode -> FileMode -> Bool
Eq, forall x. Rep FileMode x -> FileMode
forall x. FileMode -> Rep FileMode x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep FileMode x -> FileMode
$cfrom :: forall x. FileMode -> Rep FileMode x
Generic)

instance FromJSON FileMode where
  parseJSON :: Value -> Parser FileMode
parseJSON = forall a. String -> (Text -> Parser a) -> Value -> Parser a
A.withText String
"FileMode" \case
    Text
"hosted" -> forall (f :: * -> *) a. Applicative f => a -> f a
pure FileMode
Hosted
    Text
"external" -> forall (f :: * -> *) a. Applicative f => a -> f a
pure FileMode
External
    Text
"snippet" -> forall (f :: * -> *) a. Applicative f => a -> f a
pure FileMode
Snippet
    Text
"post" -> forall (f :: * -> *) a. Applicative f => a -> f a
pure FileMode
Post
    Text
"file_access" -> forall (f :: * -> *) a. Applicative f => a -> f a
pure FileMode
FileAccess
    Text
"email" -> forall (f :: * -> *) a. Applicative f => a -> f a
pure FileMode
Email
    Text
other -> forall (f :: * -> *) a. Applicative f => a -> f a
pure forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. Text -> FileMode
Other forall a b. (a -> b) -> a -> b
$ Text
other

instance ToJSON FileMode where
  toJSON :: FileMode -> Value
toJSON =
    Text -> Value
A.String forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. \case
      FileMode
Hosted -> Text
"hosted"
      FileMode
External -> Text
"external"
      FileMode
Snippet -> Text
"snippet"
      FileMode
Post -> Text
"post"
      FileMode
FileAccess -> Text
"file_access"
      FileMode
Email -> Text
"email"
      Other Text
s -> Text
s

-- | <https://api.slack.com/types/file>
data FileObjectVisible = FileObjectVisible
  { FileObjectVisible -> FileId
id :: FileId
  , FileObjectVisible -> UnixTimestamp
created :: UnixTimestamp
  , FileObjectVisible -> Text
name :: Text
  , FileObjectVisible -> Text
title :: Text
  , FileObjectVisible -> Text
mimetype :: Text
  , FileObjectVisible -> Text
urlPrivate :: Text
  , FileObjectVisible -> Bool
isExternal :: Bool
  , FileObjectVisible -> Int
size :: Int
  , FileObjectVisible -> FileMode
mode :: FileMode
  }
  deriving stock (Int -> FileObjectVisible -> ShowS
[FileObjectVisible] -> ShowS
FileObjectVisible -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [FileObjectVisible] -> ShowS
$cshowList :: [FileObjectVisible] -> ShowS
show :: FileObjectVisible -> String
$cshow :: FileObjectVisible -> String
showsPrec :: Int -> FileObjectVisible -> ShowS
$cshowsPrec :: Int -> FileObjectVisible -> ShowS
Show, FileObjectVisible -> FileObjectVisible -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: FileObjectVisible -> FileObjectVisible -> Bool
$c/= :: FileObjectVisible -> FileObjectVisible -> Bool
== :: FileObjectVisible -> FileObjectVisible -> Bool
$c== :: FileObjectVisible -> FileObjectVisible -> Bool
Eq)

$(deriveJSON snakeCaseOptions ''FileObjectVisible)

data FileObject
  = -- | File object is visible
    VisibleFileObject FileObjectVisible
  | -- | File object is in a shared channel so @files.info@ must be invoked to
    -- get any further details. See
    -- <https://api.slack.com/types/file#slack_connect_files> for more details.
    CheckFileInfo FileId
  deriving stock (Int -> FileObject -> ShowS
[FileObject] -> ShowS
FileObject -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [FileObject] -> ShowS
$cshowList :: [FileObject] -> ShowS
show :: FileObject -> String
$cshow :: FileObject -> String
showsPrec :: Int -> FileObject -> ShowS
$cshowsPrec :: Int -> FileObject -> ShowS
Show, FileObject -> FileObject -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: FileObject -> FileObject -> Bool
$c/= :: FileObject -> FileObject -> Bool
== :: FileObject -> FileObject -> Bool
$c== :: FileObject -> FileObject -> Bool
Eq)

instance FromJSON FileObject where
  parseJSON :: Value -> Parser FileObject
parseJSON = forall a. String -> (Object -> Parser a) -> Value -> Parser a
withObject String
"FileObject" forall a b. (a -> b) -> a -> b
$ \Object
obj -> do
    -- "visible" is undocumented, thanks Slack!
    Text
ty :: Text <- Object
obj forall a. FromJSON a => Object -> Key -> Parser (Maybe a)
.:? Key
"file_access" forall a. Parser (Maybe a) -> a -> Parser a
.!= Text
"visible"
    case Text
ty of
      Text
"visible" -> FileObjectVisible -> FileObject
VisibleFileObject forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall a. FromJSON a => Value -> Parser a
parseJSON (Object -> Value
A.Object Object
obj)
      Text
"check_file_info" -> FileId -> FileObject
CheckFileInfo forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Object
obj forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"id"
      Text
_ -> forall (m :: * -> *) a. MonadFail m => String -> m a
fail forall a b. (a -> b) -> a -> b
$ String
"unknown file_access type " forall a. Semigroup a => a -> a -> a
<> forall mono. MonoFoldable mono => mono -> [Element mono]
unpack Text
ty

instance ToJSON FileObject where
  toJSON :: FileObject -> Value
toJSON (VisibleFileObject FileObjectVisible
obj) = case forall a. ToJSON a => a -> Value
toJSON FileObjectVisible
obj of
    A.Object Object
o -> Object -> Value
A.Object forall a b. (a -> b) -> a -> b
$ Object
o forall a. Semigroup a => a -> a -> a
<> forall v. [(Key, v)] -> KeyMap v
KM.fromList [(Key
"file_access", Value
"visible")]
    Value
_ -> forall a. HasCallStack => String -> a
error String
"impossible"
  toJSON (CheckFileInfo FileId
fid) = [Pair] -> Value
A.object [(Key
"file_access", Value
"check_file_info"), (Key
"id", forall a. ToJSON a => a -> Value
toJSON FileId
fid)]