Compare commits

...

5 Commits

6 changed files with 45 additions and 58 deletions

17
.gitignore vendored
View File

@ -1,16 +1,3 @@
dist dist
cabal-dev result
*.o default.nix
*.hi
*.chi
*.chs.h
*.dyn_o
*.dyn_hi
.virtualenv
.hpc
.hsenv
.cabal-sandbox/
cabal.sandbox.config
*.prof
*.aux
*.hp

View File

@ -23,19 +23,21 @@ source-repository head
location: https://maxwell.ydns.eu/git/rnhmjoj/breve location: https://maxwell.ydns.eu/git/rnhmjoj/breve
executable breve executable breve
main-is: Main.hs main-is: Main.hs
hs-source-dirs: src hs-source-dirs: src
default-language: Haskell2010 default-language: Haskell2010
other-modules: Application, Views, Breve.Settings, other-modules: Application, Views, Breve.Settings,
Breve.Generator, Breve.UrlTable, Breve.Generator, Breve.UrlTable,
Paths_breve Paths_breve
other-extensions: OverloadedStrings default-extensions: OverloadedStrings
build-depends: base >=4.8 && <5.0, other-extensions: RecordWildCards, DeriveGeneric,
warp, warp-tls, tls, blaze-html, blaze-markup, DataKinds, KindSignatures, TypeOperators
servant-server, servant, servant-blaze, build-depends: base >=4.8 && <5.0,
wai, wai-extra, streaming-commons, http-api-data, warp, warp-tls, tls, blaze-html,
transformers, mtl, servant, servant-server, servant-blaze,
text, aeson, bytestring, binary, wai, wai-extra, streaming-commons, http-api-data,
hashtables, cryptohash, random,
configurator, directory mtl, text, aeson, bytestring, binary,
ghc-options: -threaded -O2 hashtables, cryptohash, random,
configurator, directory
ghc-options: -threaded -O2 "-with-rtsopts=-N -qg"

View File

