Building a Blog with Yesod - Part 3

Posted on 1 May 2020

Hello again, ready for the next hop? Ok, wait, it was me asking a brake.

The last article was long and full of new stuff but we were already inside it, we were moving around, having felt that relationship between things, don't we?

Ok, let's recap. The second section of config/models.p...

BlogPost
    title Text
    article Markdown
    slug Slug
    posted UTCTime
    UniqueSlug slug
    deriving Show

defines our data-structure BlogPost needed for something like a Blog. It will be used in src/Handler/Profile.hs like

blogPostForm :: AForm Handler BlogPost
blogPostForm = BlogPost 
    <$> areq textField (bfs ("Title" :: Text)) Nothing 
    <*> areq markdownField (bfs ("Article" :: Text)) Nothing 
    <*> areq slugField "Slug" Nothing 
    <*> lift (liftIO getCurrentTime)

to connect a "input" e.g. textField with our data-structure BlogPost and to build out of that the function blogPostForm which is of type AForm Handler Blogpost, which then

  • will be used to create our Handler getProfileR to parse it into Html for our inputform,
  • and create postProfileR to get the whole thing into the database.

Again we try to name things simple here. But feel save, quite a lot of things circle around our data-structure BlogPost. You name it - Yesod will handle it into something useful.

When learning from other Yesod projects I often look at the config/models file first. Here it is where types are being declared. So if you write the above like this

data BlogPost = BlogPost
    { title :: Text
    , article :: Markdown
    , slug :: Slug
    , posted :: UTCTime
    , UniqueSlug :: slug
    }
    deriving Show

it might be more clear. To refresh memories

[https://www.yesodweb.com/book/forms#forms_synopsis]

Both, gitlab.com and github.com have a search-function for looking at code others have used.

E.g. for a more complex example

[https://github.com/tzemanovic/haskell-yesod-realworld-example-app/blob/master/app/config/models]

You might feel the air above our heads. But anyway for now we begin with our data-structure BlogPost and than create Handlers and make them use it. And yeah it is back, that feeling that we have laying out the street-map on the table and remember how to get from a -> b? At least in a good part and by looking up, we also have an idea about the direction in which we walk.

But never mind to refresh insights: [https://www.youtube.com/watch?v=SadfV-qbVg8]

Proir to delve in Authentication again, I should mention that I left quite a lot of Css and Html artefacts in the yesodblog-templates. Make use of them like change the general title of the yesodblog page, change the favicon, have a look on the output of yesod-devel in your Terminal. You will note that there is a missing .jpg file from the static/img folder. Go to templates/homepage.lucius and get rid of that error.

Authentication once more

So in the last post we also have already

  • inserted a HashDBUser instance and corresponding imports to src/Models.hs,
  • added the authPlugin, the new form action widgetFile and import in src/Foundation.hs.

AuthHashDB works with a hashed pre-defined password that we have to store, so we need to create and hash it and then store the complete login credentials in the database.

For to do that we need to install cabal. In some parts of the world, people again might now say: Mama Mia, quando finisce questo casino? And yes, it would be nice to have all done by stack, but for now we have to (if not already done)

[https://www.haskell.org/cabal/index.html#install-upgrade]

After another glass of water type in

cabal install yesod-auth

Than we learn to know the "interactive" side of Ghc and start it directly with a language-pragma

ghci -XOverloadedStrings

If you do not have used it, you may have a look here

[https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/ghci.html]

don't get irritated by the mentioned Hugs. When you are already familiar with ghci, we have to

import Yesod.Auth.Util.PasswordStore

which Ghci loads easily.

Now we let some magic happen

makePassword "MyPassword" 19

which produces with the given input of

makePassword "nevermindthebollocks" 19

something like

"sha256|19|5n4WQefN5UpdxV6+G07vRw==|ClhWvqz+YA7AVFbv11odI38U+FSwWfjCqAd6fgh2KXQ="

That is our password hashed with strength 19, by the time of writing a secure default value. Pin it down somewhere.

Ok, now we - for once and ever - put it into the database.

sudo su - postgres
psql blogpost
INSERT INTO "user" (name, password) VALUES ('usernameofyourchoice', 'sha256|19|5n4WQefN5UpdxV6+G07vRw==|ClhWvqz+YA7AVFbv11odI38U+FSwWfjCqAd6fgh2KXQ=');

do a

\q

refresh our browser window and make use of it.

It seems that we have reached a point of no return here, were we - oh, have a look down there: what a nice little creek! Cold, fresh, clear water were we directly stick our feet in. Yeah, time to rest and relax a bit. Sun is gleaming through the green of the trees and we feel good and pleased and, we certainly know that we want to say a big, big thank you to Michael and all the others who have worked on and contributed to Yesod.

Don't mind to contact me - see the about section how - in case I have missed something or for critics and suggestions. Thanks for reading so far.