Why is Happstack (toResponse) using text/plain per default? - haskell

I'm using HStringTemplate to render a very simple template using a data structure to fill in the "holes". The result of the template rendering is just a String I fed toResponse with.
Even though this rendered template is valid html happstack uses text/plain for Content-Type.
What is the reason for this? Shouldn't text/html be default since it is a webserver?
Do I really need to use toResponseBS and set text/html by myself?
Here is the code that creates the ServerPart Response
data Person = Person
{ name :: String
, age ::Int
} deriving (Data, Typeable)
buildTemplate :: Person -> String -> FilePath -> ServerPart Response
buildTemplate fields name template = do
unrendered <- liftIO $ readFile template
ok $ toResponse $ renderTemplate name fields unrendered
renderTemplate :: String -> Person -> String -> String
renderTemplate name fields unrendered = toString rendered
where rendered = setAttribute name fields $ newSTMP unrendered
And here is the output from the webserver:
Head
Connection:Keep-Alive
Content-Type:text/plain; charset=UTF-8
Date:Wed, 09 Jan 2013 14:51:27 GMT
Server:Happstack/7.1.1
Transfer-Encoding:chunked
Body
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Memlikweb</title>
</head>
<body>
<h1>Hello, Richard!<h1>
<p>Do you have 25 for me?</p>
</body>
</html>

If you pass Text.Html to toResponse the content type will be text/html. You are passing a string, which toResponse takes to mean that the content type is plain text.

The happstack-hstringtemplate package provides an instance for ToMessage StringTemplate which means if you import it and then use toResponse on the template without rendering it, it will do the right thing.

Related

How to fetch a website as unicode?

I want to fetch a website looking like this¹: naked unicode between tags
<html>
한국어
</html>
I'm currently using
openURL :: String -> IO String
openURL x = getResponseBody =<< simpleHTTP (getRequest x)
But when inspecting the string 한국어 is displayed as \237\149\156\234\181\173\236\150\180, 9 characters.
And what I want would be 3 escaped characters like \u???\u???\u???
I tried Text.pack on page where page <- openURL "url" but it's already to late then.
¹ If I let firefox show me the source, and page info says UTF-8
You need to decode the text, for example with Data.Text.Encoding.decodeUtf8 from text or Codec.Binary.UTF8.String.decodeString from utf8-string.

How to parse HTML page with accented words (Spanish) without losing them?

I'm reading an HTML web page that contains literal accented words (Spanish):
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<title>Web page</title>
<body>
<p>Título</p>
<p>Año</p>
<p>Ángel</p>
<p>¿por qué nos vamos?</p>
</body>
I'm using HXT:
...
let doc = readDocument [ withValidate no
, withInputEncoding iso8859_1
, withParseHTML yes
, withWarnings no
, withEncodingErrors no
, withCurl []] url
...
Using the option
withInputEncoding utf8
discard those chars, getting as result the following words: Ttulo, Ao, ngel, por qu nos vamos?
Using the option
withInputEncoding iso8859_1
convert those chars to strings, getting as result words like: Rom\225ntica, Man\180s, H\233ctor. Where \225, \180 or \233 are strings, not chars.
What is the best method/way/approach to properly manage this situation in HXT and get all words without modifications?
Thanks.
I bet you already have everything you need
Prelude> putStrLn $ read "\"Rom\225ntica\""
Romántica
Looks like you are looking to result of show applied to the string, not the string itself? Note that print uses show:
Prelude> print (read "\"Rom\225ntica\"" :: String)
"Rom\225ntica"

Writing Yesod test case for handler with an id parameter, where id is a key to an Entity

