module Yesod.Transloadit (
YesodTransloadit(..),
mkParams,
transloadIt,
handleTransloadit,
tokenText,
extractFirstResult,
ParamsResult,
ParamsError(..),
Key(..),
Template(..),
Secret(..),
TransloaditParams,
Signature
) where
import Control.Applicative
import Control.Lens.Operators hiding ((.=))
import Control.Monad (mzero)
import Crypto.Hash
import Data.Aeson
import Data.Aeson.Encode (encodeToTextBuilder)
import Data.Aeson.Lens hiding (key)
import qualified Data.Aeson.Lens as AL
import qualified Data.ByteString as BS
import qualified Data.ByteString.Lazy as BSL
import Data.Maybe
import Data.Monoid
import Data.Text
import qualified Data.Text.Lazy as TL
import Data.Text.Lazy.Builder (toLazyText)
import Data.Time
import System.Locale
import Text.Julius
import Yesod hiding (Key)
import Yesod.Form.Jquery (YesodJquery (..))
class YesodTransloadit master where
transloaditRoot :: master -> Text
transloaditRoot _ = "https://assets.transloadit.com/js/"
newtype Secret = Secret { secret :: BS.ByteString } deriving (Eq, Show)
newtype Key = Key { key :: Text } deriving (Eq, Show)
newtype Template = Template { template :: Text } deriving (Eq, Show)
data TransloaditParams = TransloaditParams {
authExpires :: UTCTime,
transloaditKey :: Key,
transloaditTemplate :: Template,
formIdent :: Text,
transloaditSecret :: Secret
} deriving (Show)
data ParamsError = UnknownError
type ParamsResult = Either ParamsError TransloaditParams
mkParams :: UTCTime
-> Key
-> Template
-> Text
-> Secret
-> ParamsResult
mkParams u k t f s = return (TransloaditParams u k t f s)
data TransloaditResponse = TransloaditResponse { raw :: Text, token :: Text } deriving (Show)
data Upload = Upload Text deriving (Show)
instance FromJSON Upload where
parseJSON (Object o) = Upload <$> (o .: "ssl_url")
parseJSON _ = mzero
formatExpiryTime :: UTCTime -> Text
formatExpiryTime = pack . formatTime defaultTimeLocale "%Y/%m/%d %H:%M:%S+00:00"
instance ToJSON TransloaditParams where
toJSON (TransloaditParams a (Key k) (Template t) _ _) = object [
"auth" .= object [
"key" .= k,
"expires" .= (formatExpiryTime a)
],
"template_id" .= t
]
encodeText :: ToJSON a => a -> TL.Text
encodeText = toLazyText . encodeToTextBuilder . toJSON
type Signature = Text
sign :: TransloaditParams -> Signature
sign cfg = (pack . show . hmacGetDigest) h
where h :: HMAC SHA1
h = hmac (s cfg) ((BSL.toStrict . encode) cfg)
s (transloaditSecret -> Secret s') = s'
transloadIt :: (YesodJquery m, YesodTransloadit m) => TransloaditParams -> WidgetT m IO Signature
transloadIt t@(TransloaditParams {..}) = do
master <- getYesod
let root = transloaditRoot master
signature = sign t
addScriptEither $ urlJqueryJs master
addScriptRemote $ root <> "jquery.transloadit2-v2-latest.js"
toWidget [julius|
$(function() {
$('##{rawJS formIdent}').transloadit({
wait : true,
params : JSON.parse('#{(rawJS . encodeText) t}')
});
});
|]
return signature
tokenText :: (YesodJquery m, YesodTransloadit m) => WidgetT m IO Text
tokenText = do
csrfToken <- fmap reqToken getRequest
return $ fromMaybe mempty csrfToken
handleTransloadit :: (RenderMessage m FormMessage, YesodJquery m, YesodTransloadit m) => WidgetT m IO (Maybe Text)
handleTransloadit = do
d <- runInputPost $ TransloaditResponse <$> ireq hiddenField "transloadit"
<*> ireq hiddenField "_token"
t <- tokenText
return $ case (token d == t) of
True -> return $ raw d
_ -> Nothing
extractFirstResult :: AsValue s => Text -> Maybe s -> Maybe Value
extractFirstResult _ Nothing = Nothing
extractFirstResult k (Just uploads) = uploads ^? AL.key "results" . AL.key k . nth 0 . AL.key "ssl_url"