gdritter repos new-inf-blog / master src / Main.hs
master

Tree @master (Download .tar.gz)

Main.hs @master

3a0faa3
 
 
 
4ea169f
78f200d
7466633
 
 
 
3a0faa3
7466633
3a0faa3
7466633
 
 
 
4ea169f
7466633
57dadc3
7466633
3a0faa3
57dadc3
 
 
 
4ea169f
57dadc3
 
0a84539
57dadc3
 
4ea169f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0a84539
4ea169f
 
 
 
d53b307
57dadc3
 
0a84539
57dadc3
d53b307
57dadc3
4ea169f
 
 
 
 
d53b307
57dadc3
 
0a84539
cbfcd0a
 
 
 
 
d53b307
cbfcd0a
 
0a84539
d53b307
4ea169f
 
 
 
 
 
 
 
0a84539
4ea169f
 
 
 
 
 
 
 
 
 
 
 
 
 
0a84539
4ea169f
 
 
 
 
 
 
 
0a84539
4ea169f
d53b307
4ea169f
aeec4b9
 
 
 
 
0a84539
aeec4b9
 
 
 
4ea169f
 
 
 
0a84539
4ea169f
d53b307
4ea169f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
57dadc3
 
0a84539
57dadc3
 
 
0a84539
57dadc3
 
 
 
 
 
 
78f200d
 
 
 
 
 
 
 
57dadc3
 
