X-Git-Url: http://git.cielonegro.org/gitweb.cgi?a=blobdiff_plain;f=Rakka%2FResource%2FPageEntity.hs;h=c805ae5fe9af0ec4f44152c8a7e2278523ecb7a8;hb=88747f2463963ff2895a597b3054b12b2288530e;hp=0b5459447419ffab669650e8f08f5bd1c6abe381;hpb=b101c0a9aad609704eaa9157fe809be80d2aacf7;p=Rakka.git diff --git a/Rakka/Resource/PageEntity.hs b/Rakka/Resource/PageEntity.hs index 0b54594..c805ae5 100644 --- a/Rakka/Resource/PageEntity.hs +++ b/Rakka/Resource/PageEntity.hs @@ -2,16 +2,14 @@ module Rakka.Resource.PageEntity ( fallbackPageEntity ) where - -import Control.Arrow -import Control.Arrow.ArrowIO -import Control.Arrow.ArrowIf -import Control.Arrow.ArrowList import Control.Monad.Trans +import qualified Data.ByteString.Lazy as L hiding (ByteString) import Data.Char +import qualified Data.Map as M import Data.Maybe +import Data.Time +import qualified Data.Time.W3C as W3C import Network.HTTP.Lucu -import Network.HTTP.Lucu.Utils import Network.URI hiding (path) import Rakka.Environment import Rakka.Page @@ -20,51 +18,46 @@ import Rakka.Storage import Rakka.SystemConfig import Rakka.Utils import Rakka.Wiki.Engine -import System.FilePath -import Text.XML.HXT.Arrow.Namespace -import Text.XML.HXT.Arrow.WriteDocument -import Text.XML.HXT.Arrow.XmlArrow -import Text.XML.HXT.Arrow.XmlIOStateArrow -import Text.XML.HXT.Arrow.XmlNodeSet -import Text.XML.HXT.DOM.TypeDefs -import Text.XML.HXT.DOM.XmlKeywords +import System.FilePath.Posix +import Text.HyperEstraier hiding (getText) +import Text.XML.HXT.XPath fallbackPageEntity :: Environment -> [String] -> IO (Maybe ResourceDef) fallbackPageEntity env path - | null path = return Nothing - | null $ head path = return Nothing - | isLower $ head $ head path = return Nothing -- 先頭の文字が小文字であってはならない + | null name = return Nothing + | isLower $ head name = return Nothing -- 先頭の文字が小文字であってはならない | otherwise = return $ Just $ ResourceDef { resUsesNativeThread = False , resIsGreedy = True - , resGet = Just $ handleGet env (toPageName path) + , resGet = Just $ handleGet env name , resHead = Nothing , resPost = Nothing - , resPut = Just $ handlePut env (toPageName path) - , resDelete = Just $ handleDelete env (toPageName path) + , resPut = Just $ handlePut env name + , resDelete = Just $ handleDelete env name } where - toPageName :: [String] -> PageName - toPageName = decodePageName . dropExtension . joinWith "/" + name :: PageName + name = (dropExtension . UTF8.decodeString . joinPath) path handleGet :: Environment -> PageName -> Resource () handleGet env name - = runIdempotentA $ proc () - -> do pageM <- getPageA (envStorage env) -< (name, Nothing) - case pageM of - Nothing - -> do items <- getDirContentsA (envStorage env) -< (name, Nothing) - case items of - [] -> handlePageNotFound env -< name - _ -> handleGetPageListing env -< (name, items) - Just page - -> if isEntity page then - handleGetEntity env -< page - else - handleRedirect env -< page + = do BaseURI baseURI <- getSysConf (envSysConf env) + runIdempotentA baseURI $ proc () + -> do pageM <- getPageA (envStorage env) -< (name, Nothing) + case pageM of + Nothing + -> do items <- getDirContentsA (envStorage env) -< (name, Nothing) + case items of + [] -> handlePageNotFound env -< name + _ -> handleGetPageListing env -< (name, items) + Just page + -> if isEntity page then + handleGetEntity env -< page + else + handleRedirect env -< page {- @@ -76,14 +69,6 @@ handleRedirect env = proc redir -> returnA -< do mType <- getEntityType case mType of - MIMEType "application" "xhtml+xml" _ - -> do BaseURI baseURI <- getSysConf (envSysConf env) - let uri = mkPageFragmentURI - baseURI - (redirDest redir) - ("Redirect:" ++ redirName redir) - redirect Found uri - MIMEType "text" "xml" _ -> do setContentType mType [resultStr] <- liftIO $ runX ( setErrorMsgHandler False fail @@ -92,28 +77,27 @@ handleRedirect env >>> xmlizePage >>> - writeDocumentToString [ (a_indent, v_1) ] + writeDocumentToString [ (a_indent , v_1 ) + , (a_output_encoding, utf8) + , (a_no_xml_pi , v_0 ) ] ) output resultStr - _ -> fail ("internal error: getEntityType returned " ++ show mType) + _ -> do BaseURI baseURI <- getSysConf (envSysConf env) + let uri = mkPageFragmentURI + baseURI + (redirDest redir) + ("Redirect:" ++ redirName redir) + redirect Found uri handleGetEntity :: (ArrowXml a, ArrowChoice a, ArrowIO a) => Environment -> a Page (Resource ()) handleGetEntity env = proc page -> do tree <- xmlizePage -< page - returnA -< do -- text/x-rakka の場合は、内容が動的に生成され - -- てゐる可能性があるので、ETag も - -- Last-Modified も返す事が出來ない。 - case entityType page of - MIMEType "text" "x-rakka" _ - -> return () - _ -> case entityRevision page of - 0 -> foundTimeStamp (entityLastMod page) -- 0 はデフォルトページ - rev -> foundEntity (strongETag $ show rev) (entityLastMod page) - - outputXmlPage tree (entityToXHTML env) + returnA -< outputXmlPage tree [ (MIMEType "application" "xhtml+xml" [], entityToXHTML env) + , (MIMEType "application" "rss+xml" [], entityToRSS env) + ] entityToXHTML :: (ArrowXml a, ArrowChoice a, ArrowIO a) => Environment -> a XmlTree XmlTree @@ -140,7 +124,7 @@ entityToXHTML env += sattr "xmlns" "http://www.w3.org/1999/xhtml" += ( getXPathTreesInDoc "/page/@lang" `guards` - qattr (QN "xml" "lang" "") + qattr (mkQName "xml" "lang" "") ( getXPathTreesInDoc "/page/@lang/text()" ) ) += ( eelem "head" @@ -156,6 +140,7 @@ entityToXHTML env += sattr "type" "text/css" += attr "href" (arr id >>> mkText) ) + += mkFeedList env += ( constL scriptSrc >>> eelem "script" @@ -168,6 +153,7 @@ entityToXHTML env += txt ("Rakka.isLocked=" ++ trueOrFalse isLocked ++ ";") += txt ("Rakka.isGlobalLocked=" ++ trueOrFalse isGLocked ++ ";") ) + += mkGlobalJSList env ) += ( eelem "body" += ( eelem "div" @@ -207,15 +193,129 @@ entityToXHTML env ) ) -<< page +entityToRSS :: (ArrowXml a, ArrowChoice a, ArrowIO a) => Environment -> a XmlTree XmlTree +entityToRSS env + = proc page + -> do SiteName siteName <- getSysConfA (envSysConf env) -< () + BaseURI baseURI <- getSysConfA (envSysConf env) -< () + + name <- (getXPathTreesInDoc "/page/@name/text()" >>> getText) -< page + summary <- maybeA (getXPathTreesInDoc "/page/summary/text()" >>> getText) -< page + pages <- makePageLinkList (envStorage env) (envSysConf env) (envInterpTable env) -< page + + ( eelem "/" + += ( eelem "rdf:RDF" + += sattr "xmlns" "http://purl.org/rss/1.0/" + += sattr "xmlns:rdf" "http://www.w3.org/1999/02/22-rdf-syntax-ns#" + += sattr "xmlns:dc" "http://purl.org/dc/elements/1.1/" + += sattr "xmlns:trackback" "http://madskills.com/public/xml/rss/module/trackback/" + += ( eelem "channel" + += sattr "rdf:about" (uriToString id (mkFeedURI baseURI name) "") + += ( eelem "title" + += txt siteName + += txt " - " + += getXPathTreesInDoc "/page/@name/text()" + ) + += ( eelem "link" + += txt (uriToString id baseURI "") + ) + += ( eelem "description" + += txt (case summary of + Nothing -> "RSS Feed for " ++ siteName + Just s -> s) + ) + += ( eelem "items" + += ( eelem "rdf:Seq" + += ( constL pages + >>> + eelem "rdf:li" + += attr "resource" (arr (mkPageURIStr baseURI) >>> mkText) + ) + ) + ) + ) + += ( constL pages + >>> + arr (\ n -> (n, Nothing)) + >>> + getPageA (envStorage env) + >>> + arr fromJust + >>> + eelem "item" + += attr "rdf:about" (arr (mkPageURIStr baseURI . entityName) >>> mkText) + += ( eelem "title" + += (arr entityName >>> mkText) + ) + += ( eelem "link" + += (arr (mkPageURIStr baseURI . entityName) >>> mkText) + ) + += ( arrL (\ p -> case entitySummary p of + Nothing -> [] + Just s -> [s]) + >>> + eelem "description" + += mkText + ) + += ( eelem "dc:date" + += ( arrIO (utcToLocalZonedTime . entityLastMod) + >>> + arr W3C.format + >>> + mkText + ) + ) + += ( eelem "trackback:ping" + += attr "rdf:resource" (arr (mkTrackbackURIStr baseURI . entityName) >>> mkText) + ) + ) + >>> + uniqueNamespacesFromDeclAndQNames + ) ) -<< page + where + mkPageURIStr :: URI -> PageName -> String + mkPageURIStr baseURI name + = uriToString id (mkPageURI baseURI name) "" + + mkTrackbackURIStr :: URI -> PageName -> String + mkTrackbackURIStr baseURI name + = uriToString id (mkAuxiliaryURI baseURI ["trackback"] name) "" + + readSubPage :: (ArrowXml a, ArrowChoice a, ArrowIO a) => Environment -> a (PageName, Maybe XmlTree, PageName) XmlTree readSubPage env = proc (mainPageName, mainPage, subPageName) -> - do subPage <- getPageA (envStorage env) >>> arr fromJust >>> xmlizePage -< (subPageName, Nothing) - subXHTML <- makeSubXHTML (envStorage env) (envSysConf env) (envInterpTable env) - -< (mainPageName, mainPage, subPage) + do langM <- case mainPage of + Nothing + -> returnA -< Nothing + Just p + -> maybeA (getXPathTreesInDoc "/page/@lang/text()" >>> getText) -< p + subPage <- getPageA (envStorage env) >>> arr fromJust -< (subPageName, Nothing) + localSubPage <- case langM of + Nothing + -> returnA -< subPage + Just l + -> localize (envStorage env) -< (l, subPage) + subPageXml <- xmlizePage -< localSubPage + subXHTML <- makeSubXHTML (envStorage env) (envSysConf env) (envInterpTable env) + -< (Just mainPageName, mainPage, subPageXml) returnA -< subXHTML + where + localize :: (ArrowChoice a, ArrowIO a) => Storage -> a (LanguageTag, Page) Page + localize sto + = proc (lang, origPage) + -> do let otherLang = entityOtherLang origPage + localName = M.lookup lang otherLang + case localName of + Nothing + -> returnA -< origPage + Just ln + -> do localPage <- getPageA sto -< (ln, Nothing) + returnA -< case localPage of + Nothing -> origPage + Just p -> p {- @@ -238,7 +338,7 @@ handleGetPageListing env ) ) ) -< (dir, items) - returnA -< outputXmlPage tree (pageListingToXHTML env) + returnA -< outputXmlPage' tree (pageListingToXHTML env) -- FIXME: rss 對應 pageListingToXHTML :: (ArrowXml a, ArrowChoice a, ArrowIO a) => Environment -> a XmlTree XmlTree @@ -274,6 +374,7 @@ pageListingToXHTML env += sattr "type" "text/css" += attr "href" (arr id >>> mkText) ) + += mkFeedList env += ( constL scriptSrc >>> eelem "script" @@ -285,6 +386,7 @@ pageListingToXHTML env += txt ("Rakka.baseURI = \"" ++ uriToString id baseURI "" ++ "\";") += txt ("Rakka.isGlobalLocked=" ++ trueOrFalse isGLocked ++ ";") ) + += mkGlobalJSList env ) += ( eelem "body" += ( eelem "div" @@ -350,7 +452,7 @@ handlePageNotFound env ) ) -< name returnA -< do setStatus NotFound - outputXmlPage tree (notFoundToXHTML env) + outputXmlPage' tree (notFoundToXHTML env) notFoundToXHTML :: (ArrowXml a, ArrowChoice a, ArrowIO a) => Environment -> a XmlTree XmlTree @@ -386,6 +488,7 @@ notFoundToXHTML env += sattr "type" "text/css" += attr "href" (arr id >>> mkText) ) + += mkFeedList env += ( constL scriptSrc >>> eelem "script" @@ -397,6 +500,7 @@ notFoundToXHTML env += txt ("Rakka.baseURI = \"" ++ uriToString id baseURI "" ++ "\";") += txt ("Rakka.isGlobalLocked=" ++ trueOrFalse isGLocked ++ ";") ) + += mkGlobalJSList env ) += ( eelem "body" += ( eelem "div" @@ -450,3 +554,72 @@ handleDelete env name = do userID <- getUserID env status <- deletePage (envStorage env) userID name setStatus status + + +mkFeedList :: (ArrowIO a, ArrowXml a) => Environment -> a b XmlTree +mkFeedList env + = proc _ -> do SiteName siteName <- getSysConfA (envSysConf env) -< () + BaseURI baseURI <- getSysConfA (envSysConf env) -< () + + feed <- unlistA <<< arrIO0 (findFeeds $ envStorage env) -< () + + ( eelem "link" + += sattr "rel" "alternate" + += sattr "type" "application/rss+xml" + += attr "title" (txt siteName <+> txt " - " <+> mkText) + += attr "href" (arr (mkFeedURIStr baseURI) >>> mkText) ) -<< feed + + +findFeeds :: Storage -> IO [PageName] +findFeeds sto + = do cond <- newCondition + setPhrase cond "[UVSET]" + addAttrCond cond "rakka:isFeed STREQ yes" + setOrder cond "@uri STRA" + result <- searchPages sto cond + return (map hpPageName $ srPages result) + + +mkGlobalJSList :: (ArrowIO a, ArrowXml a, ArrowChoice a) => Environment -> a b XmlTree +mkGlobalJSList env + = proc _ -> do BaseURI baseURI <- getSysConfA (envSysConf env) -< () + + scriptName <- unlistA <<< arrIO0 (findJavaScripts $ envStorage env) -< () + pageM <- getPageA (envStorage env) -< (scriptName, Nothing) + + case pageM of + Nothing -> none -< () + Just page + | isEntity page + -> ( if entityIsBinary page then + ( eelem "script" + += sattr "type" "text/javascript" + += attr "src" (arr (mkObjectURIStr baseURI . pageName) >>> mkText) ) + else + ( eelem "script" + += sattr "type" "text/javascript" + += (arr (UTF8.decode . L.unpack . entityContent) >>> mkText) ) + ) -<< page + | otherwise + -> none -< () + + +findJavaScripts :: Storage -> IO [PageName] +findJavaScripts sto + = do cond <- newCondition + setPhrase cond "[UVSET]" + addAttrCond cond "@title STRBW Global/" + addAttrCond cond "@type STRBW text/javascript" + setOrder cond "@uri STRA" + result <- searchPages sto cond + return (map hpPageName $ srPages result) + + +mkFeedURIStr :: URI -> PageName -> String +mkFeedURIStr baseURI name + = uriToString id (mkFeedURI baseURI name) "" + + +mkObjectURIStr :: URI -> PageName -> String +mkObjectURIStr baseURI name + = uriToString id (mkObjectURI baseURI name) ""