Get a session value with lookupSession - haskell

I try to put a session value in a variable to display it in my .hamlet but it does not focntion!
getEtatR :: Handler Html
getEtatR = do
mSessionValue <- lookupSession "myKey"
let myValue = mSessionValue :: Maybe Text
defaultLayout $ do
aDomId <- newIdent
setTitle "mon titre"
$(widgetFile "etatWidget")
I need #{myValue} to put it in my etat.hamlet

The problem is the type of myValue, which is Maybe Text. In order for a variable to show up in the template, it has to be an instance of Text.Blaze.ToMarkup.... So Text, String, or Int would all work, but "Maybe a" does not.
There are many ways to convert a "Maybe Text" to a ToMarkup. If you know for sure that the Maybe will not be a "Nothing", just strip the maybe using fromJust (imported from Data.Maybe).... But beware that if it ever does come up as a Nothing the program will crash. Similarly you could use a case statement to fill in the Nothing case, like this
myVariable = case mSessionValue of
Just x -> x
Nothing -> "<No session value>"
You can also do a quick check by converting mSessionValue to a string using show.
The following works for me....
getEtatR :: Handler Html
getEtatR = do
mSessionValue <- lookupSession "myKey"
let myValue = show mSessionValue
defaultLayout $ do
aDomId <- newIdent
setTitle "mon titre"
$(widgetFile "etatWidget")
using etatWidget.hamlet
<h1>#{myValue}

If all you want is to display the value and get it out of Maybe, you can do this directly inside the hamlet
$maybe val <- mSessionValue
<p>#{val}
$nothing
<p>No Value Set

Related

Couldn't match expected type 'SomeEntity’ with actual type ‘Key SomeEntity’

Hi I am a beginner in Haskell and Yesod and I need help with this problem.
These are my entities:
Location
name Text sqltype=varchar(255)
address AddressId Maybe sqltype=varchar(255)
UniqueLocationName name
deriving Show Typeable
Manifestation
name Text sqltype=varchar(255)
description Text Maybe sqltype=varchar(255)
category Category Maybe
startDateTime UTCTime sqltype=DateTime
location LocationId Maybe sqltype=varchar(255)
UniqueManName name
deriving Show Typeable
This is my handler that calls the man-details template:
getManDetailsR :: ManifestationId -> Handler Html
getManDetailsR mid = do
(_, user) <- requireAuthPair
md <- runDB $ get404 mid -- type is Manifestation
defaultLayout $ do
setTitle "Manifestation details"
$(widgetFile "man-details")
And part of the man-details hamlet file where I want to display information about the event:
<div class="row">
<div class="col-md-5">
<div class="project-info-box mt-0">
<h2>#{manifestationName md}
<p class="mb-0">#{fromJust(manifestationDescription md)}
<div class="project-info-box">
<p><b>Start :</b>{show $ manifestationStartDateTime md}
<p><b>Location :</b>#{locationName (manifestationLocation md)}
In this case error is :
Couldn't match expected type ‘Location’
with actual type ‘Maybe (Key Location)’
Then I try like this :
$maybe l <- manifestationLocation md
<p><b>Location :</b>{locationName l}
And error is :
Couldn't match expected type ‘Location’
with actual type ‘Key Location’
I apologize for the huge question, but I don't know how to get out of this, ie how to get only the value out of this pair (Key Location)?
Any advice and help is welcome,
Thanks.
I'll post my solution, it's a beginner's problem, but it might be useful to someone.
As #Willem Van Onsem wrote in the comment, I again made a query to the database
now for a location.
Now handler looks like this, with the fromJust function because of the Maybe wrapper:
getManDetailsR :: ManifestationId -> Handler Html
getManDetailsR mid = do
(_, user) <- requireAuthPair
md <- runDB $ get404 mid
loc <- runDB $ get404 $ fromJust(manifestationLocation md) -- and now use loc in template
liftIO $ print (loc)
defaultLayout $ do
setTitle "Manifestation details"
$(widgetFile "man-details")

Creation of monadic yesod form without hamlet

