How can I include post teasers in my installation? - haskell

I'm following the official instructions on the Hakyll site to get post teasers up and running on my site. Unfortunately, I've hit a snag, and the instructions aren't much help.
I'm getting an out-of-scope error for the item value referenced in this snippet:
loadAndApplyTemplate
"template/postitem.html"
(teaserField "teaser" "content" <> defaultContext)
item
When embedding it into my site.hs. On a side note for reproducibility's sake, it also wasn't made clear where the <> operator came from; this required the import of one of Literate Haskell's modules.
It's completely unclear where this reference to item came from, and because it's a fairly common word, I have to sift through thousands of results even when using find and grep on my machine.
What should I declare or import to gain access to item here?

The tutorial page isn't a complete example. item isn't a reference to some function. It's just a placeholder name for an Item. Usually you'll get it from pandocCompiler or one of the many other "compilers". In this example, loadAndApplyTemplate is just like any other use of it. The only difference is that $teaser$ will be bound to the teaser text in the template.
That said, this isn't that great of an example since you usually want to use the teaser text on page listing multiple posts. This will probably involve using listField to make a collection of posts that you will iterate upon in the template. For example, this is the rule for my index page:
match "index.html" $ do
route idRoute
compile $ do
posts <- fmap (take indexRecentPostCount) . recentFirst =<< loadAllSnapshots postsPattern "postContent"
let indexCtx =
constField "title" "Home" <>
baseCtx
getResourceBody
>>= applyAsTemplate (listField "posts" (teaserField "teaser" "postContent" <> postCtx) (return posts) <> indexCtx)
>>= loadAndApplyDefaultTemplate indexCtx
>>= relativizeUrls
The "item" in this case is what getResourceBody returns, i.e. the body of index.html. This binds $posts$ to a list of posts. Ignoring the metadata, my index.html is just:
$for(posts)$
$partial("templates/teaser.html")$
$endfor$
$teaser$ is then bound in the template/teaser.html template.

Related

Authentication with Snap: Using a snaplet several times

