packages feed

happstack-facebook 0.9 → 0.16

raw patch · 8 files changed

+244/−117 lines, 8 files

Files

Happstack/Facebook/Application.hs view
@@ -14,26 +14,23 @@ import Data.List (isPrefixOf, sortBy) import Data.Maybe (fromJust) import Data.Time.Clock.POSIX (POSIXTime)-import Happstack.Crypto.MD5 ( md5, stringMD5)+import Happstack.Crypto.MD5 (md5, stringMD5) import Happstack.Facebook.Common import Happstack.Facebook.FacebookT--- import qualified Happstack.Facebook.Feed as Feed--- import Happstack.Server.Extra (lookPairsUnicode)-import Happstack.State (Proxy(..))--- import HSP (HSPT,XML,XMLMetaData,evalHSPT,renderXML) import qualified Network.HTTP as HTTP import Network.Browser (Form(..),formToRequest, request, browse) import Network.URI-import Happstack.Server-+import Happstack.Server (Method(POST, GET), ServerMonad, withDataFn, lookPairs)  -- |This data type holds all the informaton that facebook pass along with the request -- http://wiki.developers.facebook.com/index.php/Your_callback_page_and_you+-- NOTE: the order of these fields is subject to change, so use the field labels for minimum breakage. data FacebookData =     FacebookData      { fbPairs         :: [(String, String)]     , _fb_sig_added   :: Bool-    , _fb_sig_in_canvas :: Bool+    , _fb_sig_is_admin       :: Maybe Bool+    , _fb_sig_in_canvas      :: Bool     , _fb_sig_request_method :: Method     , _fb_sig_position_fix :: Bool     , _fb_user        :: Maybe User@@ -46,6 +43,9 @@     , _fb_sig_session_key         :: Maybe SessionKey     , _fb_sig_expires             :: Maybe POSIXTime     , _fb_sig_profile_update_time :: Maybe POSIXTime+    , _fb_sig_profile_user        :: Maybe User+    , _fb_sig_profile_session_key :: Maybe SessionKey+    , _fb_sig_page_id             :: Maybe Page     , _fb_valid_sig :: Bool     }     deriving (Eq, Show)@@ -56,6 +56,9 @@ fb_sig_added :: (HasFacebookData FacebookData m) => m Bool fb_sig_added = fbd _fb_sig_added +fb_sig_is_admin :: (HasFacebookData FacebookData m) => m (Maybe Bool)+fb_sig_is_admin = fbd _fb_sig_is_admin+ fb_sig_in_canvas :: (HasFacebookData FacebookData m) => m Bool fb_sig_in_canvas = fbd _fb_sig_in_canvas @@ -112,18 +115,25 @@ fb_sig_profile_update_time = fbd _fb_sig_profile_update_time  +-- |The user ID of the profile owner for the tab being requested.+fb_sig_profile_user  :: (HasFacebookData FacebookData m) => m (Maybe User)+fb_sig_profile_user = fbd _fb_sig_profile_user +-- |The session key for the profile owner, which you use to render this user's profile tab content.+fb_sig_profile_session_key  :: (HasFacebookData FacebookData m) => m (Maybe SessionKey)+fb_sig_profile_session_key = fbd _fb_sig_profile_session_key++fb_sig_page_id :: (HasFacebookData FacebookData m) => m (Maybe Page)+fb_sig_page_id = fbd _fb_sig_page_id+ validateSignature :: AppSecret -> String -> [(String, String)] -> Bool validateSignature secret sig pairs =     let fb_sigs = map (first (drop 7)) $ filter (\(k,v) -> isPrefixOf "fb_sig_" k) pairs         (sig',_) = signature secret fb_sigs     in sig == sig' --- todo: add code to validate the sent fb_sig-withFacebookData :: (Monad m, MonadPlus m, ServerMonad m) => FacebookConfig -> (FacebookData -> m r) -> m r-withFacebookData config f =-    withDataFn -       (do pairs <- lookPairs+parseFacebookData :: FacebookConfig -> [(String, String)] -> FacebookData+parseFacebookData config pairs =            let lookupString k = case lookup k pairs of                                   Nothing -> error ("Could not find required field " ++ k)                                   (Just v) -> v@@ -133,6 +143,7 @@                readTime :: String -> POSIXTime                readTime str = realToFrac (read' str :: Double)                fb_sig_added' = lookupBool "fb_sig_added" pairs+               fb_sig_is_admin = lookupMBool "fb_sig_is_admin" pairs                fb_user' =                    case lookup "fb_sig_user" pairs of                      (Just uid) -> Just $ User (read' uid)@@ -149,33 +160,50 @@                fb_sig_session_key' = lookup "fb_sig_session_key" pairs                fb_sig_expires' = fmap readTime $ lookup "fb_sig_expires" pairs                fb_sig_profile_update_time' = fmap readTime $ lookup "fb_sig_profile_update_time" pairs+               fb_sig_profile_user' =+                   case lookup "fb_sig_profile_user" pairs of+                     (Just uid) -> Just $ User (read' uid)+                     Nothing -> Nothing+               fb_sig_profile_session_key' = lookup "fb_sig_profile_session_key" pairs+               fb_sig_page_id = case lookup "fb_sig_page_id" pairs of+                                  (Just pid) -> Just $ Page (read' pid)+                                  Nothing -> Nothing                valid_sig = validateSignature (appSecret config) fb_sig' pairs-           return (FacebookData { fbPairs = pairs -                                , _fb_sig_added = fb_sig_added'-                                , _fb_sig_in_canvas = lookupBool "fb_sig_in_canvas" pairs-                                , _fb_sig_request_method = -                                    case lookupString "fb_sig_request_method" of-                                      "GET" -> GET-                                      "POST" -> POST-                                , _fb_sig_position_fix = lookupBool "fb_sig_position_fix" pairs-                                , _fb_user = fb_user'-                                , _fb_sig_time = fb_sig_time'-                                , _fb_sig_api_key = fb_sig_api_key'-                                , _fb_sig_locale = fb_sig_locale' -                                , _fb_sig = fb_sig' -                                , _fb_sig_friends = fb_sig_friends' -                                , _fb_sig_session_key = fb_sig_session_key' -                                , _fb_sig_expires = fb_sig_expires' -                                , _fb_sig_profile_update_time = fb_sig_profile_update_time' -                                , _fb_valid_sig = valid_sig-                                }))+           in (FacebookData { fbPairs = pairs +                            , _fb_sig_added = fb_sig_added'+                            , _fb_sig_is_admin = fb_sig_is_admin+                            , _fb_sig_in_canvas = lookupBool "fb_sig_in_canvas" pairs+                            , _fb_sig_request_method = +                                case lookupString "fb_sig_request_method" of+                                  "GET" -> GET+                                  "POST" -> POST+                            , _fb_sig_position_fix = lookupBool "fb_sig_position_fix" pairs+                            , _fb_user = fb_user'+                            , _fb_sig_time = fb_sig_time'+                            , _fb_sig_api_key = fb_sig_api_key'+                            , _fb_sig_locale = fb_sig_locale' +                            , _fb_sig = fb_sig' +                            , _fb_sig_friends = fb_sig_friends' +                            , _fb_sig_session_key = fb_sig_session_key' +                            , _fb_sig_expires = fb_sig_expires' +                            , _fb_sig_profile_update_time = fb_sig_profile_update_time' +                            , _fb_sig_profile_user = fb_sig_profile_user'+                            , _fb_sig_profile_session_key = fb_sig_profile_session_key'+                            , _fb_sig_page_id = fb_sig_page_id+                            , _fb_valid_sig = valid_sig+                            })++-- todo: add code to validate the sent fb_sig+withFacebookData :: (Monad m, MonadPlus m, ServerMonad m) => FacebookConfig -> (FacebookData -> m r) -> m r+withFacebookData config f =+    withDataFn +       (do pairs <- lookPairs+           return $ parseFacebookData config pairs)        f  withFacebook :: (Monad m, MonadPlus m, ServerMonad m) => FacebookConfig -> FacebookT (FacebookState FacebookData) m a -> m a withFacebook config sp = withFacebookData config $ \fbd -> withFacebook' config fbd sp -- withUserSP :: ( HasFacebookConfig (FacebookT (s d) m)               , HasFacebookData d (FacebookT (s d) m)               , HasFacebookData FacebookData (FacebookT (s d) m)@@ -189,6 +217,19 @@          (Just user) -> withUser user handler  +withProfileUserSP :: ( HasFacebookConfig (FacebookT (s d) m)+              , HasFacebookData d (FacebookT (s d) m)+              , HasFacebookData FacebookData (FacebookT (s d) m)+              , MonadPlus m+              ) +              => FacebookT (FacebookStateU d) m a -> FacebookT (s d) m a+withProfileUserSP handler =+    do mUser <- fb_sig_profile_user+       case mUser of+         Nothing     -> mzero+         (Just user) -> withUser user handler++ withSessionSP :: ( HasFacebookConfig (FacebookT (s d) m)                  , HasFacebookData d (FacebookT (s d) m)                  , HasFacebookData FacebookData (FacebookT (s d) m)@@ -207,6 +248,7 @@                            Nothing -> mzero                            (Just sessionKey) ->                                withSession sessionKey handler+   {-
Happstack/Facebook/Common.hs view
@@ -7,7 +7,7 @@ import qualified Data.ByteString.Lazy.Char8 as L import qualified Data.ByteString.Lazy.UTF8 as L import Control.Monad(mzero, ap)-import Control.Monad.Reader(MonadReader(..),ReaderT(..))+import Control.Monad.Reader(MonadReader(..),ReaderT(..), mapReaderT) import Control.Monad.Trans(MonadTrans(..)) import Control.Monad.Trans(MonadIO(liftIO)) import qualified Data.ByteString.Char8 as P@@ -33,12 +33,15 @@ import Network.URI import System.Time (ClockTime(TOD),getClockTime) import Text.RJson -- FIXME: use different JSON library?+import URLT(URLT)  data FacebookConfig =      FacebookConfig { apiKey     :: ApiKey                    , appSecret  :: AppSecret                    , appId      :: AppId                    , canvasURL  :: URI+                   , canvasCallbackURL  :: URI+                   , tabURL     :: Maybe URI                    , connectURL :: URI                    }     deriving (Show, Eq)@@ -52,13 +55,22 @@  -- | $(deriveAll  [''Eq, ''Ord, ''Read, ''Show, ''Ix, ''Default]-  [d| newtype User = User { uid :: Integer }-      newtype Flid = Flid { unFlid :: Integer }+  [d| newtype Flid = Flid { unFlid :: Integer }       data    Sex  = Male | Female    |])++newtype User = User { uid :: Integer }+      deriving (Eq, Ord, Read, Show, Ix, Typeable, Data)+$(deriveNewData [''User]) instance Version User $(deriveSerialize ''User) +newtype Page = Page { pageId :: Integer }+      deriving (Eq, Ord, Read, Show, Ix, Typeable, Data)+$(deriveNewData [''Page])+instance Version Page+$(deriveSerialize ''Page)+ instance Version Sex $(deriveSerialize ''Sex) @@ -111,10 +123,10 @@                     }  instance (Monad m) => HasFacebookConfig (FacebookT (FacebookState d) m) where-    askFacebookConfig = fbConfig <$> ask+    askFacebookConfig = fbConfig <$> askFacebookState  instance (Monad m) => HasFacebookData d (FacebookT (FacebookState d) m) where-    askFacebookData = fbData <$> ask+    askFacebookData = fbData <$> askFacebookState  data FacebookStateU d     = FacebookStateU { fbuConfig :: FacebookConfig -- our api id, etc,@@ -123,14 +135,13 @@                      }  instance (Monad m) => HasFacebookConfig (FacebookT (FacebookStateU d) m) where-    askFacebookConfig = fbuConfig <$> ask+    askFacebookConfig = fbuConfig <$> askFacebookState  instance (Monad m) => HasFacebookData d (FacebookT (FacebookStateU d) m) where-    askFacebookData = fbuData <$> ask+    askFacebookData = fbuData <$> askFacebookState  instance (Monad m) => HasUser (FacebookT (FacebookStateU d) m) where-    askUser = fbuUser <$> ask-+    askUser   = fbuUser <$> askFacebookState  data FacebookStateS d     = FacebookStateS { fbsConfig     :: FacebookConfig -- our api id, etc,@@ -141,17 +152,16 @@   instance (Monad m) => HasFacebookConfig (FacebookT (FacebookStateS d) m) where-    askFacebookConfig = fbsConfig <$> ask-+    askFacebookConfig = fbsConfig <$> askFacebookState  instance (Monad m) => HasFacebookData d (FacebookT (FacebookStateS d) m) where-    askFacebookData = fbsData <$> ask+    askFacebookData = fbsData <$> askFacebookState  instance (Monad m) => HasUser (FacebookT (FacebookStateS d) m) where-    askUser = fbsUser <$> ask+    askUser = fbsUser <$> askFacebookState  instance (Monad m) => HasSessionKey (FacebookT (FacebookStateS d) m) where-    askSessionKey = fbsSessionKey <$> ask+    askSessionKey = fbsSessionKey <$> askFacebookState   -- ** XMLGenT @@ -170,10 +180,37 @@     askSessionKey = XMLGenT $ askSessionKey  +-- ** ServerPartT ++instance (HasFacebookData d m) => HasFacebookData d (ServerPartT m) where+    askFacebookData = lift askFacebookData++instance (HasFacebookConfig m) => HasFacebookConfig (ServerPartT m) where+    askFacebookConfig = lift askFacebookConfig++instance (HasUser m) => HasUser (ServerPartT m) where+    askUser = lift askUser++instance (HasSessionKey m) => HasSessionKey (ServerPartT m) where+    askSessionKey = lift askSessionKey++-- ** URLT++instance (HasFacebookData d m) => HasFacebookData d (URLT u m) where+    askFacebookData = lift askFacebookData    ++instance (HasFacebookConfig m) => HasFacebookConfig (URLT url m) where+    askFacebookConfig = lift askFacebookConfig++instance (HasUser m) => HasUser (URLT url m) where+    askUser = lift askUser++instance (HasSessionKey m) => HasSessionKey (URLT url m) where+    askSessionKey = lift askSessionKey+ assocToJSON :: [(String, String)] -> JsonData assocToJSON assoc = JDObject $ Map.fromList (map (second toJson) assoc) - parseResponseBool :: String -> Either String Bool parseResponseBool str =     case fromJsonString [] str of@@ -199,9 +236,16 @@     case lookup key assoc of       Nothing -> error ("required key " ++ key ++ " was not found.")       (Just "0") -> False-      (Just "1") -> False+      (Just "1") -> True       (Just str) -> error ("key " ++ key ++ " has unparsable value " ++ str) +lookupMBool :: String -> [(String, String)] -> Maybe Bool+lookupMBool key assoc =+    case lookup key assoc of+      Nothing -> Nothing+      (Just "0") -> Just False+      (Just "1") -> Just True+      (Just str) -> Nothing   toCommaList :: [String] -> String toCommaList = intercalate ","@@ -359,10 +403,13 @@     do d <- askFacebookData        return (select d) -withUser :: (HasFacebookData d (FacebookT (s d) m), HasFacebookConfig (FacebookT (s d) m))-         => User-         -> FacebookT (FacebookStateU d) m a-         -> FacebookT (s d) m a++-- TODO: figure how to implement this so that it can be called when the FacebookT is embed inside other monad transformers+withUser ::+  ( HasFacebookConfig (FacebookT r m)+  , HasFacebookData d (FacebookT r m)+  ) +  => User -> FacebookT (FacebookStateU d) m a -> FacebookT r m a withUser u (FacebookT action) =     do c <- askFacebookConfig        d <- askFacebookData
Happstack/Facebook/Connect.hs view
@@ -23,6 +23,7 @@     , _fbc_sig_ss            :: Maybe String     , _fbc_user              :: Maybe User     , _fbc_sig               :: Maybe String+    , _fbc_valid_sig         :: Bool     }     deriving (Eq, Show) @@ -50,40 +51,19 @@ fb_sig :: (HasFacebookData FacebookConnectData m) => m (Maybe String) fb_sig = fbd _fbc_sig -validateSignature :: AppSecret -> FacebookConnectData -> Bool-validateSignature secret d = (Just sig) == (_fbc_sig d)-  where sorted = sortBy (compare `on` fst) (_fbc_cookies d)-        dataStr = concatMap (\(k,v) -> k ++ '=' : (cookieValue v)) sorted-        sig = stringMD5 (md5 (L.pack (dataStr++(unAppSecret secret))))                                                             +fb_sig_cookies :: (HasFacebookData FacebookConnectData m) => m [(String, Cookie)]+fb_sig_cookies = fbd _fbc_cookies --- todo: add code to validate the sent fb_sig-{--withFacebookConnectData :: (Monad m) => FacebookConfig -> (FacebookConnectData -> ServerPartT m r) -> ServerPartT m r-withFacebookConnectData config f =-  withDataFn buildFBCData f-  where read' str = case reads str of-                         [(a,[])] -> a-                         r -> error ("Failed to read " ++ str ++ " got " ++ show r)-        readTime :: String -> POSIXTime-        readTime str = realToFrac (read' str :: Double)-        lookupString :: String -> RqData (Maybe String)-        lookupString k = do-          cookies <- asks snd-          return $ fmap cookieValue $ lookup (map toLower (unApiKey (apiKey config) ++k)) cookies-        buildFBCData :: RqData FacebookConnectData-        buildFBCData = do-          expires <- lookupString "_expires"-          sesKey <- lookupString "_session_key"                                                                                               -          ss <- lookupString "_ss"                                                                                                             -          sig <- lookupString ""-          user <- lookupString "_user"-          cookies <- asks snd-          return $ FacebookConnectData-            (filter (isPrefixOf (unApiKey (apiKey config)++"_") . fst) cookies)-            (fmap readTime expires) sesKey ss (fmap (User . read) user) sig--}+-- |is the signature valid+fb_valid_sig :: (HasFacebookData FacebookConnectData m) => m Bool+fb_valid_sig = fbd _fbc_valid_sig --- TODO: add code to validate the sent fb_sig+validateSignature :: AppSecret -> Maybe String -> [(String, Cookie)] -> Bool+validateSignature secret sig cookies = sig == sig'+  where sorted = sortBy (compare `on` fst) cookies+        dataStr = concatMap (\(k,v) -> k ++ '=' : (cookieValue v)) sorted+        sig' = Just $ stringMD5 (md5 (L.pack (dataStr++(unAppSecret secret))))                                                             + withFacebookConnectData ::      ( Monad m     , MonadPlus m@@ -108,14 +88,16 @@           sig <- lookupString ""           user <- lookupString "_user"           cookies <- asks snd+          let fbcCookies = map (\(k,v) -> (drop ((length (unApiKey (apiKey config)))+1) k, v)) $ filter (isPrefixOf ((unApiKey (apiKey config))++"_") . fst) cookies           return $ FacebookConnectData-            (filter (isPrefixOf (unApiKey (apiKey config)++"_") . fst) cookies)-            (fmap readTime expires) sesKey ss (fmap (User . read) user) sig--{--withFacebookConnect :: (Monad m) => FacebookConfig -> FacebookT (FacebookState FacebookConnectData) (ServerPartT m) a -> ServerPartT m a-withFacebookConnect config sp = withFacebookConnectData config $ \fbd -> withFacebook' config fbd sp--}+                     { _fbc_cookies = fbcCookies+                     , _fbc_sig_expires = (fmap readTime expires) +                     , _fbc_sig_session_key = sesKey +                     , _fbc_sig_ss = ss+                     , _fbc_user = (fmap (User . read) user) +                     , _fbc_sig = sig+                     , _fbc_valid_sig = (validateSignature (appSecret config) sig fbcCookies)+                     }  withFacebookConnect ::      ( Monad m@@ -155,3 +137,15 @@                            Nothing -> mzero                            (Just sessionKey) ->                                withSession sessionKey handler++-- |clear the facebook connect cookies effectively logging the user out+fbcLogout :: (HasFacebookData FacebookConnectData m, HasFacebookConfig m, FilterMonad Response m) => m ()+fbcLogout =+    do cookies <- fb_sig_cookies+       config <- askFacebookConfig+       let clear c =+               do let key = unApiKey (apiKey config) ++"_"++ c+                      cookie = (mkCookie key "0")+                  addCookie 0 cookie+       mapM (clear . fst) cookies+       return ()
Happstack/Facebook/FacebookT.hs view
@@ -6,15 +6,35 @@ import Control.Applicative (Applicative((<*>), pure), Alternative((<|>), empty), WrappedMonad(WrapMonad, unwrapMonad), (<$>)) import Control.Monad.Identity import Control.Monad.Reader+import Control.Monad.Writer+import Control.Monad.State import Data.List (intersperse) import qualified HSX.XMLGenerator as HSX-import Happstack.Server (ServerMonad(askRq, localRq), FilterMonad(setFilter,composeFilter,getFilter), WebMonad(finishWith))+import Happstack.Server (ServerMonad(askRq, localRq), ServerPartT, FilterMonad(setFilter,composeFilter,getFilter), WebMonad(finishWith), mapServerPartT) import URLT (ShowURL(showURL), URL)  newtype FacebookT s m a =     FacebookT { unFacebookT :: ReaderT s m a }               deriving (Functor, Monad, MonadFix, MonadPlus, MonadIO, MonadTrans) +class MonadFacebook m where+    type FacebookTState m+    askFacebookState :: m (FacebookTState m)++instance (Monad m) => MonadFacebook (FacebookT s m) where+    type FacebookTState (FacebookT s m) = s+    askFacebookState = FacebookT ask++instance (Monad m, MonadFacebook m) => MonadFacebook (ServerPartT m) where+    type FacebookTState (ServerPartT m) = FacebookTState m+    askFacebookState = lift askFacebookState++runFacebookT :: FacebookT s m a -> s -> m a+runFacebookT = runReaderT . unFacebookT ++mapFacebookT :: (m a -> n b) -> FacebookT s m a -> FacebookT s n b+mapFacebookT f (FacebookT (ReaderT m)) = FacebookT $ ReaderT $ \s -> f (m s)+ instance (Monad m) => Applicative (FacebookT s m) where     pure = FacebookT . return     (FacebookT m) <*> (FacebookT n) = FacebookT (m `ap` n)@@ -35,11 +55,18 @@ instance (WebMonad a m) => WebMonad a (FacebookT s m) where     finishWith = lift . finishWith --- normally we would just derive this, but trhsx can't handle it--- (haddock used to break as well, I wonder if that is fixed now?)-instance (Monad m) => MonadReader s (FacebookT s m) where-    ask = FacebookT ask-    local f (FacebookT m) = FacebookT (local f m)+instance (MonadReader r m) => MonadReader r (FacebookT s m) where+    ask = lift ask+    local f = mapFacebookT (local f)++instance (MonadWriter w m) => MonadWriter w (FacebookT s m) where+    tell   = lift . tell+    listen = mapFacebookT listen+    pass   = mapFacebookT pass++instance (MonadState st m) => MonadState st (FacebookT s m) where+    get = lift get+    put = lift . put  instance (ShowURL m) => ShowURL (FacebookT s m) where     type URL (FacebookT s m) = URL m
+ Happstack/Facebook/Pages.hs view
@@ -0,0 +1,26 @@+{-# LANGUAGE DeriveDataTypeable, FlexibleInstances, MultiParamTypeClasses, TypeFamilies #-}+module Happstack.Facebook.Pages where++import Data.Maybe (catMaybes)+import Happstack.Facebook.Common hiding (uid, name)+import qualified Happstack.Facebook.Common as C+import Text.JSON++-- |checks whether a given user is an admin for a given page+-- http://wiki.developers.facebook.com/index.php/Pages.isAdmin+data IsAdmin = IsAdmin Page (Maybe User)++instance (HasSessionKey m) => FacebookMethod m IsAdmin where+    type FacebookResponse IsAdmin = Bool+    parseResponse _ jstr =+        case decode jstr of+          (Ok bool) -> Right bool+          (Error msg) -> Left msg+    toParams (IsAdmin page mUser) =+        do sessionKey <- askSessionKey+           return $  [ ("method", "Pages.isAdmin")+                     , ("session_key", sessionKey)+                     , ("page_id", show (pageId page))+                     ] ++ catMaybes +                     [ fmap (\user -> ("uid", show (C.uid user))) mUser+                     ]
Happstack/Facebook/XdReceiver.hs view
@@ -8,6 +8,7 @@ import HSP import Happstack.Server.HSP.HTML (webHSP) import Happstack.Facebook.Common+import Happstack.Facebook.FacebookT import qualified HSX.XMLGenerator as HSX import Network.URI (uriPath) import System.FilePath ((</>), splitPath)
− examples/FacebookConfig.hs
@@ -1,14 +0,0 @@-module FacebookConfig {-# WARNING "This demo requires that you provide your own facebook connect configuration information. http://www.facebook.com/developers/?ref=sb" #-} (facebookConfig) where--import Data.Maybe (fromJust)-import Happstack.Facebook.Common (FacebookConfig(..), ApiKey(..), AppId(..), AppSecret(..))-import Network.URI (parseURI)--facebookConfig :: FacebookConfig-facebookConfig =-    FacebookConfig { apiKey     = ApiKey    ""-                   , appSecret  = AppSecret ""-                   , appId      = AppId     ""-                   , canvasURL  = fromJust $ parseURI ""-                   , connectURL = fromJust $ parseURI ""-                   }
happstack-facebook.cabal view
@@ -1,15 +1,15 @@ Name:             happstack-facebook-Version:          0.9+Version:          0.16 License:          BSD3 License-file:     debian/copyright Author:           jeremy@seereason.com Maintainer:       partners@seereason.com Synopsis:         A package for building Facebook applications using Happstack Description:      A package for building Facebook applications using Happstack-Homepage:         http://src.seereason.com/ghc6103/happstack-facebook/+Homepage:         http://src.seereason.com/happstack-facebook/ Bug-Reports:      http://bugzilla.seereason.com/ Build-Type:       Custom-Cabal-version:    >= 1.4.0.0+Cabal-version:    >= 1.6 Category:         Web, Language  Flag base4@@ -41,6 +41,7 @@                         Happstack.Facebook.Connect                         Happstack.Facebook.XdReceiver                         Happstack.Facebook.Users+                        Happstack.Facebook.Pages   if flag(formlets)      Exposed-Modules:   Happstack.Facebook.Formlets      Build-Depends: happstack-extra, formlets, formlets-hsp@@ -49,7 +50,10 @@  Executable demo  Main-Is: ConnectDemo.hs- Other-modules: FacebookConfig  Hs-source-dirs: . examples  GHC-options: -threaded -O2 -Wall -fwarn-missing-signatures -fno-warn-name-shadowing -fwarn-orphans -fwarn-tabs -fwarn-unused-binds -fwarn-unused-imports  Build-Tools: trhsx++source-repository head+    type:     darcs+    location: http://src.seereason.com/happstack-facebook/