yesod-fb (empty) → 0.1
raw patch · 5 files changed
+193/−0 lines, 5 filesdep +aesondep +basedep +bytestringsetup-changed
Dependencies added: aeson, base, bytestring, conduit, crypto-api, fb, http-conduit, text, wai, yesod-core
Files
- LICENSE +30/−0
- README +0/−0
- Setup.hs +2/−0
- src/Yesod/Facebook.hs +121/−0
- yesod-fb.cabal +40/−0
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright (c)2012, Felipe Lessa++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++ * Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.++ * Redistributions in binary form must reproduce the above+ copyright notice, this list of conditions and the following+ disclaimer in the documentation and/or other materials provided+ with the distribution.++ * Neither the name of Felipe Lessa nor the names of other+ contributors may be used to endorse or promote products derived+ from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ README view
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ src/Yesod/Facebook.hs view
@@ -0,0 +1,121 @@+{-# LANGUAGE OverloadedStrings #-}+module Yesod.Facebook+ ( -- * Running @FacebookT@ actions inside @GHandler@+ YesodFacebook(..)+ , runFacebookT+ , runNoAuthFacebookT+ , getFbCredentials++ -- * Real-time update notifications+ , parseRealTimeUpdateNotifications+ , answerRealTimeUpdateChallenge+ ) where++import Control.Applicative ((<$>))+import Crypto.Classes (constTimeEq)+import Data.ByteString.Char8 () -- IsString+import qualified Data.Aeson as A+import qualified Data.ByteString.Lazy.Char8 as L+import qualified Data.Conduit as C+import qualified Data.Conduit.List as CL+import qualified Data.Text.Encoding as TE+import qualified Facebook as FB+import qualified Network.Wai as W+import qualified Network.HTTP.Conduit as HTTP+import qualified Yesod.Core as Y+++-- | The 'YesodFacebook' class for foundation datatypes that+-- support running 'FB.FacebookT' actions.+class Y.Yesod master => YesodFacebook master where+ -- | The credentials of your app.+ fbCredentials :: master -> FB.Credentials+ -- | HTTP manager used for contacting Facebook (may be the same+ -- as the one used for @yesod-auth@).+ fbHttpManager :: master -> HTTP.Manager+++-- | Returns Facebook's 'FB.Credentials' from inside a+-- 'Y.GHandler'. Just a convenience wrapper around+-- 'fbCredentials'.+getFbCredentials :: YesodFacebook master =>+ Y.GHandler sub master FB.Credentials+getFbCredentials = fbCredentials <$> Y.getYesod+++-- | Run a 'FacebookT' action inside a 'Y.GHandler' using your+-- credentials.+runFacebookT ::+ YesodFacebook master =>+ FB.FacebookT FB.Auth (Y.GHandler sub master) a+ -> Y.GHandler sub master a+runFacebookT act = do+ master <- Y.getYesod+ let creds = fbCredentials master+ manager = fbHttpManager master+ FB.runFacebookT creds manager act+++-- | Run a 'FacebookT' action inside a 'Y.GHandler' without using+-- your credentials. Usually you won't need to use this function+-- but it's provided for completeness' sake.+runNoAuthFacebookT ::+ YesodFacebook master =>+ FB.FacebookT FB.NoAuth (Y.GHandler sub master) a+ -> Y.GHandler sub master a+runNoAuthFacebookT act = do+ master <- Y.getYesod+ let manager = fbHttpManager master+ FB.runNoAuthFacebookT manager act+++----------------------------------------------------------------------+++-- | Same as 'getRealTimeUpdateNotifications' but does the+-- heavy-lifting for you. Throws an exception whenever any step+-- fails (signature header not found, invalid signature, invalid+-- JSON).+parseRealTimeUpdateNotifications ::+ (YesodFacebook master, A.FromJSON a) =>+ Y.GHandler sub master (FB.RealTimeUpdateNotification a)+parseRealTimeUpdateNotifications = do+ let myFail = fail . ("parseRealTimeUpdateNotifications: " ++)+ -- Get request's signature.+ waiReq <- Y.waiRequest+ case lookup "X-Hub-Signature" (W.requestHeaders waiReq) of+ Nothing -> myFail "X-Hub-Signature not found."+ Just sig -> do+ uncheckedData <- L.fromChunks <$> Y.lift (W.requestBody waiReq C.$$ CL.consume)+ mcheckedData <- runFacebookT $ FB.verifyRealTimeUpdateNotifications sig uncheckedData+ case mcheckedData of+ Nothing -> myFail "Signature is invalid."+ Just checkedData ->+ case A.decode checkedData of+ Nothing -> myFail "Could not decode data."+ Just ret -> return ret+++-- | Answer Facebook's challenge if the 'FB.RealTimeUpdateToken'+-- matches.+--+-- Whenever you modify your subscriptions, Facebook will try to+-- contact your server with the 'FB.RealTimeUpdateToken' that you+-- gave on your call to 'FB.modifySubscription'. This function+-- will correctly answer Facebook's challenge if the+-- 'FB.RealTimeUpdateToken' matches, otherwise it will return+-- 'Y.notFound'.+answerRealTimeUpdateChallenge ::+ FB.RealTimeUpdateToken+ -> Y.GHandler sub master Y.RepPlain+answerRealTimeUpdateChallenge token = do+ mhubMode <- Y.lookupGetParam "hub.mode"+ mhubChallenge <- Y.lookupGetParam "hub.challenge"+ mhubVerifyToken <- Y.lookupGetParam "hub.verify_token"+ case (mhubMode, mhubChallenge, mhubVerifyToken) of+ -- FIXME: Is hub.mode always subscribe? Facebook's docs say+ -- so, but I don't believe them =).+ (Just "subscribe", Just hubChallenge, Just hubVerifyToken)+ | TE.encodeUtf8 hubVerifyToken `constTimeEq` token ->+ return $ Y.RepPlain (Y.toContent hubChallenge)+ _ -> Y.notFound
+ yesod-fb.cabal view
@@ -0,0 +1,40 @@+Name: yesod-fb+Version: 0.1+Synopsis: Useful glue functions between the fb library and Yesod.+Homepage: https://github.com/meteficha/yesod-fb+License: BSD3+License-file: LICENSE+Author: Felipe Lessa+Maintainer: Felipe Lessa <felipe.lessa@gmail.com>+Category: Web+Build-type: Simple+Cabal-version: >= 1.6+Extra-source-files: README++Description:+ This package contains useful glue functions between the fb+ package (http://hackage.haskell.org/package/fb) and Yesod.+ These functions can't be included on the fb package itself+ because it should not depend on Yesod.++Source-repository head+ type: git+ location: git://github.com/meteficha/yesod-fb.git++Library+ hs-source-dirs: src++ Build-depends: base >= 4.3 && < 5+ , yesod-core == 1.1.*+ , fb >= 0.11.1 && < 0.12++ , crypto-api+ , http-conduit+ , wai+ , conduit+ , aeson+ , text+ , bytestring++ Exposed-modules: Yesod.Facebook+ GHC-options: -Wall