packages feed

hMollom 0.1.1 → 0.2

raw patch · 5 files changed

+294/−167 lines, 5 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

- Network.Mollom: MollomConn :: String -> String -> String -> [String] -> MollomConn
- Network.Mollom: data MollomConn
- Network.Mollom: instance Eq MollomValue
- Network.Mollom: instance Monad MollomMonad
- Network.Mollom: instance Show MollomValue
- Network.Mollom: instance XmlRpcType MollomValue
- Network.Mollom: mcServerList :: MollomConn -> [String]
- Network.Mollom: mcSessionID :: MollomConn -> String
+ Network.Mollom: MBool :: Bool -> MollomValue
+ Network.Mollom: MDouble :: Double -> MollomValue
+ Network.Mollom: MInt :: Int -> MollomValue
+ Network.Mollom: MString :: String -> MollomValue
+ Network.Mollom: MollomConfiguration :: String -> String -> String -> MollomConfiguration
+ Network.Mollom: data MollomConfiguration
+ Network.Mollom: data MollomValue
+ Network.Mollom: mcAPIVersion :: MollomConfiguration -> String
+ Network.Mollom.Auth: getAuthenticationInformation :: String -> String -> [(String, String)]
+ Network.Mollom.Internals: HMollomError :: String -> MollomError
+ Network.Mollom.Internals: MBool :: Bool -> MollomValue
+ Network.Mollom.Internals: MDouble :: Double -> MollomValue
+ Network.Mollom.Internals: MInt :: Int -> MollomValue
+ Network.Mollom.Internals: MString :: String -> MollomValue
+ Network.Mollom.Internals: MollomConfiguration :: String -> String -> String -> MollomConfiguration
+ Network.Mollom.Internals: MollomInternalError :: MollomError
+ Network.Mollom.Internals: MollomNoMoreServers :: MollomError
+ Network.Mollom.Internals: MollomRefresh :: MollomError
+ Network.Mollom.Internals: MollomServerBusy :: MollomError
+ Network.Mollom.Internals: MollomServerList :: [String] -> MollomServerList
+ Network.Mollom.Internals: UninitialisedServerList :: MollomServerList
+ Network.Mollom.Internals: data MollomConfiguration
+ Network.Mollom.Internals: data MollomError
+ Network.Mollom.Internals: data MollomServerList
+ Network.Mollom.Internals: data MollomValue
+ Network.Mollom.Internals: instance Eq MollomConfiguration
+ Network.Mollom.Internals: instance Eq MollomError
+ Network.Mollom.Internals: instance Eq MollomServerList
+ Network.Mollom.Internals: instance Eq MollomValue
+ Network.Mollom.Internals: instance Error MollomError
+ Network.Mollom.Internals: instance Ord MollomConfiguration
+ Network.Mollom.Internals: instance Ord MollomError
+ Network.Mollom.Internals: instance Ord MollomServerList
+ Network.Mollom.Internals: instance Ord MollomValue
+ Network.Mollom.Internals: instance Show MollomConfiguration
+ Network.Mollom.Internals: instance Show MollomError
+ Network.Mollom.Internals: instance Show MollomServerList
+ Network.Mollom.Internals: instance Show MollomValue
+ Network.Mollom.Internals: instance XmlRpcType MollomValue
+ Network.Mollom.Internals: mcAPIVersion :: MollomConfiguration -> String
+ Network.Mollom.Internals: mcPrivateKey :: MollomConfiguration -> String
+ Network.Mollom.Internals: mcPublicKey :: MollomConfiguration -> String
+ Network.Mollom.Internals: mollomApiVersion :: String
+ Network.Mollom.Internals: mollomTimeFormat :: [Char]
+ Network.Mollom.MollomMonad: type MollomMonad = ErrorT MollomError (StateT (Maybe SessionID) MollomState)
+ Network.Mollom.MollomMonad: type MollomState = ReaderT MollomConfiguration (StateT MollomServerList IO)
- Network.Mollom: addBlacklistText :: MollomConn -> String -> String -> String -> IO Bool
+ Network.Mollom: addBlacklistText :: String -> String -> String -> MollomMonad Bool
- Network.Mollom: addBlacklistURL :: MollomConn -> String -> IO Bool
+ Network.Mollom: addBlacklistURL :: String -> MollomMonad Bool
- Network.Mollom: checkCaptcha :: MollomConn -> String -> String -> IO Bool
+ Network.Mollom: checkCaptcha :: String -> MollomMonad Bool
- Network.Mollom: checkContent :: MollomConn -> [(String, String)] -> IO [(String, MollomValue)]
+ Network.Mollom: checkContent :: [(String, String)] -> MollomMonad [(String, MollomValue)]
- Network.Mollom: detectLanguage :: MollomConn -> String -> IO [[(String, MollomValue)]]
+ Network.Mollom: detectLanguage :: String -> MollomMonad [[(String, MollomValue)]]
- Network.Mollom: getAudioCaptcha :: MollomConn -> Maybe String -> Maybe String -> IO [(String, MollomValue)]
+ Network.Mollom: getAudioCaptcha :: Maybe String -> MollomMonad [(String, MollomValue)]
- Network.Mollom: getImageCaptcha :: MollomConn -> Maybe String -> Maybe String -> IO [(String, MollomValue)]
+ Network.Mollom: getImageCaptcha :: Maybe String -> MollomMonad [(String, MollomValue)]
- Network.Mollom: getServerList :: MollomConn -> IO [String]
+ Network.Mollom: getServerList :: MollomMonad [String]
- Network.Mollom: getStatistics :: MollomConn -> String -> IO Int
+ Network.Mollom: getStatistics :: String -> MollomMonad Int
- Network.Mollom: listBlacklistText :: MollomConn -> IO ()
+ Network.Mollom: listBlacklistText :: MollomMonad [[(String, MollomValue)]]
- Network.Mollom: listBlacklistURL :: MollomConn -> IO [[(String, MollomValue)]]
+ Network.Mollom: listBlacklistURL :: MollomMonad [[(String, MollomValue)]]
- Network.Mollom: mcPrivateKey :: MollomConn -> String
+ Network.Mollom: mcPrivateKey :: MollomConfiguration -> String
- Network.Mollom: mcPublicKey :: MollomConn -> String
+ Network.Mollom: mcPublicKey :: MollomConfiguration -> String
- Network.Mollom: removeBlacklistText :: MollomConn -> String -> IO Bool
+ Network.Mollom: removeBlacklistText :: String -> MollomMonad Bool
- Network.Mollom: removeBlacklistURL :: MollomConn -> String -> IO Bool
+ Network.Mollom: removeBlacklistURL :: String -> MollomMonad Bool
- Network.Mollom: sendFeedback :: MollomConn -> String -> String -> IO Bool
+ Network.Mollom: sendFeedback :: String -> MollomMonad Bool
- Network.Mollom: verifyKey :: MollomConn -> IO Bool
+ Network.Mollom: verifyKey :: MollomMonad Bool

