How get the user ID from the Session at (Yesod / Haskell Project - haskell

guys i got a little projet and i need to extrat de ID of the user from the Session.
I can't put it in a Text/Int because it says that the Session carry an Key (Sql Key i think) how can i converte it to Int to use in other methods from my project
I Tried to do it to recover the ID from session
getInicioR :: Handler Html
getInicioR = do
uid <- lookupSession "_ID"
user <- runDB $ get404 uid
Shows the follow error message:
Couldn't match expected type ‘Key t0’ with actual type ‘Maybe Text’
In the first argument of ‘get404’, namely ‘uid’
In the second argument of ‘($)’, namely ‘get404 uid’

Use keyToValues to get a list of PersistValue values.
keyToValues :: Key record -> [PersistValue]
If you know, for instance, that the key is a Text value, then your list will consist of a single PersistText value and you could proceed like this:
do uid <- lookupSession "_ID"
let pvals = keyToValues uid
[ PersistText txt ] = pvals
liftIO $ print pvals -- to see what pvals is
-- now txt is a Text value
...

Related

How to build a pre-selected option for a selectField in Yesod?

(This was asked before but it has no answers).
I have a list of countries in a database:
share [mkPersist sqlSettings] [persistLowerCase|
Country
name Text
UniqueCountryName name
deriving Show
|]
And I can show a form to select one of them:
countries = do
rows <- runDB $ selectList [] [Asc CountryName]
optionsPairs $ map (\ r -> (countryName $ entityVal r, entityKey r)) rows
surveyForm :: Html -> MForm Handler (FormResult SurveyAnswerSet, Widget)
surveyForm extra = do
(countryR, countryV) <- mreq (selectField countries) "" Nothing
I know that I should replace the Nothing in the last line with the desired default value but I still don't get how to do it. Looking at the mreq and the optionsPairs signatures my thought was that in this case I should provide a Maybe Option with the default country but my attempts have raised so many type errors that probably I am quite far from the right answer.
The Yesod book has an example using seems more simple than what I tried to achieve so I am not sure how to extrapolate it.
By the way I am getting the default country from the database so I don't need to hardcode its internal id:
defaultCountry = do
row <- runDB $ getBy $ UniqueCountryName $ countryName "United States"
(countryName $ entityVal row, entityKey row)
When I pass it as an argument to mreq I get the following errors:
Couldn't match type ‘(,) Text’ with ‘HandlerFor site’
Expected type: HandlerFor site (Key record)
Actual type: (Text, Key record)
That's on the last line of the of the defaultContry function ((countryName $ entityVal row, entityKey row)). I understand that I should take the Key record from the pair and return it in a HandlerFor site but at the same time I also get:
Couldn't match expected type ‘Maybe (Key Country)’
with actual type ‘HandlerFor site0 (Key record0)’
In the (countryR, countryV) <- mreq (selectField countries) "" defaultCountry line. I interprete this as "you are passing me a HandlerFor site0 (Key record0) but I only accept Maybe (Key Country) which seems in conflict with the first error...
In the (countryName $ entityVal row, entityKey row) line I also see:
Couldn't match expected type ‘Entity Country’
with actual type ‘Maybe (Entity Country)’
in the row argument. I understand that I should extract the Entity Country from the Maybe but if I pattern match and pass just the Entity Country (i. e.: Just (Entity countryId country) -> (countryName $ entityVal (Entity countryId country), entityKey (Entity countryId country)) I still get the first error.
Thanks in advance.
Alright, this looks like a few type errors. The first
Couldn't match type ‘(,) Text’ with ‘HandlerFor site’ Expected type: HandlerFor site (Key record) Actual type: (Text, Key record)
comes from not using return in your do notation to lift the value to the monad:
defaultCountry :: HandlerFor site (Text, Key record)
defaultCountry = do
row <- runDB $ getBy $ UniqueCountryName $ countryName "United States"
return (countryName $ entityVal row, entityKey row)
The error on row
Couldn't match expected type ‘Entity Country’ with actual type ‘Maybe (Entity Country)’
is because it's a Maybe, so let's correct that
defaultCountry :: HandlerFor site (Text, Key record)
defaultCountry = do
Just row <- runDB $ getBy $ UniqueCountryName $ countryName "United States"
return (countryName $ entityVal row, entityKey row)
Now that defaultCountry is a good monad, you should be able to use it in your other code. But be careful of that third error
Couldn't match expected type ‘Maybe (Key Country)’ with actual type ‘HandlerFor site0 (Key record0)’
You need to unwrap the value from the HandlerFor monad, and rewrap it in a Maybe
surveyForm :: Html -> MForm Handler (FormResult SurveyAnswerSet, Widget)
surveyForm extra = do
(defaultName, defaultKey) <- defaultCountry -- (defaultName, defaultKey) :: (Text, Key record)
(countryR, countryV) <- mreq (selectField countries) "" (Just defaultKey)

Yesod: Passing the current user to a form

I've looked for this, but the answer found here ends up on a list containing the value. I'm wondering if there isn't another, more straightforward way to do what I need.
I have a form:
formReview :: UserId -> Form Review
formReview uid = renderDivs $ Review <$>
areq textField "Text" Nothing <*>
areq intField "Rating" Nothing <*>
areq (selectField films) "Film" Nothing <*>
pure uid
as you can see I'm trying to pass an user ID to the form, because these are the fields for Review:
Review
text Text
rating Int
film FilmId
author UserId
it requires the ID of the author.
The way I'm trying to do this is by doing the following on postReviewsR:
postReviewsR :: Handler Html
postReviewsR = do
uid <- lookupSession "_ID"
case uid of
Nothing -> do
defaultLayout [whamlet| <h1> User isn't logged in.|]
Just uid ->
((result, _), _) <- runFormPost $ formReview uid
case result of
FormSuccess review -> do
runDB $ insert review
defaultLayout [whamlet|
<h1> Review posted.
|]
_ -> redirect ReviewsR
it has to be a Maybe because in theory you could try to post something without being logged in, so uid could be empty. If I try to go straight to ((result, _), _) <- runFormPost $ formReview uid it says there's a Maybe Text.
Now my problem is similar the other post, it's this error:
• Couldn't match type ‘Text’ with ‘Key User’
Expected type: UserId
Actual type: Text
• In the first argument of ‘formReview’, namely ‘uid’
In the second argument of ‘($)’, namely ‘formReview uid’
In a stmt of a 'do' block:
((result, _), _) <- runFormPost $ formReview uid
and the suggestion in the linked post is to use keyToValues :: Key record -> [PersistValue] to turn the Key, which apparently is just Text, into what I need, the UserId.
It seems too clunky to me that I would need to do all this, then use head on that list to get the value within, all to get the ID into the form. There has to be another, more correct way, right? What am I missing here? How do I get the ID of the user who's making the Review in there?
EDIT: I should point out that I'm not using Yesod.Auth so I can't use its functions.
Assuming you're using a SQL backend, check out the persistent SQL documentation. You'll find the toSqlKey :: ToBackendKey SqlBackend record => Int64 -> Key record function. Basically, you'll need to parse your Text to Int64 and get a key using toSqlKey. You should probably also check if the key you're getting is actually valid.
(You've apparently misread the error, your uid is just a Text value, but you need a UserID which is a Key User).

convert PersistValue to Text in Yesod

I want get the attribute value from Persist Entity; so i have the following code
userToText userId = do
user <- runDB $ get404 userId
userName user
This code doesn't compile, so I wrote those alternative version
userToText userId = do
user <- runDB $ get404 userId
listToJSON [user]
userToText userId = do
(_,_,_,_,_,name,_,_) <- runDB $ get404 userId
show name
All generate the same error
Handler/Report.hs:105:9:
Couldn't match expected type ‘HandlerT site IO b’
with actual type ‘Text’
Relevant bindings include
userToText :: Key PersistValue -> HandlerT site IO b
(bound at Handler/Report.hs:102:1)
In a stmt of a 'do' block: listToJSON [user]
In the expression:
do { user <- runDB $ get404 userId;
listToJSON [user] }
thanks for the help
Your code is in the Handler monad, so your function needs to return something of the type Handler Text rather than just Text:
userToText :: UserId -> Handler Text
userToText userId = do
user <- runDB $ get404 userId
return $ userName user -- Note the `return` here
(This is similar to how functions like getLine have type IO String rather than String).

How can I select record by column value?

I have a realy simple data in my config/model
Author
name Text
and I want to select author by name and not by id
I tried this ( the information comes from a form) :
FormSuccess book -> do
result <- runDB $ selectSource [ AuthorName ==. title book]
And book is a data
data FormBook = FormBook {
isbn :: Text
, author :: Text
, title :: Text
, description :: Maybe Text
}
But I got this error
Couldn't match type `[SelectOpt Author]' with `HandlerT App IO'
Expected type: YesodPersistBackend
App
(HandlerT App IO)
(Data.Conduit.Internal.Source m0 (Entity Author))
Actual type: [SelectOpt Author]
-> Data.Conduit.Internal.Source m0 (Entity Author)
In the return type of a call of `selectSource'
Probable cause: `selectSource' is applied to too few arguments
In the second argument of `($)', namely
`selectSource [AuthorName ==. (author book)]'
In a stmt of a 'do' block:
authorresult <- runDB $ selectSource [AuthorName ==. (author book)]
I tried th put before Author PersistenceEntity and PersistenceField but they are not in scope.
I do not have any other idea, except raw query.

Resulting Ambiguous Type Variable in Persistent's `get` call

I'm having the following error while trying to retrieve a list of Entities from a list of foreign attributes.
Handler/ContactList.hs:21:57:
Couldn't match type `PersistMonadBackend m0'
with `persistent-1.3.0.6:Database.Persist.Sql.Types.SqlBackend'
The type variable `m0' is ambiguous
Possible fix: add a type sig`enter code here`nature that fixes these type variable(s)
Expected type: PersistEntityBackend User
Actual type: PersistMonadBackend m0
In the expression: `enter code here`get
In the expression: (get $ ((contactContact val) :: UserId))
In the first argument of `map', namely
`(\ (Entity key val) -> (get $ ((contactContact val) :: UserId)))'
The code below gets a List entity which has a one-to-many relationship with contact. In the Contact Model, there is an attribute called contact to represent the foreign key constraint to User (The type for conctact is UserId).
I'm Trying to retrieve the list of contacts (list of userIds) and perform a map get to retrieve the list of user entities.
For my understanding, there is a problem of type generalization while using get on a Contact Entity with UserId type, but I can't figure out what is the proper type it can work with.
getContactsR :: Handler Html
getContactsR = do
muser <- maybeAuth
case muser of
Just (Entity userId user) -> do
(list, contacts) <- runDB $ do
maybeList <- getBy (UniqueList userId)
case maybeList of
Just (Entity listId list) -> do
contacts' <- selectList [ContactList ==. listId] []
let contacts = map (\(Entity key val) -> (get $ ((contactContact val) :: UserId) )) contacts'
return (list, contacts')
Nothing -> error "Could not retrieve contact list"
defaultLayout $(widgetFile "contacts")
Nothing -> do
setMessage $ toHtml ("Error getting contact list" :: Text)
redirect HomeR
Thanks in advance
I think you need to replace:
let contacts = map (\(Entity key val) -> (get $ ((contactContact val) :: UserId) )) contacts'
with:
contacts <- mapM (\(Entity key val) -> (get $ ((contactContact val) :: UserId) )) contacts'
(Yes, the Persistent error messages here are terrible, we're working on that for Persistent 2.0.) I think the UserId type annotation may not even be necessary.

Resources