{- | Module : Web.RBB Description : This module re-exports all necessary and some useful modules Copyright : (c) Sebastian Witte License : BSD3 Maintainer : woozletoff@gmail.com Stability : experimental -} module Web.RBB ( -- * Configuration -- $configuration BlogConfig (..), createDefaultBlogConfig, -- * Usage -- ** General -- $usage Blog, getBlogConfig, withBlog, blogEntries, -- ** XMonad style usage -- $example rbb, -- * Entry querying -- ** Entry Entry, entryId, -- | Unique 'Entry' identifier. It you do not mess with the repositories -- history, this should be the same across restarts. title, -- | Title of the 'Entry'. author, -- | Author of the 'Entry'. authorEmail, tags, fileType, -- $ixsetquery Title(..), AuthorName(..), AuthorEmail(..), Tags(..), Index(..), -- ** FileType FileType(..), def, ) where import Data.Default (Default (..)) import Web.RBB.Blog (Blog, blogEntries, getBlogConfig, withBlog) import Web.RBB.Config (BlogConfig (..)) import Web.RBB.Main (rbb) import Web.RBB.Templates.Default (createDefaultBlogConfig) import Web.RBB.Types.Entry import Web.RBB.Types.FileType (FileType (..)) -- $configuration -- The blog configuration is essentially done by setting the fields of the -- 'BlogConfig' data type. A basic configuration can be created with the -- function 'createDefaultBlogConfig' that only takes the absolutely necessary -- parameters. -- $usage -- To use the blog in an web application, you have to create an abstact 'Blog' -- value via the 'withBlog' function and pass it to functions that need access -- to it because they call blog related functions. -- -- > importWeb.RBB -- > -- > myBlogConfig = createDefaultBlogConfig -- > "/path/to/repository/with/blog/entries" -- > "/path/to/folder/with/static/resources" -- > -- > main = withBlog myBlogConfig $ \blog -> do -- > putStrLn "Replace this with your web application code." -- $example -- -- You can also define an xmonad-like configuration for your blog. If the few -- functions from this module do not give you a basic idea on how to use this -- library, a trivial example will not suffice. -- The following example will contain two modules and for the sake of this -- example, I will assume that the configuration is in -- @~\/.config\/repo-based-blog@. -- -- The first file is @repo-based-blog.hs@. It will containt the markup and a -- minimal happstack server example. The blog will be present at -- . -- -- > {-# LANGUAGE OverloadedStrings #-} -- > import Web.RBB -- > -- > import Query -- > -- > import Text.Blaze.Html5 as H -- > import Control.Applicative ((<$>), optional) -- > import Control.Monad -- > import Control.Monad.IO.Class -- > import Data.Text (Text, unpack) -- > import Happstack.Server -- > import Data.Maybe -- > import qualified Data.IxSet as IxSet -- > import System.Directory -- > import Text.Blaze.Html5.Attributes as A hiding (dir, start, id) -- > import Happstack.Server (Conf (port), notFound, nullConf, toResponse, simpleHTTP) -- > -- > siteTemplate :: (Monad m, Functor m) -- > => [Html] -- ^ Additional Headers -- > -> [Html] -- ^ Body content -- > -> m Html -- > siteTemplate hs bodyContent = return $ do -- > docType -- > html $ do -- > H.head $ do -- > meta ! httpEquiv "Content-Type" -- > ! content "text/html;charset=utf-8" -- > meta ! content "width=device-width, initial-scale=1, maximum-scale=1" -- > ! name "viewport" -- > link ! rel "stylesheet" ! type_ "text/css" -- > ! href "resources/default.css" -- > sequence_ hs -- > H.body $ do -- > topNavigationBar [ ("Blog", Just "?") -- > , ("Github", Just "https://github.com/saep") -- > ] -- > sequence_ bodyContent -- > -- > topNavigationBar :: [(Html, Maybe String)] -> Html -- > topNavigationBar [] = return () -- > topNavigationBar xs = -- > H.div ! class_ "horiz-nav" $ -- > H.nav ! A.class_ "horiz-nav" $ -- > ul ! class_ "horiz-nav" $ -- > forM_ xs $ \(t, ml) -> -- > case ml of -- > Just l -> li $ a ! href (toValue l) $ t -- > _ -> li t -- > -- > serveBlog :: Blog (ServerPartT IO) -- > -> ServerPartT IO Response -- > serveBlog blog = do -- > qd <- parseQueryRqData -- > mId <- join . fmap readMaybe <$> optional (look "id") -- > let qfun = fmap (IxSet.getEQ . Index) mId -- > entries <- join $ blogEntries blog qd qfun -- > blogMarkup <- siteTemplate hs [entries] -- > ok . toResponse $ blogMarkup -- happstack specific -- > where -- > hs = [ H.title "Saeptain's log" ] -- > -- > myBlogConfig :: BlogConfig (ServerPartT IO) -- > myBlogConfig = -- > let cfg = createDefaultBlogConfig "/home/saep/git/myblog" -- > in cfg { baseURL = return "http://127.0.0.1:8000/blog" } -- > -- > main :: IO () -- > main = rbb $ withBlog myBlogConfig $ \b -> do -- > liftIO $ simpleHTTP (nullConf { port = 8000 }) $ msum -- > [ dir "resources" $ serveDirectory DisableBrowsing [] "/home/saep/git/blog/resources" -- > , serveBlog b -- > , notFound $ toResponse () -- > ] -- -- The Query module, which you will be missing apart from the obvious missing -- libraries is located in @lib/Query.hs@ -- -- > module Query where -- > -- > import Happstack.Server (look, HasRqData, ServerPartT) -- > import Web.RBB.Blog.Query -- > import Control.Applicative -- > import Data.Maybe -- > -- > readMaybe :: Read a => String -> Maybe a -- > readMaybe x = case reads x of -- > [(v,_)] -> Just v -- > _ -> Nothing -- > -- > -- | 'look' at the request data of the given name and try to parse it via -- > -- 'readMaybe'. If the parse failed or the request data did not exist, return -- > -- the provided default. -- > maybeLookAndRead :: (Monad m, Read a, Alternative m, HasRqData m) -- > => a -> String -> m a -- > maybeLookAndRead a qry = do -- > l <- optional $ look qry -- > return $ fromMaybe a (maybe (Just a) readMaybe l) -- > -- > -- | Parse the supported request data and present it in a data type. -- > parseQueryRqData :: ServerPartT IO EntryQuery -- > parseQueryRqData = EntryQuery -- > <$> (sortMethodToComparator -- > <$> maybeLookAndRead Update "sortBy" -- > <*> maybeLookAndRead Descending "sortOrder") -- $ixsetquery -- These newtype wrappers are used by the 'IxSet' of 'Entry' values and needed -- for search queries. -- -- > queryEntryForIdentifier :: Ixset Entry -> Maybe Entry -- > queryEntryForIdentifier set = getOne $ set @= Index 42 --