Files

hMollom.cabal view
@@ -1,5 +1,5 @@ name:                hMollom-version:             0.1.1+version:             0.2 cabal-version:       >= 1.6 stability:           experimental synopsis:            Library to interact with the Mollom anti-spam service@@ -12,6 +12,8 @@ maintainer:          itkovian@gmail.com build-Type:          Simple extra-source-files:  src/Network/Mollom/Auth.hs+                     src/Network/Mollom/Internals.hs+                     src/Network/Mollom/MollomMonad.hs   library
src/Network/Mollom.hs view
@@ -1,3 +1,5 @@+{-# LANGUAGE TypeSynonymInstances #-}+{-# LANGUAGE FlexibleInstances #-} -- |Interface to the Mollom API module Network.Mollom   ( getServerList@@ -15,163 +17,180 @@   , addBlacklistURL   , removeBlacklistURL   , listBlacklistURL-  , MollomConn(..)+  , MollomConfiguration(..)+  , MollomValue(..)   ) where +import Control.Arrow (second) import Control.Monad.Error+import Control.Monad.Reader+import Control.Monad.State import Data.Maybe(fromJust, isJust) import Network.XmlRpc.Client import Network.XmlRpc.Internals  --import Network.XmlRpc.THDeriveXmlRpcType (asXmlRpcStruct) +import Network.Mollom.Internals import Network.Mollom.Auth+import Network.Mollom.MollomMonad  -mollomApiVersion :: String-mollomApiVersion = "1.0"- mollomFallbackServer :: String mollomFallbackServer = "http://xmlrpc2.mollom.com/" --- FIXME: This should be specified in some configuration file--- or use the system locale-mollomTimeFormat = "%Y-%m-%dT%H:%M:%S.000+0200" --- |Describes connection with the Mollom server-data MollomConn = MollomConn-  { mcPublicKey :: String-  , mcPrivateKey :: String-  , mcSessionID :: String-  , mcServerList :: [String]-  }---- |A computation that interacts with the Mollom server.-data MollomMonad a = MollomMonad (MollomConn -> IO (a, MollomConn))--instance Monad MollomMonad where-  return a = MollomMonad $ \conn -> return (a, conn)--  (MollomMonad m) >>= k = MollomMonad $ \conn -> do-    (a, conn') <- m conn-    let (MollomMonad m') = k a-    m' conn'-+-- |The hardcoded server list+-- XXX: this should go at the back of the state tracking the serverlist, rather than have it here. When the+-- state tracked list is empty, then we refill it next time with this list+hardCodedMollomServerList :: [String]+hardCodedMollomServerList = ["http://xmlrpc1.mollom.com", "http://xmlrpc2.mollom.com", "http://xmlrpc3.mollom.com"]  data MollomRequest = MollomRequest [(String, String)] -data MollomValue = MInt Int-                 | MBool Bool-                 | MDouble Double-                 | MString String deriving (Show, Eq)+-- | Retrieve a new server list using the MollomMonad approach+-- This is a computation that may fail. Upon failure, we return Nothing.+-- This function should only be called from the service function. There is+-- no fall back if this fails, as we need a valid list of servers to begin with.+retrieveNewServerList :: MollomConfiguration -> IO (Maybe [String])+retrieveNewServerList config = do+  let publicKey = mcPublicKey config+      privateKey = mcPrivateKey config+      apiVersion = mcAPIVersion config+      requestStruct = getAuthenticationInformation publicKey privateKey+  newServerList <- rsl requestStruct apiVersion hardCodedMollomServerList+  case newServerList of+    Left s -> return Nothing+    Right sl -> return $ Just sl -instance XmlRpcType MollomValue where-  toValue (MInt i) = toValue i-  toValue (MBool b) = toValue b-  toValue (MDouble d) = toValue d-  toValue (MString s) = toValue s -  fromValue (ValueInt i) = maybeToM "" (Just (MInt i))-  fromValue (ValueBool b) = maybeToM "" (Just (MBool b)) -  fromValue (ValueDouble d) = maybeToM "" (Just (MDouble d))-  fromValue (ValueString s) = maybeToM "" (Just (MString s))-  -  getType (MInt _) = TInt-  getType (MBool _) = TBool-  getType (MDouble _) = TDouble-  getType (MString _) = TString+-- | rsl does the actual polling of the service' function.+-- Keeping this as a top-level function for now. +rsl :: [(String, String)] -> String -> [String] -> IO (Either String [String])+rsl _ _ [] = return $ Left "Error: no more servers left"+rsl rq a (server:ss) = do+   response <- service' rq server a "mollom.getServerList" +   case response of+      Left s -> rsl rq a ss+      Right v -> return $ Right v  --- | make the actual XML-RPC call to the Mollom servers-service :: XmlRpcType a -        => MollomConn    -- ^connection to the Mollom service-        -> String        -- ^remote function name+-- | The 'service' function implements the basic load balancing scheme from+-- <http://mollom.com/api/client-side-load-balancing>. +--+-- FIXME: It expects the MollomConfiguration record to contain a list of valid servers,+-- obtained either through a cache or a call to getServerList with one of the+-- hardCoded server.+service :: XmlRpcType a+        => String        -- ^remote function name         -> MollomRequest -- ^request specific data -        -> IO a-service conn function (MollomRequest fields) = do-  let publicKey = mcPublicKey conn-      privateKey = mcPrivateKey conn-      timeStamp = getMollomTime mollomTimeFormat-      nonce = getMollomNonce-      hash = authenticate publicKey privateKey timeStamp nonce-      requestStruct = [("public_key", publicKey), ("time", timeStamp), ("hash", hash), ("nonce", nonce)] ++ fields-  response <- remote (mollomFallbackServer ++ mollomApiVersion ++ "/") function requestStruct-  return response-{---- | make the actual XML-RPC call to the Mollom server returning---   the raw XML response, for debug purposes---   This requires that haxr exports the post function!-service__ :: MollomConn    -- ^connection to the Mollom service-          -> String        -- ^remote function name-          -> MollomRequest -- ^request specific data-          -> IO String-service__ conn function (MollomRequest fields) = do-  let publicKey = mcPublicKey conn-      privateKey = mcPrivateKey conn-      timeStamp = getMollomTime mollomTimeFormat-      nonce = getMollomNonce-      hash = authenticate publicKey privateKey timeStamp nonce-  response <- post (mollomFallbackServer ++ mollomApiVersion ++ "/") (renderCall $ MethodCall function [toValue ([("public_key", publicKey), ("time", timeStamp), ("hash", hash), ("nonce", nonce)] ++ fields)] )-  return response-  -}+        -> ErrorT MollomError MollomState a+service function (MollomRequest fields) = do+  config <- ask+  let publicKey = mcPublicKey config+      privateKey = mcPrivateKey config+      apiVersion = mcAPIVersion config+      requestStruct = getAuthenticationInformation publicKey privateKey ++ fields+  serviceLoop config requestStruct apiVersion function   --- | request a list of Mollom servers that can handle a site's calls.-getServerList :: MollomConn -- ^connection to the Mollom service-              -> IO [String]-- ^list of servers that can be used-getServerList conn  = -  service conn "mollom.getServerList" (MollomRequest [])+serviceLoop :: XmlRpcType a => MollomConfiguration -> [(String, String)] -> String -> String -> ErrorT MollomError MollomState a+serviceLoop config r a f = serviceLoop' +  where serviceLoop' = do serverList <- get+                          case serverList of+                            UninitialisedServerList -> refetchAndLoop+                            MollomServerList [] -> throwError MollomNoMoreServers+                            MollomServerList (server:ss) -> do response <- liftIO $ service' r server a f+                                                               case response of +                                                                  Left s -> case take 10 s of+                                                                              "Error 1100" -> refetchAndLoop +                                                                              "Error 1000" -> throwError MollomInternalError+                                                                              _            -> put (MollomServerList ss) >> serviceLoop'+                                                                  Right v -> return v+        refetchAndLoop = do nsl <- liftIO $ retrieveNewServerList config+                            case nsl of+                              Nothing -> throwError MollomNoMoreServers+                              Just sl -> put (MollomServerList sl) >> serviceLoop' +-- | Make the actual call to the given Mollom server. +-- +-- We unwrap the ErrorT such that we get the Left error message back when Mollom gives a fault. +service' :: XmlRpcType a => [(String, String)] -> String -> String -> String -> IO (Either String a)+service' requestStruct server api function = do+  response <- runErrorT $ call (mollomFallbackServer ++ mollomApiVersion ++ "/") function [toValue . map (second toValue) $ requestStruct]+  case response of +    Left s -> return $ Left s+    Right v -> runErrorT $ fromValue v --- | asks Mollom whether the specified message is legitimate.-checkContent :: MollomConn -- ^connection to the Mollom service-             -> [(String, String)] -- ^data-             -> IO [(String, MollomValue)] -- ^contains spam decision and session ID-checkContent conn ds = -  service conn "mollom.checkContent" (MollomRequest ds) +returnStateT a = StateT $ \s -> liftM (flip (,) s) a +-- | request a list of Mollom servers that can handle a site's calls.+getServerList :: MollomMonad [String]+getServerList = do+  put Nothing -- no session ID here+  response <- ErrorT . returnStateT . runErrorT $ service "mollom.getServerList" (MollomRequest [])+  lift . lift . put $ MollomServerList response+  return response+  +-- | asks Mollom whether the specified message is legitimate.+checkContent :: [(String, String)] -- ^data+             -> MollomMonad [(String, MollomValue)] -- ^contains spam decision and session ID+checkContent ds = do+  response <- ErrorT . returnStateT . runErrorT $ service "mollom.checkContent" (MollomRequest ds)+  case lookup "session_id" response of+    Nothing -> put Nothing+    Just (MString sessionID) -> put $ Just sessionID +  return response --- | tells Mollom that the specifieed message was spam or otherwise abusive.-sendFeedback :: MollomConn -- ^connection to the Mollom service-             -> String -- ^session ID-             -> String -- ^feedback: "spam", "profanity", "low-quality" or "unwanted"-             -> IO Bool -- ^always returns True-sendFeedback conn sessionID feedback = do             -  service conn  "mollom.sendFeedback" (MollomRequest [("session_id", sessionID), ("feedback", feedback)])+-- | tells Mollom that the specified message was spam or otherwise abusive.+sendFeedback :: String -- ^feedback: "spam", "profanity", "low-quality" or "unwanted"+            -> MollomMonad Bool -- ^always returns true+sendFeedback feedback = do+  sessionID <- get +  case sessionID of+    Nothing -> throwError $ HMollomError "Mollom Error: no session ID provided"+    Just s -> do let mRequest = MollomRequest [("session_id", s), ("feedback", feedback)]+                 ErrorT . returnStateT . runErrorT $ service "mollom.sendFeedback" mRequest   -- | requests Mollom to generate a image CAPTCHA.-getImageCaptcha :: MollomConn -- ^connection to the Mollom service-                -> Maybe String -- ^session ID-                -> Maybe String -- ^author IP address-                -> IO [(String, MollomValue)] -- ^session ID and CAPTCHA url-getImageCaptcha conn sessionID authorIP = do-  let ds = map (\(n, v) -> (n, fromJust v)) $ filter (isJust . snd) [("session_id", sessionID), ("author_ip", authorIP)]-  service conn "mollom.getImageCaptcha" (MollomRequest ds)-+getImageCaptcha :: Maybe String -- ^author IP address+                -> MollomMonad [(String, MollomValue)] -- ^session ID and CAPTCHA url+getImageCaptcha authorIP = do+  sessionID <- get+  let mRequest = MollomRequest $ map (second fromJust) $ filter (isJust . snd) [("session_id", sessionID), ("author_ip", authorIP)]+  response <- ErrorT . returnStateT . runErrorT $ service "mollom.getImageCaptcha" mRequest+  case lookup "session_id" response of+    Nothing -> put Nothing+    Just (MString s) -> put $ Just s+  return response  -- | requests Mollom to generate an audio CAPTCHA-getAudioCaptcha :: MollomConn -- ^connection to the Mollom service-                -> Maybe String -- ^session ID-                -> Maybe String -- ^author IP address-                -> IO [(String, MollomValue)] -- ^session ID and CAPTCHA url-getAudioCaptcha conn sessionID authorIP = do-  let ds = map (\(n, v) -> (n, fromJust v)) $ filter (isJust . snd) [("session_id", sessionID), ("author_ip", authorIP)]-  service conn "mollom.getAudioCaptcha" (MollomRequest ds)+getAudioCaptcha :: Maybe String -- ^author IP address+                -> MollomMonad [(String, MollomValue)]+getAudioCaptcha authorIP = do+  sessionID <- get+  let mRequest = MollomRequest $ map (second fromJust) $ filter (isJust . snd) [("session_id", sessionID), ("author_ip", authorIP)]+  response <- ErrorT . returnStateT . runErrorT $ service "mollom.getAudioCaptcha" mRequest+  case lookup "session_id" response of+    Nothing -> put Nothing+    Just (MString s) -> put $ Just s+  return response +    -- | requests Mollom to verify the result of a CAPTCHA.-checkCaptcha :: MollomConn -- ^connection to the Mollom service-             -> String -- ^session ID associated with the CAPTCHA-             -> String -- ^solution to the CAPTCHA-             -> IO Bool -- ^True if correct, False if wrong-checkCaptcha conn sessionID solution = do-  let ds = [("session_id", sessionID), ("solution", solution)]-  service conn "mollom.checkCaptcha" (MollomRequest ds)-+checkCaptcha :: String -- ^solution to the CAPTCHA+             -> MollomMonad Bool+checkCaptcha solution = do+  --sessionID <- get+  let sessionID = Just "ll"+  case sessionID of+    Nothing -> throwError (HMollomError "Mollom Error: no session ID provided")+    Just s -> do let mRequest = MollomRequest [("session_id", s), ("solution", solution)]+                 ErrorT . returnStateT . runErrorT $ service "mollom.checkCaptcha" mRequest  -- | retrieves usage statistics from Mollom.-getStatistics :: MollomConn -- ^connection to the Mollom service-              -> String -- ^type of statistics demanded+getStatistics :: String -- ^type of statistics demanded                         -- total_days — Number of days Mollom has been used.                         -- total_accepted — Total accepted posts.                         -- total_rejected — Total rejected spam posts.@@ -179,78 +198,64 @@                         -- yesterday_rejected — Number of spam posts blocked yesterday.                         -- today_accepted — Number of posts accepted today.                         -- today_rejected — Number of spam posts rejected today.-              -> IO Int -- ^Value of requested statistic-getStatistics conn statType = do-  service conn "mollom.getStatistics" (MollomRequest [("type", statType)])+              -> MollomMonad Int -- ^Value of requested statistic+getStatistics statType = do+  let mRequest = MollomRequest [("type", statType)]+  ErrorT . returnStateT . runErrorT $ service "mollom.getStatistics" mRequest   -- | return a status value.-verifyKey :: MollomConn -- ^connection to the Mollom service-          -> IO Bool -- ^Always returns True-verifyKey conn = do-  service conn "mollom.verifyKey" (MollomRequest [])+verifyKey :: MollomMonad Bool -- ^Always returns True+verifyKey = ErrorT . returnStateT . runErrorT $ service "mollom.verifyKey" (MollomRequest [])   -- | analyze text and return its most likely language code.-detectLanguage :: MollomConn -- ^connection to the Mollom service-              -> String -- ^text to analyse-              -- -> IO [[DetectLanguageResponseStruct]] -- ^list of (language, confidence) tuples-              -> IO [[(String, MollomValue)]] -- ^list of (language, confidence) tuples-detectLanguage conn text = do-  service conn "mollom.detectLanguage" (MollomRequest [("text", text)]) +detectLanguage :: String -- ^text to analyse+              -> MollomMonad [[(String, MollomValue)]] -- ^list of (language, confidence) tuples+detectLanguage text = ErrorT . returnStateT . runErrorT $ service "mollom.detectLanguage" (MollomRequest [("text", text)])    -- | add text to your site's custom text blacklist.-addBlacklistText :: MollomConn -- ^connection to the Mollom service-                 -> String -- ^text to blacklist+addBlacklistText :: String -- ^text to blacklist                  -> String -- ^match used to search for the text, either "exact" or "contains"                  -> String -- ^reason: "spam", "profanity", "low-quality", or "unwanted"-                 -> IO Bool -- ^always returns True-addBlacklistText conn text match reason = do-  let ds = [("text", text), ("match", match), ("reason", reason)]-  service conn "mollom.addBlacklistText" (MollomRequest ds)+                 -> MollomMonad Bool -- ^always returns True+addBlacklistText text match reason = do+  let mRequest = MollomRequest [("text", text), ("match", match), ("reason", reason)]+  ErrorT . returnStateT . runErrorT $ service "mollom.addBlacklistText" mRequest   -- | remove text from your site's custom text blacklist.-removeBlacklistText :: MollomConn -- ^connection to the Mollom service-                 -> String -- ^text to blacklist-                 -> IO Bool -- ^always returns True-removeBlacklistText conn text = do-  let ds = [("text", text)]-  service conn "mollom.removeBlacklistText" (MollomRequest ds)+removeBlacklistText :: String -- ^text to blacklist+                    -> MollomMonad Bool -- ^always returns True+removeBlacklistText text = do+  let mRequest = MollomRequest [("text", text)]+  ErrorT . returnStateT . runErrorT $ service "mollom.removeBlacklistText" mRequest   -- | return the contents of your site's custom text blacklist.-listBlacklistText :: MollomConn -- ^connection to the Mollom service-                  -- -> IO [[(String, MollomValue)]] -- ^List of the current blacklisted URLs for the website corresponding to the public and private keypair-                  -> IO () -- ^List of the current blacklisted URLs for the website corresponding to the public and private keypair-listBlacklistText conn = do-  r <- service conn "mollom.listBlacklistText" (MollomRequest []) -  p <- handleError fail (parseResponse r)-  putStrLn $ show p+listBlacklistText :: MollomMonad [[(String, MollomValue)]] -- ^List of the current blacklisted URLs for the website corresponding to the public and private keypair+listBlacklistText = ErrorT . returnStateT . runErrorT $ service "mollom.listBlacklistText" (MollomRequest [])  + -- | add a URL to your site's custom URL blacklist.-addBlacklistURL :: MollomConn -- ^connection to the Mollom service-                -> String -- ^URL to be added to custom URL blacklist for the website identified by the public and private keypair-                -> IO Bool -- ^always returns True-addBlacklistURL conn url = do-  let ds = [("url", url)]-  service conn "mollom.addBlacklistURL" (MollomRequest ds)+addBlacklistURL :: String -- ^URL to be added to custom URL blacklist for the website identified by the public and private keypair+                -> MollomMonad Bool -- ^always returns True+addBlacklistURL url = do+  let mRequest = MollomRequest [("url", url)]+  ErrorT . returnStateT . runErrorT $ service "mollom.addBlacklistURL" mRequest   -- | remove a URL from your site's custom URL blacklist.-removeBlacklistURL :: MollomConn -- ^connection to the Mollom service-                   -> String -- ^URL to be removed from the custom URL blacklist for the website identified by the public and private keypair-                   -> IO Bool -- ^always returns True-removeBlacklistURL conn url = do-  let ds = [("url", url)]-  service conn "mollom.removeBlacklistURL" (MollomRequest ds)+removeBlacklistURL :: String -- ^URL to be removed from the custom URL blacklist for the website identified by the public and private keypair+                   -> MollomMonad Bool -- ^always returns True+removeBlacklistURL url = do+  let mRequest = MollomRequest [("url", url)]+  ErrorT . returnStateT . runErrorT $ service "mollom.removeBlacklistURL" mRequest   -- | return the contents of your site's custom URL blacklist.-listBlacklistURL :: MollomConn -- ^connection to the Mollom service-                 -> IO [[(String, MollomValue)]] -- ^List of the current blacklisted URLs for the website corresponding to the public and private keypair-listBlacklistURL conn = do-  service conn "mollom.listBlacklistURL" (MollomRequest [])+listBlacklistURL :: MollomMonad [[(String, MollomValue)]] -- ^List of the current blacklisted URLs for the website corresponding to the public and private keypair+listBlacklistURL = ErrorT . returnStateT . runErrorT $ service "mollom.listBlacklistURL" (MollomRequest [])  
src/Network/Mollom/Auth.hs view
@@ -3,6 +3,7 @@   ( authenticate   , getMollomTime   , getMollomNonce+  , getAuthenticationInformation   ) where  import Codec.Binary.Base64(encode)@@ -14,6 +15,8 @@ import System.IO.Unsafe (unsafePerformIO) import System.Locale (defaultTimeLocale) +import Network.Mollom.Internals+ authenticate :: String -- ^public key              -> String -- ^private key              -> String -- ^timestamp@@ -35,3 +38,10 @@ getMollomNonce = "FIXME_NONCE"  +getAuthenticationInformation :: String -> String -> [(String, String)]+getAuthenticationInformation publicKey privateKey = +  let timeStamp = getMollomTime mollomTimeFormat+      nonce = getMollomNonce+      hash = authenticate publicKey privateKey timeStamp nonce+  in [("public_key", publicKey), ("time", timeStamp), ("hash", hash), ("nonce", nonce)]+ 
+ src/Network/Mollom/Internals.hs view
@@ -0,0 +1,62 @@+-- |Internal data structures and functions to the Mollom service+module Network.Mollom.Internals +  ( mollomApiVersion+  , mollomTimeFormat+  , MollomConfiguration(..)+  , MollomError(..)+  , MollomValue(..)+  , MollomServerList(..)+  ) where++import Control.Monad.Error+import Network.XmlRpc.Client+import Network.XmlRpc.Internals ++mollomApiVersion :: String+mollomApiVersion = "1.0"++-- FIXME: This should be specified in some configuration file+-- or use the system locale+mollomTimeFormat = "%Y-%m-%dT%H:%M:%S.000+0200"++data MollomConfiguration = MollomConfiguration +  { mcPublicKey :: String+  , mcPrivateKey :: String+  , mcAPIVersion :: String+  } deriving (Eq, Ord, Show)++data MollomServerList = UninitialisedServerList | MollomServerList [String] deriving (Eq, Ord, Show)++data MollomError = MollomInternalError +                 | MollomRefresh+                 | MollomServerBusy +                 | MollomNoMoreServers+                 | HMollomError String deriving (Eq, Ord, Show)++instance Error MollomError where +  noMsg = HMollomError "Unknown Error"+  strMsg str = HMollomError str+++data MollomValue = MInt Int+                 | MBool Bool+                 | MDouble Double+                 | MString String deriving (Eq, Ord, Show)++instance XmlRpcType MollomValue where+  toValue (MInt i) = toValue i+  toValue (MBool b) = toValue b+  toValue (MDouble d) = toValue d+  toValue (MString s) = toValue s++  fromValue (ValueInt i) = maybeToM "" (Just (MInt i))+  fromValue (ValueBool b) = maybeToM "" (Just (MBool b)) +  fromValue (ValueDouble d) = maybeToM "" (Just (MDouble d))+  fromValue (ValueString s) = maybeToM "" (Just (MString s))+  +  getType (MInt _) = TInt+  getType (MBool _) = TBool+  getType (MDouble _) = TDouble+  getType (MString _) = TString++
+ src/Network/Mollom/MollomMonad.hs view
@@ -0,0 +1,48 @@+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+-- |Module that implements the Mollom monad stack+-- We wrap the configuration and the serverlist+-- in a Reader and a State, respectively+module Network.Mollom.MollomMonad +  ( MollomMonad+--  , createMollomMonad+--  , runMollomMonad+  , MollomState+--  , runMollomState+  ) where+++import Control.Monad.Reader+import Control.Monad.Writer+import Control.Monad.State+import Control.Monad.Error+import Data.Monoid++import Network.Mollom.Internals++type SessionID = String+type Server = String++++type MollomState = ReaderT MollomConfiguration (StateT MollomServerList IO)+type MollomMonad = ErrorT MollomError (StateT (Maybe SessionID) MollomState)++++{-+newtype Eq a => MollomState a = MollomState {+    runMollomState :: ReaderT MollomConfiguration (StateT MollomServerList IO) a+  } deriving (Monad, MonadIO, MonadReader MollomConfiguration, MonadState MollomServerList)+  -}++{-+newtype Eq a => MollomMonad a = MollomMonad { +    runMollomMonad :: ErrorT String (StateT SessionID MollomState) a+  } deriving (Monad, MonadIO, MonadState SessionID)++-}++-- createMollomMonad :: MollomConfiguration -> MollomMonad ()+-- createMollomMonad configuration = MollomMonad $ ++