{-# LANGUAGE BlockArguments #-} {-# LANGUAGE ImportQualifiedPost #-} {-# LANGUAGE OverloadedStrings #-} module Server where import Data.ByteString.Lazy qualified as BL import Data.ByteString.Lazy.Char8 qualified as L8 import Data.Text qualified as T import Data.Text.Encoding qualified as TE import Data.Text.IO qualified as TIO import Data.Text.Lazy qualified as TL import Data.Text.Lazy.Encoding qualified as TLE import FileActions qualified as FA import Network.HTTP.Types import Network.HTTP.Types.URI (urlDecode) import Network.Wai import Network.Wai.Handler.Warp (run) import TodoListItem application req respond = case (requestMethod req, pathInfo req) of ("GET", []) -> do content <- FA.readF "./app/res/" "b" respond $ responseLBS status200 [("Content-Type", "text/html")] $ convert $ simpleSite (show content) -- TODO: check if necessary to use text ("GET", ["edit"]) -> do content <- FA.readF "./app/res/" "b" respond $ responseLBS status200 [("Content-Type", "text/html")] $ convert $ editPage (show content) ("POST", ["edit"]) -> do -- TODO: refactor this shit, add sanitisation, make sure text ends with \n body <- strictRequestBody req print body let args = L8.split '&' body case args of [newList] -> f newList _ -> error "should have exactly one arg" where f newList = do let pair = BL.splitAt 5 newList case pair of ("list=", t) -> do let text = TE.decodeUtf8 (urlDecode True (BL.toStrict t)) let result = map read (lines $ T.unpack text) :: [TodoListItem] FA.writeF "./app/res/" "b" result _ -> error "incorrect args" respond $ responseLBS status303 [(hLocation, "/")] "Redirecting..." ("POST", ["check", name]) -> do FA.check "./app/res/" "b" (read $ T.unpack name) respond $ responseLBS status303 [(hLocation, "/")] "Redirecting..." -- TODO: refactor this using where better and creating meaningfull local functions ("POST", ["add"]) -> do putStrLn "adding item" body <- strictRequestBody req let args = L8.split '&' body case args of [item] -> f item _ -> error "should have exactly one arg" where f item = do let pair = BL.splitAt 5 item case pair of ("text=", t) -> do let text = TE.decodeUtf8 (urlDecode True (BL.toStrict t)) let item = read (T.unpack text) :: TodoListItem FA.appendF "./app/res/" "b" [item] _ -> error "incorrect args" respond $ responseLBS status303 [(hLocation, "/")] "Redirecting..." (method, array) -> do respond $ responseLBS status303 [(hLocation, "/")] "Redirecting..." splitKeyValue bs = case L8.break (== '=') bs of (key, rest) -> (key, L8.drop 1 rest) openingTag tag = "<" <> tag <> ">" closingTag tag = " tag <> ">" wrapContent tag content = openingTag tag <> content <> closingTag tag wrapContentWithArgs tag arg content = openingTag (tag <> " " <> arg) <> content <> closingTag tag singleWrap content = "<" <> content <> "/>" headHtml lang title = " lang <> "\">" <> title <> "" tailHtml = "" br = "
" h1 = wrapContent "h1" h2 = wrapContent "h2" h3 = wrapContent "h3" link href = wrapContentWithArgs "a" ("href=\"" <> href <> "\"") li = wrapContent "li" p = wrapContent "p" checkboxPrimitive id name True = singleWrap $ "input type='checkbox' id=" <> id <> " name=" <> name <> " checked" checkboxPrimitive id name False = singleWrap $ "input type='checkbox' id=" <> id <> " name=" <> name label for = wrapContentWithArgs "label" ("for=" <> for) textArea id rows cols = wrapContentWithArgs "textarea" ("id=\"" <> id <> "\" name=\"" <> id <> "\" rows=\"" <> rows <> "\" cols=\"" <> cols <> "\"") checkbox id name checked = checkboxPrimitive id name checked <> label id name simpleSite :: String -> String simpleSite content = headHtml "en" "todo" <> h1 "Bienvenue" <> h2 "Site exemple" <> p "this website is a simple example of how haskell can quickly become a great tool to write websites fast" <> f content <> newItemForm <> rawEditButton <> tailHtml where f content = concatMap item (lines content) item rawLine = "
rawLine <> "\" method=\"POST\">
" newItemForm = "
" editForm content = editLabel <> br <> editTextArea content <> br <> editButton where editLabel = label "list" "Edit the todo list" editTextArea = textArea "list" "30" "33" editButton = wrapContentWithArgs "button" "type=\"submit\"" "submit" editPage content = headHtml "en" "edit" <> wrapContentWithArgs "form" "action=\"/edit\" method=\"post\"" (editForm content) <> tailHtml rawEditButton = link "/edit" "edit todo list" runServer = do run 3000 application convert = BL.fromStrict . TE.encodeUtf8 . T.pack