I'm building a web application with Snap that needs to authenticate both staff and customers. So far I'm using the auth snaplet provided by snaplet-postgresql-simple to authenticate the two types of users from the same table in the database.
The initialization code therefore looks something like this:
s <- nestSnaplet "sess" sess $ initCookieSessionManager sessionKeyfile "sess" Nothing (Just sessionTimeout)
db <- nestSnaplet "pg" pg Pg.pgsInit
a <- nestSnaplet "auth" auth $ initPostgresAuth sess db
I'm considering separating the two types of users into two tables for these reasons:
the information associated with each type of user (i.e. the columns) is actually different (e.g. I don't need to know first and last names of staff)
I want to allow the staff to be authenticate to the backend without being logged into the frontend (I'd need separate cookies then, I guess)
I think security could benefit if the two types of users are in separate tables
I'm considering using two instances of the snaplets for postgresql-simple and sessions.
The initialization code would then look something like this:
s1 <- nestSnaplet "sess1" sess1 $ initCookieSessionManager sessionKeyfile "sess1" Nothing (Just sessionTimeout)
s2 <- nestSnaplet "sess2" sess2 $ initCookieSessionManager sessionKeyfile "sess2" Nothing (Just sessionTimeout)
db <- nestSnaplet "pg" pg Pg.pgsInit
a1 <- nestSnaplet "auth1" auth1 $ initPostgresAuth sess1 db
a2 <- nestSnaplet "auth2" auth2 $ initPostgresAuth sess2 db
Is that possible to use several instances of a snaplet like that?
Or does my problem have a better solution?
I wouldn't use two instances. I'd use a single instance where a user represents whatever is common to both, and then you add a user type column and put the extra information in other tables linked with a foreign key.

Exception from Warp: stack overflow when logging in

I'm making a little app for work to handle shared to-do lists, I'm almost done but I'd like to add some very simple authentication. I followed the doc to add hashdb to the scaffolded site (https://github.com/yesodweb/yesod-cookbook/blob/master/cookbook/Using-HashDB-In-a-Scaffolded-Site.md), and it compiles fine, but when I log in with correct username / password (added by hand in the database) I get this :
10/Dec/2016:13:36:02 +0100 [Debug#SQL] SELECT `name`,`password` FROM `user` WHERE `name`=?; [PersistText "Ulrar"]
10/Dec/2016:13:36:08 +0100 [Error#yesod] Exception from Warp: stack overflow #(cstod_GjWCdZJB9K0EGPCbjz5gnP:Application Application.hs:133:15)
Line 133 of Application.hs is this one : $(qLocation >>= liftLoc)
That's from the default code.
As you can see my "User" table is pretty simple, I have a primary key on the name and a password, and that's it. The name must be unique, of course.
I'll be adding the few user by hand in the database, that'll be more than enough for us.
I tried the query by hand, it returns what you'd expect, and trying to log in with the wrong username / password does "work", it redirects to the login form with an error. Only using the correct username / password couple will give that Exception, and it does seem to load for a while before throwing it after clicking on the button.
I end up on http://localhost:3000/auth/page/hashdb/login with just "Something went wrong" written.
I assume I must have missed something, I'm using the yesod-mysql scaffolded site and I have this in the YesodAuth instance :
authPlugins app = [authHashDB (Just . UniqueUser)]
I removed the getAuthId definition since I had no idea what to put there, the definition from the doc doesn't compile because getAuthIdHashDB isn't exported anymore apparently. Is this my problem ?
Thanks !
Yep, my problem was indeed removing getAuthId !
Solved it by adding this instead :
authenticate creds = runDB $ do
x <- getBy $ UniqueUser $ credsIdent creds
case x of
Just (Entity uid _) -> return $ Authenticated uid
Nothing -> return $ UserError InvalidUsernamePass

Bind list value in ArangoDB query

I'm facing some issues when trying to bind a list variable in an ArangoDB query. More concretely, the list might look like as follows and comes from a URL parameter in a certain Foxx controller endpoint:
.../someAPIEndpoint?list=A,B,C,D
I would like to be able to do something like this:
stmt = db._createStatement({query: "for i in [#list] return i"});
stmt.bind('list', req.params('list').split(','));
Since I do not know how many values will I receive from the API call, I can't create n bindings for each possible one. Is what I want to achieve even possible?
Thanks in advance.
you were almost there, you can bind an array directly to the parameter (i just removed "[" and "]" from your query:
stmt = db._createStatement({query: "for i in #list return i"});
stmt.bind('list', req.params('list').split(','));

How can I get some particular link form the links collection

I'm using watir-webdriver have several lines of the same code shown below:
...
<p class="schedule-text">
by
MarketingClub
in
Marketing
</p>
I need to get the first links included in p tag and the second links included in p tag
so using page object I've added the following code:
links(:followees_category, :css => "#home-followees li.animate-in ul li[data-show-id] p.schedule-text a")
...
followees_category_elements.attribute("href")
the last row will give me both links : http://www.somesite2.com, http://www.somesite2.com
Unfortunately, I can't indicate in css :last/:first etc.
the second link can be gotten by changing css to :
#home-followees li.animate-in ul li[data-show-id] p.schedule-text a + a
but how can I get just the first links from such blocks?
Of course, I can get both links and work with every 2nd, but maybe there is an alternative solution?
You can use the css nth-of-type pseudo class to get elements based on their index (or relative position).
For example, a:nth-of-type(1) can be used to return all links that are the first line of their parent:
links(:followees_category, :css => "p.schedule-text a:nth-of-type(1)")
For the second links, you can do a:nth-of-type(2). Note that it is 1-based index.
links(:followees_category, :css => "p.schedule-text a:nth-of-type(2)")
For the first link, you can also do a:first-of-type:
links(:followees_category, :css => "p.schedule-text a:first-of-type")
If the second link is always the last link, you can also do a:last-of-type:
links(:followees_category, :css => "p.schedule-text a:last-of-type")
I would not recommend using css selectors like these, because they make your tests harder to read and more fragile.
But, whatever the selector is in the end, i would use Ruby's Enumerable methods to get the second links like this:
links.select.each_with_index {|_, i| i.odd? }

Multiple button form cause invalid arguments error

I want to add another button to a working monadic get form, which triggers a different processing of the entire form (like preview and submit buttons commonly found in forum post forms).
So I tried to follow the advice from this answer to this older question:
First, adding another named input button:
<input type="submit" name="preview" value="Preview">
Second, adding a call to runInputGet:
((res,widget),enc) <- runFormGet myform
isPreview <- runInputGet $ iopt boolField "preview"
... -- pre-processing the form input, i.e. basic error checks
case (isPreview,res') of
(Just True, Just checkedRes) -> ... -- preview processing
( _ , Just checkedRes) -> ... -- proper processing
Unfortunately, it does not work: whenever I press my new button, I get an invalid arguments page, saying that there is an invalid boolean with the name attached to the second submit button.
A difference to the earlier question is, that I am using a GET form instead of a POST from. However, it appears to me that I need to include the boolean field in the original form, but adding an optional boolean field with the same name in the original monadic form does not change anything at all:
_ <- mopt boolField ((String.fromString "preview") { fsName = "preview" }) Nothing
(I do not know what to do with the result from this mopt, as I neither need the view (no additional form field should be shown to the user) nor the result (since this is what the additional runInputGet already provides for))
If you look at the code for boolField, you'll see that it has a strict requirement for the format that the value is supposed to be in. Instead, you probably want to use textField- which accepts anything- and then simply test if the value was present.

Resources