My goal is to write a monadic yesod form without usage of hamlet.
Let's say I have such example form:
userForm :: Maybe User -> Html -> MForm Handler (FormResult User, Widget)
userForm u extra = do
(nameR, nameV) <- mreq textField "" (userName <$> u)
(passR, passV) <- mreq passwordField "" Nothing
let userRes = User <$> nameR <*> passR
let widget = do
toWidget $ \render -> do
extra
-- fvInput nameV?
-- fvInput passV?
H.input ! type_ "submit" ! value "Submit"
return (userRes, widget)
In the case of hamlet usage it will be like that:
let widget = do
toWidget [whamlet|
^{fvInput nameV}
^{fvInput passV}
|]
But the return type of fvInput is FieldView App and I need to convert it to Html to compose with blaze well.
Perhaps, it will be easier to use Input Form for this task(i.e. implementing forms without w/hamlet), but the docs on yesodbook say it doesn't have a proper handling of the wrong input case. I tend to use monadic form here since I want a recreation of user input in the case of failed validation "for free" here. Will it work this way?
Use lift with widgetToPageContent:
userForm :: Maybe MyUser -> Html -> MForm Handler (FormResult MyUser, Widget)
userForm u extra = do
(nameR, nameV) <- mreq textField "" (myUserName <$> u)
(passR, passV) <- mreq passwordField "" Nothing
nameContents <- lift $ widgetToPageContent (fvInput nameV)
passContents <- lift $ widgetToPageContent (fvInput passV)
let userRes = MyUser <$> nameR <*> passR
let widget = do
toWidget $ \render -> do
extra
pageBody nameContents render
pageBody passContents render
H.input H.! A.type_ "submit" H.! A.value "Submit"
return (userRes, widget)

Lookup query parameters in Yesod

I just initialized a Yesod project (no database) using yesod init.
My HomeR GET handler looks like this:
getHomeR :: Handler Html
getHomeR = do
(formWidget, formEnctype) <- generateFormPost sampleForm
let submission = Nothing :: Maybe (FileInfo, Text)
handlerName = "getHomeR" :: Text
defaultLayout $ do
aDomId <- newIdent
setTitle "Welcome To Yesod!"
$(widgetFile "homepage")
When using yesod devel, I can access the default homepage at http://localhost:3000/.
How can I modify the handler listed above to retrieve (and display) a HTTP GET query parameter like id=abc123 when accessing this URL:
http://localhost:3000/?id=abc123
Note: This question was answered Q&A-style and therefore intentionally doesn't show research effort!
I'll show two different methods to achieve this. For both, you'll need to add this code to your template, e.g. in homepage.hamlet:
Note that it is not guaranteed there is any id parameter present when accessing the URL, therefore the type resulting from both methods is Maybe Text. See the Shakespearean template docs for a detailed explanation of the template parameters.
Method 1: lookupGetParam
The easiest way you can do this is using lookupGetParam like this:
idValueMaybe <- lookupGetParam "id"
When using the default setting as generated by yesod init, idValueMaybe needs to be defined in both getHomeR and postHomeR if idValueMaybe is used in the template.
Your HomeR GET handler could look like this:
getHomeR :: Handler Html
getHomeR = do
idValueMaybe <- lookupGetParam "id"
(formWidget, formEnctype) <- generateFormPost sampleForm
let submission = Nothing :: Maybe (FileInfo, Text)
handlerName = "getHomeR" :: Text
defaultLayout $ do
aDomId <- newIdent
setTitle "Welcome To Yesod!"
$(widgetFile "homepage")
Method 2: reqGetParams
Instead of looking up the query parameters by name, you can also retrieve a list of query key/value pairs using reqGetParams. This can be advantageous in certain situations, e.g. if you don't know all possible keys in advance. Using the standard lookup function you can easily lookup a certain key in that list.
The relevant part of your code could look like this:
getParameters <- reqGetParams <$> getRequest
let idValueMaybe = lookup "id" getParameters :: Maybe Text
Your getHomeR could look like this:
getHomeR :: Handler Html
getHomeR = do
getParameters <- reqGetParams <$> getRequest
let idValueMaybe = lookup "id" getParameters :: Maybe Text
(formWidget, formEnctype) <- generateFormPost sampleForm
let submission = Nothing :: Maybe (FileInfo, Text)
handlerName = "getHomeR" :: Text
defaultLayout $ do
aDomId <- newIdent
setTitle "Welcome To Yesod!"
$(widgetFile "homepage")

