mediawiki (empty) → 0.2
raw patch · 97 files changed
+6723/−0 lines, 97 filesdep +HTTPdep +basedep +mimesetup-changed
Dependencies added: HTTP, base, mime, network, pretty, utf8-string, xml
Files
- LICENSE +27/−0
- Main.hs +83/−0
- MediaWiki/API.hs +194/−0
- MediaWiki/API/Action/Block.hs +63/−0
- MediaWiki/API/Action/Delete.hs +50/−0
- MediaWiki/API/Action/Edit.hs +90/−0
- MediaWiki/API/Action/EmailUser.hs +46/−0
- MediaWiki/API/Action/ExpandTemplates.hs +44/−0
- MediaWiki/API/Action/ExpandTemplates/Import.hs +39/−0
- MediaWiki/API/Action/FeedWatchlist.hs +49/−0
- MediaWiki/API/Action/Login.hs +67/−0
- MediaWiki/API/Action/Login/Import.hs +61/−0
- MediaWiki/API/Action/Move.hs +57/−0
- MediaWiki/API/Action/OpenSearch.hs +44/−0
- MediaWiki/API/Action/ParamInfo.hs +59/−0
- MediaWiki/API/Action/Parse.hs +89/−0
- MediaWiki/API/Action/Parse/Import.hs +102/−0
- MediaWiki/API/Action/Protect.hs +50/−0
- MediaWiki/API/Action/Rollback.hs +47/−0
- MediaWiki/API/Action/Sitematrix.hs +48/−0
- MediaWiki/API/Action/Unblock.hs +47/−0
- MediaWiki/API/Action/Undelete.hs +43/−0
- MediaWiki/API/Action/Watch.hs +37/−0
- MediaWiki/API/Base.hs +329/−0
- MediaWiki/API/Output.hs +209/−0
- MediaWiki/API/Query/AllCategories.hs +62/−0
- MediaWiki/API/Query/AllCategories/Import.hs +33/−0
- MediaWiki/API/Query/AllImages.hs +75/−0
- MediaWiki/API/Query/AllImages/Import.hs +25/−0
- MediaWiki/API/Query/AllLinks.hs +66/−0
- MediaWiki/API/Query/AllLinks/Import.hs +31/−0
- MediaWiki/API/Query/AllMessages.hs +66/−0
- MediaWiki/API/Query/AllMessages/Import.hs +31/−0
- MediaWiki/API/Query/AllPages.hs +76/−0
- MediaWiki/API/Query/AllPages/Import.hs +37/−0
- MediaWiki/API/Query/AllUsers.hs +60/−0
- MediaWiki/API/Query/AllUsers/Import.hs +33/−0
- MediaWiki/API/Query/BackLinks.hs +62/−0
- MediaWiki/API/Query/BackLinks/Import.hs +31/−0
- MediaWiki/API/Query/Blocks.hs +107/−0
- MediaWiki/API/Query/Blocks/Import.hs +58/−0
- MediaWiki/API/Query/Categories.hs +57/−0
- MediaWiki/API/Query/Categories/Import.hs +45/−0
- MediaWiki/API/Query/CategoryInfo.hs +59/−0
- MediaWiki/API/Query/CategoryInfo/Import.hs +50/−0
- MediaWiki/API/Query/CategoryMembers.hs +71/−0
- MediaWiki/API/Query/CategoryMembers/Import.hs +32/−0
- MediaWiki/API/Query/DeletedRevisions.hs +85/−0
- MediaWiki/API/Query/DeletedRevisions/Import.hs +51/−0
- MediaWiki/API/Query/EmbeddedIn.hs +62/−0
- MediaWiki/API/Query/EmbeddedIn/Import.hs +31/−0
- MediaWiki/API/Query/ExternalLinks.hs +50/−0
- MediaWiki/API/Query/ExternalLinks/Import.hs +44/−0
- MediaWiki/API/Query/ExternalURLUsage.hs +63/−0
- MediaWiki/API/Query/ExternalURLUsage/Import.hs +35/−0
- MediaWiki/API/Query/ImageInfo.hs +90/−0
- MediaWiki/API/Query/ImageInfo/Import.hs +75/−0
- MediaWiki/API/Query/ImageUsage.hs +62/−0
- MediaWiki/API/Query/ImageUsage/Import.hs +31/−0
- MediaWiki/API/Query/Images.hs +49/−0
- MediaWiki/API/Query/Images/Import.hs +42/−0
- MediaWiki/API/Query/Info.hs +90/−0
- MediaWiki/API/Query/Info/Import.hs +54/−0
- MediaWiki/API/Query/LangLinks.hs +62/−0
- MediaWiki/API/Query/LangLinks/Import.hs +45/−0
- MediaWiki/API/Query/Links.hs +55/−0
- MediaWiki/API/Query/Links/Import.hs +45/−0
- MediaWiki/API/Query/LogEvents.hs +114/−0
- MediaWiki/API/Query/LogEvents/Import.hs +81/−0
- MediaWiki/API/Query/Random.hs +47/−0
- MediaWiki/API/Query/Random/Import.hs +31/−0
- MediaWiki/API/Query/RecentChanges.hs +110/−0
- MediaWiki/API/Query/RecentChanges/Import.hs +80/−0
- MediaWiki/API/Query/Revisions.hs +110/−0
- MediaWiki/API/Query/Revisions/Import.hs +62/−0
- MediaWiki/API/Query/Search.hs +62/−0
- MediaWiki/API/Query/Search/Import.hs +32/−0
- MediaWiki/API/Query/SiteInfo.hs +114/−0
- MediaWiki/API/Query/SiteInfo/Import.hs +143/−0
- MediaWiki/API/Query/Templates.hs +55/−0
- MediaWiki/API/Query/Templates/Import.hs +40/−0
- MediaWiki/API/Query/UserContribs.hs +100/−0
- MediaWiki/API/Query/UserContribs/Import.hs +48/−0
- MediaWiki/API/Query/UserInfo.hs +46/−0
- MediaWiki/API/Query/UserInfo/Import.hs +91/−0
- MediaWiki/API/Query/Users.hs +66/−0
- MediaWiki/API/Query/Users/Import.hs +47/−0
- MediaWiki/API/Query/WatchList.hs +100/−0
- MediaWiki/API/Query/WatchList/Import.hs +56/−0
- MediaWiki/API/Types.hs +241/−0
- MediaWiki/API/Utils.hs +94/−0
- MediaWiki/Util/Codec/Percent.hs +59/−0
- MediaWiki/Util/Codec/URLEncoder.hs +33/−0
- MediaWiki/Util/Fetch.hs +136/−0
- Setup.hs +7/−0
- examples/ListCat.hs +133/−0
- mediawiki.cabal +123/−0
+ LICENSE view
@@ -0,0 +1,27 @@+Copyright (c) Sigbjorn Finne 2008++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions+are met:+1. Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.+2. 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.+3. Neither the name of the author nor the names of his contributors+ may be used to endorse or promote products derived from this software+ without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``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 AUTHORS 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.
+ Main.hs view
@@ -0,0 +1,83 @@+module Main(main) where + +import MediaWiki.API +import MediaWiki.API.Types + +import MediaWiki.API.Query.Info +import MediaWiki.API.Query.Info.Import as I +import MediaWiki.API.Query.LangLinks +import MediaWiki.API.Query.LangLinks.Import as LL +import MediaWiki.API.Query.SiteInfo + +import System.Environment +import Data.List ( isPrefixOf ) + +mw_api_url :: String +mw_api_url = "http://en.wikipedia.org/w/" + +main :: IO () +main = do + ls <- getArgs + let + (url,pg) = + case ls of + ("WP":y:_) -> (mw_api_url,y) + (x:y:_) -> (x,y) + _ -> (mw_api_url, "Main_Page") + i <- queryInfo url pg + case I.stringXml i of + Left x -> putStrLn ("Error getting info for page " ++ pg ++ " error: " ++ show x) + Right x -> putStrLn ("Page last touched: " ++ headS (map infTouched (infPages x))) + lns <- getAll url pg [] Nothing + putStrLn ("The page " ++ pg ++ " is available in other languages:") + iwMap <- getIWUrlMap url + let + getIWUrl (x,y) = + case filter ((x==).iwPrefix) iwMap of + (a:_) -> (x,subst y (iwUrl a)) + _ -> (x,"<unknown>") + let lns1 = map getIWUrl lns + putStrLn (' ':' ':unlines (map (\ (a,b) -> a ++ "=> " ++ b) lns1)) + where + subst ss x = + case spanUntil ("$1" `isPrefixOf`) x of + (as,_:_:bs) -> as ++ ss ++ subst ss bs + (as,_) -> as + +spanUntil :: ([a] -> Bool) -> [a] -> ([a],[a]) +spanUntil _ [] = ([],[]) +spanUntil p ls@(x:xs) + | p ls = ([],ls) + | otherwise = + case spanUntil p xs of + (as,bs) -> (x:as,bs) + +getAll :: String -> String -> [[(String,String)]] -> Maybe String -> IO [(String,String)] +getAll url pg acc mbCont = do +-- i <- catch (queryLangPage url pg mbCont) (\ _ -> return "") + i <- queryLangPage url pg mbCont + case LL.stringXml i of + Left{} -> return (concat $ reverse acc) + Right ll -> do + let lls = map (\ lli -> (langName lli, lTitle lli)) (concat (map snd (llPages ll))) + case llContinue ll of + Nothing -> return $ concat $ reverse (lls:acc) + Just mb -> do + getAll url pg (lls:acc) (Just mb) + where + lTitle x = + case langTitle x of + Nothing -> pg + Just "" -> pg + Just xs -> xs + +getIWUrlMap :: String -> IO [InterwikiEntry] +getIWUrlMap api_url = do + mb <- querySiteIWInfo api_url + case mb of + Nothing -> return [] + Just si -> return (siInterwiki si) + +headS :: [String] -> String +headS [] = "" +headS (x:_) = x
+ MediaWiki/API.hs view
@@ -0,0 +1,194 @@+{-# OPTIONS_GHC -XExistentialQuantification -XDeriveDataTypeable #-} +-------------------------------------------------------------------- +-- | +-- Module : MediaWiki.API +-- Description : A Haskell MediaWiki API binding +-- Copyright : (c) Sigbjorn Finne, 2008 +-- License : BSD3 +-- +-- Maintainer: Sigbjorn Finne <sof@forkIO.com> +-- Stability : provisional +-- Portability: portable +-- +-- A Haskell MediaWiki API binding. +-- +-------------------------------------------------------------------- +module MediaWiki.API + ( module MediaWiki.API + , URLString + ) where + +import MediaWiki.API.Base +import MediaWiki.API.Types +import MediaWiki.API.Output + +import MediaWiki.Util.Fetch as Fetch +import Codec.MIME.Type + +import MediaWiki.API.Query.SiteInfo as SI +import MediaWiki.API.Query.SiteInfo.Import as SI +import MediaWiki.API.Action.Login.Import as Login + +import Data.Maybe + +import Control.Exception as CE +import Data.Typeable + +import MediaWiki.API.Utils +import Text.XML.Light.Types +import Control.Monad + +-- | @webGet url req@ issues a GET to a MediaWiki server, appending +-- @api.php?@ followed by the request @req@ to the URL base @url@. +webGet :: URLString -> Request -> IO String +webGet url req = do + let url_q = url ++ "api.php?" ++ showRequest req +-- print url_q + readContentsURL url_q + +-- | @webGet mbUser url req@ issues a POST to a MediaWiki server, appending +-- @api.php?@ followed by the request @req@ to the URL base @url@. +webPost :: Maybe Fetch.User -> URLString -> String -> Request -> IO ([(String,String)], String) +webPost mbUser url act req = do + let url_q = url ++ "api.php?action="++act + let pload = showRequest req + postContentsURL mbUser url_q + [ ("Content-Length", show $ length pload) + , ("Content-Type", showMIMEType form_mime_ty) + ] + pload + where + form_mime_ty = Application "x-www-form-urlencoded" + +webPostXml :: (String -> Either (String,[String]) a) + -> Maybe Fetch.User + -> URLString + -> String + -> Request + -> IO (Maybe a) +webPostXml p mbUser url act req = do + (hs,mb) <- webPost mbUser url act req + case mb of + "" -> return Nothing + ls -> do + case p ls of + Left (x,errs) -> + case parseError ls of + Right e -> throwMWError e + _ -> putStrLn (x ++ ':':' ':unlines errs) >> return Nothing + Right x -> return (Just x) + +webGetXml :: (String -> Either (String,[String]) a) + -> URLString + -> Request + -> IO (Maybe a) +webGetXml p url req = do + ls <- webGet url req + case p ls of + Left (x,errs) -> + case parseError ls of + Right e -> throwMWError e + _ -> putStrLn (x ++ ':':' ':unlines errs) >> return Nothing + Right x -> return (Just x) + +queryPage :: PageName -> QueryRequest +queryPage pg = emptyQuery{quTitles=[pg]} + +mkQueryAction :: APIRequest a => QueryRequest -> a -> Action +mkQueryAction q qr = + case queryKind qr of + QProp s -> Query q{quProps=(PropKind s):quProps q} (toReq qr) + QList s -> Query q{quLists=(ListKind s):quLists q} (toReq qr) + QMeta s -> Query q{quMetas=(MetaKind s):quMetas q} (toReq qr) + QGen s -> Query q{quGenerator=(Just (GeneratorKind s))} (toReq qr) + +-- | @loginWiki u usr pass +loginWiki :: URLString -> String -> String -> IO (Maybe LoginResponse) +loginWiki url usr pwd = webPostXml Login.stringXml Nothing url "login" req + where + req = emptyXmlRequest (Login (emptyLogin usr pwd)) + +queryInfo :: URLString -> PageName -> IO String +queryInfo url pgName = webGet url req + where + req = emptyXmlRequest (mkQueryAction (queryPage pgName) infoRequest) + +querySiteIWInfo :: URLString -> IO (Maybe SiteInfoResponse) +querySiteIWInfo url = webGetXml SI.stringXml url req + where + req = emptyXmlRequest + (mkQueryAction (queryPage "XP") + siteInfoRequest{siProp=["interwikimap"]}) + +queryLangPage :: URLString -> PageName -> Maybe String -> IO String +queryLangPage url pgName mb = webGet url req + where + req = emptyXmlRequest + (mkQueryAction (queryPage pgName) + langLinksRequest{llContinueFrom=mb}) + + +parseError :: String -> Either (String,[{-Error msg-}String]) MediaWikiError +parseError s = parseDoc xmlError s + +xmlError :: Element -> Maybe MediaWikiError +xmlError e = do + guard (elName e == nsName "api") + let es1 = children e + p <- pNode "error" es1 + return mwError{ mwErrorCode = fromMaybe "" $ pAttr "code" p + , mwErrorInfo = fromMaybe "" $ pAttr "info" p + } + +-- MW exceptions/errors: + +data MediaWikiError + = MediaWikiError + { mwErrorCode :: String + , mwErrorInfo :: String + } deriving ( Typeable ) + +mwError :: MediaWikiError +mwError = MediaWikiError{mwErrorCode="",mwErrorInfo=""} + +data SomeMWException = forall e . Exception e => SomeMWException e + deriving Typeable + +instance Show SomeMWException where + show (SomeMWException e) = show e + +instance Exception SomeMWException + +mwToException :: Exception e => e -> SomeException +mwToException = toException . SomeMWException + +mwFromException :: Exception e => SomeException -> Maybe e +mwFromException x = do + SomeMWException a <- fromException x + cast a + +instance Exception MediaWikiError where + toException = mwToException + fromException = mwFromException + +handleMW :: (MediaWikiError -> IO a) -> IO a -> IO a +handleMW h e = catchMW e h + +tryMW :: IO a -> IO (Either MediaWikiError a) +tryMW f = handleMW (\ x -> return (Left x)) (f >>= return.Right) + +throwMWError :: MediaWikiError -> IO a +throwMWError e = throwIO e + +catchMW :: IO a -> (MediaWikiError -> IO a) -> IO a +catchMW f hdlr = + CE.catch f + (\ e1 -> hdlr e1) + +instance Show MediaWikiError where + show x = unlines ( + [ "MediaWiki error:" + , "" + , " Code: " ++ mwErrorCode x + , " Info: " ++ mwErrorInfo x + ])
+ MediaWiki/API/Action/Block.hs view
@@ -0,0 +1,63 @@+--------------------------------------------------------------------+-- |+-- Module : MediaWiki.API.Action.Block+-- Description : Representing Block requests.+-- Copyright : (c) Sigbjorn Finne, 2008+-- License : BSD3+--+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>+-- Stability : provisional+-- Portability: portable+--+-- Representing Block requests.+-- +--------------------------------------------------------------------+module MediaWiki.API.Action.Block where++import MediaWiki.API.Types+import MediaWiki.API.Utils++data BlockRequest+ = BlockRequest+ { blkUser :: UserName+ , blkToken :: Token+ , blkGetToken :: Bool+ , blkExpiry :: Maybe Timestamp+ , blkReason :: Maybe String+ , blkAnonOnly :: Bool+ , blkNoCreate :: Bool+ , blkAutoBlock :: Bool+ , blkNoEmail :: Bool+ , blkHide :: Bool+ }++instance APIRequest BlockRequest where+ isPostable _ = True+ showReq r =+ [ opt "user" (blkUser r)+ , opt "token" (blkToken r)+ , optB "gettoken" (blkGetToken r)+ , mbOpt "expiry" id (blkExpiry r)+ , mbOpt "reason" id (blkReason r)+ , optB "anononly" (blkAnonOnly r)+ , optB "nocreate" (blkNoCreate r)+ , optB "autoblock" (blkAutoBlock r)+ , optB "noemail" (blkNoEmail r)+ , optB "hidename" (blkHide r)+ ]+++emptyBlockRequest :: BlockRequest+emptyBlockRequest = BlockRequest+ { blkUser = ""+ , blkToken = ""+ , blkGetToken = False+ , blkExpiry = Nothing+ , blkReason = Nothing+ , blkAnonOnly = False+ , blkNoCreate = False+ , blkAutoBlock = False+ , blkNoEmail = False+ , blkHide = False+ }+
+ MediaWiki/API/Action/Delete.hs view
@@ -0,0 +1,50 @@+--------------------------------------------------------------------+-- |+-- Module : MediaWiki.API.Action.Delete+-- Description : Representing Delete requests.+-- Copyright : (c) Sigbjorn Finne, 2008+-- License : BSD3+--+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>+-- Stability : provisional+-- Portability: portable+--+-- Representing Delete requests.+-- +--------------------------------------------------------------------+module MediaWiki.API.Action.Delete where++import MediaWiki.API.Types+import MediaWiki.API.Utils++data DeleteRequest+ = DeleteRequest+ { delTitle :: PageName+ , delToken :: Token+ , delReason :: Maybe String+ , delWatch :: Maybe Bool+ , delUnwatch :: Maybe Bool + , delOldImage :: Maybe String+ }++instance APIRequest DeleteRequest where+ isPostable _ = True+ showReq r = + [ opt "title" (delTitle r)+ , opt "token" (delToken r)+ , mbOpt "reason" id (delReason r)+ , optB "watch" (fromMaybe False $ delWatch r)+ , optB "unwatch" (fromMaybe False $ delUnwatch r)+ , mbOpt "oldimage" id (delOldImage r)+ ]++emptyDeleteRequest :: DeleteRequest+emptyDeleteRequest = DeleteRequest+ { delTitle = ""+ , delToken = ""+ , delReason = Nothing+ , delWatch = Nothing+ , delUnwatch = Nothing+ , delOldImage = Nothing+ } +
+ MediaWiki/API/Action/Edit.hs view
@@ -0,0 +1,90 @@+--------------------------------------------------------------------+-- |+-- Module : MediaWiki.API.Action.Edit+-- Description : Representing Edit requests.+-- Copyright : (c) Sigbjorn Finne, 2008+-- License : BSD3+--+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>+-- Stability : provisional+-- Portability: portable+--+-- Representing Edit requests.+-- +--------------------------------------------------------------------+module MediaWiki.API.Action.Edit where++import MediaWiki.API.Types+import MediaWiki.API.Utils++data EditRequest+ = EditRequest+ { edTitle :: Maybe PageName+ , edSection :: Maybe String+ , edText :: Maybe String -- ^ Page content+ , edToken :: Maybe Token -- ^ Edit token. You can get one of these through prop=info+ , edSummary :: Maybe String+ , edIsMinor :: Bool+ , edIsNonMinor :: Bool+ , edAsBot :: Bool+ , edBaseTimestamp :: Maybe Timestamp+ , edRecreate :: Bool+ , edCreateOnly :: Bool+ , edNoCreate :: Bool+ , edCaptchaWord :: Maybe String+ , edCaptchaId :: Maybe String+ , edWatch :: Bool+ , edUnwatch :: Bool+ , edMD5 :: Maybe String+ , edPrependText :: Maybe String+ , edAppendText :: Maybe String+ }++instance APIRequest EditRequest where+ isPostable _ = True+ showReq r = + [ mbOpt "title" id (edTitle r)+ , mbOpt "section" id (edSection r)+ , mbOpt "text" id (edText r)+ , mbOpt "token" id (edToken r)+ , mbOpt "summary" id (edSummary r)+ , optB "minor" (edIsMinor r)+ , optB "notminor" (edIsNonMinor r)+ , optB "bot" (edAsBot r)+ , mbOpt "basetimestamp" id (edBaseTimestamp r)+ , optB "recreate" (edRecreate r)+ , optB "createonly" (edCreateOnly r)+ , optB "nocreate" (edNoCreate r)+ , mbOpt "captchaword" id (edCaptchaWord r)+ , mbOpt "captchaid" id (edCaptchaId r)+ , optB "watch" (edWatch r)+ , optB "unwatch" (edUnwatch r)+ , mbOpt "md5" id (edMD5 r)+ , mbOpt "prependtext" id (edPrependText r)+ , mbOpt "appendtext" id (edAppendText r)+ ]+++emptyEditRequest :: EditRequest+emptyEditRequest = EditRequest+ { edTitle = Nothing+ , edSection = Nothing+ , edText = Nothing+ , edToken = Nothing+ , edSummary = Nothing+ , edIsMinor = False+ , edIsNonMinor = True+ , edAsBot = False+ , edBaseTimestamp = Nothing+ , edRecreate = False+ , edCreateOnly = False+ , edNoCreate = False+ , edCaptchaWord = Nothing+ , edCaptchaId = Nothing+ , edWatch = False+ , edUnwatch = False+ , edMD5 = Nothing+ , edPrependText = Nothing+ , edAppendText = Nothing+ }+
+ MediaWiki/API/Action/EmailUser.hs view
@@ -0,0 +1,46 @@+--------------------------------------------------------------------+-- |+-- Module : MediaWiki.API.Action.EmailUser+-- Description : Representing EmailUser requests.+-- Copyright : (c) Sigbjorn Finne, 2008+-- License : BSD3+--+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>+-- Stability : provisional+-- Portability: portable+--+-- Representing EmailUser requests.+-- +--------------------------------------------------------------------+module MediaWiki.API.Action.EmailUser where++import MediaWiki.API.Types+import MediaWiki.API.Utils++data EmailUserRequest+ = EmailUserRequest+ { emTarget :: Maybe String+ , emSubject :: Maybe String+ , emText :: Maybe String+ , emToken :: Maybe Token+ , emCcMe :: Bool+ }++instance APIRequest EmailUserRequest where+ isPostable _ = True+ showReq r = + [ mbOpt "target" id (emTarget r)+ , mbOpt "subject" id (emSubject r)+ , mbOpt "text" id (emText r)+ , mbOpt "token" id (emToken r)+ , optB "ccme" (emCcMe r)+ ]++emptyEmailUserRequest :: EmailUserRequest+emptyEmailUserRequest = EmailUserRequest+ { emTarget = Nothing+ , emSubject = Nothing+ , emText = Nothing+ , emToken = Nothing+ , emCcMe = False+ }
+ MediaWiki/API/Action/ExpandTemplates.hs view
@@ -0,0 +1,44 @@+-------------------------------------------------------------------- +-- | +-- Module : MediaWiki.API.Action.ExpandTemplates +-- Description : Representing ExpandTemplates requests. +-- Copyright : (c) Sigbjorn Finne, 2008 +-- License : BSD3 +-- +-- Maintainer: Sigbjorn Finne <sof@forkIO.com> +-- Stability : provisional +-- Portability: portable +-- +-- Representing ExpandTemplates requests. +-- +-------------------------------------------------------------------- +module MediaWiki.API.Action.ExpandTemplates where + +import MediaWiki.API.Types + +data ExpandTemplatesRequest + = ExpandTemplatesRequest + { etTitle :: Maybe PageName + , etText :: String + , etGenXml :: Maybe Bool + } + +emptyExpandTemplatesRequest :: ExpandTemplatesRequest +emptyExpandTemplatesRequest = ExpandTemplatesRequest + { etTitle = Nothing + , etText = "" + , etGenXml = Nothing + } + +data ExpandTemplatesResponse + = ExpandTemplatesResponse + { etExpandedText :: String + , etExpandedXml :: Maybe String + } + +emptyExpandTemplatesResponse :: ExpandTemplatesResponse +emptyExpandTemplatesResponse = ExpandTemplatesResponse + { etExpandedText = "" + , etExpandedXml = Nothing + } +
+ MediaWiki/API/Action/ExpandTemplates/Import.hs view
@@ -0,0 +1,39 @@+--------------------------------------------------------------------+-- |+-- Module : MediaWiki.API.Action.ExpandTemplates.Import+-- Description : Serializing ExpandTemplates requests.+-- Copyright : (c) Sigbjorn Finne, 2008+-- License : BSD3+--+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>+-- Stability : provisional+-- Portability: portable+--+-- Serializing ExpandTemplates requests.+-- +--------------------------------------------------------------------+module MediaWiki.API.Action.ExpandTemplates.Import where++--import MediaWiki.API.Types+import MediaWiki.API.Utils+import MediaWiki.API.Action.ExpandTemplates++import Text.XML.Light.Types+import Text.XML.Light.Proc ( strContent )++import Control.Monad+import Data.Maybe++stringXml :: String -> Either (String,[{-Error msg-}String]) ExpandTemplatesResponse+stringXml s = parseDoc xml s++xml :: Element -> Maybe ExpandTemplatesResponse+xml e = do+ guard (elName e == nsName "api")+ let es1 = children e+ p <- pNode "expandtemplates" es1+ let xm = fmap strContent $ pNode "parsetree" es1+ return emptyExpandTemplatesResponse+ { etExpandedText = strContent p+ , etExpandedXml = xm+ }
+ MediaWiki/API/Action/FeedWatchlist.hs view
@@ -0,0 +1,49 @@+-------------------------------------------------------------------- +-- | +-- Module : MediaWiki.API.Action.FeedWatchlist +-- Description : Representing FeedWatchList requests. +-- Copyright : (c) Sigbjorn Finne, 2008 +-- License : BSD3 +-- +-- Maintainer: Sigbjorn Finne <sof@forkIO.com> +-- Stability : provisional +-- Portability: portable +-- +-- Representing FeedWatchList requests. +-- +-------------------------------------------------------------------- +module MediaWiki.API.Action.FeedWatchlist where + +import MediaWiki.API.Types + +data FeedWatchListRequest + = FeedWatchListRequest + { feAsAtom :: Bool -- False => rss + , feHours :: Maybe Int + , feAllRev :: Bool + } + +emptyFeedWatchListRequest :: FeedWatchListRequest +emptyFeedWatchListRequest = FeedWatchListRequest + { feAsAtom = False + , feHours = Nothing + , feAllRev = False + } + +data FeedWatchListResponse + = FeedWatchListResponse + { fwFeedFormat :: String + , fwFeedRaw :: String + , fwFeedItems :: [FeedItem] + } + +data FeedItem + = FeedItem + { fiTitle :: String + , fiUrl :: URLString + , fiComment :: String + , fiTimestamp :: String + , fiUser :: String + , fiText :: String + } +
+ MediaWiki/API/Action/Login.hs view
@@ -0,0 +1,67 @@+-------------------------------------------------------------------- +-- | +-- Module : MediaWiki.API.Action.Login +-- Description : Representing Login requests. +-- Copyright : (c) Sigbjorn Finne, 2008 +-- License : BSD3 +-- +-- Maintainer: Sigbjorn Finne <sof@forkIO.com> +-- Stability : provisional +-- Portability: portable +-- +-- Representing Login requests. +-- +-------------------------------------------------------------------- +module MediaWiki.API.Action.Login where + +import MediaWiki.API.Types +import MediaWiki.API.Utils + +data LoginRequest + = LoginRequest + { lgName :: User + , lgPassword :: Password + , lgDomain :: Maybe String + } + +instance APIRequest LoginRequest where + isPostable _ = True + showReq r = + [ opt "lgname" (lgName r) + , opt "lgpassword" (lgPassword r) + , mbOpt "lgdomain" id (lgDomain r) + ] + +emptyLogin :: User -> Password -> LoginRequest +emptyLogin u p + = LoginRequest + { lgName = u + , lgPassword = p + , lgDomain = Nothing + } + +data LoginResponse + -- error responses, all together: + = LoginError + { lgSuccess :: Bool + , lgeError :: String -- NeedToWait/NoName/Illegal/WrongPluginPass/NotExists/WrongPass/EmptyPass/future ones. + -- (resist the temptation(?) to encode errors via a separate type, keep it loose for now in a String. + , lgeDetails :: Maybe String + , lgeWait :: String + } + -- Successfully logged in, bundle up the result in a separate record so as to ease + -- the carrying around of a user session. + -- + -- Notice the use of a shared boolean field betw. the constructors; eases the processing of + -- responses in code where conds/guards are more convenient: + -- + -- x <- submitLoginRequest lgReq + -- when (not $ lgSuccess x) (handleError x) + -- let sess = lgSession x + -- ... + -- + | LoginResponse + { lgSuccess :: Bool + , lgSession :: UserSession + } +
+ MediaWiki/API/Action/Login/Import.hs view
@@ -0,0 +1,61 @@+--------------------------------------------------------------------+-- |+-- Module : MediaWiki.API.Action.Login.Import+-- Description : Serializing Login requests.+-- Copyright : (c) Sigbjorn Finne, 2008+-- License : BSD3+--+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>+-- Stability : provisional+-- Portability: portable+--+-- Serializing Login requests.+-- +--------------------------------------------------------------------+module MediaWiki.API.Action.Login.Import where++import MediaWiki.API.Types+import MediaWiki.API.Utils+import MediaWiki.API.Action.Login++import Text.XML.Light.Types+import Text.XML.Light.Proc ( strContent )++import Control.Monad+import Data.Maybe++stringXml :: String -> Either (String,[{-Error msg-}String]) LoginResponse+stringXml s = parseDoc xml s++xml :: Element -> Maybe LoginResponse+xml e = do+ guard (elName e == nsName "api")+ let es1 = children e+ p <- pNode "login" es1+ let res = pAttr "result" p+ let uid = pAttr "lguserid" p+ let unm = pAttr "lgusername" p+ let tok = pAttr "lgtoken" p+ let coo = pAttr "cookieprefix" p+ let ses = pAttr "sessionid" p+ case res of+ Just "Success" -> + return LoginResponse{ lgSuccess=True+ , lgSession=UserSession+ { sessUserId = fromMaybe "" uid+ , sessUserName = fromMaybe "" unm+ , sessPassword = Nothing+ , sessCookiePrefix = coo+ , sessSessionId = ses+ , sessToken = fromMaybe "" tok+ }}+ Just x -> do+ let det = pAttr "details" p+ let wai = pAttr "wait" p+ return LoginError+ { lgSuccess = False+ , lgeError = x+ , lgeDetails = det+ , lgeWait = fromMaybe "" wai+ }+
+ MediaWiki/API/Action/Move.hs view
@@ -0,0 +1,57 @@+--------------------------------------------------------------------+-- |+-- Module : MediaWiki.API.Action.Move+-- Description : Representing Move requests.+-- Copyright : (c) Sigbjorn Finne, 2008+-- License : BSD3+--+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>+-- Stability : provisional+-- Portability: portable+--+-- Representing Move requests.+-- +--------------------------------------------------------------------+module MediaWiki.API.Action.Move where++import MediaWiki.API.Types+import MediaWiki.API.Utils++data MoveRequest+ = MoveRequest+ { mvFrom :: Maybe PageName+ , mvTo :: Maybe PageName+ , mvToken :: Token+ , mvReason :: Maybe String+ , mvMoveTalk :: Bool+ , mvNoRedir :: Bool+ , mvWatch :: Bool+ , mvUnwatch :: Bool+ }++instance APIRequest MoveRequest where+ isPostable _ = True+ showReq r = + [ mbOpt "from" id (mvFrom r)+ , mbOpt "to" id (mvTo r)+ , opt "token" (mvToken r)+ , mbOpt "reason" id (mvReason r)+ , optB "movetalk" (mvMoveTalk r)+ , optB "noredirect" (mvNoRedir r)+ , optB "watch" (mvWatch r)+ , optB "unwatch" (mvUnwatch r)+ ]+++emptyMoveRequest :: MoveRequest+emptyMoveRequest = MoveRequest+ { mvFrom = Nothing+ , mvTo = Nothing+ , mvToken = ""+ , mvReason = Nothing+ , mvMoveTalk = False+ , mvNoRedir = False+ , mvWatch = False+ , mvUnwatch = False+ }+
+ MediaWiki/API/Action/OpenSearch.hs view
@@ -0,0 +1,44 @@+-------------------------------------------------------------------- +-- | +-- Module : MediaWiki.API.Action.OpenSearch +-- Description : Representing OpenSearch requests. +-- Copyright : (c) Sigbjorn Finne, 2008 +-- License : BSD3 +-- +-- Maintainer: Sigbjorn Finne <sof@forkIO.com> +-- Stability : provisional +-- Portability: portable +-- +-- Representing OpenSearch requests. +-- +-------------------------------------------------------------------- +module MediaWiki.API.Action.OpenSearch where + +import MediaWiki.API.Types + +data OpenSearchRequest + = OpenSearchRequest + { osSearch :: String + , osLimit :: Maybe Int + , osNamespaces :: Maybe [Int] + } + +emptyOpenSearchRequest :: String -> OpenSearchRequest +emptyOpenSearchRequest tit + = OpenSearchRequest + { osSearch = tit + , osLimit = Nothing + , osNamespaces = Nothing + } + +data OpenSearchResponse + = OpenSearchResponse + { osHits :: [OpenSearchHit] + } + +data OpenSearchHit + = OpenSearchHit + { oshTitle :: String + , oshMatches :: [String] + } +
+ MediaWiki/API/Action/ParamInfo.hs view
@@ -0,0 +1,59 @@+-------------------------------------------------------------------- +-- | +-- Module : MediaWiki.API.Action.ParamInfo +-- Description : Representing ParamInfo requests. +-- Copyright : (c) Sigbjorn Finne, 2008 +-- License : BSD3 +-- +-- Maintainer: Sigbjorn Finne <sof@forkIO.com> +-- Stability : provisional +-- Portability: portable +-- +-- Representing ParamInfo requests. +-- +-------------------------------------------------------------------- +module MediaWiki.API.Action.ParamInfo where + +import MediaWiki.API.Types + +data ParamInfoRequest + = ParamInfoRequest + { paModules :: [String] + , paQueryModules :: [String] + } + +emptyParamInfoRequest :: ParamInfoRequest +emptyParamInfoRequest = ParamInfoRequest + { paModules = [] + , paQueryModules = [] + } + +data ParamInfoResponse + = ParamInfoResponse + { parModules :: [APIModule] + } + +data APIModule + = APIModule + { modName :: String + , modClass :: String + , modDescription :: String + , modParams :: [ModuleParam] + } + +data ModuleParam + = ModuleParam + { modParamName :: String + , modParamDefault :: String + , modParamDescription :: String + , modParamPrefix :: String + , modParamType :: ParamType + } + +data ParamType + = TypeBool + | TypeString + | TypeInteger + | TypeTimestamp + | TypeName String + | TypeEnum [String]
+ MediaWiki/API/Action/Parse.hs view
@@ -0,0 +1,89 @@+-------------------------------------------------------------------- +-- | +-- Module : MediaWiki.API.Action.Parse +-- Description : Representing Parse requests. +-- Copyright : (c) Sigbjorn Finne, 2008 +-- License : BSD3 +-- +-- Maintainer: Sigbjorn Finne <sof@forkIO.com> +-- Stability : provisional +-- Portability: portable +-- +-- Representing Parse requests. +-- +-------------------------------------------------------------------- +module MediaWiki.API.Action.Parse where + +import MediaWiki.API.Types + +data ParseRequest + = ParseRequest + { paTitle :: Maybe PageName + , paText :: String + , paPage :: Maybe PageName + , paOldId :: Maybe RevID + , paProp :: [String] + } + +emptyParseRequest :: String -> ParseRequest +emptyParseRequest txt = ParseRequest + { paTitle = Nothing + , paText = txt + , paPage = Nothing + , paOldId = Nothing + , paProp = [] + } + +data ParseResponse + = ParseResponse + { parText :: String + , parRevId :: Maybe RevID + , parLangLinks :: Maybe [LanguageLink] + , parCategories :: Maybe [CategoryLink] + , parLinks :: Maybe [Link] + , parTemplates :: Maybe [Link] + , parImages :: Maybe [String] + , parExternalLinks :: Maybe [URLString] + , parSections :: Maybe [TOCSection] + } + +emptyParseResponse :: ParseResponse +emptyParseResponse = ParseResponse + { parText = "" + , parRevId = Nothing + , parLangLinks = Nothing + , parCategories = Nothing + , parLinks = Nothing + , parTemplates = Nothing + , parImages = Nothing + , parExternalLinks = Nothing + , parSections = Nothing + } + +data LanguageLink + = LanguageLink + { laLang :: String + , laLink :: String + } + +data CategoryLink + = CategoryLink + { caSortKey :: String + , caLink :: String + } + +data Link + = Link + { liNamespace :: String + , liExists :: Bool + , liLink :: String + } + +data TOCSection + = TOCSection + { tocTocLevel :: Int + , tocLevel :: Int + , tocLine :: String + , tocNumber :: String + } +
+ MediaWiki/API/Action/Parse/Import.hs view
@@ -0,0 +1,102 @@+--------------------------------------------------------------------+-- |+-- Module : MediaWiki.API.Action.Parse.Import+-- Description : Serializing Parse requests.+-- Copyright : (c) Sigbjorn Finne, 2008+-- License : BSD3+--+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>+-- Stability : provisional+-- Portability: portable+--+-- Serializing Parse requests.+-- +--------------------------------------------------------------------+module MediaWiki.API.Action.Parse.Import where++import MediaWiki.API.Types+import MediaWiki.API.Utils+import MediaWiki.API.Action.Parse++import Text.XML.Light.Types+import Text.XML.Light.Proc ( strContent )++import Control.Monad+import Data.Maybe++stringXml :: String -> Either (String,[{-Error msg-}String]) ParseResponse+stringXml s = parseDoc xml s++xml :: Element -> Maybe ParseResponse+xml e = do+ guard (elName e == nsName "api")+ let es1 = children e+ p <- pNode "parse" es1+ let es = children p+ let txt = fromMaybe "" (pNode "text" es >>= return.strContent)+ let rev = pAttr "revid" p+ let ll = fmap (mapMaybe xmlLL) (fmap children $ pNode "langlinks" es)+ let ca = fmap (mapMaybe xmlCat) (fmap children $ pNode "categories" es)+ let li = fmap (mapMaybe xmlLi) (fmap children $ pNode "links" es)+ let te = fmap (mapMaybe xmlTe) (fmap children $ pNode "templates" es)+ let im = fmap (mapMaybe xmlIm) (fmap children $ pNode "images" es)+ let ex = fmap (mapMaybe xmlEx) (fmap children $ pNode "externallinks" es)+ let se = fmap (mapMaybe xmlSe) (fmap children $ pNode "sections" es)+ return emptyParseResponse+ { parText = txt+ , parRevId = rev+ , parLangLinks = ll+ , parCategories = ca+ , parLinks = li+ , parTemplates = te+ , parImages = im+ , parExternalLinks = ex+ , parSections = se+ }++xmlLL :: Element -> Maybe LanguageLink+xmlLL e = do+ guard (elName e == nsName "ll")+ let lng = fromMaybe "en" $ pAttr "lang" e+ return LanguageLink{laLang=lng,laLink=strContent e}++xmlCat :: Element -> Maybe CategoryLink+xmlCat e = do+ guard (elName e == nsName "cl")+ let sk = fromMaybe "" $ pAttr "sortkey" e+ return CategoryLink{caSortKey=sk,caLink=strContent e}++xmlLi :: Element -> Maybe Link+xmlLi e = do+ guard (elName e == nsName "pl")+ let ex = isJust (pAttr "exists" e)+ let ns = fromMaybe mainNamespace $ pAttr "ns" e+ return Link{liNamespace=ns,liExists=ex,liLink=strContent e}+++xmlTe :: Element -> Maybe Link+xmlTe e = do+ guard (elName e == nsName "tl")+ let ex = isJust (pAttr "exists" e)+ let ns = fromMaybe mainNamespace $ pAttr "ns" e + return Link{liNamespace=ns,liExists=ex,liLink=strContent e}++xmlIm :: Element -> Maybe URLString+xmlIm e = do+ guard (elName e == nsName "img")+ return (strContent e)++xmlEx :: Element -> Maybe URLString+xmlEx e = do+ guard (elName e == nsName "el")+ return (strContent e)++xmlSe :: Element -> Maybe TOCSection+xmlSe e = do+ guard (elName e == nsName "s")+ let tlev = fromMaybe 0 $ pAttr "toclevel" e >>= readMb+ let lev = fromMaybe 0 $ pAttr "level" e >>= readMb+ let lin = fromMaybe "" $ pAttr "line" e+ let num = fromMaybe "" $ pAttr "number" e+ return TOCSection{tocTocLevel=tlev,tocLevel=lev,tocLine=lin,tocNumber=num}+
+ MediaWiki/API/Action/Protect.hs view
@@ -0,0 +1,50 @@+--------------------------------------------------------------------+-- |+-- Module : MediaWiki.API.Action.Protect+-- Description : Representing Protect requests.+-- Copyright : (c) Sigbjorn Finne, 2008+-- License : BSD3+--+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>+-- Stability : provisional+-- Portability: portable+--+-- Representing Protect requests.+-- +--------------------------------------------------------------------+module MediaWiki.API.Action.Protect where++import MediaWiki.API.Types+import MediaWiki.API.Utils++data ProtectRequest+ = ProtectRequest+ { protTitle :: PageName+ , protToken :: Token+ , protProtections :: [(String,String)]+ , protExpiry :: Maybe Timestamp+ , protReason :: Maybe String+ , protCascade :: Maybe Bool+ }++instance APIRequest ProtectRequest where+ isPostable _ = True+ showReq r =+ [ opt "title" (protTitle r)+ , opt "token" (protToken r)+ , opt1 "protections" (map (\ (a,b) -> a ++ '=':b) (protProtections r))+ , mbOpt "expiry" id (protExpiry r)+ , mbOpt "reason" id (protReason r)+ , optB "cascade" (fromMaybe False $ protCascade r)+ ]++emptyProtectRequest :: ProtectRequest+emptyProtectRequest = ProtectRequest+ { protTitle = ""+ , protToken = ""+ , protProtections = []+ , protExpiry = Nothing+ , protReason = Nothing+ , protCascade = Nothing+ } +
+ MediaWiki/API/Action/Rollback.hs view
@@ -0,0 +1,47 @@+--------------------------------------------------------------------+-- |+-- Module : MediaWiki.API.Action.Rollback+-- Description : Representing Rollback requests.+-- Copyright : (c) Sigbjorn Finne, 2008+-- License : BSD3+--+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>+-- Stability : provisional+-- Portability: portable+--+-- Representing Rollback requests.+-- +--------------------------------------------------------------------+module MediaWiki.API.Action.Rollback where++import MediaWiki.API.Types+import MediaWiki.API.Utils++data RollbackRequest+ = RollbackRequest+ { rbTitle :: PageName+ , rbUser :: UserName+ , rbToken :: Token+ , rbSummary :: Maybe String+ , rbMarkBot :: Maybe Bool+ }++instance APIRequest RollbackRequest where+ isPostable _ = True+ showReq r = + [ opt "title" (rbTitle r)+ , opt "user" (rbUser r)+ , opt "token" (rbToken r)+ , mbOpt "summary" id (rbSummary r)+ , mbOpt "markbot" (\ x -> if x then "1" else "0") (rbMarkBot r)+ ] ++emptyRollbackRequest :: RollbackRequest+emptyRollbackRequest = RollbackRequest+ { rbTitle = ""+ , rbUser = ""+ , rbToken = ""+ , rbSummary = Nothing+ , rbMarkBot = Nothing+ } +
+ MediaWiki/API/Action/Sitematrix.hs view
@@ -0,0 +1,48 @@+-------------------------------------------------------------------- +-- | +-- Module : MediaWiki.API.Action.Sitematrix +-- Description : Representing Sitematrix requests. +-- Copyright : (c) Sigbjorn Finne, 2008 +-- License : BSD3 +-- +-- Maintainer: Sigbjorn Finne <sof@forkIO.com> +-- Stability : provisional +-- Portability: portable +-- +-- Representing Sitematrix requests. +-- +-------------------------------------------------------------------- +module MediaWiki.API.Action.Sitematrix where + +import MediaWiki.API.Types + +-- 1.12+ and later +data SitematrixRequest + = SitematrixRequest + +emptySitematrixRequest :: SitematrixRequest +emptySitematrixRequest = SitematrixRequest + +data SitematrixResponse + = SitematrixResponse + { smCount :: Int + , smSpecials :: [SiteSpecialInfo] + , smLanguages :: [LanguageInfo] + } + +data SiteSpecialInfo + = SiteSpecialInfo + { siCode :: String + , siUrl :: URLString + } + +data LanguageInfo + = LanguageInfo + { liCode :: String + , liName :: String + , liSites :: [SiteInfos] + } + +data SiteInfos + = SiteInfos + { siInfo :: String }
+ MediaWiki/API/Action/Unblock.hs view
@@ -0,0 +1,47 @@+--------------------------------------------------------------------+-- |+-- Module : MediaWiki.API.Action.Unblock+-- Description : Representing Unblock requests.+-- Copyright : (c) Sigbjorn Finne, 2008+-- License : BSD3+--+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>+-- Stability : provisional+-- Portability: portable+--+-- Representing Unblock requests.+-- +--------------------------------------------------------------------+module MediaWiki.API.Action.Unblock where++import MediaWiki.API.Types+import MediaWiki.API.Utils++data UnblockRequest+ = UnblockRequest+ { ublkId :: Maybe String+ , ublkUser :: Maybe UserName+ , ublkToken :: Maybe Token+ , ublkGetToken :: Bool+ , ublkReason :: Maybe String+ }++instance APIRequest UnblockRequest where+ isPostable _ = True+ showReq r = + [ mbOpt "id" id (ublkId r)+ , mbOpt "user" id (ublkUser r)+ , mbOpt "token" id (ublkToken r)+ , optB "gettoken" (ublkGetToken r)+ , mbOpt "reason" id (ublkReason r)+ ]++emptyUnblockRequest :: UnblockRequest+emptyUnblockRequest = UnblockRequest+ { ublkId = Nothing+ , ublkUser = Nothing+ , ublkToken = Nothing+ , ublkGetToken = False+ , ublkReason = Nothing+ }+
+ MediaWiki/API/Action/Undelete.hs view
@@ -0,0 +1,43 @@+--------------------------------------------------------------------+-- |+-- Module : MediaWiki.API.Action.Undelete+-- Description : Representing Undelete requests.+-- Copyright : (c) Sigbjorn Finne, 2008+-- License : BSD3+--+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>+-- Stability : provisional+-- Portability: portable+--+-- Representing Undelete requests.+-- +--------------------------------------------------------------------+module MediaWiki.API.Action.Undelete where++import MediaWiki.API.Types+import MediaWiki.API.Utils++data UndeleteRequest+ = UndeleteRequest+ { udelTitle :: PageName+ , udelToken :: Token+ , udelReason :: Maybe String+ , udelTimestamps :: [Timestamp]+ }++instance APIRequest UndeleteRequest where+ isPostable _ = True+ showReq r = + [ opt "title" (udelTitle r)+ , opt "token" (udelToken r)+ , mbOpt "reason" id (udelReason r)+ , opt1 "timestamps" (udelTimestamps r)+ ]+emptyUndeleteRequest :: UndeleteRequest+emptyUndeleteRequest = UndeleteRequest+ { udelTitle = ""+ , udelToken = ""+ , udelReason = Nothing+ , udelTimestamps = []+ } +
+ MediaWiki/API/Action/Watch.hs view
@@ -0,0 +1,37 @@+--------------------------------------------------------------------+-- |+-- Module : MediaWiki.API.Action.Watch+-- Description : Representing Watch requests.+-- Copyright : (c) Sigbjorn Finne, 2008+-- License : BSD3+--+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>+-- Stability : provisional+-- Portability: portable+--+-- Representing Watch requests.+-- +--------------------------------------------------------------------+module MediaWiki.API.Action.Watch where++import MediaWiki.API.Types+import MediaWiki.API.Utils++data WatchRequest+ = WatchRequest+ { waTitle :: PageName+ , waIsUnwatch :: Bool+ }++instance APIRequest WatchRequest where+ isPostable _ = True+ showReq r = + [ opt "title" (waTitle r)+ , optB "unwatch" (waIsUnwatch r)+ ]++emptyWatchRequest :: WatchRequest+emptyWatchRequest = WatchRequest+ { waTitle = ""+ , waIsUnwatch = False+ }
+ MediaWiki/API/Base.hs view
@@ -0,0 +1,329 @@+-------------------------------------------------------------------- +-- | +-- Module : MediaWiki.API.Base +-- Description : Collector module of types used by the MediaWiki API +-- Copyright : (c) Sigbjorn Finne, 2008 +-- License : BSD3 +-- +-- Maintainer: Sigbjorn Finne <sof@forkIO.com> +-- Stability : provisional +-- Portability: portable +-- +-- Collector module of types used by the MediaWiki API +-- +-------------------------------------------------------------------- +module MediaWiki.API.Base + ( module MediaWiki.API.Base + , module MediaWiki.API.Query.AllCategories + , module MediaWiki.API.Query.AllImages + , module MediaWiki.API.Query.AllLinks + , module MediaWiki.API.Query.AllMessages + , module MediaWiki.API.Query.AllPages + , module MediaWiki.API.Query.AllUsers + , module MediaWiki.API.Query.BackLinks + , module MediaWiki.API.Query.Blocks + , module MediaWiki.API.Query.Categories + , module MediaWiki.API.Query.CategoryInfo + , module MediaWiki.API.Query.CategoryMembers + , module MediaWiki.API.Query.DeletedRevisions + , module MediaWiki.API.Query.EmbeddedIn + , module MediaWiki.API.Query.ExternalLinks + , module MediaWiki.API.Query.ExternalURLUsage + , module MediaWiki.API.Query.ImageInfo + , module MediaWiki.API.Query.Images + , module MediaWiki.API.Query.ImageUsage + , module MediaWiki.API.Query.Info + , module MediaWiki.API.Query.LangLinks + , module MediaWiki.API.Query.LogEvents + , module MediaWiki.API.Query.Random + , module MediaWiki.API.Query.RecentChanges + , module MediaWiki.API.Query.Revisions + , module MediaWiki.API.Query.Search + , module MediaWiki.API.Query.SiteInfo + , module MediaWiki.API.Query.Templates + , module MediaWiki.API.Query.UserContribs + , module MediaWiki.API.Query.UserInfo + , module MediaWiki.API.Query.Users + , module MediaWiki.API.Query.WatchList + + , module MediaWiki.API.Action.Login + , module MediaWiki.API.Action.ParamInfo + , module MediaWiki.API.Action.Parse + , module MediaWiki.API.Action.OpenSearch + , module MediaWiki.API.Action.FeedWatchlist + , module MediaWiki.API.Action.ExpandTemplates + , module MediaWiki.API.Action.Sitematrix + , module MediaWiki.API.Action.Unblock + , module MediaWiki.API.Action.Watch + , module MediaWiki.API.Action.EmailUser + , module MediaWiki.API.Action.Edit + , module MediaWiki.API.Action.Move + , module MediaWiki.API.Action.Block + , module MediaWiki.API.Action.Protect + , module MediaWiki.API.Action.Undelete + , module MediaWiki.API.Action.Delete + , module MediaWiki.API.Action.Rollback + + ) where + +import MediaWiki.API.Types +import MediaWiki.API.Query.AllCategories +import MediaWiki.API.Query.AllImages +import MediaWiki.API.Query.AllLinks +import MediaWiki.API.Query.AllMessages +import MediaWiki.API.Query.AllPages +import MediaWiki.API.Query.AllUsers +import MediaWiki.API.Query.BackLinks +import MediaWiki.API.Query.Blocks +import MediaWiki.API.Query.Categories +import MediaWiki.API.Query.CategoryInfo +import MediaWiki.API.Query.CategoryMembers +import MediaWiki.API.Query.DeletedRevisions +import MediaWiki.API.Query.EmbeddedIn +import MediaWiki.API.Query.ExternalLinks +import MediaWiki.API.Query.ExternalURLUsage +import MediaWiki.API.Query.ImageInfo +import MediaWiki.API.Query.Images +import MediaWiki.API.Query.ImageUsage +import MediaWiki.API.Query.Info +import MediaWiki.API.Query.LangLinks +import MediaWiki.API.Query.Links +import MediaWiki.API.Query.LogEvents +import MediaWiki.API.Query.Random +import MediaWiki.API.Query.RecentChanges +import MediaWiki.API.Query.Revisions +import MediaWiki.API.Query.Search +import MediaWiki.API.Query.SiteInfo +import MediaWiki.API.Query.Templates +import MediaWiki.API.Query.UserContribs +import MediaWiki.API.Query.UserInfo +import MediaWiki.API.Query.Users +import MediaWiki.API.Query.WatchList + +import MediaWiki.API.Action.Login +import MediaWiki.API.Action.ParamInfo +import MediaWiki.API.Action.Parse +import MediaWiki.API.Action.OpenSearch +import MediaWiki.API.Action.FeedWatchlist +import MediaWiki.API.Action.ExpandTemplates +import MediaWiki.API.Action.Sitematrix +import MediaWiki.API.Action.Unblock +import MediaWiki.API.Action.Watch +import MediaWiki.API.Action.EmailUser +import MediaWiki.API.Action.Edit +import MediaWiki.API.Action.Move +import MediaWiki.API.Action.Block +import MediaWiki.API.Action.Protect +import MediaWiki.API.Action.Undelete +import MediaWiki.API.Action.Delete +import MediaWiki.API.Action.Rollback + +-- | Type collecting together the main parts of a MediaWiki API request. +data Request + = Request + { reqAction :: Action + , reqFormat :: Format + , reqMaxLag :: Maybe Int + } + +emptyRequest :: Action -> Format -> Request +emptyRequest a f + = Request + { reqAction = a + , reqFormat = f + , reqMaxLag = Nothing + } + +emptyXmlRequest :: Action -> Request +emptyXmlRequest a = emptyRequest a xmlFormat + +data Action + = Sitematrix + | Login LoginRequest + | Logout + | Query QueryRequest [String] + | ExpandTemplates ExpandTemplatesRequest + | Parse ParseRequest + | OpenSearch OpenSearchRequest + | FeedWatch FeedWatchListRequest + | Help HelpRequest + | ParamInfo ParamInfoRequest + | Unblock UnblockRequest + | Watch WatchRequest + | EmailUser EmailUserRequest + | Edit EditRequest + | Move MoveRequest + | Block BlockRequest + | Protect ProtectRequest + | Undelete UndeleteRequest + | Delete DeleteRequest + | Rollback RollbackRequest + | OtherAction String [ValueName] + + +infoRequest :: InfoRequest +infoRequest = emptyInfoRequest + +revisionRequest :: RevisionRequest +revisionRequest = emptyRevisionRequest + +linksRequest :: LinksRequest +linksRequest = emptyLinksRequest + +langLinksRequest :: LangLinksRequest +langLinksRequest = emptyLangLinksRequest + +imagesRequest :: ImagesRequest +imagesRequest = emptyImagesRequest + +imageInfoRequest :: ImageInfoRequest +imageInfoRequest = emptyImageInfoRequest + +templatesRequest :: TemplatesRequest +templatesRequest = emptyTemplatesRequest + +categoriesRequest :: CategoriesRequest +categoriesRequest = emptyCategoriesRequest + +allCategoriesRequest :: AllCategoriesRequest +allCategoriesRequest = emptyAllCategoriesRequest + +allImagesRequest :: AllImagesRequest +allImagesRequest = emptyAllImagesRequest + +allLinksRequest :: AllLinksRequest +allLinksRequest = emptyAllLinksRequest + +allMessagesRequest :: AllMessagesRequest +allMessagesRequest = emptyAllMessagesRequest + +allPagesRequest :: AllPagesRequest +allPagesRequest = emptyAllPagesRequest + +allUsersRequest :: AllUsersRequest +allUsersRequest = emptyAllUsersRequest + +backLinksRequest :: BackLinksRequest +backLinksRequest = emptyBackLinksRequest + +embeddedInRequest :: EmbeddedInRequest +embeddedInRequest = emptyEmbeddedInRequest + +imageUsageRequest :: ImageUsageRequest +imageUsageRequest = emptyImageUsageRequest + +categoryInfoRequest :: CategoryInfoRequest +categoryInfoRequest = emptyCategoryInfoRequest + +categoryMembersRequest :: CategoryMembersRequest +categoryMembersRequest = emptyCategoryMembersRequest + +externalLinksRequest :: ExternalLinksRequest +externalLinksRequest = emptyExternalLinksRequest + +externalURLUsageRequest :: ExternalURLUsageRequest +externalURLUsageRequest = emptyExternalURLUsageRequest + +logEventsRequest :: LogEventsRequest +logEventsRequest = emptyLogEventsRequest + +recentChangesRequest :: RecentChangesRequest +recentChangesRequest = emptyRecentChangesRequest + +searchRequest :: String -> SearchRequest +searchRequest = emptySearchRequest + +siteInfoRequest :: SiteInfoRequest +siteInfoRequest = emptySiteInfoRequest + +userContribsRequest :: UserContribsRequest +userContribsRequest = emptyUserContribsRequest + +userInfoRequest :: UserInfoRequest +userInfoRequest = emptyUserInfoRequest + +watchListRequest :: WatchListRequest +watchListRequest = emptyWatchListRequest + +blocksRequest :: BlocksRequest +blocksRequest = emptyBlocksRequest + +deletedRevisionsRequest :: DeletedRevisionsRequest +deletedRevisionsRequest = emptyDeletedRevisionsRequest + +usersRequest :: UsersRequest +usersRequest = emptyUsersRequest + +randomPagesRequest :: RandomPagesRequest +randomPagesRequest = emptyRandomPagesRequest + +data QueryRequestKind + = InfoProp InfoRequest + | RevisionsProp RevisionRequest + | LinksPropProp LinksRequest + | LangLinksProp LangLinksRequest + | ImagesProp ImagesRequest + | ImageInfoProp ImageInfoRequest + | TemplatesProp TemplatesRequest + | CategoriesProp CategoriesRequest + | AllCategoriesProp AllCategoriesRequest + | AllImagesProp AllImagesRequest + | AllLinksProp AllLinksRequest + | AllMessagesProp AllMessagesRequest + | AllPagesProp AllPagesRequest + | AllUsersProp AllUsersRequest + | BacklinksProp BackLinksRequest + | EmbeddedInProp EmbeddedInRequest + | ImageUsageProp ImageUsageRequest + | CategoryInfoProp CategoryInfoRequest + | CategoryMembersProp CategoryMembersRequest + | ExternalLinksProp ExternalLinksRequest + | ExternalURLUsageProp ExternalURLUsageRequest + | LogEventsProp LogEventsRequest + | RecentChangesProp RecentChangesRequest + | SearchProp SearchRequest + | SiteInfoProp SiteInfoRequest + | UserContribsProp UserContribsRequest + | UserInfoProp UserInfoRequest + | WatchListProp WatchListRequest + | BlocksProp BlocksRequest + | DeletedRevsProp DeletedRevisionsRequest + | UsersProp UsersRequest + | RandomProp RandomPagesRequest + +qKind :: QueryRequestKind -> QueryKind +qKind q = + case q of + InfoProp k -> queryKind k + RevisionsProp k -> queryKind k + LinksPropProp k -> queryKind k + LangLinksProp k -> queryKind k + ImagesProp k -> queryKind k + ImageInfoProp k -> queryKind k + TemplatesProp k -> queryKind k + CategoriesProp k -> queryKind k + AllCategoriesProp k -> queryKind k + AllImagesProp k -> queryKind k + AllLinksProp k -> queryKind k + AllMessagesProp k -> queryKind k + AllPagesProp k -> queryKind k + AllUsersProp k -> queryKind k + BacklinksProp k -> queryKind k + EmbeddedInProp k -> queryKind k + ImageUsageProp k -> queryKind k + CategoryInfoProp k -> queryKind k + CategoryMembersProp k -> queryKind k + ExternalLinksProp k -> queryKind k + ExternalURLUsageProp k -> queryKind k + LogEventsProp k -> queryKind k + RecentChangesProp k -> queryKind k + SearchProp k -> queryKind k + SiteInfoProp k -> queryKind k + UserContribsProp k -> queryKind k + UserInfoProp k -> queryKind k + WatchListProp k -> queryKind k + BlocksProp k -> queryKind k + DeletedRevsProp k -> queryKind k + UsersProp k -> queryKind k + RandomProp k -> queryKind k +
+ MediaWiki/API/Output.hs view
@@ -0,0 +1,209 @@+-------------------------------------------------------------------- +-- | +-- Module : MediaWiki.API.Output +-- Description : Serializing MediaWiki API types +-- Copyright : (c) Sigbjorn Finne, 2008 +-- License : BSD3 +-- +-- Maintainer: Sigbjorn Finne <sof@forkIO.com> +-- Stability : provisional +-- Portability: portable +-- +-- Serializing MediaWiki API types +-- +-------------------------------------------------------------------- +module MediaWiki.API.Output where + +import MediaWiki.API.Types +import MediaWiki.API.Base + +import Data.List +import Data.Maybe + + +showRequest :: Request + -> String +showRequest req = + join (showAction (reqAction req) : showMaxLag (reqMaxLag req) (showFormat (reqFormat req))) + +showMaxLag :: Maybe Int -> String -> [String] +showMaxLag Nothing rs = [rs] +showMaxLag (Just l) rs = [field "maxlag" (show l), rs] + +showFormat :: Format -> String +showFormat f = field "format" $ isFormatted (formatFormatted f) $ + case formatKind f of + FormatJSON -> "json" + FormatPHP -> "php" + FormatWDDX -> "wddx" + FormatXML -> "xml" + FormatYAML -> "yaml" + FormatTxt -> "txt" + FormatDbg -> "dbg" + where + isFormatted False xs = xs + isFormatted _ xs = xs++"fm" + +toReq :: APIRequest a => a -> [String] +toReq x = + case catMaybes $ showReq x of + [] -> [] + xs -> map showP xs + where + showP (a,b) = a ++ '=':b + +showQueryRequestKind :: QueryRequestKind -> [String] +showQueryRequestKind r = + case r of + InfoProp p -> toReq p + RevisionsProp p -> toReq p + LinksPropProp p -> toReq p + LangLinksProp p -> toReq p + ImagesProp p -> toReq p + ImageInfoProp p -> toReq p + TemplatesProp p -> toReq p + CategoriesProp p -> toReq p + AllCategoriesProp p -> toReq p + AllImagesProp p -> toReq p + AllLinksProp p -> toReq p + AllMessagesProp p -> toReq p + AllPagesProp p -> toReq p + AllUsersProp p -> toReq p + BacklinksProp p -> toReq p + EmbeddedInProp p -> toReq p + ImageUsageProp p -> toReq p + CategoryInfoProp p -> toReq p + CategoryMembersProp p -> toReq p + ExternalLinksProp p -> toReq p + ExternalURLUsageProp p -> toReq p + LogEventsProp p -> toReq p + RecentChangesProp p -> toReq p + SearchProp p -> toReq p + SiteInfoProp p -> toReq p + UserContribsProp p -> toReq p + UserInfoProp p -> toReq p + WatchListProp p -> toReq p + BlocksProp p -> toReq p + DeletedRevsProp p -> toReq p + UsersProp p -> toReq p + RandomProp p -> toReq p + + +showAction :: Action -> String +showAction act = join $ + case act of + Sitematrix -> [field "action" "sitematrix"] + Login l -> (field "action" "login"): (toReq l) + Logout -> [field "action" "logout"] + Query q qr -> (field "action" "query") : (showQuery q) ++ qr + ExpandTemplates et -> (field "action" "expandtemplates") : (showExpandTemplates et) + Parse pt -> (field "action" "parse") : (showParseRequest pt) + OpenSearch os -> (field "action" "opensearch") : (showOpenSearch os) + FeedWatch f -> (field "action" "feedwatchlist") : (showFeedWatch f) + Help h -> (field "action" "help") : (showHelpRequest h) + ParamInfo pin -> (field "action" "paraminfo") : (showParamInfoRequest pin) + Unblock r -> (field "action" "unblock") : toReq r + Watch r -> (field "action" "watch") : toReq r + EmailUser r -> (field "action" "emailuser") : toReq r + Edit r -> (field "action" "edit") : toReq r + Move r -> (field "action" "move") : toReq r + Block r -> (field "action" "block") : toReq r + Protect r -> (field "action" "protect") : toReq r + Undelete r -> (field "action" "undelete") : toReq r + Delete r -> (field "action" "delete") : toReq r + Rollback r -> (field "action" "rollback") : toReq r + OtherAction at vs -> (field "action" at) : (map showValueName vs) + +{- +showLoginRequest :: LoginRequest -> [String] +showLoginRequest l = catMaybes + [ Just $ field "name" (lgName l) + , Just $ field "password" (lgPassword l) + , fieldMb "version" id (lgDomain l) + ] +-} + +showHelpRequest :: HelpRequest -> [String] +showHelpRequest h = + maybeToList (fieldMb "version" showBool (helpVersion h)) + +showQuery :: QueryRequest -> [String] +showQuery q = catMaybes + [ fieldList "titles" "," (quTitles q) + , fieldList "pageids" "," (quPageIds q) + , fieldList "revids" "," (quRevIds q) + , fieldList "prop" "|" (map showPropKind $ quProps q) + , fieldList "list" "|" (map showListKind $ quLists q) + , fieldList "meta" "|" (map showMetaKind $ quMetas q) + , fieldMb "generator" showGeneratorKind (quGenerator q) + , fieldMb "redirects" showBool (quFollowRedirects q) + , fieldMb "indexpageids" showBool (quIndexPageIds q) + ] + +showExpandTemplates :: ExpandTemplatesRequest -> [String] +showExpandTemplates et = catMaybes + [ fieldMb "title" id (etTitle et) + , Just $ field "text" (etText et) + ] + +showPropKind :: PropKind -> String +showPropKind pk = prKind pk + +showListKind :: ListKind -> String +showListKind lk = liKind lk + +showMetaKind :: MetaKind -> String +showMetaKind mk = meKind mk + +showParseRequest :: ParseRequest -> [String] +showParseRequest p = catMaybes + [ fieldMb "title" id (paTitle p) + , Just $ field "text" (paText p) + , fieldMb "page" id (paPage p) + , fieldList "prop" "|" (paProp p) + ] + +showOpenSearch :: OpenSearchRequest -> [String] +showOpenSearch o = catMaybes + [ Just $ field "search" (osSearch o) + , fieldMb "limit" show (osLimit o) + ] + +showFeedWatch :: FeedWatchListRequest -> [String] +showFeedWatch f = catMaybes + [ Just $ field "feedformat" (if feAsAtom f then "atom" else "rss") + , fieldMb "hours" show (feHours f) + , if feAllRev f then (Just $ field "allrev" "") else Nothing + ] + +showParamInfoRequest :: ParamInfoRequest -> [String] +showParamInfoRequest p = catMaybes + [ fieldList "modules" "," (paModules p) + , fieldList "querymodules" "|" (paQueryModules p) + ] + +showGeneratorKind :: GeneratorKind -> String +showGeneratorKind gk = genKind gk + +showValueName :: ValueName -> String +showValueName (n,v) = field n v + +showBool :: Bool -> String +showBool True = "true" +showBool _ = "false" + +join :: [String] -> String +join [] = "" +join xs = concat (intersperse "&" xs) + +field :: String -> String -> String +field a b = a ++ '=':b + +fieldMb :: String -> (a -> String) -> Maybe a -> Maybe String +fieldMb _ _ Nothing = Nothing +fieldMb n f (Just x) = Just (field n (f x)) + +fieldList :: String -> String -> [String] -> Maybe String +fieldList _ _ [] = Nothing +fieldList n s xs = Just (field n (concat $ intersperse s xs)) +
+ MediaWiki/API/Query/AllCategories.hs view
@@ -0,0 +1,62 @@+--------------------------------------------------------------------+-- |+-- Module : MediaWiki.API.Query.AllCategories+-- Description : Representing 'allcategories' requests.+-- Copyright : (c) Sigbjorn Finne, 2008+-- License : BSD3+--+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>+-- Stability : provisional+-- Portability: portable+--+-- Representing 'allcategories' requests.+-- +--------------------------------------------------------------------+module MediaWiki.API.Query.AllCategories where++import MediaWiki.API.Types+import MediaWiki.API.Utils+import MediaWiki.API.Query.CategoryInfo ( CategoryInfo )++data AllCategoriesRequest+ = AllCategoriesRequest+ { acFrom :: Maybe PageName+ , acPrefix :: Maybe PageName+ , acDir :: Maybe Direction+ , acLimit :: Maybe Int+ , acProp :: [String]+ }++instance APIRequest AllCategoriesRequest where+ queryKind _ = QList "allcategories"+ showReq r + = [ mbOpt "acfrom" id (acFrom r)+ , mbOpt "acprefix" id (acPrefix r)+ , mbOpt "acdir" (\ x -> if x == Up then "ascending" else "descending")+ (acDir r)+ , mbOpt "aclimit" show (acLimit r)+ , opt1 "acprop" (acProp r)+ ]++emptyAllCategoriesRequest :: AllCategoriesRequest+emptyAllCategoriesRequest = AllCategoriesRequest+ { acFrom = Nothing+ , acPrefix = Nothing+ , acDir = Nothing+ , acLimit = Nothing+ , acProp = []+ }++ +data AllCategoriesResponse+ = AllCategoriesResponse+ { acCategories :: [CategoryInfo]+ , acContinue :: Maybe String+ }+ +emptyAllCategoriesResponse :: AllCategoriesResponse+emptyAllCategoriesResponse+ = AllCategoriesResponse+ { acCategories = []+ , acContinue = Nothing+ }
+ MediaWiki/API/Query/AllCategories/Import.hs view
@@ -0,0 +1,33 @@+module MediaWiki.API.Query.AllCategories.Import where++import MediaWiki.API.Types+import MediaWiki.API.Utils+import MediaWiki.API.Query.AllCategories+import MediaWiki.API.Query.CategoryInfo+import MediaWiki.API.Query.CategoryInfo.Import ( xmlCI )++import Text.XML.Light.Types+import Text.XML.Light.Proc ( strContent )++import Control.Monad+import Data.Maybe++stringXml :: String -> Either (String,[{-Error msg-}String]) AllCategoriesResponse+stringXml s = parseDoc xml s++xml :: Element -> Maybe AllCategoriesResponse+xml e = do+ guard (elName e == nsName "api")+ let es1 = children e+ p <- pNode "query" es1+ let es = children p+ ps <- fmap (mapMaybe xmlCII) (fmap children $ pNode "allcategories" es)+ let cont = pNode "query-continue" es1 >>= xmlContinue "allcategories" "acfrom"+ return emptyAllCategoriesResponse{acCategories=ps,acContinue=cont}++xmlCII :: Element -> Maybe CategoryInfo+xmlCII e = do+ c <- xmlCI emptyPageTitle "c" e+ let tit = strContent e+ return c{ciPage=(ciPage c){pgTitle=tit}}+
+ MediaWiki/API/Query/AllImages.hs view
@@ -0,0 +1,75 @@+--------------------------------------------------------------------+-- |+-- Module : MediaWiki.API.Query.AllImages+-- Description : Representing 'allimages' requests.+-- Copyright : (c) Sigbjorn Finne, 2008+-- License : BSD3+--+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>+-- Stability : provisional+-- Portability: portable+--+-- Representing 'allimages' requests.+-- +--------------------------------------------------------------------+module MediaWiki.API.Query.AllImages where++import MediaWiki.API.Types+import MediaWiki.API.Utils+import MediaWiki.API.Query.ImageInfo ( ImageInfo )++data AllImagesRequest+ = AllImagesRequest+ { aiFrom :: Maybe PageName+ , aiPrefix :: Maybe PageName+ , aiMinSize :: Maybe Int+ , aiMaxSize :: Maybe Int+ , aiLimit :: Maybe Int+ , aiDir :: Maybe Direction+ , aiSha1 :: Maybe String+ , aiSha1Base36 :: Maybe String+ , aiProp :: [String]+ }++instance APIRequest AllImagesRequest where+ queryKind _ = QList "allimages"+ showReq r+ = [ mbOpt "aifrom" id (aiFrom r)+ , mbOpt "aiprefix" id (aiPrefix r)+ , mbOpt "aiminsize" show (aiMinSize r)+ , mbOpt "aimaxsize" show (aiMaxSize r)+ , mbOpt "ailimit" show (aiLimit r)+ , mbOpt "aidir" (\ x -> if x == Up then "ascending" else "descending")+ (aiDir r)+ , mbOpt "aisha1" id (aiSha1 r)+ , mbOpt "aisha1base36" id (aiSha1Base36 r)+ , opt1 "aiprop" (aiProp r)+ ]+++emptyAllImagesRequest :: AllImagesRequest+emptyAllImagesRequest = AllImagesRequest+ { aiFrom = Nothing+ , aiPrefix = Nothing+ , aiMinSize = Nothing+ , aiMaxSize = Nothing+ , aiLimit = Nothing+ , aiDir = Nothing+ , aiSha1 = Nothing+ , aiSha1Base36 = Nothing+ , aiProp = []+ }++ +data AllImagesResponse+ = AllImagesResponse+ { aiImages :: [ImageInfo]+ , aiContinue :: Maybe String+ }+ +emptyAllImagesResponse :: AllImagesResponse+emptyAllImagesResponse+ = AllImagesResponse+ { aiImages = []+ , aiContinue = Nothing+ }
+ MediaWiki/API/Query/AllImages/Import.hs view
@@ -0,0 +1,25 @@+module MediaWiki.API.Query.AllImages.Import where++import MediaWiki.API.Types+import MediaWiki.API.Utils+import MediaWiki.API.Query.AllImages+import MediaWiki.API.Query.ImageInfo.Import ( xmlII )++import Text.XML.Light.Types+import Text.XML.Light.Proc ( strContent )++import Control.Monad+import Data.Maybe++stringXml :: String -> Either (String,[{-Error msg-}String]) AllImagesResponse+stringXml s = parseDoc xml s++xml :: Element -> Maybe AllImagesResponse+xml e = do+ guard (elName e == nsName "api")+ let es1 = children e+ p <- pNode "query" es1+ let es = children p+ ps <- fmap (mapMaybe (xmlII "img")) (fmap children $ pNode "allimages" es)+ let cont = pNode "query-continue" es1 >>= xmlContinue "allimages" "aifrom"+ return emptyAllImagesResponse{aiImages=ps,aiContinue=cont}
+ MediaWiki/API/Query/AllLinks.hs view
@@ -0,0 +1,66 @@+--------------------------------------------------------------------+-- |+-- Module : MediaWiki.API.Query.AllLinks+-- Description : Representing 'alllinks' requests.+-- Copyright : (c) Sigbjorn Finne, 2008+-- License : BSD3+--+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>+-- Stability : provisional+-- Portability: portable+--+-- Representing 'alllinks' requests.+-- +--------------------------------------------------------------------+module MediaWiki.API.Query.AllLinks where++import MediaWiki.API.Types+import MediaWiki.API.Utils++data AllLinksRequest+ = AllLinksRequest+ { alContinueFrom :: Maybe String+ , alFrom :: Maybe PageName+ , alPrefix :: Maybe PageName+ , alUnique :: Bool+ , alProp :: [String]+ , alNamespace :: Maybe NamespaceID+ , alLimit :: Maybe Int+ }++instance APIRequest AllLinksRequest where+ queryKind _ = QList "alllinks"+ showReq r =+ [ mbOpt "alcontinue" id (alContinueFrom r)+ , mbOpt "alfrom" id (alFrom r)+ , mbOpt "alprefix" id (alPrefix r)+ , optB "alunique" (alUnique r)+ , opt1 "alprop" (alProp r)+ , mbOpt "alnamespace" id (alNamespace r)+ , mbOpt "allimit" show (alLimit r)+ ]++emptyAllLinksRequest :: AllLinksRequest+emptyAllLinksRequest = AllLinksRequest+ { alContinueFrom = Nothing+ , alFrom = Nothing+ , alPrefix = Nothing+ , alUnique = False+ , alProp = []+ , alNamespace = Nothing+ , alLimit = Nothing+ }+ +data AllLinksResponse+ = AllLinksResponse+ { alLinks :: [PageTitle]+ , alContinue :: Maybe String+ }+ +emptyAllLinksResponse :: AllLinksResponse+emptyAllLinksResponse+ = AllLinksResponse+ { alLinks = []+ , alContinue = Nothing+ }+
+ MediaWiki/API/Query/AllLinks/Import.hs view
@@ -0,0 +1,31 @@+module MediaWiki.API.Query.AllLinks.Import where++import MediaWiki.API.Types+import MediaWiki.API.Utils+import MediaWiki.API.Query.AllLinks++import Text.XML.Light.Types++import Control.Monad+import Data.Maybe++stringXml :: String -> Either (String,[{-Error msg-}String]) AllLinksResponse+stringXml s = parseDoc xml s++xml :: Element -> Maybe AllLinksResponse+xml e = do+ guard (elName e == nsName "api")+ let es1 = children e+ p <- pNode "query" es1+ let es = children p+ ps <- fmap (mapMaybe xmlLink) (fmap children $ pNode "alllinks" es)+ let cont = pNode "query-continue" es1 >>= xmlContinue "alllinks" "alcontinue"+ return emptyAllLinksResponse{alLinks=ps,alContinue=cont}++xmlLink :: Element -> Maybe PageTitle+xmlLink e = do+ guard (elName e == nsName "l")+ let ns = fromMaybe "0" $ pAttr "ns" e+ let tit = fromMaybe "" $ pAttr "title" e+ let pid = pAttr "fromid" e+ return emptyPageTitle{pgNS=ns,pgTitle=tit,pgMbId=pid}
+ MediaWiki/API/Query/AllMessages.hs view
@@ -0,0 +1,66 @@+--------------------------------------------------------------------+-- |+-- Module : MediaWiki.API.Query.AllMessages+-- Description : Representing 'allmessages' requests.+-- Copyright : (c) Sigbjorn Finne, 2008+-- License : BSD3+--+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>+-- Stability : provisional+-- Portability: portable+--+-- Representing 'allmessages' requests.+-- +--------------------------------------------------------------------+module MediaWiki.API.Query.AllMessages where++import MediaWiki.API.Types+import MediaWiki.API.Utils++data AllMessagesRequest+ = AllMessagesRequest+ { amMessages :: [String]+ , amFilter :: Maybe String+ , amLang :: Maybe String+ }++instance APIRequest AllMessagesRequest where+ queryKind _ = QMeta "allmessages"+ showReq r = [ opt1 "ammessages" (amMessages r)+ , mbOpt "amfilter" id (amFilter r)+ , mbOpt "amlang" id (amLang r)+ ]++emptyAllMessagesRequest :: AllMessagesRequest+emptyAllMessagesRequest = AllMessagesRequest+ { amMessages = []+ , amFilter = Nothing+ , amLang = Nothing+ }++ +data AllMessagesResponse+ = AllMessagesResponse+ { amsgMessages :: [MessageInfo]+ }+ +emptyAllMessagesResponse :: AllMessagesResponse+emptyAllMessagesResponse+ = AllMessagesResponse+ { amsgMessages = []+ }++data MessageInfo+ = MessageInfo+ { msgiName :: String+ , msgiMissing :: Bool+ , msgiContent :: String+ }+ +emptyMessageInfo :: MessageInfo+emptyMessageInfo = MessageInfo+ { msgiName = ""+ , msgiMissing = False+ , msgiContent = ""+ }+
+ MediaWiki/API/Query/AllMessages/Import.hs view
@@ -0,0 +1,31 @@+module MediaWiki.API.Query.AllMessages.Import where++import MediaWiki.API.Types+import MediaWiki.API.Utils+import MediaWiki.API.Query.AllMessages++import Text.XML.Light.Types+import Text.XML.Light.Proc ( strContent )++import Control.Monad+import Data.Maybe++stringXml :: String -> Either (String,[{-Error msg-}String]) AllMessagesResponse+stringXml s = parseDoc xml s++xml :: Element -> Maybe AllMessagesResponse+xml e = do+ guard (elName e == nsName "api")+ let es1 = children e+ p <- pNode "query" es1+ let es = children p+ ps <- fmap (mapMaybe xmlPage) (fmap children $ pNode "pages" es)+ return emptyAllMessagesResponse{amsgMessages=ps}++xmlPage :: Element -> Maybe MessageInfo+xmlPage e = do+ guard (elName e == nsName "message")+ let nm = fromMaybe "" $ pAttr "name" e+ let mi = isJust (pAttr "missing" e)+ return emptyMessageInfo{msgiName=nm,msgiMissing=mi,msgiContent=strContent e}+
+ MediaWiki/API/Query/AllPages.hs view
@@ -0,0 +1,76 @@+--------------------------------------------------------------------+-- |+-- Module : MediaWiki.API.Query.AllPages+-- Description : Representing 'allpages' requests.+-- Copyright : (c) Sigbjorn Finne, 2008+-- License : BSD3+--+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>+-- Stability : provisional+-- Portability: portable+--+-- Representing 'allpages' requests.+-- +--------------------------------------------------------------------+module MediaWiki.API.Query.AllPages where++import MediaWiki.API.Types+import MediaWiki.API.Utils++data AllPagesRequest+ = AllPagesRequest+ { apFrom :: Maybe PageName+ , apPrefix :: Maybe PageName+ , apNamespace :: NamespaceID+ , apFilterRedir :: Maybe WithRedirects+ , apMinSize :: Maybe Int+ , apMaxSize :: Maybe Int+ , apProtTypeLevel :: ([String],[String])+ , apLimit :: Maybe Int+ , apDir :: Maybe Direction+ , apFilterLangLinks :: Maybe FilterLang+ }++instance APIRequest AllPagesRequest where+ queryKind _ = QList "allpages"+ showReq r = + [ mbOpt "apfrom" id (apFrom r)+ , mbOpt "apprefix" id (apPrefix r)+ , mbOpt "apnamespace" id (Just $ apNamespace r)+ , mbOpt "apfilterredir" id (apFilterRedir r)+ , mbOpt "apminsize" show (apMinSize r)+ , mbOpt "apmaxsize" show (apMaxSize r)+ , mbOpt "apprtype" (piped.fst) (Just $ apProtTypeLevel r)+ , mbOpt "apprlevel" (piped.snd) (Just $ apProtTypeLevel r)+ , mbOpt "aplimit" show (apLimit r)+ , mbOpt "apdir" (\ x -> if x==Up then "ascending" else "descending") (apDir r)+ , mbOpt "apfilterlanglinks" id (apFilterLangLinks r)+ ]++emptyAllPagesRequest :: AllPagesRequest+emptyAllPagesRequest = AllPagesRequest+ { apFrom = Nothing+ , apPrefix = Nothing+ , apNamespace = mainNamespace+ , apFilterRedir = Nothing+ , apMinSize = Nothing+ , apMaxSize = Nothing+ , apProtTypeLevel = ([],[])+ , apLimit = Nothing+ , apDir = Nothing+ , apFilterLangLinks = Nothing+ }++ +data AllPagesResponse+ = AllPagesResponse+ { apLinks :: [PageTitle] -- seems to have evolved now (1.13) to PageInfo.+ , apContinue :: Maybe String+ }+ +emptyAllPagesResponse :: AllPagesResponse+emptyAllPagesResponse+ = AllPagesResponse+ { apLinks = []+ , apContinue = Nothing+ }
+ MediaWiki/API/Query/AllPages/Import.hs view
@@ -0,0 +1,37 @@+module MediaWiki.API.Query.AllPages.Import where++import MediaWiki.API.Types+import MediaWiki.API.Utils+import MediaWiki.API.Query.AllPages++import Text.XML.Light.Types+import Text.XML.Light.Proc ( strContent )++import Control.Monad+import Data.Maybe++stringXml :: String -> Either (String,[{-Error msg-}String]) AllPagesResponse+stringXml s = parseDoc xml s++xml :: Element -> Maybe AllPagesResponse+xml e = do+ guard (elName e == nsName "api")+ let es1 = children e+ p <- pNode "query" es1+ let es = children p+ ps <- fmap (mapMaybe xmlPage) (fmap children $ pNode "pages" es)+ let cont = pNode "query-continue" es1 >>= xmlContinue "allpages" "gapfrom"+ return emptyAllPagesResponse{apLinks=ps,apContinue=cont}++xmlPage :: Element -> Maybe PageTitle+xmlPage e = do+ guard (elName e == nsName "page")+ let ns = fromMaybe "0" $ pAttr "ns" e+ let tit = fromMaybe "" $ pAttr "title" e+ let pid = pAttr "pageid" e+ -- more to follow, I'm also seeing these with 1.13:+ let tou = pAttr "touched" e+ let las = pAttr "lastrevid" e+ let views = pAttr "counter" e+ let len = pAttr "length" e+ return emptyPageTitle{pgNS=ns,pgTitle=tit,pgMbId=pid}
+ MediaWiki/API/Query/AllUsers.hs view
@@ -0,0 +1,60 @@+--------------------------------------------------------------------+-- |+-- Module : MediaWiki.API.Query.AllUsers+-- Description : Representing 'allusers' requests.+-- Copyright : (c) Sigbjorn Finne, 2008+-- License : BSD3+--+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>+-- Stability : provisional+-- Portability: portable+--+-- Representing 'allusers' requests.+-- +--------------------------------------------------------------------+module MediaWiki.API.Query.AllUsers where++import MediaWiki.API.Types+import MediaWiki.API.Utils++data AllUsersRequest+ = AllUsersRequest+ { auFrom :: Maybe UserName+ , auPrefix :: Maybe UserName+ , auGroup :: Maybe GroupName+ , auProp :: [String]+ , auLimit :: Maybe Int+ }+ +instance APIRequest AllUsersRequest where+ queryKind _ = QList "allusers"+ showReq r = + [ mbOpt "aufrom" id (auFrom r)+ , mbOpt "auprefix" id (auPrefix r)+ , mbOpt "augroup" id (auGroup r)+ , opt1 "auprop" (auProp r)+ , mbOpt "aulimit" show (auLimit r)+ ]+ ++emptyAllUsersRequest :: AllUsersRequest+emptyAllUsersRequest = AllUsersRequest+ { auFrom = Nothing+ , auPrefix = Nothing+ , auGroup = Nothing+ , auProp = []+ , auLimit = Nothing+ }++data AllUsersResponse+ = AllUsersResponse+ { auUsers :: [(UserName, Maybe Int, Maybe String)]+ , auContinue :: Maybe String+ }+ +emptyAllUsersResponse :: AllUsersResponse+emptyAllUsersResponse+ = AllUsersResponse+ { auUsers = []+ , auContinue = Nothing+ }
+ MediaWiki/API/Query/AllUsers/Import.hs view
@@ -0,0 +1,33 @@+module MediaWiki.API.Query.AllUsers.Import where++import MediaWiki.API.Types+import MediaWiki.API.Utils+import MediaWiki.API.Query.AllUsers++import Text.XML.Light.Types+import Text.XML.Light.Proc ( strContent )++import Control.Monad+import Data.Maybe++stringXml :: String -> Either (String,[{-Error msg-}String]) AllUsersResponse+stringXml s = parseDoc xml s++xml :: Element -> Maybe AllUsersResponse+xml e = do+ guard (elName e == nsName "api")+ let es1 = children e+ p <- pNode "query" es1+ let es = children p+ ps <- fmap (mapMaybe xmlUser) (fmap children $ pNode "allusers" es)+ let cont = pNode "query-continue" es1 >>= xmlContinue "allusers" "aufrom"+ return emptyAllUsersResponse{auUsers=ps,auContinue=cont}++xmlUser :: Element -> Maybe (UserName,Maybe Int, Maybe String)+xmlUser e = do+ guard (elName e == nsName "u")+ let ns = fromMaybe "0" $ pAttr "ns" e+ let nm = fromMaybe "" $ pAttr "name" e+ let ec = pAttr "editcount" e >>= \ x -> case reads x of { ((v,_):_) -> Just v; _ -> Nothing}+ let grps = pAttr "groups" e+ return (nm,ec,grps)
+ MediaWiki/API/Query/BackLinks.hs view
@@ -0,0 +1,62 @@+--------------------------------------------------------------------+-- |+-- Module : MediaWiki.API.Query.BackLinks+-- Description : Representing 'backlinks' requests.+-- Copyright : (c) Sigbjorn Finne, 2008+-- License : BSD3+--+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>+-- Stability : provisional+-- Portability: portable+--+-- Representing 'backlinks' requests.+-- +--------------------------------------------------------------------+module MediaWiki.API.Query.BackLinks where++import MediaWiki.API.Types+import MediaWiki.API.Utils++data BackLinksRequest+ = BackLinksRequest+ { blTitle :: Maybe String+ , blContinueFrom :: Maybe String+ , blNamespace :: [NamespaceID]+ , blFilterRedir :: Maybe Redirect+ , blRedirect :: Maybe Bool+ , blLimit :: Maybe Int+ }++instance APIRequest BackLinksRequest where+ queryKind _ = QList "backlinks"+ showReq r = + [ mbOpt "bltitle" id (blTitle r)+ , mbOpt "blcontinue" id (blContinueFrom r)+ , opt1 "blnamespace" (blNamespace r)+ , mbOpt "blfilterredir" id (blFilterRedir r)+ , optB "blredirect" (fromMaybe False $ blRedirect r)+ , mbOpt "bllimit" show (blLimit r)+ ]++emptyBackLinksRequest :: BackLinksRequest+emptyBackLinksRequest = BackLinksRequest+ { blTitle = Nothing+ , blContinueFrom = Nothing+ , blNamespace = []+ , blFilterRedir = Nothing+ , blRedirect = Nothing+ , blLimit = Nothing+ }++data BackLinksResponse+ = BackLinksResponse+ { blLinks :: [PageTitle]+ , blContinue :: Maybe String+ }+ +emptyBackLinksResponse :: BackLinksResponse+emptyBackLinksResponse+ = BackLinksResponse+ { blLinks = []+ , blContinue = Nothing+ }
+ MediaWiki/API/Query/BackLinks/Import.hs view
@@ -0,0 +1,31 @@+module MediaWiki.API.Query.BackLinks.Import where++import MediaWiki.API.Types+import MediaWiki.API.Utils+import MediaWiki.API.Query.BackLinks++import Text.XML.Light.Types++import Control.Monad+import Data.Maybe++stringXml :: String -> Either (String,[{-Error msg-}String]) BackLinksResponse+stringXml s = parseDoc xml s++xml :: Element -> Maybe BackLinksResponse+xml e = do+ guard (elName e == nsName "api")+ let es1 = children e+ p <- pNode "query" es1+ let es = children p+ ps <- fmap (mapMaybe xmlPage) (fmap children $ pNode "backlinks" es)+ let cont = pNode "query-continue" es1 >>= xmlContinue "backlinks" "blcontinue"+ return emptyBackLinksResponse{blLinks=ps,blContinue=cont}++xmlPage :: Element -> Maybe PageTitle+xmlPage e = do+ guard (elName e == nsName "bl")+ let ns = fromMaybe "0" $ pAttr "ns" e+ let tit = fromMaybe "" $ pAttr "title" e+ let mbpid = pAttr "pageid" e+ return emptyPageTitle{pgNS=ns,pgTitle=tit,pgMbId=mbpid}
+ MediaWiki/API/Query/Blocks.hs view
@@ -0,0 +1,107 @@+--------------------------------------------------------------------+-- |+-- Module : MediaWiki.API.Query.Blocks+-- Description : Representing 'blocks' requests.+-- Copyright : (c) Sigbjorn Finne, 2008+-- License : BSD3+--+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>+-- Stability : provisional+-- Portability: portable+--+-- Representing 'blocks' requests.+-- +--------------------------------------------------------------------+module MediaWiki.API.Query.Blocks where++import MediaWiki.API.Types+import MediaWiki.API.Utils++data BlocksRequest+ = BlocksRequest+ { bkStart :: Maybe Timestamp+ , bkEnd :: Maybe Timestamp+ , bkDir :: Maybe TimeArrow+ , bkIds :: [UserID]+ , bkUsers :: [UserID]+ , bkIp :: [String]+ , bkLimit :: Maybe Int+ , bkProp :: [String]+ }++instance APIRequest BlocksRequest where+ queryKind _ = QList "blocks"+ showReq r+ = [ mbOpt "bkstart" id (bkStart r)+ , mbOpt "bkend" id (bkEnd r)+ , mbOpt "bkdir" (\ x -> if x==Earlier then "older" else "newer")+ (bkDir r)+ , opt1 "bkids" (bkIds r)+ , opt1 "bkusers" (bkUsers r)+ , opt1 "bkip" (bkIp r)+ , mbOpt "bklimit" show (bkLimit r)+ , opt1 "bkprop" (bkProp r)+ ]++emptyBlocksRequest :: BlocksRequest+emptyBlocksRequest = BlocksRequest+ { bkStart = Nothing+ , bkEnd = Nothing+ , bkDir = Nothing+ , bkIds = []+ , bkUsers = []+ , bkIp = []+ , bkLimit = Nothing+ , bkProp = []+ }+ +data BlocksResponse+ = BlocksResponse+ { bkBlocks :: [BlockInfo]+ , bkContinue :: Maybe String+ }+ +emptyBlocksResponse :: BlocksResponse+emptyBlocksResponse = BlocksResponse+ { bkBlocks = []+ , bkContinue = Nothing+ }++data BlockInfo+ = BlockInfo+ { bkId :: Maybe String+ , bkUser :: Maybe UserName+ , bkBy :: Maybe UserName+ , bkTimestamp :: Maybe Timestamp+ , bkExpiry :: Maybe Timestamp+ , bkReason :: Maybe String+ , bkRangeStart :: Maybe String+ , bkRangeEnd :: Maybe String+ , bkIsAuto :: Bool+ , bkIsAnonOnly :: Bool+ , bkIsNoCreate :: Bool+ , bkIsAutoBlock :: Bool+ , bkIsNoEmail :: Bool+ , bkIsHidden :: Bool+ }+ +emptyBlockInfo :: BlockInfo+emptyBlockInfo = BlockInfo+ { bkId = Nothing+ , bkUser = Nothing+ , bkBy = Nothing+ , bkTimestamp = Nothing+ , bkExpiry = Nothing+ , bkReason = Nothing+ , bkRangeStart = Nothing+ , bkRangeEnd = Nothing+ , bkIsAuto = False+ , bkIsAnonOnly = False+ , bkIsNoCreate = False+ , bkIsAutoBlock = False+ , bkIsNoEmail = False+ , bkIsHidden = False+ }+++
+ MediaWiki/API/Query/Blocks/Import.hs view
@@ -0,0 +1,58 @@+module MediaWiki.API.Query.Blocks.Import where++import MediaWiki.API.Types+import MediaWiki.API.Utils+import MediaWiki.API.Query.Blocks++import Text.XML.Light.Types+import Text.XML.Light.Proc ( strContent )++import Control.Monad+import Data.Maybe++stringXml :: String -> Either (String,[{-Error msg-}String]) BlocksResponse+stringXml s = parseDoc xml s++xml :: Element -> Maybe BlocksResponse+xml e = do+ guard (elName e == nsName "api")+ let es1 = children e+ p <- pNode "query" es1+ let es = children p+ ps <- fmap (mapMaybe xmlB) (fmap children $ pNode "blocks" es)+ let cont = pNode "query-continue" es1 >>= xmlContinue "blocks" "blfrom"+ return emptyBlocksResponse{bkBlocks=ps,bkContinue=cont}++xmlB :: Element -> Maybe BlockInfo+xmlB e = do+ guard (elName e == nsName "block")+ let i = pAttr "id" e+ let usr = pAttr "user" e+ let by = pAttr "by" e+ let ts = pAttr "timestamp" e+ let ex = pAttr "expiry" e+ let re = pAttr "reason" e+ let ras = pAttr "rangestart" e+ let rae = pAttr "rangeend" e+ let isa = isJust $ pAttr "automatic" e+ let isan = isJust $ pAttr "anononly" e+ let isnc = isJust $ pAttr "nocreate" e+ let isab = isJust $ pAttr "autoblock" e+ let isne = isJust $ pAttr "noemail" e+ let ishi = isJust $ pAttr "hidden" e+ return emptyBlockInfo+ { bkId = i+ , bkUser = usr+ , bkBy = by+ , bkTimestamp = ts+ , bkExpiry = ex+ , bkReason = re+ , bkRangeStart = ras+ , bkRangeEnd = rae+ , bkIsAuto = isa+ , bkIsAnonOnly = isan+ , bkIsNoCreate = isnc+ , bkIsAutoBlock = isab+ , bkIsNoEmail = isne+ , bkIsHidden = ishi+ }
+ MediaWiki/API/Query/Categories.hs view
@@ -0,0 +1,57 @@+--------------------------------------------------------------------+-- |+-- Module : MediaWiki.API.Query.Categories+-- Description : Representing 'categories' requests.+-- Copyright : (c) Sigbjorn Finne, 2008+-- License : BSD3+--+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>+-- Stability : provisional+-- Portability: portable+--+-- Representing 'categories' requests.+-- +--------------------------------------------------------------------+module MediaWiki.API.Query.Categories where++import MediaWiki.API.Types+import MediaWiki.API.Utils++data CategoriesRequest+ = CategoriesRequest+ { clProps :: [PropKind]+ , clShow :: Maybe Bool+ , clLimit :: Maybe Int+ , clContinueFrom :: Maybe String+ }++instance APIRequest CategoriesRequest where+ queryKind _ = QProp "categories"+ showReq r = + [ opt1 "clprop" (map prKind $ clProps r)+ , mbOpt "clshow" (\ x -> if x then "!hidden" else "hidden") (clShow r)+ , mbOpt "cllimit" show (clLimit r)+ , mbOpt "clcontinue" id (clContinueFrom r)+ ]++emptyCategoriesRequest :: CategoriesRequest+emptyCategoriesRequest = CategoriesRequest+ { clProps = []+ , clShow = Nothing+ , clLimit = Nothing+ , clContinueFrom = Nothing+ }+++data CategoriesResponse+ = CategoriesResponse+ { clPages :: [(PageTitle,[PageTitle])]+ , clContinue :: Maybe String+ }+ +emptyCategoriesResponse :: CategoriesResponse+emptyCategoriesResponse+ = CategoriesResponse+ { clPages = []+ , clContinue = Nothing+ }
+ MediaWiki/API/Query/Categories/Import.hs view
@@ -0,0 +1,45 @@+module MediaWiki.API.Query.Categories.Import where++import MediaWiki.API.Types+import MediaWiki.API.Utils+import MediaWiki.API.Query.Categories++import Text.XML.Light.Types++import Control.Monad+import Data.Maybe++stringXml :: String -> Either (String,[{-Error msg-}String]) CategoriesResponse+stringXml s = parseDoc xml s++xml :: Element -> Maybe CategoriesResponse+xml e = do+ guard (elName e == nsName "api")+ let es1 = children e+ p <- pNode "query" es1+ let es2 = children p+ p <- pNode "pages" es2+ let es = children p+ ps <- fmap (mapMaybe xmlPage) (fmap children $ pNode "page" es)+ let cont = pNode "query-continue" es1 >>= xmlContinue "categories" "clcontinue"+ return emptyCategoriesResponse{clPages=ps,clContinue=cont}++xmlPage :: Element -> Maybe (PageTitle,[PageTitle])+xmlPage e = do+ guard (elName e == nsName "page")+ let es = children e+ p <- pNode "categories" es+ let es1 = children p+ cs <- fmap (mapMaybe xmlCL) (fmap children $ pNode "cl" es1)+ let ns = fromMaybe "0" $ pAttr "ns" p+ let tit = fromMaybe "" $ pAttr "title" p+ let mbpid = pAttr "pageid" p+ return (emptyPageTitle{pgNS=ns,pgTitle=tit,pgMbId=mbpid}, cs)++xmlCL :: Element -> Maybe PageTitle+xmlCL e = do+ guard (elName e == nsName "cl")+ let ns = fromMaybe "0" $ pAttr "ns" e+ let tit = fromMaybe "" $ pAttr "title" e+ let mbpid = pAttr "pageid" e+ return emptyPageTitle{pgNS=ns,pgTitle=tit,pgMbId=mbpid}
+ MediaWiki/API/Query/CategoryInfo.hs view
@@ -0,0 +1,59 @@+--------------------------------------------------------------------+-- |+-- Module : MediaWiki.API.Query.CategoryInfo+-- Description : Representing CategoryInfo requests.+-- Copyright : (c) Sigbjorn Finne, 2008+-- License : BSD3+--+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>+-- Stability : provisional+-- Portability: portable+--+-- Representing CategoryInfo requests.+-- +--------------------------------------------------------------------+module MediaWiki.API.Query.CategoryInfo where++import MediaWiki.API.Types+import MediaWiki.API.Utils ()++data CategoryInfoRequest+ = CategoryInfoRequest+ +instance APIRequest CategoryInfoRequest where+ queryKind _ = QProp "categoryinfo"+ showReq _ = []++emptyCategoryInfoRequest :: CategoryInfoRequest+emptyCategoryInfoRequest = CategoryInfoRequest++data CategoryInfoResponse + = CategoryInfoResponse+ { ciPages :: [CategoryInfo]+ }+ +emptyCategoryInfoResponse :: CategoryInfoResponse+emptyCategoryInfoResponse = CategoryInfoResponse+ { ciPages = []+ }++data CategoryInfo+ = CategoryInfo+ { ciPage :: PageTitle+ , ciSize :: Maybe Int+ , ciPageSize :: Maybe Int+ , ciFiles :: Maybe Int+ , ciSubCats :: Maybe Int+ , ciHidden :: Bool+ }++emptyCategoryInfo :: CategoryInfo+emptyCategoryInfo = CategoryInfo+ { ciPage = emptyPageTitle+ , ciSize = Nothing+ , ciPageSize = Nothing+ , ciFiles = Nothing+ , ciSubCats = Nothing+ , ciHidden = False+ }+
+ MediaWiki/API/Query/CategoryInfo/Import.hs view
@@ -0,0 +1,50 @@+module MediaWiki.API.Query.CategoryInfo.Import where++import MediaWiki.API.Types+import MediaWiki.API.Utils+import MediaWiki.API.Query.CategoryInfo++import Text.XML.Light.Types++import Control.Monad+import Data.Maybe++stringXml :: String -> Either (String,[{-Error msg-}String]) CategoryInfoResponse+stringXml s = parseDoc xml s++xml :: Element -> Maybe CategoryInfoResponse+xml e = do+ guard (elName e == nsName "api")+ let es1 = children e+ p <- pNode "query" es1+ let es = children p+ ps <- fmap (mapMaybe xmlPage) (fmap children $ pNode "pages" es)+ return emptyCategoryInfoResponse{ciPages=ps}++xmlPage :: Element -> Maybe CategoryInfo+xmlPage e = do+ guard (elName e == nsName "page")+ let ns = fromMaybe "0" $ pAttr "ns" e+ let tit = fromMaybe "" $ pAttr "title" e+ let pid = pAttr "pageid" e+ let pg = emptyPageTitle{pgNS=ns,pgTitle=tit,pgMbId=pid}+ let cs = mapMaybe (xmlCI pg "categoryinfo") (children e)+ listToMaybe cs+ +xmlCI :: PageTitle -> String -> Element -> Maybe CategoryInfo+xmlCI pg tg e = do+ guard (elName e == nsName tg)+ let sz = pAttr "size" e >>= readMb+ let psz = pAttr "pagesize" e >>= readMb+ let fi = pAttr "files" e >>= readMb+ let su = pAttr "subcats" e >>= readMb+ let hi = isJust (pAttr "hidden" e)+ return emptyCategoryInfo+ { ciPage = pg+ , ciSize = sz+ , ciPageSize = psz+ , ciFiles = fi+ , ciSubCats = su+ , ciHidden = hi+ }+
+ MediaWiki/API/Query/CategoryMembers.hs view
@@ -0,0 +1,71 @@+--------------------------------------------------------------------+-- |+-- Module : MediaWiki.API.Query.CategoryMembers+-- Description : Representing 'categorymembers' requests.+-- Copyright : (c) Sigbjorn Finne, 2008+-- License : BSD3+--+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>+-- Stability : provisional+-- Portability: portable+--+-- Representing 'categorymembers' requests.+-- +--------------------------------------------------------------------+module MediaWiki.API.Query.CategoryMembers where++import MediaWiki.API.Types+import MediaWiki.API.Utils++data CategoryMembersRequest+ = CategoryMembersRequest+ { cmTitle :: Maybe PageName+ , cmProp :: [String]+ , cmNamespace :: [NamespaceID]+ , cmContinueFrom :: Maybe String+ , cmLimit :: Maybe Int+ , cmSort :: Maybe SortKind+ , cmDir :: Maybe Direction+ , cmStart :: Maybe Timestamp+ , cmEnd :: Maybe Timestamp+ }++instance APIRequest CategoryMembersRequest where+ queryKind _ = QList "categorymembers"+ showReq r = + [ mbOpt "cmtitle" id (cmTitle r)+ , opt1 "cmprop" (cmProp r)+ , opt1 "cmnamespace" (cmNamespace r)+ , mbOpt "cmcontinue" id (cmContinueFrom r)+ , mbOpt "cmlimit" show (cmLimit r)+ , mbOpt "cmsort" id (cmSort r)+ , mbOpt "cmdir" (\ x -> if x==Up then "asc" else "desc") (cmDir r)+ , mbOpt "cmstart" id (cmStart r)+ , mbOpt "cmend" id (cmEnd r)+ ]++emptyCategoryMembersRequest :: CategoryMembersRequest+emptyCategoryMembersRequest = CategoryMembersRequest+ { cmTitle = Nothing+ , cmProp = []+ , cmNamespace = []+ , cmContinueFrom = Nothing+ , cmLimit = Nothing+ , cmSort = Nothing+ , cmDir = Nothing+ , cmStart = Nothing+ , cmEnd = Nothing+ }++data CategoryMembersResponse+ = CategoryMembersResponse+ { cmPages :: [PageTitle]+ , cmContinue :: Maybe String+ }+ +emptyCategoryMembersResponse :: CategoryMembersResponse+emptyCategoryMembersResponse = CategoryMembersResponse+ { cmPages = []+ , cmContinue = Nothing+ }+
+ MediaWiki/API/Query/CategoryMembers/Import.hs view
@@ -0,0 +1,32 @@+module MediaWiki.API.Query.CategoryMembers.Import where++import MediaWiki.API.Types+import MediaWiki.API.Utils+import MediaWiki.API.Query.CategoryMembers++import Text.XML.Light.Types++import Control.Monad+import Data.Maybe++stringXml :: String -> Either (String,[{-Error msg-}String]) CategoryMembersResponse+stringXml s = parseDoc xml s++xml :: Element -> Maybe CategoryMembersResponse+xml e = do+ guard (elName e == nsName "api")+ let es1 = children e+ p <- pNode "query" es1+ let es = children p+ ps <- fmap (mapMaybe xmlPage) (fmap children $ pNode "categorymembers" es)+ let cont = pNode "query-continue" es1 >>= xmlContinue "categorymembers" "cmcontinue"+ return emptyCategoryMembersResponse{cmPages=ps,cmContinue=cont}++xmlPage :: Element -> Maybe PageTitle+xmlPage e = do+ guard (elName e == nsName "cm")+ let ns = fromMaybe "0" $ pAttr "ns" e+ let tit = fromMaybe "" $ pAttr "title" e+ let mbpid = pAttr "pageid" e+ let ts = pAttr "timestamp" e+ return emptyPageTitle{pgNS=ns,pgTitle=tit,pgMbId=mbpid}
+ MediaWiki/API/Query/DeletedRevisions.hs view
@@ -0,0 +1,85 @@+--------------------------------------------------------------------+-- |+-- Module : MediaWiki.API.Query.DeletedRevisions+-- Description : Representing 'deletedrevs' requests.+-- Copyright : (c) Sigbjorn Finne, 2008+-- License : BSD3+--+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>+-- Stability : provisional+-- Portability: portable+--+-- Representing 'deletedrevs' requests.+-- +--------------------------------------------------------------------+module MediaWiki.API.Query.DeletedRevisions where++import MediaWiki.API.Types+import MediaWiki.API.Utils++data DeletedRevisionsRequest+ = DeletedRevisionsRequest+ { drStart :: Maybe Timestamp+ , drEnd :: Maybe Timestamp+ , drDir :: Maybe TimeArrow+ , drLimit :: Maybe Int+ , drProp :: [String]+ }++instance APIRequest DeletedRevisionsRequest where+ queryKind _ = QList "deletedrevs"+ showReq r = [ mbOpt "drstart" id (drStart r)+ , mbOpt "drend" id (drEnd r)+ , mbOpt "drdir" (\ x -> if x==Earlier then "older" else "newer")+ (drDir r)+ , mbOpt "drlimit" show (drLimit r)+ , opt1 "drprop" (drProp r)+ ]++emptyDeletedRevisionsRequest :: DeletedRevisionsRequest+emptyDeletedRevisionsRequest = DeletedRevisionsRequest+ { drStart = Nothing+ , drEnd = Nothing+ , drDir = Nothing+ , drLimit = Nothing+ , drProp = []+ }++data DeletedRevisionsResponse+ = DeletedRevisionsResponse+ { drRevisions :: [DeletedRevision]+ , drContinue :: Maybe String+ }++emptyDeletedRevisionsResponse :: DeletedRevisionsResponse+emptyDeletedRevisionsResponse = DeletedRevisionsResponse+ { drRevisions = []+ , drContinue = Nothing+ }++data DeletedRevision+ = DeletedRevision+ { drPage :: PageTitle+ , drTimestamp :: Maybe Timestamp+ , drRevId :: Maybe RevID+ , drUser :: Maybe UserName+ , drComment :: Maybe String+ , drIsMinor :: Bool+ , drLength :: Maybe Int+ , drContent :: Maybe String+ , drToken :: Maybe String+ }+ +emptyDeletedRevision :: DeletedRevision+emptyDeletedRevision + = DeletedRevision+ { drPage = emptyPageTitle+ , drTimestamp = Nothing+ , drRevId = Nothing+ , drUser = Nothing+ , drComment = Nothing+ , drIsMinor = False+ , drLength = Nothing+ , drContent = Nothing+ , drToken = Nothing+ }
+ MediaWiki/API/Query/DeletedRevisions/Import.hs view
@@ -0,0 +1,51 @@+module MediaWiki.API.Query.DeletedRevisions.Import where++import MediaWiki.API.Types+import MediaWiki.API.Utils+import MediaWiki.API.Query.DeletedRevisions++import Text.XML.Light.Types+import Text.XML.Light.Proc ( strContent )++import Control.Monad+import Data.Maybe++stringXml :: String -> Either (String,[{-Error msg-}String]) DeletedRevisionsResponse+stringXml s = parseDoc xml s++xml :: Element -> Maybe DeletedRevisionsResponse+xml e = do+ guard (elName e == nsName "api")+ let es1 = children e+ p <- pNode "query" es1+ let es = children p+ ps <- fmap (mapMaybe xmlPage) (fmap children $ pNode "revisions" es)+ let cont = pNode "query-continue" es1 >>= xmlContinue "deletedrevs" "drstart"+ return emptyDeletedRevisionsResponse{drRevisions=ps,drContinue=cont}++xmlPage :: Element -> Maybe DeletedRevision+xmlPage e = do+ guard (elName e == nsName "page")+ let ns = fromMaybe "0" $ pAttr "ns" e+ let tit = fromMaybe "" $ pAttr "title" e+ let pid = pAttr "pageid" e+ let pg = emptyPageTitle{pgNS=ns,pgTitle=tit,pgMbId=pid}+ let ts = pAttr "timestamp" e+ let re = pAttr "revid" e+ let usr = pAttr "user" e+ let co = pAttr "comment" e+ let ism = isJust $ pAttr "minor" e+ let le = pAttr "len" e >>= readMb+ let cts = case (strContent e) of { "" -> Nothing; xs -> Just xs}+ let tok = pAttr "token" e+ return emptyDeletedRevision+ { drPage = pg+ , drTimestamp = ts+ , drRevId = re+ , drUser = usr+ , drComment = co+ , drIsMinor = ism+ , drLength = le+ , drContent = cts+ , drToken = tok+ }
+ MediaWiki/API/Query/EmbeddedIn.hs view
@@ -0,0 +1,62 @@+--------------------------------------------------------------------+-- |+-- Module : MediaWiki.API.Query.EmbeddedIn+-- Description : Representing 'embeddedin' requests.+-- Copyright : (c) Sigbjorn Finne, 2008+-- License : BSD3+--+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>+-- Stability : provisional+-- Portability: portable+--+-- Representing 'embeddedin' requests.+-- +--------------------------------------------------------------------+module MediaWiki.API.Query.EmbeddedIn where++import MediaWiki.API.Types+import MediaWiki.API.Utils++data EmbeddedInRequest+ = EmbeddedInRequest+ { eiTitle :: Maybe String+ , eiContinueFrom :: Maybe String+ , eiNamespace :: [NamespaceID]+ , eiFilterRedir :: Maybe Redirect+ , eiRedirect :: Bool+ , eiLimit :: Maybe Int+ }++instance APIRequest EmbeddedInRequest where+ queryKind _ = QList "embeddedin"+ showReq r = + [ mbOpt "eititle" id (eiTitle r)+ , mbOpt "eicontinue" id (eiContinueFrom r)+ , opt1 "einamespace" (eiNamespace r)+ , mbOpt "eifilterredir" id (eiFilterRedir r)+ , optB "eirdirect" (eiRedirect r)+ , mbOpt "eilimit" show (eiLimit r)+ ]++emptyEmbeddedInRequest :: EmbeddedInRequest+emptyEmbeddedInRequest = EmbeddedInRequest+ { eiTitle = Nothing+ , eiContinueFrom = Nothing+ , eiNamespace = []+ , eiFilterRedir = Nothing+ , eiRedirect = False+ , eiLimit = Nothing+ }++data EmbeddedInResponse+ = EmbeddedInResponse+ { eiLinks :: [PageTitle]+ , eiContinue :: Maybe String+ }+ +emptyEmbeddedInResponse :: EmbeddedInResponse+emptyEmbeddedInResponse+ = EmbeddedInResponse+ { eiLinks = []+ , eiContinue = Nothing+ }
+ MediaWiki/API/Query/EmbeddedIn/Import.hs view
@@ -0,0 +1,31 @@+module MediaWiki.API.Query.EmbeddedIn.Import where++import MediaWiki.API.Types+import MediaWiki.API.Utils+import MediaWiki.API.Query.EmbeddedIn++import Text.XML.Light.Types++import Control.Monad+import Data.Maybe++stringXml :: String -> Either (String,[{-Error msg-}String]) EmbeddedInResponse+stringXml s = parseDoc xml s++xml :: Element -> Maybe EmbeddedInResponse+xml e = do+ guard (elName e == nsName "api")+ let es1 = children e+ p <- pNode "query" es1+ let es = children p+ ps <- fmap (mapMaybe xmlPage) (fmap children $ pNode "embeddedin" es)+ let cont = pNode "query-continue" es1 >>= xmlContinue "embeddedin" "eicontinue"+ return emptyEmbeddedInResponse{eiLinks=ps,eiContinue=cont}++xmlPage :: Element -> Maybe PageTitle+xmlPage e = do+ guard (elName e == nsName "ei")+ let ns = fromMaybe "0" $ pAttr "ns" e+ let tit = fromMaybe "" $ pAttr "title" e+ let mbpid = pAttr "pageid" e+ return emptyPageTitle{pgNS=ns,pgTitle=tit,pgMbId=mbpid}
+ MediaWiki/API/Query/ExternalLinks.hs view
@@ -0,0 +1,50 @@+--------------------------------------------------------------------+-- |+-- Module : MediaWiki.API.Query.ExternalLinks+-- Description : Representing 'extlinks' requests.+-- Copyright : (c) Sigbjorn Finne, 2008+-- License : BSD3+--+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>+-- Stability : provisional+-- Portability: portable+--+-- Representing 'extlinks' requests.+-- +--------------------------------------------------------------------+module MediaWiki.API.Query.ExternalLinks where++import MediaWiki.API.Types+import MediaWiki.API.Utils++data ExternalLinksRequest+ = ExternalLinksRequest+ { elLimit :: Maybe Int+ , elOffset :: Maybe String+ }+ +instance APIRequest ExternalLinksRequest where+ queryKind _ = QProp "extlinks"+ showReq r =+ [ mbOpt "ellimit" show (elLimit r)+ , mbOpt "eloffset" id (elOffset r)+ ]++emptyExternalLinksRequest :: ExternalLinksRequest+emptyExternalLinksRequest = ExternalLinksRequest+ { elLimit = Nothing+ , elOffset = Nothing+ }+ +data ExternalLinksResponse+ = ExternalLinksResponse+ { elPages :: [(PageTitle,[URLString])]+ , elContinue :: Maybe String+ }+ +emptyExternalLinksResponse :: ExternalLinksResponse+emptyExternalLinksResponse = ExternalLinksResponse+ { elPages = []+ , elContinue = Nothing+ }+
+ MediaWiki/API/Query/ExternalLinks/Import.hs view
@@ -0,0 +1,44 @@+module MediaWiki.API.Query.ExternalLinks.Import where++import MediaWiki.API.Types+import MediaWiki.API.Utils+import MediaWiki.API.Query.ExternalLinks++import Text.XML.Light.Types+import Text.XML.Light.Proc ( strContent )++import Control.Monad+import Data.Maybe++stringXml :: String -> Either (String,[{-Error msg-}String]) ExternalLinksResponse+stringXml s = parseDoc xml s++xml :: Element -> Maybe ExternalLinksResponse+xml e = do+ guard (elName e == nsName "api")+ let es1 = children e+ p <- pNode "query" es1+ let es2 = children p+ p <- pNode "pages" es2+ let es = children p+ ps <- fmap (mapMaybe xmlPage) (fmap children $ pNode "page" es)+ let cont = pNode "query-continue" es1 >>= xmlContinue "extlinks" "eloffset"+ return emptyExternalLinksResponse{elPages=ps,elContinue=cont}++xmlPage :: Element -> Maybe (PageTitle,[URLString])+xmlPage e = do+ guard (elName e == nsName "page")+ let es = children e+ p <- pNode "extlinks" es+ let es1 = children p+ cs <- fmap (mapMaybe xmlEL) (fmap children $ pNode "el" es1)+ let ns = fromMaybe "0" $ pAttr "ns" p+ let tit = fromMaybe "" $ pAttr "title" p+ let mbpid = pAttr "pageid" p+ return (emptyPageTitle{pgNS=ns,pgTitle=tit,pgMbId=mbpid}, cs)++xmlEL :: Element -> Maybe URLString+xmlEL e = do+ guard (elName e == nsName "el")+ return (strContent e)+
+ MediaWiki/API/Query/ExternalURLUsage.hs view
@@ -0,0 +1,63 @@+--------------------------------------------------------------------+-- |+-- Module : MediaWiki.API.Query.ExternalURLUsage+-- Description : Representing 'exturlusage' requests.+-- Copyright : (c) Sigbjorn Finne, 2008+-- License : BSD3+--+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>+-- Stability : provisional+-- Portability: portable+--+-- Representing 'exturlusage' requests.+-- +--------------------------------------------------------------------+module MediaWiki.API.Query.ExternalURLUsage where++import MediaWiki.API.Types+import MediaWiki.API.Utils++data ExternalURLUsageRequest+ = ExternalURLUsageRequest+ { euProp :: [String]+ , euOffset :: Maybe String+ , euProtocol :: Maybe String+ , euQuery :: Maybe String+ , euNamespaces :: [NamespaceID]+ , euLimit :: Maybe Int+ }++instance APIRequest ExternalURLUsageRequest where+ queryKind _ = QList "exturlusage"+ showReq r = + [ opt1 "euprop" (euProp r)+ , mbOpt "euoffset" id (euOffset r)+ , mbOpt "euprotocol" id (euProtocol r)+ , mbOpt "euquery" id (euQuery r)+ , opt1 "eunamespace" (euNamespaces r)+ , mbOpt "eulimit" show (euLimit r)+ ]++emptyExternalURLUsageRequest :: ExternalURLUsageRequest+emptyExternalURLUsageRequest = ExternalURLUsageRequest+ { euProp = []+ , euOffset = Nothing+ , euProtocol = Nothing+ , euQuery = Nothing+ , euNamespaces = []+ , euLimit = Nothing+ }+ +data ExternalURLUsageResponse+ = ExternalURLUsageResponse+ { euPages :: [(URLString,PageTitle)]+ , euContinue :: Maybe String+ }++emptyExternalURLUsageResponse :: ExternalURLUsageResponse+emptyExternalURLUsageResponse = ExternalURLUsageResponse+ { euPages = []+ , euContinue = Nothing+ }+ +
+ MediaWiki/API/Query/ExternalURLUsage/Import.hs view
@@ -0,0 +1,35 @@+module MediaWiki.API.Query.ExternalURLUsage.Import where++import MediaWiki.API.Types+import MediaWiki.API.Utils+import MediaWiki.API.Query.ExternalURLUsage++import Text.XML.Light.Types+import Text.XML.Light.Proc ( strContent )++import Control.Monad+import Data.Maybe++stringXml :: String -> Either (String,[{-Error msg-}String]) ExternalURLUsageResponse+stringXml s = parseDoc xml s++xml :: Element -> Maybe ExternalURLUsageResponse+xml e = do+ guard (elName e == nsName "api")+ let es1 = children e+ p <- pNode "query" es1+ let es = children p+ ps <- fmap (mapMaybe xmlPage) (fmap children $ pNode "exturlusage" es)+ let cont = pNode "query-continue" es1 >>= xmlContinue "exturlusage" "euoffset"+ return emptyExternalURLUsageResponse{euPages=ps,euContinue=cont}++xmlPage :: Element -> Maybe (URLString,PageTitle)+xmlPage e = do+ guard (elName e == nsName "eu")+ let ns = fromMaybe "0" $ pAttr "ns" e+ let tit = fromMaybe "" $ pAttr "title" e+ let mbpid = pAttr "pageid" e+ let url = fromMaybe "" $ pAttr "url" e+ return (url,emptyPageTitle{pgNS=ns,pgTitle=tit,pgMbId=mbpid})++
+ MediaWiki/API/Query/ImageInfo.hs view
@@ -0,0 +1,90 @@+--------------------------------------------------------------------+-- |+-- Module : MediaWiki.API.Query.ImageInfo+-- Description : Representing 'imageinfo' requests.+-- Copyright : (c) Sigbjorn Finne, 2008+-- License : BSD3+--+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>+-- Stability : provisional+-- Portability: portable+--+-- Representing 'imageinfo' requests.+-- +--------------------------------------------------------------------+module MediaWiki.API.Query.ImageInfo where++import MediaWiki.API.Types+import MediaWiki.API.Utils++data ImageInfo+ = ImageInfo+ { iiTimestamp :: Timestamp+ , iiUser :: UserName+ , iiWidth :: Maybe Int+ , iiHeight :: Maybe Int+ , iiSize :: Maybe Int+ , iiURL :: Maybe URLString+ , iiComment :: Maybe String+ , iiSHA1 :: Maybe String+ , iiArchive :: Maybe String+ , iiBitDepth :: Maybe Int+ , iiMime :: Maybe String+ }+ +emptyImageInfo :: ImageInfo+emptyImageInfo = ImageInfo+ { iiTimestamp = nullTimestamp+ , iiUser = nullUser+ , iiWidth = Nothing+ , iiHeight = Nothing+ , iiSize = Nothing+ , iiURL = Nothing+ , iiComment = Nothing+ , iiSHA1 = Nothing+ , iiArchive = Nothing+ , iiBitDepth = Nothing+ , iiMime = Nothing+ }++data ImageInfoRequest+ = ImageInfoRequest + { iiProp :: [PropKind]+ , iiLimit :: Maybe Int+ , iiStart :: Maybe Timestamp+ , iiEnd :: Maybe Timestamp+ , iiURLSize :: Maybe (Int,Int)+ }++instance APIRequest ImageInfoRequest where+ queryKind _ = QProp "imageinfo"+ showReq r =+ [ opt1 "iiprop" (map prKind $ iiProp r)+ , mbOpt "iilimit" show (iiLimit r)+ , mbOpt "iistart" id (iiStart r)+ , mbOpt "iiend" id (iiEnd r)+ , mbOpt "iiurlwidth" (show.fst) (iiURLSize r)+ , mbOpt "iiurlheight" (show.snd) (iiURLSize r)+ ]++emptyImageInfoRequest :: ImageInfoRequest+emptyImageInfoRequest = ImageInfoRequest+ { iiProp = []+ , iiLimit = Nothing+ , iiStart = Nothing+ , iiEnd = Nothing+ , iiURLSize = Nothing+ }++data ImageInfoResponse + = ImageInfoResponse+ { iiPages :: [(PageTitle,[ImageInfo])]+ , iiContinue :: Maybe String+ }++emptyImageInfoResponse :: ImageInfoResponse+emptyImageInfoResponse = ImageInfoResponse+ { iiPages = []+ , iiContinue = Nothing+ }+
+ MediaWiki/API/Query/ImageInfo/Import.hs view
@@ -0,0 +1,75 @@+module MediaWiki.API.Query.ImageInfo.Import where++import MediaWiki.API.Types+import MediaWiki.API.Utils+import MediaWiki.API.Query.ImageInfo++import Text.XML.Light.Types+import Text.XML.Light.Proc ( strContent )++import Control.Monad+import Data.Maybe++stringXml :: String -> Either (String,[{-Error msg-}String]) ImageInfoResponse+stringXml s = parseDoc xml s++xml :: Element -> Maybe ImageInfoResponse+xml e = do+ guard (elName e == nsName "api")+ let es1 = children e+ p <- pNode "query" es1 >>= (pNode "pages").children+ let es = children p+ ps <- fmap (mapMaybe xmlPage) (fmap children $ pNode "page" es)+ let cont = pNode "query-continue" es1 >>= xmlContinue "imageinfo" "iistart"+ return emptyImageInfoResponse{iiPages=ps,iiContinue=cont}++xmlPage :: Element -> Maybe (PageTitle,[ImageInfo])+xmlPage e = do+ guard (elName e == nsName "page")+ let es = children e+ p <- pNode "imageinfo" es+ let es1 = children p+ cs <- fmap (mapMaybe (xmlII "ii")) (fmap children $ pNode "ii" es1)+ let ns = fromMaybe "0" $ pAttr "ns" p+ let tit = fromMaybe "" $ pAttr "title" p+ let mbpid = pAttr "pageid" p+ let miss = isJust (pAttr "missing" p)+ let rep = pAttr "imagerepository" p+ return (emptyPageTitle{pgNS=ns,pgTitle=tit,pgMbId=mbpid}, cs)++xmlII :: String -> Element -> Maybe ImageInfo+xmlII tg p = do+ guard (elName p == nsName tg) + let ts = fromMaybe nullTimestamp (pAttr "timestamp" p)+ let us = fromMaybe nullUser (pAttr "user" p)+ let wi = pAttr "width" p >>= readI+ let he = pAttr "height" p >>= readI+ let si = pAttr "size" p >>= readI+ let ur = pAttr "url" p+ let co = pAttr "comment" p+ let sh = pAttr "sha1" p+ let ar = pAttr "archivename" p+ let bi = pAttr "bitdepth" p >>= readI+ let mi = pAttr "mime" p+ return emptyImageInfo+ { iiTimestamp = ts+ , iiUser = us+ , iiWidth = wi+ , iiHeight = he+ , iiSize = si+ , iiURL = ur+ , iiComment = co+ , iiSHA1 = sh+ , iiArchive = ar+ , iiBitDepth = bi+ , iiMime = mi+ }++ +readI :: String -> Maybe Int+readI s = + case reads s of+ ((v,_):_) -> Just v+ _ -> Nothing+ +
+ MediaWiki/API/Query/ImageUsage.hs view
@@ -0,0 +1,62 @@+--------------------------------------------------------------------+-- |+-- Module : MediaWiki.API.Query.ImageUsage+-- Description : Representing 'imageusage' requests.+-- Copyright : (c) Sigbjorn Finne, 2008+-- License : BSD3+--+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>+-- Stability : provisional+-- Portability: portable+--+-- Representing 'imageusage' requests.+-- +--------------------------------------------------------------------+module MediaWiki.API.Query.ImageUsage where++import MediaWiki.API.Types+import MediaWiki.API.Utils++data ImageUsageRequest+ = ImageUsageRequest+ { iuTitle :: Maybe String+ , iuContinueFrom :: Maybe String+ , iuNamespace :: [NamespaceID]+ , iuFilterRedir :: Maybe Redirect+ , iuRedirect :: Bool+ , iuLimit :: Maybe Int+ }++instance APIRequest ImageUsageRequest where+ queryKind _ = QList "imageusage"+ showReq r = + [ mbOpt "iutitle" id (iuTitle r)+ , mbOpt "iucontinue" id (iuContinueFrom r)+ , opt1 "iunamespace" (iuNamespace r)+ , mbOpt "iufilterredir" id (iuFilterRedir r)+ , optB "iuredirect" (iuRedirect r)+ , mbOpt "iulimit" show (iuLimit r)+ ]++emptyImageUsageRequest :: ImageUsageRequest+emptyImageUsageRequest = ImageUsageRequest+ { iuTitle = Nothing+ , iuContinueFrom = Nothing+ , iuNamespace = []+ , iuFilterRedir = Nothing+ , iuRedirect = False+ , iuLimit = Nothing+ }++data ImageUsageResponse+ = ImageUsageResponse+ { iuLinks :: [PageTitle]+ , iuContinue :: Maybe String+ }+ +emptyImageUsageResponse :: ImageUsageResponse+emptyImageUsageResponse+ = ImageUsageResponse+ { iuLinks = []+ , iuContinue = Nothing+ }
+ MediaWiki/API/Query/ImageUsage/Import.hs view
@@ -0,0 +1,31 @@+module MediaWiki.API.Query.ImageUsage.Import where++import MediaWiki.API.Types+import MediaWiki.API.Utils+import MediaWiki.API.Query.ImageUsage++import Text.XML.Light.Types++import Control.Monad+import Data.Maybe++stringXml :: String -> Either (String,[{-Error msg-}String]) ImageUsageResponse+stringXml s = parseDoc xml s++xml :: Element -> Maybe ImageUsageResponse+xml e = do+ guard (elName e == nsName "api")+ let es1 = children e+ p <- pNode "query" es1+ let es = children p+ ps <- fmap (mapMaybe xmlPage) (fmap children $ pNode "imageusage" es)+ let cont = pNode "query-continue" es1 >>= xmlContinue "imageusage" "iucontinue"+ return emptyImageUsageResponse{iuLinks=ps,iuContinue=cont}++xmlPage :: Element -> Maybe PageTitle+xmlPage e = do+ guard (elName e == nsName "iu")+ let ns = fromMaybe "0" $ pAttr "ns" e+ let tit = fromMaybe "" $ pAttr "title" e+ let mbpid = pAttr "pageid" e+ return emptyPageTitle{pgNS=ns,pgTitle=tit,pgMbId=mbpid}
+ MediaWiki/API/Query/Images.hs view
@@ -0,0 +1,49 @@+--------------------------------------------------------------------+-- |+-- Module : MediaWiki.API.Query.Images+-- Description : Representing 'images' requests.+-- Copyright : (c) Sigbjorn Finne, 2008+-- License : BSD3+--+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>+-- Stability : provisional+-- Portability: portable+--+-- Representing 'images' requests.+-- +--------------------------------------------------------------------+module MediaWiki.API.Query.Images where++import MediaWiki.API.Types+import MediaWiki.API.Utils++data ImagesRequest+ = ImagesRequest+ { imLimit :: Maybe Int+ , imContinueFrom :: Maybe String+ }++instance APIRequest ImagesRequest where+ queryKind _ = QProp "images"+ showReq r = + [ mbOpt "imlimit" show (imLimit r)+ , mbOpt "imcontinue" id (imContinueFrom r)+ ]++emptyImagesRequest :: ImagesRequest+emptyImagesRequest = ImagesRequest+ { imLimit = Nothing+ , imContinueFrom = Nothing+ }+ +data ImagesResponse+ = ImagesResponse+ { imLinks :: [(PageTitle,[PageTitle])]+ , imContinue :: Maybe String+ }+ +emptyImagesResponse :: ImagesResponse+emptyImagesResponse = ImagesResponse+ { imLinks = []+ , imContinue = Nothing+ }
+ MediaWiki/API/Query/Images/Import.hs view
@@ -0,0 +1,42 @@+module MediaWiki.API.Query.Images.Import where++import MediaWiki.API.Types+import MediaWiki.API.Utils+import MediaWiki.API.Query.Images++import Text.XML.Light.Types++import Control.Monad+import Data.Maybe++stringXml :: String -> Either (String,[{-Error msg-}String]) ImagesResponse+stringXml s = parseDoc xml s++xml :: Element -> Maybe ImagesResponse+xml e = do+ guard (elName e == nsName "api")+ let es1 = children e+ p <- pNode "query" es1+ let es = children p+ ps <- fmap (mapMaybe xmlPage) (fmap children $ pNode "pages" es)+ let cont = pNode "query-continue" es1 >>= xmlContinue "imageinfo" "iistart"+ return emptyImagesResponse{imLinks=ps,imContinue=cont}++xmlPage :: Element -> Maybe (PageTitle,[PageTitle])+xmlPage e = do+ guard (elName e == nsName "page")+ let pid = fmap read $ pAttr "pageid" e+ let ns = fromMaybe mainNamespace $ pAttr "ns" e+ let tit = fromMaybe "" $ pAttr "title" e+ let es = children e+ ls <- fmap (mapMaybe xmlIm) (fmap children $ pNode "images" es)+ let pg = emptyPageTitle{pgNS=ns,pgMbId=pid,pgTitle=tit}+ return (pg, ls)++xmlIm :: Element -> Maybe PageTitle+xmlIm e = do+ guard (elName e == nsName "im")+ let ns = fromMaybe ns_IMAGE $ pAttr "ns" e+ let ti = fromMaybe "" $ pAttr "title" e+ let pid = pAttr "pageid" e+ return emptyPageTitle{pgNS=ns,pgTitle=ti,pgMbId=pid}
+ MediaWiki/API/Query/Info.hs view
@@ -0,0 +1,90 @@+-------------------------------------------------------------------- +-- | +-- Module : MediaWiki.API.Query.Info +-- Description : Representing 'info' requests. +-- Copyright : (c) Sigbjorn Finne, 2008 +-- License : BSD3 +-- +-- Maintainer: Sigbjorn Finne <sof@forkIO.com> +-- Stability : provisional +-- Portability: portable +-- +-- Representing 'info' requests. +-- +-------------------------------------------------------------------- +module MediaWiki.API.Query.Info where + +import MediaWiki.API.Types +import MediaWiki.API.Utils + +data InfoRequest + = InfoRequest + { inProps :: [String] + , inTokens :: [String] + } + +instance APIRequest InfoRequest where + queryKind _ = QProp "info" + showReq r = + [ opt1 "inprop" (inProps r) + , opt1 "intoken" (inTokens r) + ] + +emptyInfoRequest :: InfoRequest +emptyInfoRequest = InfoRequest + { inProps = [] + , inTokens = [] + } + +data InfoResponse + = InfoResponse + { infPages :: [InfoPage] + } + +data InfoPage + = InfoPage + { infPage :: PageTitle + , infTouched :: TimeString + , infLastRevId :: RevID + , infCounter :: Integer + , infLength :: Integer + , infIsRedirect :: Bool + , infIsNew :: Bool + , infEditTok :: Maybe Token + , infDeleteTok :: Maybe Token + , infProtectTok :: Maybe Token + , infMoveTok :: Maybe Token + , infProtection :: [PageRestriction] + } + +emptyInfoResponse :: InfoResponse +emptyInfoResponse = + InfoResponse{ infPages= [] + } + +emptyInfoPage :: InfoPage +emptyInfoPage = + InfoPage + { infPage = emptyPageTitle + , infTouched = "" + , infLastRevId = "" + , infCounter = 0 + , infLength = 0 + , infIsRedirect = False + , infIsNew = False + , infEditTok = Nothing + , infDeleteTok = Nothing + , infProtectTok = Nothing + , infMoveTok = Nothing + , infProtection = [] + } + +data PageRestriction + = PageRestriction + { prPageId :: PageID + , prSource :: PageName + , prType :: String + , prLevel :: Integer + , prExpiry :: TimeString + , prCascade :: Bool + }
+ MediaWiki/API/Query/Info/Import.hs view
@@ -0,0 +1,54 @@+module MediaWiki.API.Query.Info.Import where + +import MediaWiki.API.Types +import MediaWiki.API.Utils +import MediaWiki.API.Query.Info + +import Text.XML.Light.Types + +import Control.Monad +import Data.Maybe + +stringXml :: String -> Either (String,[{-Error msg-}String]) InfoResponse +stringXml s = parseDoc xml s + +xml :: Element -> Maybe InfoResponse +xml e = do + guard (elName e == nsName "api") + let es1 = children e + p <- pNode "query" es1 + let es = children p + ps <- fmap (mapMaybe xmlPage) (fmap children $ pNode "pages" es) + return emptyInfoResponse{infPages=ps} + +xmlPage :: Element -> Maybe InfoPage +xmlPage e = do + guard (elName e == nsName "page") + let touched = fromMaybe "" $ pAttr "touched" e + let rvid = fromMaybe "0" $ pAttr "lastrevid" e + let cnt = fromMaybe 0 $ (pAttr "counter" e >>= readMb) + let len = fromMaybe 0 $ (pAttr "length" e >>= readMb) + let ns = fromMaybe "0" $ pAttr "ns" e + let tit = fromMaybe "" $ pAttr "title" e + let pid = pAttr "pageid" e + let miss = fromMaybe False $ fmap (const True) $ pAttr "missing" e + let red = fromMaybe False $ fmap (const True) $ pAttr "redirect" e + let new = fromMaybe False $ fmap (const True) $ pAttr "new" e + let edTok = pAttr "edittoken" e + let deTok = pAttr "deletetoken" e + let prTok = pAttr "protecttoken" e + let moTok = pAttr "movetoken" e + return emptyInfoPage + { infPage = emptyPageTitle{pgNS=ns,pgTitle=tit,pgMbId=pid,pgMissing=miss} + , infTouched = touched + , infLastRevId = rvid + , infCounter = cnt + , infLength = len + , infIsRedirect = red + , infIsNew = new + , infEditTok = edTok + , infDeleteTok = deTok + , infProtectTok = prTok + , infMoveTok = moTok + , infProtection = [] + }
+ MediaWiki/API/Query/LangLinks.hs view
@@ -0,0 +1,62 @@+--------------------------------------------------------------------+-- |+-- Module : MediaWiki.API.Query.LangLinks+-- Description : Representing 'langlinks' requests.+-- Copyright : (c) Sigbjorn Finne, 2008+-- License : BSD3+--+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>+-- Stability : provisional+-- Portability: portable+--+-- Representing 'langlinks' requests.+-- +--------------------------------------------------------------------+module MediaWiki.API.Query.LangLinks where++import MediaWiki.API.Types+import MediaWiki.API.Utils++data LangLinksRequest+ = LangLinksRequest+ { llLimit :: Maybe Int+ , llContinueFrom :: Maybe String+ }++instance APIRequest LangLinksRequest where+ queryKind _ = QProp "langlinks"+ showReq r+ = [ mbOpt "lllimit" show (llLimit r)+ , mbOpt "llcontinue" id (llContinueFrom r)+ ]++emptyLangLinksRequest :: LangLinksRequest+emptyLangLinksRequest = LangLinksRequest+ { llLimit = Nothing+ , llContinueFrom = Nothing+ }+ +data LangLinksResponse+ = LangLinksResponse+ { llPages :: [(PageTitle,[LangPageInfo])]+ , llContinue :: Maybe String+ }+ +emptyLangLinksResponse :: LangLinksResponse+emptyLangLinksResponse = LangLinksResponse+ { llPages = []+ , llContinue = Nothing+ }++data LangPageInfo+ = LangPageInfo+ { langName :: LangName+ , langTitle :: Maybe String+ }+ +emptyLangPageInfo :: LangPageInfo+emptyLangPageInfo = LangPageInfo+ { langName = "en"+ , langTitle = Nothing+ }+
+ MediaWiki/API/Query/LangLinks/Import.hs view
@@ -0,0 +1,45 @@+module MediaWiki.API.Query.LangLinks.Import where++import MediaWiki.API.Types+import MediaWiki.API.Utils+import MediaWiki.API.Query.LangLinks++import Text.XML.Light.Types+import Text.XML.Light.Proc ( strContent )++import Control.Monad+import Data.Maybe++stringXml :: String -> Either (String,[{-Error msg-}String]) LangLinksResponse+stringXml s = parseDoc xml s++xml :: Element -> Maybe LangLinksResponse+xml e = do+ guard (elName e == nsName "api")+ let es1 = children e+ p <- pNode "query" es1+ let es = children p+ ps <- fmap (mapMaybe xmlPage) (fmap children $ pNode "pages" es)+ let cont = pNode "query-continue" es1 >>= xmlContinue "langlinks" "llcontinue"+ return emptyLangLinksResponse+ { llPages = ps+ , llContinue = cont+ }++xmlPage :: Element -> Maybe (PageTitle,[LangPageInfo])+xmlPage e = do+ guard (elName e == nsName "page")+ let pid = fmap read $ pAttr "pageid" e+ let ns = fromMaybe mainNamespace $ pAttr "ns" e+ let tit = fromMaybe "" $ pAttr "title" e+ let es = children e+ ls <- fmap (mapMaybe xmlLangLink) (fmap children $ pNode "langlinks" es)+ let pg = emptyPageTitle{pgNS=ns,pgMbId=pid,pgTitle=tit}+ return (pg, ls)++xmlLangLink :: Element -> Maybe LangPageInfo+xmlLangLink e = do+ guard (elName e == nsName "ll")+ let la = fromMaybe "en" $ pAttr "lang" e+ let tit = case strContent e of { "" -> Nothing ; xs -> Just xs}+ return emptyLangPageInfo{langName=la,langTitle=tit}
+ MediaWiki/API/Query/Links.hs view
@@ -0,0 +1,55 @@+-------------------------------------------------------------------- +-- | +-- Module : MediaWiki.API.Query.Links +-- Description : Representing 'links' requests. +-- Copyright : (c) Sigbjorn Finne, 2008 +-- License : BSD3 +-- +-- Maintainer: Sigbjorn Finne <sof@forkIO.com> +-- Stability : provisional +-- Portability: portable +-- +-- Representing 'links' requests. +-- +-------------------------------------------------------------------- +module MediaWiki.API.Query.Links where + +import MediaWiki.API.Types +import MediaWiki.API.Utils + +data LinksRequest + = LinksRequest + { plNamespaces :: [NamespaceID] + , plLimit :: Maybe Int + , plContinueFrom :: Maybe String + } + +instance APIRequest LinksRequest where + queryKind _ = QProp "links" + showReq r + = [ opt1 "plnamespace" (plNamespaces r) + , mbOpt "pllimit" show (plLimit r) + , mbOpt "plcontinue" id (plContinueFrom r) + ] + + +emptyLinksRequest :: LinksRequest +emptyLinksRequest + = LinksRequest + { plNamespaces = [] + , plLimit = Nothing + , plContinueFrom = Nothing + } + +data LinksResponse + = LinksResponse + { plPages :: [(PageTitle,[PageTitle])] + , plContinue :: Maybe String + } + +emptyLinksResponse :: LinksResponse +emptyLinksResponse = LinksResponse + { plPages = [] + , plContinue = Nothing + } +
+ MediaWiki/API/Query/Links/Import.hs view
@@ -0,0 +1,45 @@+module MediaWiki.API.Query.Links.Import where++import MediaWiki.API.Types+import MediaWiki.API.Utils+import MediaWiki.API.Query.Links++import Text.XML.Light.Types++import Control.Monad+import Data.Maybe++stringXml :: String -> Either (String,[{-Error msg-}String]) LinksResponse+stringXml s = parseDoc xml s++xml :: Element -> Maybe LinksResponse+xml e = do+ guard (elName e == nsName "api")+ let es1 = children e+ p <- pNode "query" es1+ let es = children p+ ps <- fmap (mapMaybe xmlPage) (fmap children $ pNode "pages" es)+ let cont = pNode "query-continue" es1 >>= xmlContinue "langlinks" "llcontinue"+ return emptyLinksResponse+ { plPages = ps+ , plContinue = cont+ }++xmlPage :: Element -> Maybe (PageTitle,[PageTitle])+xmlPage e = do+ guard (elName e == nsName "page")+ let pid = fmap read $ pAttr "pageid" e+ let ns = fromMaybe mainNamespace $ pAttr "ns" e+ let tit = fromMaybe "" $ pAttr "title" e+ let es = children e+ ls <- fmap (mapMaybe xmlPageLink) (fmap children $ pNode "links" es)+ let pg = emptyPageTitle{pgNS=ns,pgMbId=pid,pgTitle=tit}+ return (pg,ls)++xmlPageLink :: Element -> Maybe PageTitle+xmlPageLink e = do+ guard (elName e == nsName "pl")+ let ns = fromMaybe mainNamespace $ pAttr "ns" e+ let tit = fromMaybe "" $ pAttr "title" e+ let pid = pAttr "pageid" e+ return emptyPageTitle{pgNS=ns,pgTitle=tit,pgMbId=pid}
+ MediaWiki/API/Query/LogEvents.hs view
@@ -0,0 +1,114 @@+--------------------------------------------------------------------+-- |+-- Module : MediaWiki.API.Query.LogEvents+-- Description : Representing 'logevents' requests.+-- Copyright : (c) Sigbjorn Finne, 2008+-- License : BSD3+--+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>+-- Stability : provisional+-- Portability: portable+--+-- Representing 'logevents' requests.+-- +--------------------------------------------------------------------+module MediaWiki.API.Query.LogEvents where++import MediaWiki.API.Types+import MediaWiki.API.Utils++data LogEventsRequest+ = LogEventsRequest+ { leProp :: [String]+ , leType :: [String]+ , leStart :: Maybe Timestamp+ , leEnd :: Maybe Timestamp+ , leDir :: Maybe TimeArrow+ , leUser :: Maybe UserID+ , leTitle :: Maybe PageName+ , leLimit :: Maybe Int+ }++instance APIRequest LogEventsRequest where+ queryKind _ = QList "logevents"+ showReq r = + [ opt1 "leprop" (leProp r)+ , opt1 "letype" (leType r)+ , mbOpt "lestart" id (leStart r)+ , mbOpt "leend" id (leEnd r)+ , mbOpt "ledir" (\ x -> if x==Earlier then "older" else "newer") (leDir r)+ , mbOpt "leuser" id (leUser r)+ , mbOpt "letitle" id (leTitle r)+ , mbOpt "lelimit" show (leLimit r)+ ]++emptyLogEventsRequest :: LogEventsRequest+emptyLogEventsRequest = LogEventsRequest+ { leProp = []+ , leType = []+ , leStart = Nothing+ , leEnd = Nothing+ , leDir = Nothing+ , leUser = Nothing+ , leTitle = Nothing+ , leLimit = Nothing+ }++data LogEventsResponse+ = LogEventsResponse+ { leEvents :: [LogEvent]+ , leContinue :: Maybe String+ }++emptyLogEventsResponse :: LogEventsResponse+emptyLogEventsResponse = LogEventsResponse+ { leEvents = []+ , leContinue = Nothing+ }+ +data LogEvent+ = LogEvent+ { levLogId :: Maybe String+ , levPage :: PageTitle+ , levType :: Maybe String+ , levAction :: Maybe String+ , levParams :: [LogEventParam]+ , levUser :: Maybe String+ , levTimestamp :: Maybe Timestamp+ , levComment :: Maybe String+ }+ +emptyLogEvent :: LogEvent+emptyLogEvent + = LogEvent+ { levLogId = Nothing+ , levPage = emptyPageTitle+ , levType = Nothing+ , levAction = Nothing+ , levParams = []+ , levUser = Nothing+ , levTimestamp = Nothing+ , levComment = Nothing+ }++data LogEventParam+ = LogEventMove+ { levMovePage :: PageTitle }+ | LogEventPatrol + { levPatrolCurrent :: Maybe String+ , levPatrolPrevious :: Maybe String+ , levPatrolAuto :: Maybe String+ }+ | LogEventRights+ { levRightsOld :: Maybe String+ , levRightsNew :: Maybe String+ }+ | LogEventBlock+ { levBlockDuration :: Maybe String+ , levBlockFlags :: Maybe String+ }+ | LogEventParam {levParamValue :: String }+ | LogEventOther + { levParamName :: String+ , levParamAttrs :: [(String,String)]+ }
+ MediaWiki/API/Query/LogEvents/Import.hs view
@@ -0,0 +1,81 @@+module MediaWiki.API.Query.LogEvents.Import where++import MediaWiki.API.Types+import MediaWiki.API.Utils+import MediaWiki.API.Query.LogEvents++import Text.XML.Light.Types+import Text.XML.Light.Proc ( strContent )++import Control.Monad+import Data.Maybe++stringXml :: String -> Either (String,[{-Error msg-}String]) LogEventsResponse+stringXml s = parseDoc xml s++xml :: Element -> Maybe LogEventsResponse+xml e = do+ guard (elName e == nsName "api")+ let es1 = children e+ p <- pNode "query" es1+ let es = children p+ ps <- fmap (mapMaybe xmlPage) (fmap children $ pNode "logevents" es)+ let cont = pNode "query-continue" es1 >>= xmlContinue "logevents" "lestart"+ return emptyLogEventsResponse+ { leEvents = ps+ , leContinue = cont+ }++xmlPage :: Element -> Maybe LogEvent+xmlPage e = do+ guard (elName e == nsName "item")+ let pid = pAttr "pageid" e+ let ns = fromMaybe mainNamespace $ pAttr "ns" e+ let tit = fromMaybe "" $ pAttr "title" e+ let ty = pAttr "type" e+ let act = pAttr "action" e+ let usr = pAttr "user" e+ let ts = pAttr "timestamp" e+ let co = pAttr "comment" e+ let lid = pAttr "logid" e+ let ps = mapMaybe xmlParam (children e)+ let pg = emptyPageTitle{pgNS=ns,pgMbId=pid,pgTitle=tit}+ return emptyLogEvent+ { levLogId = lid+ , levPage = pg+ , levType = ty+ , levAction = act+ , levParams = ps+ , levUser = usr+ , levTimestamp = ts+ , levComment = co+ }++xmlParam :: Element -> Maybe LogEventParam+xmlParam e = do+ case qName (elName e) of+ "move" -> do+ let ns = fromMaybe mainNamespace $ pAttr "new_ns" e+ let tit = fromMaybe "" $ pAttr "new_title" e+ let pid = pAttr "new_pageid" e+ return (LogEventMove emptyPageTitle{pgNS=ns,pgTitle=tit,pgMbId=pid})+ "patrol" -> do+ let cur = pAttr "cur" e+ let pre = pAttr "prev" e+ let auto = pAttr "auto" e+ return (LogEventPatrol{levPatrolCurrent=cur,levPatrolPrevious=pre,levPatrolAuto=auto})+ "rights" -> do+ let old = pAttr "old" e+ let new = pAttr "new" e+ return (LogEventRights{levRightsOld=old,levRightsNew=new})+ "block" -> do+ let dur = pAttr "duration" e+ let fla = pAttr "flags" e+ return (LogEventBlock{levBlockDuration=dur,levBlockFlags=fla})+ "param" -> return (LogEventParam (strContent e))+ tg -> return $+ LogEventOther{ levParamName = tg+ , levParamAttrs = map (\a -> (qName $ attrKey a,attrVal a))+ (elAttribs e)}+ +
+ MediaWiki/API/Query/Random.hs view
@@ -0,0 +1,47 @@+--------------------------------------------------------------------+-- |+-- Module : MediaWiki.API.Query.Random+-- Description : Representing 'random' requests.+-- Copyright : (c) Sigbjorn Finne, 2008+-- License : BSD3+--+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>+-- Stability : provisional+-- Portability: portable+--+-- Representing 'random' requests.+-- +--------------------------------------------------------------------+module MediaWiki.API.Query.Random where++import MediaWiki.API.Types+import MediaWiki.API.Utils++data RandomPagesRequest+ = RandomPagesRequest+ { rnNamespaces :: [NamespaceID]+ , rnLimit :: Maybe Int+ }++instance APIRequest RandomPagesRequest where+ queryKind _ = QList "random"+ showReq r = [ opt1 "rnnamespace" (rnNamespaces r)+ , mbOpt "rnlimit" show (rnLimit r)+ ]++emptyRandomPagesRequest :: RandomPagesRequest+emptyRandomPagesRequest = RandomPagesRequest+ { rnNamespaces = []+ , rnLimit = Nothing+ }++data RandomPagesResponse+ = RandomPagesResponse+ { rnPages :: [PageTitle]+ }+ +emptyRandomPagesResponse :: RandomPagesResponse+emptyRandomPagesResponse+ = RandomPagesResponse+ { rnPages = []+ }
+ MediaWiki/API/Query/Random/Import.hs view
@@ -0,0 +1,31 @@+module MediaWiki.API.Query.Random.Import where++import MediaWiki.API.Types+import MediaWiki.API.Utils+import MediaWiki.API.Query.Random++import Text.XML.Light.Types+import Text.XML.Light.Proc ( strContent )++import Control.Monad+import Data.Maybe++stringXml :: String -> Either (String,[{-Error msg-}String]) RandomPagesResponse+stringXml s = parseDoc xml s++xml :: Element -> Maybe RandomPagesResponse+xml e = do+ guard (elName e == nsName "api")+ let es1 = children e+ p <- pNode "query" es1+ let es = children p+ ps <- fmap (mapMaybe xmlPage) (fmap children $ pNode "random" es)+ return emptyRandomPagesResponse{rnPages=ps}++xmlPage :: Element -> Maybe PageTitle+xmlPage e = do+ guard (elName e == nsName "page")+ let ns = fromMaybe "0" $ pAttr "ns" e+ let tit = fromMaybe "" $ pAttr "title" e+ let pid = pAttr "pageid" e+ return emptyPageTitle{pgNS=ns,pgTitle=tit,pgMbId=pid}
+ MediaWiki/API/Query/RecentChanges.hs view
@@ -0,0 +1,110 @@+--------------------------------------------------------------------+-- |+-- Module : MediaWiki.API.Query.RecentChanges+-- Description : Representing 'recentchanges' requests.+-- Copyright : (c) Sigbjorn Finne, 2008+-- License : BSD3+--+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>+-- Stability : provisional+-- Portability: portable+--+-- Representing 'recentchanges' requests.+-- +--------------------------------------------------------------------+module MediaWiki.API.Query.RecentChanges where++import MediaWiki.API.Types+import MediaWiki.API.Utils++data RecentChangesRequest+ = RecentChangesRequest+ { rcStart :: Maybe Timestamp+ , rcEnd :: Maybe Timestamp+ , rcDir :: Maybe TimeArrow+ , rcNamespaces :: [NamespaceID]+ , rcTitles :: [PageName]+ , rcProp :: [String]+ , rcShow :: [String]+ , rcLimit :: Maybe Int+ , rcType :: [String] -- edit,new,log+ }++instance APIRequest RecentChangesRequest where+ queryKind _ = QList "recentchanges"+ showReq r =+ [ mbOpt "rcstart" id (rcStart r)+ , mbOpt "rcend" id (rcEnd r)+ , mbOpt "rcdir" (\ x -> if x == Earlier then "older" else "newer") (rcDir r)+ , opt1 "rcnamespace" (rcNamespaces r)+ , opt1 "rctitles" (rcTitles r)+ , opt1 "rcprop" (rcProp r)+ , opt1 "rcshow" (rcShow r)+ , mbOpt "rclimit" show (rcLimit r)+ , opt1 "rctype" (rcType r)+ ]++emptyRecentChangesRequest :: RecentChangesRequest+emptyRecentChangesRequest = RecentChangesRequest+ { rcStart = Nothing+ , rcEnd = Nothing+ , rcDir = Nothing+ , rcNamespaces = []+ , rcTitles = []+ , rcProp = []+ , rcShow = []+ , rcLimit = Nothing+ , rcType = []+ }+++data RecentChangesResponse+ = RecentChangesResponse+ { rchChanges :: [RecentChange]+ , rchContinue :: Maybe String+ }+ +emptyRecentChangesResponse :: RecentChangesResponse+emptyRecentChangesResponse = RecentChangesResponse+ { rchChanges = []+ , rchContinue = Nothing+ }++data RecentChange+ = RecentChange+ { rchType :: Maybe String+ , rchPage :: PageTitle+ , rchPageTo :: Maybe PageTitle+ , rchRcId :: Maybe RevID+ , rchRevId :: Maybe RevID+ , rchRevOldId :: Maybe RevID+ , rchUser :: Maybe UserName+ , rchIsAnon :: Bool+ , rchIsBot :: Bool+ , rchIsNew :: Bool+ , rchIsMinor :: Bool+ , rchLength :: Maybe Int+ , rchLengthOld :: Maybe Int+ , rchTimestamp :: Maybe String+ , rchComment :: Maybe String+ }+ +emptyRecentChange :: RecentChange+emptyRecentChange+ = RecentChange+ { rchType = Nothing+ , rchPage = emptyPageTitle+ , rchPageTo = Nothing+ , rchRcId = Nothing+ , rchRevId = Nothing+ , rchRevOldId = Nothing+ , rchUser = Nothing+ , rchIsAnon = False+ , rchIsBot = False+ , rchIsNew = False+ , rchIsMinor = False+ , rchLength = Nothing+ , rchLengthOld = Nothing+ , rchTimestamp = Nothing+ , rchComment = Nothing+ }
+ MediaWiki/API/Query/RecentChanges/Import.hs view
@@ -0,0 +1,80 @@+module MediaWiki.API.Query.RecentChanges.Import where++import MediaWiki.API.Types+import MediaWiki.API.Utils+import MediaWiki.API.Query.RecentChanges++import Text.XML.Light.Types+import Text.XML.Light.Proc ( strContent )++import Control.Monad+import Data.Maybe++stringXml :: String -> Either (String,[{-Error msg-}String]) RecentChangesResponse+stringXml s = parseDoc xml s++xml :: Element -> Maybe RecentChangesResponse+xml e = do+ guard (elName e == nsName "api")+ let es1 = children e+ p <- pNode "query" es1+ let es = children p+ ps <- fmap (mapMaybe xmlPage) (fmap children $ pNode "recentchanges" es)+ let cont = pNode "query-continue" es1 >>= xmlContinue "recentchanges" "rcstart"+ return emptyRecentChangesResponse+ { rchChanges = ps+ , rchContinue = cont+ }++xmlPage :: Element -> Maybe RecentChange+xmlPage e = do+ guard (elName e == nsName "rc")+ let ty = pAttr "type" e+ let ns = fromMaybe mainNamespace $ pAttr "ns" e+ let tit = fromMaybe "" $ pAttr "title" e+ let pid = pAttr "pageid" e+ let ns_t = pAttr "new_ns" e+ let tit_t = pAttr "new_title" e+ let pid_t = pAttr "new_pageid" e+ let pg_to + | any isJust [ns_t,tit_t,pid_t] + = Just+ emptyPageTitle{ pgNS=fromMaybe mainNamespace ns_t+ , pgTitle=fromMaybe "" tit_t+ , pgMbId=pid_t+ }+ | otherwise = Nothing+ let rcid = pAttr "rcid" e+ let revid = pAttr "revid" e+ let revido = pAttr "old_revid" e+ let usr = pAttr "user" e+ let isa = isJust (pAttr "anon" e)+ let isb = isJust (pAttr "bot" e)+ let isn = isJust (pAttr "new" e)+ let ism = isJust (pAttr "minor" e)+ let len = pAttr "newlen" e >>= readMb+ let leno = pAttr "oldlen" e >>= readMb+ let ts = pAttr "timestamp" e+ let co = pAttr "comment" e+ return emptyRecentChange+ { rchType = ty+ , rchPage = emptyPageTitle{pgNS=ns,pgTitle=tit,pgMbId=pid}+ , rchPageTo = pg_to+ , rchRcId = rcid+ , rchRevId = revid+ , rchRevOldId = revido+ , rchUser = usr+ , rchIsAnon = isa+ , rchIsBot = isb+ , rchIsNew = isn+ , rchIsMinor = ism+ , rchLength = len+ , rchLengthOld = leno+ , rchTimestamp = ts+ , rchComment = co+ }+ ++ + +
+ MediaWiki/API/Query/Revisions.hs view
@@ -0,0 +1,110 @@+-------------------------------------------------------------------- +-- | +-- Module : MediaWiki.API.Query.Revisions +-- Description : Representing 'revisions' requests. +-- Copyright : (c) Sigbjorn Finne, 2008 +-- License : BSD3 +-- +-- Maintainer: Sigbjorn Finne <sof@forkIO.com> +-- Stability : provisional +-- Portability: portable +-- +-- Representing 'revisions' requests. +-- +-------------------------------------------------------------------- +module MediaWiki.API.Query.Revisions where + +import MediaWiki.API.Types +import MediaWiki.API.Utils + +data RevisionRequest + = RevisionRequest + { rvProp :: [String] + , rvLimit :: Maybe Int + , rvStartID :: Maybe RevID + , rvEndID :: Maybe RevID + , rvStart :: Maybe TimeString + , rvEnd :: Maybe TimeString + , rvDir :: Maybe Direction + , rvUser :: Maybe UserName + , rvExcludeUser :: Maybe UserName + , rvExpandTemplates :: Maybe Bool + , rvSection :: Maybe String + , rvTokens :: [String] + } + +instance APIRequest RevisionRequest where + queryKind _ = QProp "revisions" + showReq r = + [ opt1 "rvprop" (rvProp r) + , mbOpt "rvlimit" show (rvLimit r) + , mbOpt "rvstartid" id (rvStartID r) + , mbOpt "rvendid" id (rvEndID r) + , mbOpt "rvstart" id (rvStart r) + , mbOpt "rvend" id (rvEnd r) + , mbOpt "rvdir" (\ x -> if x == Up then "ascending" else "descending") + (rvDir r) + , mbOpt "rvuser" id (rvUser r) + , mbOpt "rvexcludeuser" id (rvExcludeUser r) + , optB "rvexpandtemplates" (fromMaybe False (rvExpandTemplates r)) + , mbOpt "rvsection" id (rvSection r) + , opt1 "rvtoken" (rvTokens r) + ] + + +emptyRevisionRequest :: RevisionRequest +emptyRevisionRequest = RevisionRequest + { rvProp = [] + , rvLimit = Nothing + , rvStartID = Nothing + , rvEndID = Nothing + , rvStart = Nothing + , rvEnd = Nothing + , rvDir = Nothing + , rvUser = Nothing + , rvExcludeUser = Nothing + , rvExpandTemplates = Nothing + , rvTokens = [] + , rvSection = Nothing + } + +data RevisionsResponse + = RevisionsResponse + { rvPages :: [(PageTitle,[Revision])] + , rvContinue :: Maybe String + } + +emptyRevisionsResponse :: RevisionsResponse +emptyRevisionsResponse + = RevisionsResponse + { rvPages = [] + , rvContinue = Nothing + } + +data Revision + = Revision + { revPage :: PageTitle + , revRevId :: RevID + , revIsMinor :: Bool + , revUser :: String + , revIsAnon :: Bool + , revTimestamp :: TimeString + , revSize :: Integer + , revComment :: Maybe String +-- , revRollbackToken :: Maybe Token + , revContent :: Maybe String + } + +emptyRevision :: PageTitle -> Revision +emptyRevision pg + = Revision + { revPage = pg + , revRevId = nullRevId + , revIsMinor = False + , revUser = nullUser + , revIsAnon = False + , revTimestamp = nullTimestamp + , revSize = 0 + , revComment = Nothing + , revContent = Nothing + }
+ MediaWiki/API/Query/Revisions/Import.hs view
@@ -0,0 +1,62 @@+module MediaWiki.API.Query.Revisions.Import where++import MediaWiki.API.Types+import MediaWiki.API.Utils+import MediaWiki.API.Query.Revisions++import Text.XML.Light.Types+import Text.XML.Light.Input ( parseXMLDoc )+import Text.XML.Light.Proc ( strContent )++import Control.Monad+import Data.Maybe++stringXml :: String -> Either (String,[{-Error msg-}String]) RevisionsResponse+stringXml s = parseDoc xml s++xml :: Element -> Maybe RevisionsResponse+xml e = do+ guard (elName e == nsName "api")+ let es1 = children e+ p <- pNode "query" es1+ let es = children p+ ps <- fmap (mapMaybe xmlPage) (fmap children $ pNode "pages" es)+ let cont = pNode "query-continue" es1 >>= xmlContinue "revisions" "rvstartid"+ return emptyRevisionsResponse+ { rvPages = ps+ , rvContinue = cont+ }++xmlPage :: Element -> Maybe (PageTitle,[Revision])+xmlPage e = do+ guard (elName e == nsName "page")+ let ns = fromMaybe mainNamespace $ pAttr "ns" e+ let tit = fromMaybe "" $ pAttr "title" e+ let pid = pAttr "pageid" e+ let es = children e + p <- pNode "revisions" es+ let pg = emptyPageTitle{pgNS = ns, pgTitle=tit, pgMbId = pid}+ rs <- fmap (mapMaybe (xmlRevision pg)) (fmap children $ pNode "rev" es)+ return (pg, rs)++xmlRevision :: PageTitle -> Element -> Maybe Revision+xmlRevision pg e = do+ guard (elName e == nsName "page")+ let rid = fromMaybe "" $ pAttr "revid" e+ let min = isJust (pAttr "minor" e)+ let usr = fromMaybe "" $ pAttr "user" e+ let anon = isJust (pAttr "anon" e)+ let ts = fromMaybe "" $ pAttr "timestamp" e+ let size = fromMaybe 0 (pAttr "size" e >>= readMb)+ let com = pAttr "comment" e+ let con = case strContent e of { "" -> Nothing ; xs -> Just xs}+ return (emptyRevision pg)+ { revRevId = rid+ , revIsMinor = min+ , revUser = usr+ , revIsAnon = anon+ , revTimestamp = ts+ , revSize = size+ , revComment = com+ , revContent = con+ }
+ MediaWiki/API/Query/Search.hs view
@@ -0,0 +1,62 @@+--------------------------------------------------------------------+-- |+-- Module : MediaWiki.API.Query.Search+-- Description : Representing 'search' requests.+-- Copyright : (c) Sigbjorn Finne, 2008+-- License : BSD3+--+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>+-- Stability : provisional+-- Portability: portable+--+-- Representing 'search' requests.+-- +--------------------------------------------------------------------+module MediaWiki.API.Query.Search where++import MediaWiki.API.Types+import MediaWiki.API.Utils++data SearchRequest+ = SearchRequest+ { srSearch :: String+ , srNamespaces :: [NamespaceID]+ , srWhat :: Bool -- True => (full)text search, o/w title search.+ , srRedirects :: Bool+ , srOffset :: Maybe String+ , srLimit :: Maybe Int+ }++instance APIRequest SearchRequest where+ queryKind _ = QList "search"+ showReq r+ = [ mbOpt "srsearch" id (Just (srSearch r))+ , opt1 "srnamespace" (srNamespaces r)+ , opt "srwhat" ((\x -> if x then "text" else "title") (srWhat r))+ , optB "srredirects" (srRedirects r)+ , mbOpt "sroffset" id (srOffset r)+ , mbOpt "srlimit" show (srLimit r)+ ]++emptySearchRequest :: String -> SearchRequest+emptySearchRequest s = SearchRequest+ { srSearch = s+ , srNamespaces = []+ , srWhat = False+ , srRedirects = False+ , srOffset = Nothing+ , srLimit = Nothing+ }+ +data SearchResponse+ = SearchResponse+ { srPages :: [PageTitle]+ , srContinue :: Maybe String+ }++emptySearchResponse :: SearchResponse+emptySearchResponse = SearchResponse+ { srPages = []+ , srContinue = Nothing+ }+
+ MediaWiki/API/Query/Search/Import.hs view
@@ -0,0 +1,32 @@+module MediaWiki.API.Query.Search.Import where++import MediaWiki.API.Types+import MediaWiki.API.Utils+import MediaWiki.API.Query.Search++import Text.XML.Light.Types+import Text.XML.Light.Proc ( strContent )++import Control.Monad+import Data.Maybe++stringXml :: String -> Either (String,[{-Error msg-}String]) SearchResponse+stringXml s = parseDoc xml s++xml :: Element -> Maybe SearchResponse+xml e = do+ guard (elName e == nsName "api")+ let es1 = children e+ p <- pNode "query" es1+ let es = children p+ ps <- fmap (mapMaybe xmlPage) (fmap children $ pNode "search" es)+ let cont = pNode "query-continue" es1 >>= xmlContinue "search" "sroffset"+ return emptySearchResponse{srPages=ps,srContinue=cont}++xmlPage :: Element -> Maybe PageTitle+xmlPage e = do+ guard (elName e == nsName "p")+ let ns = fromMaybe "0" $ pAttr "ns" e+ let tit = fromMaybe "" $ pAttr "title" e+ let pid = pAttr "pageid" e+ return emptyPageTitle{pgNS=ns,pgTitle=tit,pgMbId=pid}
+ MediaWiki/API/Query/SiteInfo.hs view
@@ -0,0 +1,114 @@+--------------------------------------------------------------------+-- |+-- Module : MediaWiki.API.Query.SiteInfo+-- Description : Representing 'siteinfo' requests.+-- Copyright : (c) Sigbjorn Finne, 2008+-- License : BSD3+--+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>+-- Stability : provisional+-- Portability: portable+--+-- Representing 'siteinfo' requests.+-- +--------------------------------------------------------------------+module MediaWiki.API.Query.SiteInfo where++import MediaWiki.API.Types+import MediaWiki.API.Utils++data SiteInfoRequest+ = SiteInfoRequest+ { siProp :: [String] -- general,namespaces,namespacealiases,+ -- specialpagealiases,statistics,interwikimap,+ -- dbrepllag,usergroups+ , siFilterIW :: Maybe Bool+ , siShowAllDBs :: Bool+ }++instance APIRequest SiteInfoRequest where+ queryKind _ = QMeta "siteinfo"+ showReq r+ = [ opt1 "siprop" (siProp r)+ , mbOpt "sifilteriw" ( \x -> if x then "local" else "!local") (siFilterIW r)+ , optB "sishowalldb" (siShowAllDBs r)+ ]++emptySiteInfoRequest :: SiteInfoRequest+emptySiteInfoRequest = SiteInfoRequest+ { siProp = []+ , siFilterIW = Nothing+ , siShowAllDBs = False+ }+ +data SiteInfoResponse + = SiteInfoResponse+ { siDBReplInfo :: [DBInfo]+ , siNamespaces :: [NamespaceInfo]+ , siGeneral :: Maybe SiteInfo+ , siNamespaceAliases :: [NamespaceInfo]+ , siSpecialPageAliases :: [(String,[String])]+ , siStatistics :: Maybe SiteStatistics+ , siInterwiki :: [InterwikiEntry]+ , siUserGroups :: [UserGroup]+ }+ +emptySiteInfoResponse :: SiteInfoResponse+emptySiteInfoResponse = SiteInfoResponse+ { siDBReplInfo = []+ , siNamespaces = []+ , siGeneral = Nothing+ , siNamespaceAliases = []+ , siSpecialPageAliases = []+ , siStatistics = Nothing+ , siInterwiki = []+ , siUserGroups = []+ }++type Permission = String++data UserGroup+ = UserGroup+ { ugName :: String+ , ugRights :: [Permission]+ }++data SiteInfo+ = SiteInfo+ { siteMainPage :: PageName+ , siteBase :: URLString+ , siteName :: String+ , siteGenerator :: String+ , siteLastRevision :: Maybe String+ , siteCase :: Maybe String+ , siteRightsCode :: Maybe String+ , siteRights :: Maybe String+ , siteLang :: Maybe String+ , siteFallbackEncoding :: Maybe String+ , siteWriteAPI :: Bool+ , siteTimezone :: Maybe String+ , siteTZOffset :: Maybe Int+ }++data SiteStatistics+ = SiteStatistics+ { siPages :: Integer+ , siArticles :: Integer+ , siViews :: Integer+ , siEdits :: Integer+ , siImages :: Integer+ , siUsers :: Integer+ , siAdmins :: Integer+ , siJobs :: Integer+ }++++data DBInfo+ = DBInfo+ { dbHost :: String+ , dbLag :: String+ }+++
+ MediaWiki/API/Query/SiteInfo/Import.hs view
@@ -0,0 +1,143 @@+module MediaWiki.API.Query.SiteInfo.Import where++import MediaWiki.API.Types+import MediaWiki.API.Utils+import MediaWiki.API.Query.SiteInfo++import Text.XML.Light.Types+import Text.XML.Light.Proc ( strContent )++import Control.Monad+import Data.Maybe++stringXml :: String -> Either (String,[{-Error msg-}String]) SiteInfoResponse+stringXml s = parseDoc xml s++xml :: Element -> Maybe SiteInfoResponse+xml e = do+ guard (elName e == nsName "api")+ let es1 = children e+ p <- pNode "query" es1+ let es = children p+ let dbs = fromMaybe [] $ fmap (mapMaybe xmlDB) (fmap children $ pNode "dblrepllag" es)+ let nss = fromMaybe [] $ fmap (mapMaybe xmlNS) (fmap children $ pNode "namespaces" es)+ let nass = fromMaybe [] $ fmap (mapMaybe xmlNS) (fmap children $ pNode "namespacealiases" es)+ let gen = pNode "general" es >>= xmlSI+ let ss = fromMaybe [] $ fmap (mapMaybe xmlSS) (fmap children $ pNode "specialpagealiases" es)+ let st = pNode "statistics" es >>= xmlStat+ let iws = fromMaybe [] $ fmap (mapMaybe xmlIW) (fmap children $ pNode "interwikimap" es)+ let ugs = fromMaybe [] $ fmap (mapMaybe xmlGr) (fmap children $ pNode "usergroups" es)+ return + emptySiteInfoResponse+ { siDBReplInfo = dbs+ , siNamespaces = nss+ , siGeneral = gen+ , siNamespaceAliases = nass+ , siSpecialPageAliases = ss+ , siStatistics = st+ , siInterwiki = iws+ , siUserGroups = ugs+ }++xmlDB :: Element -> Maybe DBInfo+xmlDB e = do+ guard (elName e == nsName "db")+ let h = fromMaybe "" $ pAttr "host" e+ let l = fromMaybe "" $ pAttr "lag" e + return DBInfo{dbHost=h,dbLag=l}++xmlNS :: Element -> Maybe NamespaceInfo+xmlNS e = do+ guard (elName e == nsName "ns")+ let i = fromMaybe "" $ pAttr "id" e+ let t = strContent e+ let sub = isJust (pAttr "subpages" e)+ return NamespaceInfo{nsId=i,nsTitle=t,nsSubpages=sub}++xmlGr :: Element -> Maybe UserGroup+xmlGr e = do+ guard (elName e == nsName "group")+ let nm = fromMaybe "" $ pAttr "name" e+ rs <- fmap (mapMaybe xmlRi) (fmap children $ pNode "rights" (children e))+ return UserGroup{ugName=nm,ugRights=rs}+ where+ xmlRi p = do+ guard (elName p == nsName "permission")+ return (strContent e)++xmlIW :: Element -> Maybe InterwikiEntry+xmlIW e = do+ guard (elName e == nsName "iw")+ let pre = fromMaybe "" $ pAttr "prefix" e+ let url = fromMaybe "" $ pAttr "url" e+ let la = pAttr "lang" e+ let loc = isJust (pAttr "local" e)+ let tra = (pAttr "trans" e >>= \x -> readMb x >>= \ y -> return (y /= (0::Int)))+ return InterwikiEntry{iwPrefix=pre,iwLocal=loc,iwTranscludable=tra,iwUrl=url,iwLanguage=la}++xmlSS :: Element -> Maybe (String,[String])+xmlSS e = do+ guard (elName e == nsName "specialpage")+ let es1 = children e+ nss <- fmap (mapMaybe xmlAS) (fmap children $ pNode "aliases" es1)+ let nm = fromMaybe "" $ pAttr "realname" e+ return (nm,nss)+ where+ xmlAS p = do+ guard (elName p == nsName "alias")+ return (strContent e)++xmlSI :: Element -> Maybe SiteInfo+xmlSI e = do+ guard (elName e == nsName "general")+ let ma = fromMaybe "" $ pAttr "mainpage" e+ let ba = fromMaybe "" $ pAttr "base" e+ let nm = fromMaybe "" $ pAttr "sitename" e+ let ge = fromMaybe "" $ pAttr "generator" e+ let re = pAttr "revid" e+ let ca = pAttr "case" e+ let ri = pAttr "rights" e+ let ric = pAttr "rightscode" e+ let la = pAttr "lang" e+ let enc = pAttr "fallback8bitEncoding" e+ let wr = isJust (pAttr "writeapi" e)+ let tz = pAttr "timezone" e+ let tzo = pAttr "timeoffset" e >>= readMb+ return SiteInfo+ { siteMainPage = ma+ , siteBase = ba+ , siteName = nm+ , siteGenerator = ge+ , siteLastRevision = re+ , siteCase = ca+ , siteRightsCode = ric+ , siteRights = ri+ , siteLang = la+ , siteFallbackEncoding = enc+ , siteWriteAPI = wr+ , siteTimezone = tz+ , siteTZOffset = tzo+ }+ +xmlStat :: Element -> Maybe SiteStatistics+xmlStat e = do+ guard (elName e == nsName "statistics")+ let pgs = fromMaybe 0 $ pAttr "pages" e >>= readMb+ let arts = fromMaybe 0 $ pAttr "articles" e >>= readMb+ let views = fromMaybe 0 $ pAttr "views" e >>= readMb+ let edits = fromMaybe 0 $ pAttr "edits" e >>= readMb+ let users = fromMaybe 0 $ pAttr "users" e >>= readMb+ let admins = fromMaybe 0 $ pAttr "admins" e >>= readMb+ let jobs = fromMaybe 0 $ pAttr "jobs" e >>= readMb+ let images = fromMaybe 0 $ pAttr "images" e >>= readMb+ return + SiteStatistics+ { siPages = pgs+ , siArticles = arts+ , siViews = views+ , siEdits = edits+ , siImages = images+ , siUsers = users+ , siAdmins = admins+ , siJobs = jobs+ }
+ MediaWiki/API/Query/Templates.hs view
@@ -0,0 +1,55 @@+--------------------------------------------------------------------+-- |+-- Module : MediaWiki.API.Query.Templates+-- Description : Representing 'templates' requests.+-- Copyright : (c) Sigbjorn Finne, 2008+-- License : BSD3+--+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>+-- Stability : provisional+-- Portability: portable+--+-- Representing 'templates' requests.+-- +--------------------------------------------------------------------+module MediaWiki.API.Query.Templates where++import MediaWiki.API.Types+import MediaWiki.API.Utils++data TemplatesRequest+ = TemplatesRequest+ { tlNamespaces :: [NamespaceID]+ , tlLimit :: Maybe Int+ , tlContinueFrom :: Maybe String+ }++instance APIRequest TemplatesRequest where+ queryKind _ = QProp "templates"+ showReq r+ = [ opt1 "tlnamespace" (tlNamespaces r)+ , mbOpt "tllimit" show (tlLimit r)+ , mbOpt "tlcontinue" id (tlContinueFrom r)+ ]++emptyTemplatesRequest :: TemplatesRequest+emptyTemplatesRequest = TemplatesRequest+ { tlNamespaces = []+ , tlLimit = Nothing+ , tlContinueFrom = Nothing+ }+ +data TemplatesResponse + = TemplatesResponse+ { tlPages :: [(PageTitle,[PageTitle])]+ , tlContinue :: Maybe String+ }+ +emptyTemplatesResponse :: TemplatesResponse+emptyTemplatesResponse = TemplatesResponse+ { tlPages = []+ , tlContinue = Nothing+ }+ ++
+ MediaWiki/API/Query/Templates/Import.hs view
@@ -0,0 +1,40 @@+module MediaWiki.API.Query.Templates.Import where++import MediaWiki.API.Types+import MediaWiki.API.Utils+import MediaWiki.API.Query.Templates++import Text.XML.Light.Types+import Text.XML.Light.Proc ( strContent )++import Control.Monad+import Data.Maybe++stringXml :: String -> Either (String,[{-Error msg-}String]) TemplatesResponse+stringXml s = parseDoc xml s++xml :: Element -> Maybe TemplatesResponse+xml e = do+ guard (elName e == nsName "api")+ let es1 = children e+ p <- pNode "query" es1+ let es = children p+ ps <- fmap (mapMaybe xmlPage) (fmap children $ pNode "pages" es)+ let cont = pNode "query-continue" es1 >>= xmlContinue "templates" "tlcontinue"+ return emptyTemplatesResponse{tlPages=ps,tlContinue=cont}++xmlPage :: Element -> Maybe (PageTitle, [PageTitle])+xmlPage e = do+ guard (elName e == nsName "page")+ let ns = fromMaybe "0" $ pAttr "ns" e+ let tit = fromMaybe "" $ pAttr "title" e+ let pid = pAttr "pageid" e+ ps <- fmap (mapMaybe xmlT) (fmap children $ pNode "templates" (children e))+ return (emptyPageTitle{pgNS=ns,pgTitle=tit,pgMbId=pid}, ps)+ where+ xmlT p = do+ guard (elName p == nsName "tl")+ let ns = fromMaybe "0" $ pAttr "ns" p+ let tit = fromMaybe "" $ pAttr "title" p+ let pid = pAttr "pageid" p+ return emptyPageTitle{pgNS=ns,pgTitle=tit,pgMbId=pid}
+ MediaWiki/API/Query/UserContribs.hs view
@@ -0,0 +1,100 @@+--------------------------------------------------------------------+-- |+-- Module : MediaWiki.API.Query.UserContribs+-- Description : Representing 'usercontribs' requests.+-- Copyright : (c) Sigbjorn Finne, 2008+-- License : BSD3+--+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>+-- Stability : provisional+-- Portability: portable+--+-- Representing 'usercontribs' requests.+-- +--------------------------------------------------------------------+module MediaWiki.API.Query.UserContribs where++import MediaWiki.API.Types+import MediaWiki.API.Utils++data UserContribsRequest + = UserContribsRequest+ { ucLimit :: Maybe Int+ , ucStart :: Maybe Timestamp+ , ucEnd :: Maybe Timestamp+ , ucUser :: Maybe UserID+ , ucUserPrefix :: Maybe String+ , ucDir :: Maybe TimeArrow+ , ucNamespaces :: [NamespaceID]+ , ucProp :: [String]+ , ucShow :: [String]+ }++instance APIRequest UserContribsRequest where+ queryKind _ = QList "usercontribs"+ showReq r+ = [ mbOpt "uclimit" show (ucLimit r)+ , mbOpt "ucstart" id (ucStart r)+ , mbOpt "ucend" id (ucEnd r)+ , mbOpt "ucuser" id (ucUser r)+ , mbOpt "ucuserprefix" id (ucUserPrefix r)+ , mbOpt "ucdir" (\ x -> if x == Earlier then "older" else "newer") (ucDir r)+ , opt1 "ucnamespace" (ucNamespaces r)+ , opt1 "ucprop" (ucProp r)+ , opt1 "ucshow" (ucShow r)+ ]+++emptyUserContribsRequest :: UserContribsRequest+emptyUserContribsRequest = UserContribsRequest+ { ucLimit = Nothing+ , ucStart = Nothing+ , ucEnd = Nothing+ , ucUser = Nothing+ , ucUserPrefix = Nothing+ , ucDir = Nothing+ , ucNamespaces = []+ , ucProp = []+ , ucShow = []+ }++data UserContribsResponse+ = UserContribsResponse+ { ucPages :: [UserContrib]+ , ucContinue :: Maybe String+ }++emptyUserContribsResponse :: UserContribsResponse+emptyUserContribsResponse = UserContribsResponse+ { ucPages = []+ , ucContinue = Nothing+ }++data UserContrib+ = UserContrib+ { ucoUser :: UserName+ , ucoPage :: PageTitle+ , ucoRevId :: RevID+ , ucoTimestamp :: Maybe Timestamp+ , ucoIsNew :: Bool+ , ucoIsMinor :: Bool+ , ucoIsTop :: Bool+ , ucoComment :: Maybe String+ }+ +emptyUserContrib :: UserContrib+emptyUserContrib = UserContrib+ { ucoUser = ""+ , ucoPage = emptyPageTitle+ , ucoRevId = "0"+ , ucoTimestamp = Nothing+ , ucoIsNew = False+ , ucoIsMinor = False+ , ucoIsTop = False+ , ucoComment = Nothing+ }+ ++++
+ MediaWiki/API/Query/UserContribs/Import.hs view
@@ -0,0 +1,48 @@+module MediaWiki.API.Query.UserContribs.Import where++import MediaWiki.API.Types+import MediaWiki.API.Utils+import MediaWiki.API.Query.UserContribs++import Text.XML.Light.Types++import Control.Monad+import Data.Maybe++stringXml :: String -> Either (String,[{-Error msg-}String]) UserContribsResponse+stringXml s = parseDoc xml s++xml :: Element -> Maybe UserContribsResponse+xml e = do+ guard (elName e == nsName "api")+ let es1 = children e+ p <- pNode "query" es1+ let es = children p+ ps <- fmap (mapMaybe xmlPage) (fmap children $ pNode "usercontribs" es)+ let cont = pNode "query-continue" es1 >>= xmlContinue "usercontribs" "ucstart"+ return emptyUserContribsResponse{ucPages=ps,ucContinue=cont}++xmlPage :: Element -> Maybe UserContrib+xmlPage e = do+ guard (elName e == nsName "item")+ let ns = fromMaybe "0" $ pAttr "ns" e+ let tit = fromMaybe "" $ pAttr "title" e+ let pid = pAttr "pageid" e+ let usr = fromMaybe "" $ pAttr "user" e+ let revid = fromMaybe "0" $ pAttr "revid" e+ let ts = pAttr "timestamp" e+ let isn = isJust (pAttr "new" e)+ let ism = isJust (pAttr "minor" e)+ let ist = isJust (pAttr "top" e)+ let co = pAttr "comment" e+ return emptyUserContrib+ { ucoUser = usr+ , ucoPage = emptyPageTitle{pgNS=ns,pgTitle=tit,pgMbId=pid}+ , ucoRevId = revid+ , ucoTimestamp = ts+ , ucoIsNew = isn+ , ucoIsMinor = ism+ , ucoIsTop = ist+ , ucoComment = co+ }+
+ MediaWiki/API/Query/UserInfo.hs view
@@ -0,0 +1,46 @@+--------------------------------------------------------------------+-- |+-- Module : MediaWiki.API.Query.UserInfo+-- Description : Representing 'userinfo' requests.+-- Copyright : (c) Sigbjorn Finne, 2008+-- License : BSD3+--+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>+-- Stability : provisional+-- Portability: portable+--+-- Representing 'userinfo' requests.+-- +--------------------------------------------------------------------+module MediaWiki.API.Query.UserInfo where++import MediaWiki.API.Types+import MediaWiki.API.Utils++data UserInfoRequest+ = UserInfoRequest+ { uiProp :: [String] + -- one of (1.13): + -- blockinfo, hasmsg, groups, rights, options, editcount, ratelimits+ }++instance APIRequest UserInfoRequest where+ queryKind _ = QMeta "userinfo"+ showReq r+ = [ opt1 "uiprop" (uiProp r)+ ]++emptyUserInfoRequest :: UserInfoRequest+emptyUserInfoRequest = UserInfoRequest+ { uiProp = []+ }++data UserInfoResponse+ = UserInfoResponse+ { uiUser :: UserInfo+ }++emptyUserInfoResponse :: UserInfoResponse+emptyUserInfoResponse = UserInfoResponse+ { uiUser = emptyUserInfo+ }
+ MediaWiki/API/Query/UserInfo/Import.hs view
@@ -0,0 +1,91 @@+module MediaWiki.API.Query.UserInfo.Import where++import MediaWiki.API.Types+import MediaWiki.API.Utils+import MediaWiki.API.Query.UserInfo++import Text.XML.Light.Types+import Text.XML.Light.Proc ( strContent )++import Control.Monad+import Data.Maybe++stringXml :: String -> Either (String,[{-Error msg-}String]) UserInfoResponse+stringXml s = parseDoc xml s++xml :: Element -> Maybe UserInfoResponse+xml e = do+ guard (elName e == nsName "api")+ p0 <- pNode "query" (children e)+ p <- pNode "userinfo" (children p0)+ let es = children p+ let grps = mapMaybe xmlGroup es+ let rs = mapMaybe xmlRights es+ let os = mapMaybe xmlOption es+ let rs1 = mapMaybe xmlRateLimit es+ let ec = pAttr "editcount" p >>= readMb+ let nm = fromMaybe nullUser $ pAttr "name" p+ let uid = fromMaybe "0" $ pAttr "id" p >>= readMb+ let isa = isJust (pAttr "anon" p)+ let hasm = isJust (pAttr "mesages" p)+ let bi = xmlBlockInfo p+ let u = emptyUserInfo+ { uiName = nm+ , uiId = uid+ , uiIsAnon = isa+ , uiHasMessage = hasm+ , uiBlocked = bi+ , uiGroups = concat grps+ , uiRights = concat rs+ , uiOptions = concat os+ , uiRateLimits = concat rs1+ , uiEditCount = ec+ }+ return emptyUserInfoResponse{uiUser=u}++xmlBlockInfo :: Element -> Maybe (String,String)+xmlBlockInfo e = do+ b <- pAttr "blockedby" e+ c <- pAttr "blockreason" e+ return (b,c)++xmlGroup :: Element -> Maybe [String]+xmlGroup e = do+ guard (elName e == nsName "groups")+ let es = children e+ let gs = mapMaybe xmlG es+ return gs+ where+ xmlG g = do+ guard (elName e == nsName "g")+ return (strContent g)++xmlRights :: Element -> Maybe [String]+xmlRights e = do+ guard (elName e == nsName "rights")+ let es = children e+ let gs = mapMaybe xmlR es+ return gs+ where+ xmlR g = do+ guard (elName e == nsName "r")+ return (strContent g)++xmlRateLimit :: Element -> Maybe [RateLimit]+xmlRateLimit e = do+ guard (elName e == nsName "ratelimits")+ let es = children e+ let gs = mapMaybe xmlR es+ return gs+ where+ xmlR g = do+ let es = children g+ p <- pNode "ip" es+ let hi = fromMaybe 0 $ pAttr "hits" p >>= readMb+ let se = fromMaybe 0 $ pAttr "seconds" p >>= readMb+ return RateLimit{rlName=qName (elName e),rlHits=hi,rlSeconds=se}++xmlOption :: Element -> Maybe [(String,String)]+xmlOption e = do+ guard (elName e == nsName "options")+ return (map (\a -> (qName (attrKey a), attrVal a)) (elAttribs e))
+ MediaWiki/API/Query/Users.hs view
@@ -0,0 +1,66 @@+--------------------------------------------------------------------+-- |+-- Module : MediaWiki.API.Query.Users+-- Description : Representing 'users' requests.+-- Copyright : (c) Sigbjorn Finne, 2008+-- License : BSD3+--+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>+-- Stability : provisional+-- Portability: portable+--+-- Representing 'users' requests.+-- +--------------------------------------------------------------------+module MediaWiki.API.Query.Users where++import MediaWiki.API.Types+import MediaWiki.API.Utils++data UsersRequest+ = UsersRequest+ { usProp :: [String]+ , usUsers :: [UserID]+ }++instance APIRequest UsersRequest where+ queryKind _ = QList "users"+ showReq r = [ opt1 "usprop" (usProp r)+ , opt1 "ususers" (usUsers r)+ ]++emptyUsersRequest :: UsersRequest+emptyUsersRequest = UsersRequest+ { usProp = []+ , usUsers = []+ }++data UsersResponse+ = UsersResponse+ { usrUsers :: [UsersInfo]+ }+ +emptyUsersResponse :: UsersResponse+emptyUsersResponse+ = UsersResponse+ { usrUsers = []+ }++data UsersInfo+ = UsersInfo+ { usName :: Maybe UserName+ , usEditCount :: Maybe Int+ , usRegDate :: Maybe Timestamp+ , usGroups :: [String]+ , usBlock :: Maybe (UserName,String)+ }+ +emptyUsersInfo :: UsersInfo+emptyUsersInfo = UsersInfo+ { usName = Nothing+ , usEditCount = Nothing+ , usRegDate = Nothing+ , usGroups = []+ , usBlock = Nothing+ }+
+ MediaWiki/API/Query/Users/Import.hs view
@@ -0,0 +1,47 @@+module MediaWiki.API.Query.Users.Import where++import MediaWiki.API.Types+import MediaWiki.API.Utils+import MediaWiki.API.Query.Users++import Text.XML.Light.Types+import Text.XML.Light.Proc ( strContent )++import Control.Monad+import Data.Maybe++stringXml :: String -> Either (String,[{-Error msg-}String]) UsersResponse+stringXml s = parseDoc xml s++xml :: Element -> Maybe UsersResponse+xml e = do+ guard (elName e == nsName "api")+ let es1 = children e+ p <- pNode "query" es1+ let es = children p+ ps <- fmap (mapMaybe xmlPage) (fmap children $ pNode "users" es)+ return emptyUsersResponse{usrUsers=ps}++xmlPage :: Element -> Maybe UsersInfo+xmlPage e = do+ guard (elName e == nsName "user")+ let nm = pAttr "name" e+ let ec = pAttr "editcount" e >>= readMb+ let re = pAttr "registration" e+ let bl1 = pAttr "blockedby" e+ let bl2 = pAttr "blockreason" e+ let bl = case (bl1,bl2) of { (Just a, Just b) -> Just (a,b) ; _ -> Nothing}+ let gs = fromMaybe [] $ fmap (mapMaybe xmlG) (fmap children $ pNode "groups" (children e))+ return emptyUsersInfo+ { usName = nm+ , usEditCount = ec+ , usRegDate = re+ , usBlock = bl+ , usGroups = gs+ }+ where+ xmlG p = do+ guard (elName p == nsName "g")+ return (strContent p)+ +
+ MediaWiki/API/Query/WatchList.hs view
@@ -0,0 +1,100 @@+--------------------------------------------------------------------+-- |+-- Module : MediaWiki.API.Query.WatchList+-- Description : Representing 'watchlist' requests.+-- Copyright : (c) Sigbjorn Finne, 2008+-- License : BSD3+--+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>+-- Stability : provisional+-- Portability: portable+--+-- Representing 'watchlist' requests.+-- +--------------------------------------------------------------------+module MediaWiki.API.Query.WatchList where++import MediaWiki.API.Types+import MediaWiki.API.Utils++data WatchListRequest+ = WatchListRequest+ { wlAllRev :: Bool+ , wlStart :: Maybe Timestamp+ , wlEnd :: Maybe Timestamp+ , wlNamespaces :: [NamespaceID]+ , wlDir :: Maybe TimeArrow+ , wlLimit :: Maybe Int+ , wlProp :: [String]+ , wlShow :: [String]+ }++instance APIRequest WatchListRequest where+ queryKind _ = QList "watchlist"+ showReq r+ = [ optB "wlallrev" (wlAllRev r)+ , mbOpt "wlstart" id (wlStart r)+ , mbOpt "wlend" id (wlEnd r)+ , opt1 "wlnamespace" (wlNamespaces r)+ , mbOpt "wldir" (\ x -> if x==Earlier then "older" else "newer")+ (wlDir r)+ , mbOpt "wllimit" show (wlLimit r)+ , opt1 "wlprop" (wlProp r)+ , opt1 "wlshow" (wlShow r)+ ]++emptyWatchListRequest :: WatchListRequest+emptyWatchListRequest = WatchListRequest+ { wlAllRev = False+ , wlStart = Nothing+ , wlEnd = Nothing+ , wlNamespaces = []+ , wlDir = Nothing+ , wlLimit = Nothing+ , wlProp = []+ , wlShow = []+ }++data WatchListResponse + = WatchListResponse+ { wlWatch :: WatchList+ , wlContinue :: Maybe String+ }++emptyWatchListResponse :: WatchListResponse+emptyWatchListResponse = WatchListResponse+ { wlWatch = emptyWatchList+ , wlContinue = Nothing+ }++data WatchList+ = WatchList+ { wlPage :: PageTitle+ , wlRevId :: Maybe RevID+ , wlUser :: Maybe UserName+ , wlIsAnon :: Bool+ , wlIsNew :: Bool+ , wlIsMinor :: Bool+ , wlIsPatrolled :: Bool+ , wlTimestamp :: Maybe Timestamp+ , wlLength :: Maybe Int+ , wlOldLength :: Maybe Int+ , wlComment :: Maybe String+ }+ +emptyWatchList :: WatchList+emptyWatchList+ = WatchList+ { wlPage = emptyPageTitle+ , wlRevId = Nothing+ , wlUser = Nothing+ , wlIsAnon = False+ , wlIsNew = False+ , wlIsMinor = False+ , wlIsPatrolled = False+ , wlTimestamp = Nothing+ , wlLength = Nothing+ , wlOldLength = Nothing+ , wlComment = Nothing+ }+
+ MediaWiki/API/Query/WatchList/Import.hs view
@@ -0,0 +1,56 @@+module MediaWiki.API.Query.WatchList.Import where++import MediaWiki.API.Types+import MediaWiki.API.Utils+import MediaWiki.API.Query.WatchList++import Text.XML.Light.Types+import Text.XML.Light.Proc ( strContent )++import Control.Monad+import Data.Maybe++stringXml :: String -> Either (String,[{-Error msg-}String]) WatchListResponse+stringXml s = parseDoc xml s++xml :: Element -> Maybe WatchListResponse+xml e = do+ guard (elName e == nsName "api")+ let es1 = children e+ p <- pNode "query" es1+ let es = children p+ wl <- pNode "watchlist" es >>= xmlWatchList+ let cont = pNode "query-continue" es1 >>= xmlContinue "watchlist" "wlstart"+ return emptyWatchListResponse{wlWatch=wl,wlContinue=cont}++xmlWatchList :: Element -> Maybe WatchList+xmlWatchList e = do+ guard (elName e == nsName "watchlist")+ let ns = fromMaybe "0" $ pAttr "ns" e+ let tit = fromMaybe "" $ pAttr "title" e+ let pid = pAttr "pageid" e+ let rid = pAttr "revid" e+ let usr = pAttr "user" e+ let isa = isJust (pAttr "anon" e)+ let isn = isJust (pAttr "new" e)+ let ism = isJust (pAttr "minor" e)+ let isp = isJust (pAttr "patrolled" e)+ let ts = pAttr "timestamp" e+ let len = pAttr "newlen" e >>= readMb+ let leno = pAttr "oldlen" e >>= readMb+ let co = pAttr "comment" e+ let pg = emptyPageTitle{pgNS=ns,pgTitle=tit,pgMbId=pid}+ return emptyWatchList+ { wlPage = pg+ , wlRevId = rid+ , wlUser = usr+ , wlIsAnon = isa+ , wlIsNew = isn+ , wlIsMinor = ism+ , wlIsPatrolled = isp+ , wlTimestamp = ts+ , wlLength = len+ , wlOldLength = leno+ , wlComment = co+ }+
+ MediaWiki/API/Types.hs view
@@ -0,0 +1,241 @@+-------------------------------------------------------------------- +-- | +-- Module : MediaWiki.API.Types +-- Description : Basic MediaWiki API types +-- Copyright : (c) Sigbjorn Finne, 2008 +-- License : BSD3 +-- +-- Maintainer: Sigbjorn Finne <sof@forkIO.com> +-- Stability : provisional +-- Portability: portable +-- +-- Basic MediaWiki API types +-- +-------------------------------------------------------------------- +module MediaWiki.API.Types where + +-- base types +type UserName = String +type NamespaceID = String +type TimeString = String +data Direction = Up | Down deriving ( Eq ) +type RevID = String +type PageName = String +type UserID = String +data TimeArrow = Earlier | Later deriving ( Eq ) +type Timestamp = String +type Redirect = String +type SortKind = String +type CatName = String +type GroupName = String +type FilterLang = String +type WithRedirects = String +type URLString = String +type Token = String +type LangName = String + +nullRevId :: RevID +nullRevId = "0" + +nullTimestamp :: Timestamp +nullTimestamp = "" + +nullUser :: UserName +nullUser = "" + +data PageTitle + = PageTitle { pgNS :: NamespaceID + , pgTitle :: Title + , pgMbId :: Maybe PageID + , pgMissing :: Bool + } + +emptyPageTitle :: PageTitle +emptyPageTitle + = PageTitle { pgNS = mainNamespace + , pgTitle = "" + , pgMbId = Nothing + , pgMissing = False + } + +mainNamespace :: NamespaceID +mainNamespace = "0" + +ns_MAIN :: NamespaceID +ns_MAIN = mainNamespace + +ns_IMAGE :: NamespaceID +ns_IMAGE = "6" + +data Format + = Format + { formatKind :: FormatKind + , formatFormatted :: Bool + } + +emptyFormat :: Format +emptyFormat = Format{formatKind=FormatXML, formatFormatted=True} + +xmlFormat :: Format +xmlFormat = emptyFormat{formatKind=FormatXML, formatFormatted=False} + +data FormatKind + = FormatJSON + | FormatPHP + | FormatWDDX + | FormatXML + | FormatYAML + | FormatTxt + | FormatDbg + +type User = String +type Password = String +type LoginToken = String +type SessionID = String +type SessionToken = String +type ValueName = (String,String) + +data UserInfo + = UserInfo + { uiName :: UserName + , uiId :: UserID + , uiIsAnon :: Bool + , uiHasMessage :: Bool + , uiBlocked :: Maybe (UserName,String) + , uiGroups :: [String] + , uiRights :: [String] + , uiOptions :: [(String,String)] + , uiRateLimits :: [RateLimit] + , uiEditCount :: Maybe Int + } + +emptyUserInfo :: UserInfo +emptyUserInfo = UserInfo + { uiName = nullUser + , uiId = "0" + , uiIsAnon = True + , uiHasMessage = False + , uiBlocked = Nothing + , uiGroups = [] + , uiRights = [] + , uiOptions = [] + , uiRateLimits = [] + , uiEditCount = Nothing + } + +data RateLimit + = RateLimit + { rlName :: String + , rlHits :: Int + , rlSeconds :: Int + } + + +data NamespaceInfo + = NamespaceInfo + { nsId :: String + , nsTitle :: String + , nsSubpages :: Bool + } + +data InterwikiEntry + = InterwikiEntry + { iwPrefix :: String + , iwLocal :: Bool + , iwTranscludable :: Maybe Bool + , iwUrl :: String + , iwLanguage :: Maybe String + } + +data UserSession + = UserSession + { sessUserId :: UserID + , sessUserName :: UserName + , sessPassword :: Maybe Password -- not sure; could leave out. + , sessCookiePrefix :: Maybe String + , sessSessionId :: Maybe SessionID + , sessToken :: LoginToken + } + +data HelpRequest + = HelpRequest + { helpVersion :: Maybe Bool + } + +type Title = String -- Q: what kind of encoding/escaping can be assumed here? +type PageID = String -- numeric ID, so arguably wrong Haskell type. +type RevisionID = String -- ditto. + +newtype PropKind + = PropKind { prKind :: String } + {- Not deemed worthy to try to enumerate them all. + -- Three major reasons: + -- - supportd properties are likely to evolve with MW API. + -- - fields support subsets of the type, so using a union type + -- for these is imprecise. + -- - development of queries are driven by reading the API documentation + -- from the MW API help page, so transliterations ought to be + -- accommodated. + -- - being too lazy to write them out is not a reason; did + -- have such an enum type defined at one point :-) + -} + +newtype MetaKind + = MetaKind { meKind :: String } -- likely values: siteinfo, userinfo, allmessages + +newtype ListKind + = ListKind { liKind :: String } + +newtype GeneratorKind + = GeneratorKind { genKind :: String } + +class APIRequest a where + showReq :: a -> [Maybe (String,String)] + isPostable :: a -> Bool + isPostable _ = False + + queryKind :: a -> QueryKind + queryKind _ = QProp "" + + +data QueryKind + = QProp String | QMeta String | QList String | QGen String + deriving ( Eq ) + +data QueryRequest + = QueryRequest + { quTitles :: [Title] + , quPageIds :: [PageID] + , quRevIds :: [RevisionID] + , quProps :: [PropKind] + , quLists :: [ListKind] + , quMetas :: [MetaKind] + , quGenerator :: Maybe GeneratorKind + , quFollowRedirects :: Maybe Bool + , quIndexPageIds :: Maybe Bool + } + +emptyQuery :: QueryRequest +emptyQuery = QueryRequest + { quTitles = [] + , quPageIds = [] + , quRevIds = [] + , quProps = [] + , quLists = [] + , quMetas = [] + , quGenerator = Nothing + , quFollowRedirects = Nothing + , quIndexPageIds = Nothing + } +{- +data MetaKindProp + = SiteInfoProp + | UserInfoProp + | AllMessagesProp + | ExpandTemplatesProp + | ParseProp + | OpenSearchProp + | FeedWatchlistProp + | HelpProp + | ParamInfoProp + -}
+ MediaWiki/API/Utils.hs view
@@ -0,0 +1,94 @@+-------------------------------------------------------------------- +-- | +-- Module : MediaWiki.API.Utils +-- Description : MediaWiki API internal utility functions. +-- Copyright : (c) Sigbjorn Finne, 2008 +-- License : BSD3 +-- +-- Maintainer: Sigbjorn Finne <sof@forkIO.com> +-- Stability : provisional +-- Portability: portable +-- +-- MediaWiki API internal utility functions. +-- +-------------------------------------------------------------------- +module MediaWiki.API.Utils + ( module MediaWiki.API.Utils + , fromMaybe + ) where + +import Text.XML.Light as XML +import Data.Maybe +import Data.List +import Control.Monad + +import MediaWiki.Util.Codec.URLEncoder ( encodeString ) + +pNodes :: String -> [XML.Element] -> [XML.Element] +pNodes x es = filter ((nsName x ==) . elName) es + +pNode :: String -> [XML.Element] -> Maybe XML.Element +pNode x es = listToMaybe (pNodes x es) + +pLeaf :: String -> [XML.Element] -> Maybe String +pLeaf x es = strContent `fmap` pNode x es + +pAttr :: String -> XML.Element -> Maybe String +pAttr x e = lookup (nsName x) [ (k,v) | Attr k v <- elAttribs e ] + +pMany :: String -> (XML.Element -> Maybe a) -> [XML.Element] -> [a] +pMany p f es = mapMaybe f (pNodes p es) + +children :: XML.Element -> [XML.Element] +children e = onlyElems (elContent e) + +nsName :: String -> QName +nsName x = QName{qName=x,qURI=Nothing,qPrefix=Nothing} + +without :: [String] -> [XML.Attr] -> [XML.Attr] +without xs as = filter (\ a -> not (attrKey a `elem` qxs)) as + where + qxs = map nsName xs + +parseDoc :: (Element -> Maybe a) -> String -> Either (String,[{-error msg-}String]) a +parseDoc f s = + case parseXMLDoc s of + Nothing -> Left (s, ["not valid XML content"]) + Just d -> + case f d of + Nothing -> Left (s,["unexpected XML response"]) + Just x -> Right x + +xmlContinue :: String -> String -> Element -> Maybe String +xmlContinue tgName atName e = do + guard (elName e == nsName "query-continue") + let es1 = children e + p <- pNode tgName es1 + pAttr atName p + +mbDef :: a -> Maybe a -> Maybe a +mbDef x Nothing = Just x +mbDef _ v = v + +readMb :: Read a => String -> Maybe a +readMb x = case reads x of + ((v,_):_) -> Just v + _ -> Nothing + +piped :: [String] -> String +piped xs = intercalate "|" xs + +opt :: String -> String -> Maybe (String,String) +opt a b = Just (a, encodeString b) + +optB :: String -> Bool -> Maybe (String,String) +optB _ False = Nothing +optB a _ = Just (a,"") + +opt1 :: String -> [String] -> Maybe (String,String) +opt1 _ [] = Nothing +opt1 a b = Just (a,encodeString $ piped b) + +mbOpt :: String -> (a -> String) -> Maybe a -> Maybe (String,String) +mbOpt _ _ Nothing = Nothing +mbOpt tg f (Just x) = Just (tg,encodeString $ f x)
+ MediaWiki/Util/Codec/Percent.hs view
@@ -0,0 +1,59 @@+{- |+ + Module : MediaWiki.Util.Codec.Percent+ Copyright : (c) 2008++ Maintainer : sof@forkIO.com++ License : See the file LICENSE++ Status : Coded+ Stability : provisional+ portability : portable++ Codec for de/encoding URI strings via percent encodings+ (cf. RFC 3986.)+-}+module MediaWiki.Util.Codec.Percent where++import Data.Char ( chr, isAlphaNum )+import Numeric ( readHex, showHex )++getEncodedString :: String -> String+getEncodedString "" = ""+getEncodedString (x:xs) = + case getEncodedChar x of+ Nothing -> x : getEncodedString xs+ Just ss -> ss ++ getEncodedString xs++getDecodedString :: String -> String+getDecodedString "" = ""+getDecodedString ls@(x:xs) = + case getDecodedChar ls of+ Nothing -> x : getDecodedString xs+ Just (ch,xs1) -> ch : getDecodedString xs1++getEncodedChar :: Char -> Maybe String+getEncodedChar x+ | isAlphaNum x || + x `elem` "-_.~" = Nothing+ | xi < 0xff = Just ('%':showHex (xi `div` 16) (showHex (xi `mod` 16) ""))+ | otherwise = -- ToDo: import utf8 lib+ error "getEncodedChar: can only handle 8-bit chars right now."+ where+ xi :: Int+ xi = fromEnum x++getDecodedChar :: String -> Maybe (Char, String)+getDecodedChar str =+ case str of+ "" -> Nothing+ (x:xs) + | x /= '%' -> Nothing+ | otherwise -> do+ case xs of+ (b1:b2:bs) -> + case readHex [b1,b2] of+ ((v,_):_) -> Just (Data.Char.chr v, bs)+ _ -> Nothing+ _ -> Nothing
+ MediaWiki/Util/Codec/URLEncoder.hs view
@@ -0,0 +1,33 @@+{-+ Codec for de/encoding form data shipped in URL query strings+ or in POST request bodies. (application/x-www-form-urlencoded)+ (cf. RFC 3986.)+-}+module MediaWiki.Util.Codec.URLEncoder + ( encodeString+ , decodeString+ ) where++import qualified Codec.Binary.UTF8.String as UTF8 ( encodeString )+import MediaWiki.Util.Codec.Percent ( getEncodedChar, getDecodedChar )++encodeString :: String -> String+encodeString str = go (UTF8.encodeString str)+ where+ go "" = ""+ go (' ':xs) = '+':go xs+ go ('\r':'\n':xs) = '%':'0':'D':'%':'0':'A':go xs+ go ('\r':xs) = go ('\r':'\n':xs)+ go ('\n':xs) = go ('\r':'\n':xs)+ go (x:xs) = + case getEncodedChar x of+ Nothing -> x : go xs+ Just ss -> ss ++ go xs+ +decodeString :: String -> String+decodeString "" = ""+decodeString ('+':xs) = ' ':decodeString xs+decodeString ls@(x:xs) = + case getDecodedChar ls of+ Nothing -> x : decodeString xs+ Just (ch,xs1) -> ch : decodeString xs1
+ MediaWiki/Util/Fetch.hs view
@@ -0,0 +1,136 @@+-------------------------------------------------------------------- +-- | +-- Module : MediaWiki.Util.Fetch +-- Copyright : (c) Sigbjorn Finne, 2008 +-- License : BSD3 +-- +-- Maintainer: Sigbjorn Finne <sof@forkIO.com> +-- Stability : provisional +-- Portability: so-so +-- +-- Simple GET\/de-ref of URLs; abstracting out networking backend\/package. +-- +module MediaWiki.Util.Fetch + ( readContentsURL + , readUserContentsURL + + , postContentsURL + +-- , URLString + , User(..) + ) where + +--import Network.Curl +import Network.Browser +import Network.HTTP +import Network.URI + +type URLString = String + +data User + = User { userName :: String + , userPass :: String + } + +readContentsURL :: URLString -> IO String +readContentsURL u = do + req <- + case parseURI u of + Nothing -> fail ("ill-formed URL: " ++ u) + Just ur -> return (defaultGETRequest ur) + -- don't like doing this, but HTTP is awfully chatty re: cookie handling.. + let nullHandler _ = return () + (_u, resp) <- browse $ setOutHandler nullHandler >> request req + case rspCode resp of + (2,_,_) -> return (rspBody resp) + _ -> fail ("Failed reading URL " ++ show u ++ " code: " ++ show (rspCode resp)) + +{- Curl version: +readContentsURL :: URLString -> IO String +readContentsURL u = do + let opts = [ CurlFollowLocation True + ] + (_,xs) <- curlGetString u opts + return xs +-} + +readUserContentsURL :: User -> URLString -> IO String +readUserContentsURL usr us = do -- readContentsURL u + req <- + case parseURI us of + Nothing -> fail ("ill-formed URL: " ++ us) + Just ur -> return (defaultGETRequest ur) + -- don't like doing this, but HTTP is awfully chatty re: cookie handling.. + let nullHandler _ = return () + (u, resp) <- browse $ do + setOutHandler nullHandler + setAllowBasicAuth True + setAuthorityGen (\ _ _ -> return (Just (userName usr,userPass usr))) +{- + addAuthority AuthBasic{ auUsername = userName usr + , auPassword = userPass usr + , auRealm = "" + , auSite = nullURI{uriPath="/"} + } +-} + request req + case rspCode resp of + (2,_,_) -> return (rspBody resp) + _ -> fail ("Failed reading URL " ++ show u ++ " code: " ++ show (rspCode resp)) + + +postContentsURL :: Maybe User -> URLString -> [(String,String)] -> String -> IO ([(String,String)], String) +postContentsURL mbU u hdrs body = do + let hs = + case parseHeaders $ map (\ (x,y) -> x++": " ++ y) hdrs of + Left{} -> [] + Right xs -> xs + req0 <- + case parseURI u of + Nothing -> fail ("ill-formed URL: " ++ u) + Just ur -> return (defaultGETRequest ur) + let req = req0{rqMethod=POST + ,rqBody=body + ,rqHeaders=hs + } + let nullHandler _ = return () + (_,rsp) <- browse $ do + setOutHandler nullHandler + case mbU of + Nothing -> return () + Just usr -> do + setAllowBasicAuth True + setAuthorityGen (\ _ _ -> return (Just (userName usr,userPass usr))) + + request req + case rspCode rsp of + (2,_,_) -> return (map toP (rspHeaders rsp), rspBody rsp) + x -> fail ("POST failed - code: " ++ show x ++ ", URL: " ++ u) + where + toP (Header k v) = (show k, v) + +{- Curl versions: +readUserContentsURL :: User -> URLString -> IO String +readUserContentsURL u url = do + let opts = [ CurlHttpAuth [HttpAuthAny] + , CurlUserPwd (userName u ++ + case userPass u of {"" -> ""; p -> ':':p }) + , CurlFollowLocation True + ] + (_,xs) <- curlGetString url opts + return xs + +postContentsURL :: URLString -> [(String,String)] -> String -> IO String +postContentsURL u hdrs body = do + let opts = [ CurlCustomRequest "POST" + , CurlFollowLocation True + , CurlPost True + , CurlPostFields [body] + , CurlHttpTransferDecoding False + ] ++ [CurlHttpHeaders (map ( \ (x,y) -> (x ++ ':':y)) hdrs)] + rsp <- curlGetResponse u opts + case respStatus rsp `div` 100 of + 2 -> return (respBody rsp) + x -> fail ("POST failed - code: " ++ show x ++ ", URL: " ++ u) + +-}
+ Setup.hs view
@@ -0,0 +1,7 @@+module Main where + +import Distribution.Simple + + +main :: IO () +main = defaultMain
+ examples/ListCat.hs view
@@ -0,0 +1,133 @@+{- + Example of how to query for category members, demonstrating + the modules, types and steps used to interact with the API: + + foo$ listCat "Functional programming" + ... + foo$ +-} +module Main(main) where + +import MediaWiki.API.Base +import MediaWiki.API.Types ( PageTitle(..) ) +import MediaWiki.API +import MediaWiki.API.Query.CategoryMembers as CatMem +import MediaWiki.API.Query.CategoryMembers.Import as CatMem + +import Util.GetOpts +import System.IO +import System.Environment +import System.Exit + +import Control.Monad +--import Data.Maybe ( fromMaybe ) +import Data.List + +-- begin option handling +data Options + = Options + { optWiki :: String + , optUser :: Maybe String + , optPass :: Maybe String + , optCat :: Maybe String + } + +nullOptions :: Options +nullOptions = Options + { optWiki = "http://en.wikipedia.org/w/" + , optUser = Nothing + , optPass = Nothing + , optCat = Nothing + } + +option_descr :: [OptDescr (Options -> Options)] +option_descr = + [ Option ['u'] ["user"] + (ReqArg (\ x o -> o{optUser=Just x}) "USER") + "Wiki user name to login as" + , Option ['p'] ["pass"] + (ReqArg (\ x o -> o{optPass=Just x}) "PASSWORD") + "user's password credentials to supply if logging in" + , Option ['w'] ["wiki"] + (ReqArg (\ x o -> o{optWiki=x}) "WIKI") + "the Wiki to access" + , Option ['c'] ["cat"] + (ReqArg (\ x o -> o{optCat=Just x}) "CAT") + "the Wiki category to query for" + ] + + +parseOptions :: [String] -> (Options, [String], [String]) +parseOptions argv = getOpt2 Permute option_descr argv nullOptions + +processOptions :: IO (Options, [String]) +processOptions = do + ls <- getArgs + let (opts, ws, es) = parseOptions ls + when (not $ null es) $ do + hPutStrLn stderr (unlines es) + hPutStrLn stderr ("(try '--help' for list of options supported.)") + exitFailure + return (opts, ws) + +-- end option handling + +queryCat :: URLString -> String -> IO [PageTitle] +queryCat url catName = queryCat' url catName' req [] + where + catName' + | "Category:" `isPrefixOf` catName = wikify catName + | otherwise = "Category:"++wikify catName + + req = categoryMembersRequest{cmTitle=Just catName'} + + wikify "" = "" + wikify (' ':xs) = '_':wikify xs + wikify (x:xs) = x : wikify xs + + +queryCat' :: URLString -> String -> CategoryMembersRequest -> [PageTitle] -> IO [PageTitle] +queryCat' url catName cReq acc = do + let req = emptyXmlRequest (mkQueryAction (queryPage catName) cReq) + mb <- webGetXml CatMem.stringXml url req + case mb of + Nothing -> fail ("Failed to fetch pages for category " ++ catName ++ " from " ++ url) + Just c -> do + let acc' = (acc ++ cmPages c) + case cmContinue c of + Nothing -> return acc' + Just x -> queryCat' url catName cReq{cmContinueFrom=Just x} acc' + +main :: IO () +main = do + (opts, fs) <- processOptions + let url = optWiki opts + -- not needed here, but left in to show how to login to a Wiki. + case (optUser opts, optPass opts) of + (Just u, Just p) -> do + x <- loginWiki url u p + case x of + Nothing -> putStrLn ("Unable to login to: " ++ url) + Just lg -> print (lgSuccess lg) + _ -> return () + case mbCons (optCat opts) fs of + [] -> putStrLn "No categories specified!" + xs -> mapM_ (showCat url) xs + +showCat :: URLString -> String -> IO () +showCat url cat = do + ps <- queryCat url cat + putStrLn ("Members of category `" ++ cat ++ "'") + mapM_ (putStrLn.toTitle) ps + where + toTitle pg = ' ':pgTitle pg +{- NS prefix seems to be included in title.. + case pgNS pg of + "" -> pgTitle pg + xs -> xs ++ ':':pgTitle pg +-} + +mbCons :: Maybe a -> [a] -> [a] +mbCons Nothing xs = xs +mbCons (Just x) xs = x:xs +
+ mediawiki.cabal view
@@ -0,0 +1,123 @@+Name: mediawiki +Version: 0.2 +License: BSD3 +License-file: LICENSE +Category: Web +Synopsis: Interfacing with the MediaWiki API +Description: A complete Haskell binding to the MediaWiki API +Author: Sigbjorn Finne <sof@forkIO.com> +Maintainer: Sigbjorn Finne <sof@forkIO.com> +Cabal-version: >= 1.2 +build-type: Simple + +flag new-base + description: Build with new smaller base library + default: False + +library + Exposed-Modules: MediaWiki.API.Types, + MediaWiki.API.Output, + MediaWiki.API, + MediaWiki.API.Base, + MediaWiki.API.Utils, + MediaWiki.API.Query.AllCategories, + MediaWiki.API.Query.AllCategories.Import, + MediaWiki.API.Query.AllImages, + MediaWiki.API.Query.AllImages.Import, + MediaWiki.API.Query.AllLinks, + MediaWiki.API.Query.AllLinks.Import, + MediaWiki.API.Query.AllMessages, + MediaWiki.API.Query.AllMessages.Import, + MediaWiki.API.Query.AllPages, + MediaWiki.API.Query.AllPages.Import, + MediaWiki.API.Query.AllUsers, + MediaWiki.API.Query.AllUsers.Import, + MediaWiki.API.Query.BackLinks, + MediaWiki.API.Query.BackLinks.Import, + MediaWiki.API.Query.Blocks, + MediaWiki.API.Query.Blocks.Import, + MediaWiki.API.Query.Categories, + MediaWiki.API.Query.Categories.Import, + MediaWiki.API.Query.CategoryInfo, + MediaWiki.API.Query.CategoryInfo.Import, + MediaWiki.API.Query.CategoryMembers, + MediaWiki.API.Query.CategoryMembers.Import, + MediaWiki.API.Query.DeletedRevisions, + MediaWiki.API.Query.DeletedRevisions.Import, + MediaWiki.API.Query.EmbeddedIn, + MediaWiki.API.Query.EmbeddedIn.Import, + MediaWiki.API.Query.ExternalLinks + MediaWiki.API.Query.ExternalLinks.Import, + MediaWiki.API.Query.ExternalURLUsage + MediaWiki.API.Query.ExternalURLUsage.Import, + MediaWiki.API.Query.ImageInfo, + MediaWiki.API.Query.ImageInfo.Import, + MediaWiki.API.Query.Images, + MediaWiki.API.Query.Images.Import, + MediaWiki.API.Query.ImageUsage, + MediaWiki.API.Query.ImageUsage.Import, + MediaWiki.API.Query.Info, + MediaWiki.API.Query.Info.Import, + MediaWiki.API.Query.LangLinks, + MediaWiki.API.Query.LangLinks.Import, + MediaWiki.API.Query.Links, + MediaWiki.API.Query.Links.Import, + MediaWiki.API.Query.LogEvents, + MediaWiki.API.Query.LogEvents.Import, + MediaWiki.API.Query.Random, + MediaWiki.API.Query.Random.Import, + MediaWiki.API.Query.RecentChanges, + MediaWiki.API.Query.RecentChanges.Import, + MediaWiki.API.Query.Revisions, + MediaWiki.API.Query.Revisions.Import, + MediaWiki.API.Query.Search, + MediaWiki.API.Query.Search.Import, + MediaWiki.API.Query.SiteInfo, + MediaWiki.API.Query.SiteInfo.Import, + MediaWiki.API.Query.Templates, + MediaWiki.API.Query.Templates.Import, + MediaWiki.API.Query.UserContribs, + MediaWiki.API.Query.UserContribs.Import, + MediaWiki.API.Query.UserInfo, + MediaWiki.API.Query.UserInfo.Import, + MediaWiki.API.Query.Users, + MediaWiki.API.Query.Users.Import, + MediaWiki.API.Query.WatchList, + MediaWiki.API.Query.WatchList.Import, + MediaWiki.API.Action.Sitematrix, + MediaWiki.API.Action.Login, + MediaWiki.API.Action.Login.Import, + MediaWiki.API.Action.ParamInfo, + MediaWiki.API.Action.Parse, + MediaWiki.API.Action.Parse.Import, + MediaWiki.API.Action.Rollback, + MediaWiki.API.Action.Delete, + MediaWiki.API.Action.Undelete, + MediaWiki.API.Action.Protect, + MediaWiki.API.Action.Block, + MediaWiki.API.Action.Unblock, + MediaWiki.API.Action.Move, + MediaWiki.API.Action.Edit, + MediaWiki.API.Action.EmailUser, + MediaWiki.API.Action.Watch, + MediaWiki.API.Action.OpenSearch, + MediaWiki.API.Action.FeedWatchlist, + MediaWiki.API.Action.ExpandTemplates, + MediaWiki.API.Action.ExpandTemplates.Import, + MediaWiki.Util.Fetch, + MediaWiki.Util.Codec.Percent, + MediaWiki.Util.Codec.URLEncoder + Ghc-Options: -Wall -O2 + Build-Depends: base, xml, HTTP, network, mime, utf8-string + +executable main { + build-depends: base + main-is: Main.hs + ghc-options: -Wall -fglasgow-exts +} + +executable listCat { + build-depends: base, pretty + main-is: examples/ListCat.hs + ghc-options: -Wall -fglasgow-exts -iexamples +}