happstack-facebook 0.9 → 0.16
raw patch · 8 files changed
+244/−117 lines, 8 files
Files
- Happstack/Facebook/Application.hs +76/−34
- Happstack/Facebook/Common.hs +67/−20
- Happstack/Facebook/Connect.hs +33/−39
- Happstack/Facebook/FacebookT.hs +33/−6
- Happstack/Facebook/Pages.hs +26/−0
- Happstack/Facebook/XdReceiver.hs +1/−0
- examples/FacebookConfig.hs +0/−14
- happstack-facebook.cabal +8/−4
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/