Yesod - Extract session data (non-String), store it and use it

Hi there.
Here is the code I'm trying to make work :
getGameR :: Handler Html
getGameR = do
sess <- getSession
defaultLayout $ do
setTitle "Game"
$(widgetFile "hamletFile")
where
person = read $ fromJust $ Map.lookup "person" sess :: Person
data Person = Person
{
name :: Text
}
deriving (Show, Read)
The error is the following:
Handler/MyHandler.hs:87:56: Not in scope: `sess'
What I'm trying to do, is to extract data from Yesod Session (data of type Person) and store it inside 'person', to be able to use it inside the hamlet file.
Is there a way to get around that error?
If it's not possible, can you suggest another way around?
Thanks in advance.
sess is local to the do block, and thus it is not in scope in the person definition. As far as that error goes, using let inside the do block should be enough:
getGameR :: Handler Html
getGameR = do
sess <- getSession
let person = read $ fromJust $ Map.lookup "person" sess :: Person
defaultLayout $ do
setTitle "Game"
$(widgetFile "hamletFile")
If you just want to lookup single value, consider using lookupSession instead. Also, fromJust throws exception if key is not in session, you might use fromMaybe:
getGameR :: Handler Html
getGameR = do
mbPersonName <- lookupSession "person"
let defaultPerson = Person "anonymous"
let person = fromMaybe defaultPerson (readMaybe .unpack =<< mbPersonName) :: Person
defaultLayout $ do
setTitle "Game"
$(widgetFile "hamletFile")
Here is my helpers for dealing with session:
import Text.Read (readMaybe)
import Data.Maybe (fromMaybe)
readSession :: Read a => Text -> Handler (Maybe a)
readSession name = do
textValue <- lookupSession name
return (readMaybe . unpack =<< textValue)
readSessionDef :: Read a => a -> Text -> Handler a
readSessionDef def name = do
mbValue <- readSession name
return $ fromMaybe def mbValue
readSession reads anything that can be readden and returns a Maybe. readSessionDef returns default value if such key is not present in session:
getGameR :: Handler Html
getGameR = do
person <- readSessionDef (Person "anonymous") "person"
defaultLayout $ do
setTitle "Game"
$(widgetFile "hamletFile")

How is it used translated messages inside a Haskell file?

I have searched in internet, in the Yesod Web ebook and other tutorials (Yesod Tutorial) but I have not been able to clarify this problem. I am using the scaffolded site.
I have a handler, inside it returns a value, the email if the user is authenticated or a string if he is not. What I want is to return the localized message instead the string "(Unknown User ID)". My problem is to use a value from the message file (ex. MsgHello), if I do this, it returns errors like:
Couldn't match expected type AppMessage' with actual typeText'
I have tried using (show MsgHello) or (pack MsgHello), even calling msg <- getMessageRender but I have not been able to do what I expect. If you have any suggestions, they are welcome.
Thanks!!
PD: This is part of the code that I am working on, line :
getUserProfileR :: Handler RepHtml
getUserProfileR = do
maid <- maybeAuth
let user = case maid of
Nothing -> "(Unknown User ID)"
Just (Entity _ u) -> userEmail u
defaultLayout $ do
setTitleI MsgUserProfile
$(widgetFile "nhUserProfile")
Thanks to Tickhon Jelvis for pointing out those web pages, also I found this one: Poly Hamlet i18n where I was able to get the solution to the problem.
So, if I would like to use a localized message, I would do:
getUserProfileR :: Handler RepHtml
getUserProfileR = do
maid <- maybeAuth
msg <- getRenderMessage
let user = case maid of
Nothing -> msg MsgNoUser --"(Unknown User ID)"
Just (Entity _ u) -> userEmail u
defaultLayout $ do
setTitleI MsgUserProfile
$(widgetFile "nhUserProfile")
Also remember that there is a helper function "setTitleI" which takes directly a Msg value and avoids the use of "msg MsgThisPageTitle"
My understanding of the I18N module is that you want to take your AppMessage value and use renderMessage on it.
You need to pass in a type specifying your translation type and a list of languages as well as your message. The translation type is created using the mkMessage function and the list of languages looks something like ["en-US", "en-GB", "fr"].

Resources