@ -1,9 +1,7 @@
{-# LANGUAGE DataKinds #-} {-# LANGUAGE DataKinds #-}
{-# LANGUAGE KindSignatures #-} {-# LANGUAGE KindSignatures #-}
{-# LANGUAGE TypeOperators #-} {-# LANGUAGE TypeOperators #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE TypeSynonymInstances #-}
{-| {-|
This module contains the web application This module contains the web application
@ -17,7 +15,6 @@ import Breve.UrlTable
import Views import Views
-- Misc -- Misc
import Data.Monoid
import Control.Monad.IO.Class (liftIO) import Control.Monad.IO.Class (liftIO)
import qualified Data.Text.IO as T import qualified Data.Text.IO as T
@ -27,19 +24,19 @@ import Data.Aeson (ToJSON)
import GHC.Generics (Generic) import GHC.Generics (Generic)
-- HTML replies -- HTML replies
import Text.Blaze.Html5 (Html) import Text.Blaze.Html5 (Html)
import Text.Blaze.Renderer.Utf8 (renderMarkup) import Text.Blaze.Html.Renderer.Utf8 (renderHtml)
-- API definition -- API definition
import Servant import Servant
import Servant.HTML.Blaze (HTML) import Servant.HTML.Blaze (HTML)
import Web.FormUrlEncoded (FromForm(..), parseUnique) import Web.FormUrlEncoded (FromForm(..), parseUnique)
import GHC.TypeNats (Nat)
-- * Types -- * Types
-- | API successful reply -- | API successful reply
--
-- This is the reply returned by the JSON API -- This is the reply returned by the JSON API
-- handler when the url has been shortned -- handler when the url has been shortned
-- successfully. -- successfully.
@ -51,8 +48,13 @@ data ApiReply = ApiReply
instance ToJSON ApiReply instance ToJSON ApiReply
instance FromForm Url where -- | This type is just a wrapper around a 'Text'
fromForm f = parseUnique "url" f -- value. It's used to create a 'FromForm' instance
-- for a 'Url'.
newtype UrlForm = UrlForm Text
instance FromForm UrlForm where
fromForm f = UrlForm <$> parseUnique "url" f
-- * Breve API -- * Breve API
@ -82,22 +84,23 @@ type App =
Get '[HTML] Html Get '[HTML] Html
:<|> "static" :> Raw :<|> "static" :> Raw
:<|> Capture "name" Name :> Redirect :<|> Capture "name" Name :> Redirect
:<|> ReqBody '[FormUrlEncoded] Url :> Post '[HTML] Html :<|> ReqBody '[FormUrlEncoded] UrlForm :> Post '[HTML] Html
-- | JSON API spec -- | JSON API spec
-- --
-- +----------+------+----------------------+ -- +----------+------+----------------------+
-- | path | type | description | -- | path | type | description |
-- +==========+======+======================+ -- +==========+======+======================+
-- | / | POST | upload a new url | -- | /api | POST | upload a new url |
-- +----------+------+----------------------+ -- +----------+------+----------------------+
type API = type API =
"api" :> ReqBody '[FormUrlEncoded] Url :> Post '[JSON] ApiReply "api" :> ReqBody '[FormUrlEncoded] UrlForm :> Post '[JSON] ApiReply
-- | Breve application -- | Breve application
-- breve :: FilePath -- ^ static assets path
-- Breve takes as parameters the bind url and the urls table -> Url -- ^ bind url
breve :: FilePath -> Url -> UrlTable -> Application -> UrlTable -- ^ url hashtable
-> Application
breve static url table = serve (Proxy :: Proxy Breve) (breveServer static url table) breve static url table = serve (Proxy :: Proxy Breve) (breveServer static url table)
-- | Empty application -- | Empty application
@ -132,24 +135,24 @@ resolver table name = do
url <- liftIO (extract table name) url <- liftIO (extract table name)
case url of case url of
Nothing -> Nothing ->
throwError $ err404 { errBody = renderMarkup (message "404: not found") } throwError $ err404 { errBody = renderHtml (message "404: not found") }
Just url -> do Just url -> do
logStr ("Resolved " <> name <> " -> " <> url) logStr ("Resolved " <> name <> " -> " <> url)
pure (addHeader url NoContent) pure (addHeader url NoContent)
-- | Takes a 'Url' via POST -- | Takes a 'UrlForm' via POST
-- and prints the shortned one -- and prints the shortned one
uploader :: Url -> UrlTable -> Url -> Handler Html uploader :: Url -> UrlTable -> UrlForm -> Handler Html
uploader bindUrl table url = do uploader bindUrl table (UrlForm url) = do
name <- liftIO (insert table url) name <- liftIO (insert table url)
logStr ("Registered " <> url <> " -> " <> name) logStr ("Registered " <> url <> " -> " <> name)
pure (done $ bindUrl <> name) pure (done $ bindUrl <> name)
-- | Takes a 'Url' via POST and returns -- | Takes a 'Url' via POST and returns
-- the shortned one in an 'ApiReply' as JSON. -- the shortned one in an 'ApiReply' as JSON.
api :: Url -> UrlTable -> Url -> Handler ApiReply api :: Url -> UrlTable -> UrlForm -> Handler ApiReply
api bindUrl table url = do api bindUrl table (UrlForm url) = do
name <- liftIO (insert table url) name <- liftIO (insert table url)
logStr ("Registered " <> url <> " -> " <> name) logStr ("Registered " <> url <> " -> " <> name)
pure $ ApiReply { link = (bindUrl <> name) pure $ ApiReply { link = (bindUrl <> name)

View File

@ -1,5 +1,3 @@
{-# LANGUAGE OverloadedStrings #-}
{-| {-|
This module defines the Breve configuration This module defines the Breve configuration
parser and application settings. parser and application settings.

View File

@ -1,5 +1,4 @@
{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE RecordWildCards #-}
{-| {-|
This is the main module, which actually This is the main module, which actually
@ -8,7 +7,7 @@ run the Breve webserver.
module Main where module Main where
-- Breve modules -- Breve modules
import Application import Application (breve, emptyApp)
import Breve.Settings import Breve.Settings
import Breve.UrlTable import Breve.UrlTable
import Paths_breve (getDataFileName) import Paths_breve (getDataFileName)

View File

@ -1,5 +1,3 @@
{-# LANGUAGE OverloadedStrings #-}
{-| {-|
This module contains the HTML pages used by the This module contains the HTML pages used by the
web application. These are all obtained by filling web application. These are all obtained by filling