0a84539
57dadc3
d53b307
57dadc3
4ea169f
 
 
 
 
d53b307
57dadc3
4ea169f
{-# LANGUAGE OverloadedStrings #-}

module Main where

import           Control.Monad (join)
import qualified Data.ByteString.Lazy as BSL
import qualified Data.Text as TS
import qualified Data.Text.Encoding as EncodingS
import qualified Data.Text.Lazy as T
import qualified Network.HTTP.Types as HTTP
import qualified Network.Wai as W
import           System.FilePath ((</>))

import qualified Inf.DB.Monad as DB
import qualified Inf.DB as DB
import qualified Inf.Feed as Feed
import qualified Inf.Templates as Template
import qualified Inf.Log as Log
import           Inf.Types
import qualified Inf.Web as Web

main :: IO ()
main = Web.run route

route :: Web.Routes
route c req = do
  user <- Web.getUser c (lookup HTTP.hCookie (W.requestHeaders req))
  case (W.requestMethod req, W.pathInfo req) of
    ("GET", []) -> do
      post <- DB.runDB c DB.newestPostRef
      Web.redirect (postRefURL post)

    ("POST", []) ->
      case user of
        Nothing -> do
          Log.error [ "non-logged-in user attempted to post something" ]
          Web.redirect "/"
        Just u -> do
          formData <- Web.formData req
          let rpMb = do
                title <- join (lookup "title" formData)
                contents <- join (lookup "contents" formData)
                pure RawPost
                  { rpId       = Nothing
                  , rpTitle    = EncodingS.decodeUtf8 title
                  , rpAuthor   = User u
                  , rpContents = EncodingS.decodeUtf8 contents
                  }
          case rpMb of
            Nothing -> do
              Log.error [ "bad input data somehow" ]
              Web.redirect "/"
            Just rp -> do
              DB.runDB c (DB.submitPost (User u) rp)
              Web.redirect "/newest"

    ("GET", ["auth"]) -> do
      password <- Template.login
      Web.ok user "login" password "/"

    ("GET", ["archive"]) -> do
      posts <- DB.runDB c DB.allPostRefs
      contents <- Template.list posts
      Web.ok user "Past Entries" contents "/archive"

    ("GET", ["create"]) ->
      case user of
        Nothing -> Web.redirect "/"
        Just _  -> do
          contents <- Template.edit "/" emptyRawPost
          Web.ok user "New Post" contents "/"

    ("GET", [y, m, s]) -> do
      (post, cached) <- DB.runDB c $ do
        ps <- DB.postByDateAndSlug y m s
        ch <- DB.cachedMarkup (postId ps)
        pure (ps, ch)
      case cached of
        Just cache -> do
          Web.ok user (T.fromStrict (postTitle post)) cache (postURL post)
        Nothing -> do
          contents <- Template.post user post
          DB.runDB c (DB.storeCachedMarkup (postId post) contents)
          Web.ok user (T.fromStrict (postTitle post)) contents (postURL post)

    ("POST", [y, m, s]) ->
      case user of
        Nothing -> do
          Log.error [ "non-logged-in user attempted to edit post" ]
          Web.redirect "/"
        Just u -> do
          formData <- Web.formData req
          oldPost <- DB.runDB c (DB.postByDateAndSlug y m s)
          let rpMb = do
                title <- join (lookup "title" formData)
                contents <- join (lookup "contents" formData)
                pure RawPost
                  { rpId       = Just (postId oldPost)
                  , rpTitle    = EncodingS.decodeUtf8 title
                  , rpAuthor   = User u
                  , rpContents = EncodingS.decodeUtf8 contents
                  }
          case rpMb of
            Nothing -> do
              Log.error [ "bad input data somehow" ]
              Web.redirect "/"
            Just rp -> do
              DB.runDB c (DB.submitPost (User u) rp)
              Web.redirect (postURL oldPost)

    ("GET", [y, m, s, "edit"]) ->
      case user of
        Nothing -> do
          Log.error [ "non-logged-in user attempted to edit post" ]
          Web.redirect "/"
        Just {} -> do
          oldPost <- DB.runDB c (DB.postByDateAndSlug y m s)
          contents <- Template.edit (postURL oldPost) (postToRawPost oldPost)
          Web.ok user (T.fromStrict (postTitle oldPost)) contents "/"

    ("POST", [y, m, s, "delete"]) ->
      case user of
        Nothing -> Web.redirect "/"
        Just _ -> do
          Log.warn [ "deleting post:", show (y, m, s) ]
          DB.runDB c $ do
            post <- DB.postByDateAndSlug y m s
            DB.deletePost (postToRawPost post)
          Web.redirect "/"

    ("GET", [y, m, s, "delete"]) ->
      case user of
        Nothing -> Web.redirect "/"
        Just _ -> do
          post <- DB.runDB c (DB.postByDateAndSlug y m s)
          contents <- Template.delete post
          Web.ok user "Delete Post?" contents "/"

    ("POST", ["login"]) -> do
      formData <- Web.formData req
      Log.warn [ "attempting login"
               , case lookup "user" formData of
                   Just (Just u) -> "of user " ++ show u
                   _ -> "without a specified user"
               ]
      case (lookup "user" formData, lookup "passwd" formData) of
        (Just (Just u), Just (Just p)) -> do
          userMb <- Web.verifyUser c u p
          case userMb of
            Just _  ->
              let cookies = Web.authCookie u p
              in Web.redirectWithCookies "/" cookies
            Nothing -> Web.raise500 req (Unimplemented "Bad Password")
        _ -> Web.raise500 req (Unimplemented "Bad Login")

    ("GET", ["logout"]) ->
      Web.redirectWithCookies "/" [("USERDATA", "")]

    ("GET", ["newest"]) -> do
      post <- DB.runDB c DB.newestPostRef
      Web.redirect (postRefURL post)

    ("GET", ["oldest"]) -> do
      post <- DB.runDB c DB.oldestPostRef
      Web.redirect (postRefURL post)

    ("GET", ["static", fp]) ->
      let path = "static" </> TS.unpack fp
      in pure (W.responseFile HTTP.status200 [] path Nothing)

    ("GET", ["rss"]) -> do
      cached <- DB.runDB c DB.cachedRSS
      case cached of
        Just t -> Web.atomFeed (BSL.fromStrict t)
        Nothing -> do
          posts <- DB.runDB c DB.allPosts
          feed <- Feed.renderFeed posts
          DB.runDB c (DB.storeCachedRSS (BSL.toStrict feed))
          Web.atomFeed feed

    ("GET", [pagename]) -> do
      pg <- DB.runDB c (DB.staticPage pagename)
      contents <- Template.page (pageText pg)
      Web.ok user (T.fromStrict pagename) contents ("/" <> pagename)

    ("GET", [_page, "edit"]) ->
      case user of
        Nothing -> Web.redirect "/"
        Just _  -> do
          contents <- Template.edit "/" emptyRawPost
          Web.ok user "New Post" contents "/"

    (_, path) -> Web.raise404 req path