{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DerivingVia #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE ApplicativeDo #-}
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE RankNTypes #-}
module Dropbox
( createClient
, dropboxProxy
, Dropbox(..)
, defListFolderRequest
, FileTag(..)
, Entry(..)
, ListFolderResponse(..)
, ListFolderRequest
, path
, LinkResponse(..)
, LinkRequest(..)
) where
import Control.Exception(throwIO)
import Data.Proxy
import Data.Text(Text)
import Network.HTTP.Client.TLS
import Servant.API
import Servant.Client.Generic
import Servant.API.Generic
import Data.Aeson
import Servant.Auth
import Servant.Auth.Client
import Servant.Client
import Web.FormUrlEncoded hiding (fieldLabelModifier)
import Data.Char (isLower)
toSnake :: String -> String
toSnake = camelTo2 '_' . dropWhile isLower
data ListFolderRequest = ListFolderRequest
{ path :: String
, recursive :: Bool
, include_media_info :: Bool
, include_deleted :: Bool
, include_has_explicit_shared_members :: Bool
, include_mounted_folders :: Bool
, include_non_downloadable_files :: Bool
} deriving (Generic, ToJSON)
newtype LinkRequest = LinkRequest
{ linkPath :: String
} deriving (Generic)
instance ToJSON LinkRequest where
toJSON (LinkRequest lpath) =
object ["path" .= lpath]
defListFolderRequest :: ListFolderRequest
defListFolderRequest = ListFolderRequest
{ path = ""
, recursive = False
, include_media_info = False
, include_deleted = False
, include_has_explicit_shared_members = False
, include_mounted_folders = True
, include_non_downloadable_files = False
}
data FileTag = File | Folder
deriving (Generic, FromJSON, Show, Eq)
data Entry = Entry
{ eTag :: FileTag
, eName :: Text
, ePathDisplay :: Text
, eId :: Text
} deriving (Generic, Show, Eq)
instance FromJSON Entry where
parseJSON = withObject "Entry" $ \v -> do
tag' :: Text <- v .: ".tag"
let eTag = if tag' == "file" then File else Folder
eName <- v .: "name"
ePathDisplay <- v .: "path_display"
eId <- v .: "id"
pure $ Entry {..}
newtype ListFolderResponse = ListFolderResponse
{ entries :: [Entry]
} deriving (Generic, FromJSON, Show, Eq)
data TokenRequest = TokenRequest
{ trAccessToken :: Text
, trExpiresIn :: Maybe Int
, trTokenType :: Text
, trRefreshToken :: Maybe Text
, trScope :: Text
, trAccountId :: Text
, trUid :: Text
} deriving Generic
snakeConstructor :: Options
snakeConstructor = defaultOptions { constructorTagModifier = camelTo2 '_' }
snakeLabel :: Options
snakeLabel = snakeConstructor { fieldLabelModifier = toSnake }
instance FromJSON TokenRequest where
parseJSON = genericParseJSON snakeLabel
data TokenBody = TokenBody
{ code :: Maybe Text
, refresh_token :: Maybe Text
, grant_type :: Text
, redirect_uri :: Text
, client_id :: Text
, client_secret :: Text
} deriving (Generic, Show, ToForm)
newtype LinkResponse = LinkResponse {
link :: Text
} deriving (Generic, Show, FromJSON)
data Dropbox route = Dropbox
{
_dropbox_list_folder :: route :- "2" :> "files" :> "list_folder" :> Auth '[Bearer] Token :> ReqBody '[JSON] ListFolderRequest :> Post '[JSON] ListFolderResponse
, _dropbox_get_temporary_link :: route :- "2" :> "files" :> "get_temporary_link" :> Auth '[Bearer] Token :> ReqBody '[JSON] LinkRequest :> Post '[JSON] LinkResponse
, _dropbox_token :: route :- "oauth2" :> "token" :> ReqBody '[FormUrlEncoded] TokenBody :> Post '[JSON] TokenRequest
} deriving Generic
dropboxProxy :: Proxy (ToServant Dropbox AsApi)
dropboxProxy = genericApi (Proxy @Dropbox)
cliRoutes :: ClientEnv -> Dropbox (AsClientT IO)
cliRoutes env = genericClientHoist
(\x -> runClientM x env >>= either throwIO return)
createClient :: IO (Dropbox (AsClientT IO))
createClient = do
baseUri <- parseBaseUrl "https://api.dropboxapi.com/"
manager <- newTlsManager
pure $ cliRoutes $ mkClientEnv manager baseUri