{-# 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
(Int -> FileId -> ShowS)
-> (FileId -> String) -> ([FileId] -> ShowS) -> Show FileId
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> FileId -> ShowS
showsPrec :: Int -> FileId -> ShowS
$cshow :: FileId -> String
show :: FileId -> String
$cshowList :: [FileId] -> ShowS
showList :: [FileId] -> ShowS
Show, FileId -> FileId -> Bool
(FileId -> FileId -> Bool)
-> (FileId -> FileId -> Bool) -> Eq FileId
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: FileId -> FileId -> Bool
== :: FileId -> FileId -> Bool
$c/= :: FileId -> FileId -> Bool
/= :: FileId -> FileId -> Bool
Eq)
  deriving newtype (Value -> Parser [FileId]
Value -> Parser FileId
(Value -> Parser FileId)
-> (Value -> Parser [FileId]) -> FromJSON FileId
forall a.
(Value -> Parser a) -> (Value -> Parser [a]) -> FromJSON a
$cparseJSON :: Value -> Parser FileId
parseJSON :: Value -> Parser FileId
$cparseJSONList :: Value -> Parser [FileId]
parseJSONList :: Value -> Parser [FileId]
FromJSON, [FileId] -> Value
[FileId] -> Encoding
FileId -> Value
FileId -> Encoding
(FileId -> Value)
-> (FileId -> Encoding)
-> ([FileId] -> Value)
-> ([FileId] -> Encoding)
-> ToJSON FileId
forall a.
(a -> Value)
-> (a -> Encoding)
-> ([a] -> Value)
-> ([a] -> Encoding)
-> ToJSON a
$ctoJSON :: FileId -> Value
toJSON :: FileId -> Value
$ctoEncoding :: FileId -> Encoding
toEncoding :: FileId -> Encoding
$ctoJSONList :: [FileId] -> Value
toJSONList :: [FileId] -> Value
$ctoEncodingList :: [FileId] -> Encoding
toEncodingList :: [FileId] -> Encoding
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
(Int -> FileMode -> ShowS)
-> (FileMode -> String) -> ([FileMode] -> ShowS) -> Show FileMode
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> FileMode -> ShowS
showsPrec :: Int -> FileMode -> ShowS
$cshow :: FileMode -> String
show :: FileMode -> String
$cshowList :: [FileMode] -> ShowS
showList :: [FileMode] -> ShowS
Show, FileMode -> FileMode -> Bool
(FileMode -> FileMode -> Bool)
-> (FileMode -> FileMode -> Bool) -> Eq FileMode
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: FileMode -> FileMode -> Bool
== :: FileMode -> FileMode -> Bool
$c/= :: FileMode -> FileMode -> Bool
/= :: FileMode -> FileMode -> Bool
Eq, (forall x. FileMode -> Rep FileMode x)
-> (forall x. Rep FileMode x -> FileMode) -> Generic FileMode
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
$cfrom :: forall x. FileMode -> Rep FileMode x
from :: forall x. FileMode -> Rep FileMode x
$cto :: forall x. Rep FileMode x -> FileMode
to :: forall x. Rep FileMode x -> FileMode
Generic)

instance FromJSON FileMode where
  parseJSON :: Value -> Parser FileMode
parseJSON = String -> (Text -> Parser FileMode) -> Value -> Parser FileMode
forall a. String -> (Text -> Parser a) -> Value -> Parser a
A.withText String
"FileMode" \case
    Text
"hosted" -> FileMode -> Parser FileMode
forall a. a -> Parser a
forall (f :: * -> *) a. Applicative f => a -> f a
pure FileMode
Hosted
    Text
"external" -> FileMode -> Parser FileMode
forall a. a -> Parser a
forall (f :: * -> *) a. Applicative f => a -> f a
pure FileMode
External
    Text
"snippet" -> FileMode -> Parser FileMode
forall a. a -> Parser a
forall (f :: * -> *) a. Applicative f => a -> f a
pure FileMode
Snippet
    Text
"post" -> FileMode -> Parser FileMode
forall a. a -> Parser a
forall (f :: * -> *) a. Applicative f => a -> f a
pure FileMode
Post
    Text
"file_access" -> FileMode -> Parser FileMode
forall a. a -> Parser a
forall (f :: * -> *) a. Applicative f => a -> f a
pure FileMode
FileAccess
    Text
"email" -> FileMode -> Parser FileMode
forall a. a -> Parser a
forall (f :: * -> *) a. Applicative f => a -> f a
pure FileMode
Email
    Text
other -> FileMode -> Parser FileMode
forall a. a -> Parser a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (FileMode -> Parser FileMode)
-> (Text -> FileMode) -> Text -> Parser FileMode
forall b c a. (b -> c) -> (a -> b) -> a -> c
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 (Text -> Parser FileMode) -> Text -> Parser FileMode
forall a b. (a -> b) -> a -> b
$ Text
other

instance ToJSON FileMode where
  toJSON :: FileMode -> Value
toJSON =
    Text -> Value
A.String (Text -> Value) -> (FileMode -> Text) -> FileMode -> Value
forall b c a. (b -> c) -> (a -> b) -> a -> c
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
(Int -> FileObjectVisible -> ShowS)
-> (FileObjectVisible -> String)
-> ([FileObjectVisible] -> ShowS)
-> Show FileObjectVisible
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> FileObjectVisible -> ShowS
showsPrec :: Int -> FileObjectVisible -> ShowS
$cshow :: FileObjectVisible -> String
show :: FileObjectVisible -> String
$cshowList :: [FileObjectVisible] -> ShowS
showList :: [FileObjectVisible] -> ShowS
Show, FileObjectVisible -> FileObjectVisible -> Bool
(FileObjectVisible -> FileObjectVisible -> Bool)
-> (FileObjectVisible -> FileObjectVisible -> Bool)
-> Eq FileObjectVisible
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: FileObjectVisible -> FileObjectVisible -> Bool
== :: FileObjectVisible -> FileObjectVisible -> Bool
$c/= :: FileObjectVisible -> FileObjectVisible -> Bool
/= :: 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
(Int -> FileObject -> ShowS)
-> (FileObject -> String)
-> ([FileObject] -> ShowS)
-> Show FileObject
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> FileObject -> ShowS
showsPrec :: Int -> FileObject -> ShowS
$cshow :: FileObject -> String
show :: FileObject -> String
$cshowList :: [FileObject] -> ShowS
showList :: [FileObject] -> ShowS
Show, FileObject -> FileObject -> Bool
(FileObject -> FileObject -> Bool)
-> (FileObject -> FileObject -> Bool) -> Eq FileObject
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: FileObject -> FileObject -> Bool
== :: FileObject -> FileObject -> Bool
$c/= :: FileObject -> FileObject -> Bool
/= :: FileObject -> FileObject -> Bool
Eq)

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

instance ToJSON FileObject where
  toJSON :: FileObject -> Value
toJSON (VisibleFileObject FileObjectVisible
obj) = case FileObjectVisible -> Value
forall a. ToJSON a => a -> Value
toJSON FileObjectVisible
obj of
    A.Object Object
o -> Object -> Value
A.Object (Object -> Value) -> Object -> Value
forall a b. (a -> b) -> a -> b
$ Object
o Object -> Object -> Object
forall a. Semigroup a => a -> a -> a
<> [Pair] -> Object
forall v. [(Key, v)] -> KeyMap v
KM.fromList [(Key
"file_access", Value
"visible")]
    Value
_ -> String -> 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", FileId -> Value
forall a. ToJSON a => a -> Value
toJSON FileId
fid)]