diff --git a/LICENSE b/LICENSE new file mode 100644 index 000000000..904a76ed0 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2019 Vincent Ambo + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/services/tazblog/.gitignore b/services/tazblog/.gitignore new file mode 100644 index 000000000..a95070c31 --- /dev/null +++ b/services/tazblog/.gitignore @@ -0,0 +1,7 @@ +*.o +*.hi +BlogState/ +dist/ +.cabal-sandbox/ +*.tar.gz +.stack-work/ diff --git a/services/tazblog/.stylish.haskell.yaml b/services/tazblog/.stylish.haskell.yaml new file mode 100644 index 000000000..cb432ce23 --- /dev/null +++ b/services/tazblog/.stylish.haskell.yaml @@ -0,0 +1,20 @@ +steps: + - imports: + align: group + - language_pragmas: + style: vertical + remove_redundant: true + - records: {} + - trailing_whitespace: {} +columns: 120 +language_extensions: + - DeriveDataTypeable + - FlexibleContexts + - GeneralizedNewtypeDeriving + - MultiParamTypeClasses + - OverloadedStrings + - RecordWildCards + - ScopedTypeVariables + - TemplateHaskell + - TypeFamilies + - QuasiQuotes diff --git a/services/tazblog/blog/Main.hs b/services/tazblog/blog/Main.hs new file mode 100644 index 000000000..cfe068a8d --- /dev/null +++ b/services/tazblog/blog/Main.hs @@ -0,0 +1,41 @@ +-- | Main module for the blog's web server +module Main where + +import BlogDB (initialBlogState) +import Control.Applicative (pure, (<$>), (<*>)) +import Control.Exception (bracket) +import Data.Acid +import Data.Acid.Remote +import Data.Word (Word16) +import Locales (version) +import Network (HostName, PortID (..)) +import Options +import Server + +data MainOptions = MainOptions { + dbHost :: String, + dbPort :: Word16, + blogPort :: Int, + resourceDir :: String +} + +instance Options MainOptions where + defineOptions = pure MainOptions + <*> simpleOption "dbHost" "localhost" + "Remote acid-state database host. Default is localhost" + <*> simpleOption "dbPort" 8070 + "Remote acid-state database port. Default is 8070" + <*> simpleOption "blogPort" 8000 + "Port to serve the blog on. Default is 8000." + <*> simpleOption "resourceDir" "/opt/tazblog/static" + "Resources folder location." + +main :: IO() +main = do + putStrLn ("TazBlog " ++ version ++ " in Haskell starting") + runCommand $ \opts _ -> + let port = PortNumber $ fromIntegral $ dbPort opts + in openRemoteState skipAuthenticationPerform (dbHost opts) port >>= + (\acid -> runBlog acid (blogPort opts) (resourceDir opts)) + + diff --git a/services/tazblog/db/Main.hs b/services/tazblog/db/Main.hs new file mode 100644 index 000000000..9523041f1 --- /dev/null +++ b/services/tazblog/db/Main.hs @@ -0,0 +1,34 @@ +-- | Main module for the database server +module Main where + +import BlogDB (initialBlogState) +import Control.Applicative (pure, (<$>), (<*>)) +import Control.Exception (bracket) +import Data.Acid +import Data.Acid.Local (createCheckpointAndClose) +import Data.Acid.Remote +import Data.Word +import Network (PortID (..)) +import Options + +data DBOptions = DBOptions { + dbPort :: Word16, + stateDirectory :: String +} + +instance Options DBOptions where + defineOptions = pure DBOptions + <*> simpleOption "dbport" 8070 + "Port to serve acid-state on remotely." + <*> simpleOption "state" "/var/tazblog/state" + "Directory in which the acid-state is located." + +main :: IO () +main = do + putStrLn ("Launching TazBlog database server ...") + runCommand $ \opts args -> + bracket (openState opts) createCheckpointAndClose + (acidServer skipAuthenticationCheck $ getPort opts) + where + openState o = openLocalStateFrom (stateDirectory o) initialBlogState + getPort = PortNumber . fromIntegral . dbPort diff --git a/services/tazblog/src/Blog.hs b/services/tazblog/src/Blog.hs new file mode 100644 index 000000000..f35e3d908 --- /dev/null +++ b/services/tazblog/src/Blog.hs @@ -0,0 +1,234 @@ +module Blog where + +import BlogDB +import Data.Maybe (fromJust) +import Data.Text (Text, append, empty, pack) +import Data.Text.Lazy (fromStrict) +import Data.Time +import Locales +import Text.Blaze.Html (preEscapedToHtml) +import Text.Hamlet +import Text.Markdown + +import qualified Data.Text as T + +replace :: Eq a => a -> a -> [a] -> [a] +replace x y = map (\z -> if z == x then y else z) + +show' :: Show a => a -> Text +show' = pack . show + +-- |After this time all entries are Markdown +markdownCutoff :: UTCTime +markdownCutoff = fromJust $ parseTimeM False defaultTimeLocale "%s" "1367149834" + +-- blog HTML +blogTemplate :: BlogLang -> Text -> Html -> Html +blogTemplate lang t_append body = [shamlet| +$doctype 5 +
+ + + + + +