I have been following the yesod tutorial and I am stuck on how to build a unit test involving parameters in a view that also hit a database. Backtracking a little, I followed the Echo.hs example:
getEchoR :: Text -> Handler Html
getEchoR theText = do
defaultLayout $ do
$(widgetFile "echo")
The corresponding test, note I have to cast the parameter into Text using Data.Text.pack
yit "Echo some text" $ do
get $ EchoR $ pack "Hello"
statusIs 200
Now I have the model defined like so:
Tag
name Text
type Text
With a handler that can render that that obviously take a TagId as the parameter
getTagR :: TagId -> Handler Html
getTagR tagId = do
tag <- runDB $ get404 tagId
defaultLayout $ do
setTitle $ toHtml $ tagName tag
$(widgetFile "tag")
This is where the test fails.
yit "Get a tag" $ do
-- tagId is undefined
get $ TagR tagId
statusIs 200
I am not sure how to define the tagId. It wouldn't work with a String or Text or Num, and I can't seem to figure out how to generate one as I can't find any example code in various Data.Persist tutorials. Or better yet, some other way to call the get method.
You want to use the Key data constructor to construct an ID value, which takes a PersistValue as a parameter. A simple example of creating one is:
Key $ PersistInt64 5
Another option is to call get with a textual URL, e.g. get ("/tag/5" :: Text).
Since times have changed, I'll leave this note here to say that these days one would use something like:
fromBackendKey 5
See the docs for fromBackendKey.

customising Pandoc's HTML output with CSS or a template

I have a Happstack program that dynamically converts Markdown documents to HTML using Text.Pandoc:
import qualified Text.Pandoc as Pandoc
...
return $ toResponse $ Pandoc.writeHtml Pandoc.def contents
I.e. Pandoc is returning a Text.Blaze.Html.Html value. (This has a ToMessage instance which means it can be used as a response to a request.)
How do I insert a custom CSS stylesheet into Pandoc's output? What if I want to customise the HTML e.g. by wrapping the <body> contents with some other elements?
When Pandoc's "standalone mode" option is enabled, it uses a template to format the output.
The template and its substitions variables can be set in the writerTemplate and writerVariables members of WriterOptions.
The command line tool has a default set of template it uses. You can see the default template for a format using e.g. pandoc -D html.
When using the library, the default is to use an empty template. You can get the default template programmatically using getDefaultTemplate.
Here's some example code:
import Text.Blaze.Html.Renderer.String
import Text.Pandoc
getHtmlOpts = do
template <- either (error . show) id
`fmap` getDefaultTemplate Nothing "html"
return $ def
{ writerStandalone = True
, writerTemplate = template
, writerVariables = [
("css", "/path/to/style.css"),
("header-includes",
"<style>p { background-color: magenta; }</style>")]
}
main = do
opts <- getHtmlOpts
putStrLn $ renderHtml $ writeHtml opts $ readMarkdown def "..."
You can also write your own template, call it for instance template.html and use the --template template.html option when calling pandoc from the command-line.
The documentation is at https://pandoc.org/MANUAL.html#templates, and the default template (for inspiration) is at https://raw.githubusercontent.com/jgm/pandoc-templates/master/default.html5.
Pandoc, when run from the command line, takes some arguments that allow you to insert something into the <head> tag (-H), before content (-B) and after content (-A). I don't know about Happstack, but surely there must be a way to pass these parameters to Pandoc.writeHtml

Using html files as templates in happstack

I can find plenty of documentation on using blitz and other compiletime templating libraries with happstack but I would like to know how to use html files as templates.
Though there are many options, my favourite would be Heist, which would allow you to define a splice:
> factSplice :: (Monad m) => TemplateMonad m Template
> factSplice = do
> input <- getParamNode
> let text = T.unpack $ X.nodeText input
> n = read text :: Int
> return [X.TextNode $ T.pack $ show $ product [1..n]]
>
which could be used in a dynamic (loaded at runtime) HTML template:
<html>
<head>
<title>Factorial Page</title>
</head>
<body>
<h1>Factorial Page</h1>
<p>The factorial of 6 is <fact>6</fact></p>
</body>
</html>
To use heist in happstack, you'll need the happstack-heist package. For more detail and other options, see Using Heist.
The HStringTemplate package provides a very general runtime templating system for not only HTML, but any sort of text output:
http://hackage.haskell.org/packages/archive/HStringTemplate/0.6.6/doc/html/Text-StringTemplate.html
The HStringTemplate package integrates with Happstack nicely through a few extra instances provided by an optional package: http://hackage.haskell.org/package/happstack-hstringtemplate

Resources