X-Git-Url: http://git.cielonegro.org/gitweb.cgi?a=blobdiff_plain;f=Rakka%2FStorage%2FRepos.hs;h=e1f4b8e24049cab6d564666974328d948f1f4bf4;hb=0447be1b59496ca4266226ed52d264009cf41899;hp=0b53568b4290e9b0d433d71a291fbf1fec9b35d1;hpb=743f4a87fd557832ce67d6eb51749582820577c4;p=Rakka.git diff --git a/Rakka/Storage/Repos.hs b/Rakka/Storage/Repos.hs index 0b53568..e1f4b8e 100644 --- a/Rakka/Storage/Repos.hs +++ b/Rakka/Storage/Repos.hs @@ -3,9 +3,11 @@ module Rakka.Storage.Repos , findChangedPagesAtRevision , loadPageInRepository , putPageIntoRepository + , deletePageFromRepository ) where +import Codec.Binary.UTF8.String import Control.Exception import Control.Monad import Data.List @@ -101,12 +103,12 @@ loadPageInRepository repos name rev path = mkPagePath name loadPage' :: Rev Page - loadPage' = do redirect <- getNodeProp path "rakka:redirect" - case redirect of - Nothing - -> loadPageEntity - Just _ + loadPage' = do mType <- liftM (fmap (read . chomp)) (getNodeProp path "svn:mime-type") + case mType of + Just (MIMEType "application" "x-rakka-redirection" _) -> loadPageRedirect + _ + -> loadPageEntity loadPageEntity :: Rev Page loadPageEntity @@ -126,11 +128,9 @@ loadPageInRepository repos name rev entityName = name , entityType = mimeType , entityLanguage = fmap chomp (lookup "rakka:lang" props) - , entityFileName = fmap chomp (lookup "rakka:fileName" props) , entityIsTheme = any ((== "rakka:isTheme") . fst) props , entityIsFeed = any ((== "rakka:isFeed") . fst) props , entityIsLocked = any ((== "rakka:isLocked") . fst) props - , entityIsBoring = any ((== "rakka:isBoring") . fst) props , entityIsBinary = case mimeType of MIMEType "text" _ _ -> any ((== "rakka:isBinary") . fst) props @@ -148,40 +148,86 @@ loadPageInRepository repos name rev } loadPageRedirect :: Rev Page - loadPageRedirect = fail "FIXME: loadPageRedirect: not implemented" + loadPageRedirect + = do hist <- getNodeHistory True path + content <- getFileContents path + + let pageRev = fst $ head hist + dest = chomp $ decodeString content + + lastMod <- getRevisionProp "svn:date" + >>= return . fromJust . parseW3CDateTime . chomp . fromJust + + isLocked <- getRevisionProp "rakka:isLocked" + >>= return . isJust + return Redirection { + redirName = name + , redirDest = dest + , redirIsLocked = isLocked + , redirRevision = pageRev + , redirLastMod = zonedTimeToUTC lastMod + , redirUpdateInfo = undefined + } -putPageIntoRepository :: Repository -> Page -> IO StatusCode -putPageIntoRepository repos page + +putPageIntoRepository :: Repository -> Maybe String -> Page -> IO StatusCode +putPageIntoRepository repos userID page = filterSvnError $ - do let name = pageName page - ret <- case pageUpdateInfo page of - Just ui - -> doReposTxn - repos - (uiOldRevision ui) - "[Rakka]" - (Just "Automatic commit by Rakka for page update") - $ do case uiOldName ui of - Nothing -> return () - Just oldName -> renamePage oldName name - updatePage name - Nothing - -> do fs <- getRepositoryFS repos - rev <- getYoungestRev fs - doReposTxn repos - rev - "[Rakka]" - (Just "Automatic commit by Rakka for page creation") - $ do createPage name - updatePage name - case ret of - Left _ -> return Conflict - Right _ -> return Created + do let name = pageName page + author = fromMaybe "[Rakka]" userID + case pageUpdateInfo page of + Just ui + -> do let oldRev = uiOldRevision ui + denied <- case uiOldName ui of + Nothing -> checkDenial oldRev name + Just oldName -> checkDenial oldRev oldName + if denied then + return Forbidden + else + do ret <- doReposTxn + repos + (uiOldRevision ui) + author + (Just "Automatic commit by Rakka for page update") + $ do case uiOldName ui of + Nothing -> return () + Just oldName -> renamePage (uiOldRevision ui) oldName name + updatePage name + case ret of + Left _ -> return Conflict + Right _ -> return Created + Nothing + -> do fs <- getRepositoryFS repos + rev <- getYoungestRev fs + ret <- doReposTxn + repos + rev + author + (Just "Automatic commit by Rakka for page creation") + $ do createPage name + updatePage name + case ret of + Left _ -> return Conflict + Right _ -> return Created where - renamePage :: PageName -> PageName -> Txn () - renamePage oldName newName - = fail "FIXME: renamePage: not implemented yet" + checkDenial :: RevNum -> PageName -> IO Bool + checkDenial rev name + = do fs <- getRepositoryFS repos + withRevision fs rev + $ do prop <- getNodeProp (mkPagePath name) "rakka:isLocked" + case prop of + Just _ -> return (isNothing userID) -- 施錠されてゐるので匿名では駄目 + Nothing -> return False + + renamePage :: RevNum -> PageName -> PageName -> Txn () + renamePage oldRev oldName newName + = do let oldPath = mkPagePath oldName + newPath = mkPagePath newName + createParentDirectories newPath + copyEntry oldRev oldPath newPath + deleteEntry oldPath + deleteEmptyParentDirectories oldPath createPage :: PageName -> Txn () createPage name @@ -189,16 +235,6 @@ putPageIntoRepository repos page createParentDirectories path makeFile path - createParentDirectories :: FilePath -> Txn () - createParentDirectories path - = do let parentPath = takeDirectory path - kind <- checkPath parentPath - case kind of - NoNode -> do createParentDirectories parentPath - makeDirectory parentPath - FileNode -> fail ("createParentDirectories: already exists a file: " ++ parentPath) - DirNode -> return () - updatePage :: PageName -> Txn () updatePage name | isRedirect page = updatePageRedirect name @@ -207,18 +243,25 @@ putPageIntoRepository repos page updatePageRedirect :: PageName -> Txn () updatePageRedirect name - = fail "FIXME: updatePageRedirect: not implemented yet" + = do let path = mkPagePath name + setNodeProp path "svn:mime-type" (Just "application/x-rakka-redirection") + setNodeProp path "rakka:lang" Nothing + setNodeProp path "rakka:isTheme" Nothing + setNodeProp path "rakka:isFeed" Nothing + setNodeProp path "rakka:isLocked" (encodeFlag $ redirIsLocked page) + setNodeProp path "rakka:isBinary" Nothing + setNodeProp path "rakka:summary" Nothing + setNodeProp path "rakka:otherLang" Nothing + applyText path Nothing (encodeString (redirDest page) ++ "\n") updatePageEntity :: PageName -> Txn () updatePageEntity name = do let path = mkPagePath name setNodeProp path "svn:mime-type" ((Just . show . entityType) page) setNodeProp path "rakka:lang" (entityLanguage page) - setNodeProp path "rakka:fileName" (entityFileName page) setNodeProp path "rakka:isTheme" (encodeFlag $ entityIsTheme page) setNodeProp path "rakka:isFeed" (encodeFlag $ entityIsFeed page) setNodeProp path "rakka:isLocked" (encodeFlag $ entityIsLocked page) - setNodeProp path "rakka:isBoring" (encodeFlag $ entityIsBoring page) setNodeProp path "rakka:isBinary" (encodeFlag $ entityIsBinary page) setNodeProp path "rakka:summary" (entitySummary page) setNodeProp path "rakka:otherLang" (let otherLang = entityOtherLang page @@ -230,10 +273,62 @@ putPageIntoRepository repos page applyTextLBS path Nothing (entityContent page) encodeFlag :: Bool -> Maybe String - encodeFlag True = Just "*\n" + encodeFlag True = Just "*" encodeFlag False = Nothing +createParentDirectories :: FilePath -> Txn () +createParentDirectories path + = do let parentPath = takeDirectory path + kind <- checkPath parentPath + case kind of + NoNode -> do createParentDirectories parentPath + makeDirectory parentPath + FileNode -> fail ("createParentDirectories: already exists a file: " ++ parentPath) + DirNode -> return () + + +deletePageFromRepository :: Repository -> Maybe String -> PageName -> IO StatusCode +deletePageFromRepository repos userID name + = filterSvnError $ + do let path = mkPagePath name + fs <- getRepositoryFS repos + rev <- getYoungestRev fs + status <- withRevision fs rev + $ do exists <- isFile path + if exists then + do prop <- getNodeProp path "rakka:isLocked" + return $ case prop of + Just _ + -> if isNothing userID then + -- 施錠されてゐるので匿名では駄目 + Forbidden + else + NoContent + Nothing + -> NoContent + else + return NotFound + when (status == NoContent) + $ do doReposTxn repos + rev + "[Rakka]" + (Just "Automatic commit by Rakka for page deleting") + $ do deleteEntry path + deleteEmptyParentDirectories path + return () + return status + + +deleteEmptyParentDirectories :: FilePath -> Txn () +deleteEmptyParentDirectories path + = do let parentPath = takeDirectory path + contents <- getDirEntries parentPath + when (null contents) + $ do deleteEntry parentPath + deleteEmptyParentDirectories parentPath + + filterSvnError :: IO a -> IO a filterSvnError f = catchDyn f rethrow where