module Kirschbaum.Action.CreateThread ( resCreateThread ) where import Control.Arrow import Data.Maybe import Kirschbaum.Board import Kirschbaum.Env import Kirschbaum.Site import Kirschbaum.Thread import Kirschbaum.Utils import Kirschbaum.XmlResource import Network.HTTP.Lucu import Network.URI import System.FilePath.Posix import Text.XML.HXT.Arrow.XmlArrow import Text.XML.HXT.Arrow.XmlNodeSet import Text.XML.HXT.DOM.TypeDefs {- * 入力 blah blah... blah blah blah... ABRACADABRA BRACADABR RACADAB ACADA CAD A 3600 ... * 出力 (成功時) HTTP/1.1 201 Created Location: http://.../-/haskell/238502384.xml * 出力 (失敗時) HTTP/1.1 403 Forbidden You have already created too many threads. -} {- MySQL に直接触ってゐるのでない以上、boardId が不正だった事を檢出する 爲に一旦 INSERT してみてエラーコードを確認する事は出來ない。だから板 が實在するかどうかは事前に確かめる必要がある。しかしロック方法を制御 する事は出來ないので、もしトランザクションの最中に他のスレッドが板を 消すと…? 多分 COMMIT 時に外部キーエラーになりさう。それを防ぐ爲だ けに SELECT で良い所を UPDATE する手も無いわけではないが、汚ないハッ クだと思ふ。Haskell のコードには相應しくない。 -} resCreateThread :: Env -> ResourceDef resCreateThread env = ResourceDef { resUsesNativeThread = False , resIsGreedy = True , resGet = Nothing , resHead = Nothing , resPost = Just $ do extraPath <- getPathInfo case extraPath of [boardId] -> handleCreateThread env (dropExtension boardId) _ -> foundNoEntity Nothing , resPut = Nothing , resDelete = Nothing } handleCreateThread :: Env -> String -> Resource () handleCreateThread env boardId = runXmlTxA env "static/rng/local/createThread.rng" $ proc ctx -> do let db = ctxDB ctx tree = ctxInput ctx redirectToOwner -< (db, (boardId, makeNewURI ctx)) title <- (getXPathTreesInDoc "/createThread/title/text()" >>> getText) -< tree name <- maybeA (getXPathTreesInDoc "/createThread/name/text()" >>> getText >>> deleteIfEmpty) -< tree body <- (getXPathTreesInDoc "/createThread/body/text()" >>> getText >>> filterNewLines) -< tree -- FIXME: 眞面目に let req = PostReq { postReqName = fromMaybe "名無しさん" name , postReqBody = body , postReqFpr = Nothing , postReqIpAddr = "0.0.0.0" , postReqIsAdmin = False , postReqIsExposed = False , postReqIsSilent = False } boardInfo <- getBoardInfo -< (db, boardId) case boardInfo of {- FIXME: スレッド作成は樣々な要因により拒否され得る -} Nothing -> returnA -< foundNoEntity Nothing Just (boardTitle, _, _, _) -> do siteName <- getSiteName -< db threadId <- createThread -< (db, (boardId, title)) addPost -< (db, (boardId, (threadId, req))) touchBoard -< (db, boardId) tree <- ( eelem "/" += ( eelem "createdThread" += sattr "site" siteName += sattr "boardId" boardId += sattr "boardTitle" boardTitle += sattr "threadId" (show threadId) += sattr "threadTitle" title )) -<< () returnA -< do let baseURI = envBaseURI $ ctxEnv ctx ext = ctxCanonicalExt ctx setStatus Created setLocation $ baseURI { uriPath = joinPath [ uriPath baseURI , "-" , boardId , show threadId <.> ext ] } outputXmlPage ctx tree formatCreatedThread where makeNewURI :: Context -> URI -> URI makeNewURI ctx uri = uri { uriPath = joinPath [ uriPath uri , "createThread" , boardId <.> ctxCanonicalExt ctx ] } formatCreatedThread :: (ArrowXml a) => Context -> a XmlTree XmlTree formatCreatedThread ctx = getXPathTreesInDoc "/createdThread" >>> ( eelem "/" += ( eelem "html" += sattr "xmlns" "http://www.w3.org/1999/xhtml" += ( eelem "head" += ( eelem "title" += ( (getAttrValue "site" >>> mkText) <+> txt " - " <+> (getAttrValue "boardTitle" >>> mkText) )) += ( eelem "base" += sattr "href" (show $ envBaseURI $ ctxEnv ctx) ) += ( eelem "link" += sattr "rel" "stylesheet" += sattr "type" "text/css" += sattr "href" "./css/common.css" )) += ( eelem "body" += ( eelem "h1" += (getAttrValue "boardTitle" >>> mkText) ) += ( eelem "p" += ( eelem "a" += attr "href" ( txt "./-/" <+> (getAttrValue "boardId" >>> mkText) <+> txt "/" <+> (getAttrValue "threadId" >>> mkText) <+> txt ".html" ) += getMsgNode ctx "created-thread" [ ("title", getAttrValue "threadTitle") ] )))))