Accessing the model from a layout view in Grails - model-view-controller

I'm using the layout support (sitemesh) in Grails which works fine. I'd like to adjust my layout to have it depend on whether or not a user is logged in or not.
My grails-app/views/layouts/main.gsp contains the following code:
<g:if test="${user}">
Username: ${user.username}
</g:if>
However, it appears as if the layout-GSP:s are unable to access the model and hence the user variable (I get a "No session" exception when trying). What would be the recommended way to make my layout depend on whether or not a user is logged in or not?
Thanks in advance!

I would suggest to use either the request or the session scope for that purpose. Probably the most DRY way is to populate the scope is a filter. For example in the file grails-app/conf/SecurityFilters.groovy (you'll need to create it):
class SecurityFilters {
def filters = {
populateCurrentUser(controller: '*', action: '*') {
before = {
request.user = User.get(session.userId)
}
}
}
}
The example assumes that you store the id of the current user in the session attribute "userId" and that you have a Domain class "User". Using it in the layout is as simple as this:
<g:if test="${request.user}">
Current User: ${request.user.username}
</g:if>

Related

Updating a session and using it within my view

I have a wish list, that is throughout the shopping pages. I need to know if this makes sense/the proper way of structuring.
Store the wish list as a session, when a user adds/deletes a new item it updates the session by an ajax call that just returns true/false if successful. On the partial view of the wish list component, I check for the session and cast it to my viewModel (which the session is based on) or serialize it for my knockout.
Let me know if this makes sense, otherwise I can post some code samples
It's hard to say without having a look at your basic structure, and not knowing you exact needs.
I don't know if you know this, but you can actually access the Session directly in Views:
#{
var wishlist = (WishList)HttpContext.Current.Session["Wishlist"];
}
It's fine to use Ajax to update it server side; and then you can return a partial view from the controller, to use however you like in the Ajax success call.
I hope this makes sense.
To begin with, if the wishlist is only supposed to exist for the duration of their visit then storing it in a session would be the best thing to do. However if the wishlist is supposed to live longer than a single visit and should be available to the user upon their return then I would suggest storing it in the database against the user's credentials/account (this is presuming they have an account).
As for the session itself, whilst you can access session data from a view I would not suggest it as you start to have a dependency on the session and before long you'll have code such as this scattered throughout your views.
var wishlist = (WishList)HttpContext.Current.Session["Wishlist"];
What happens when you want to change the way the wishlist works and instead have it database driven as you'd now like to persist the wishlist? You'll have to go through all of your views updating the references to the session.
Instead I would opt for registering your session with your IoC container of choice and injecting it using dependency injection, here is a simple example of how to register the session with StructureMap:
public class WebsiteRegistry : Registry
{
public WebsiteRegistry()
{
this.For<IUserWishlist>().HybridHttpOrThreadLocalScoped().Use(() => GetUserWishlistFromSession());
}
public static IUserWishlist GetUserWishlistFromSession()
{
var session = HttpContext.Current.Session;
if (session["WishList"] != null)
{
return session["WishList"] as IUserWishlist;
}
/* Create new empty session object */
session["WishList"] = new UserWishlist();
return session["WishList"] as IUserWishlist;
}
}
Now you're able to inject your wishlist into your controller and pass the data to your view via a view model. And as you're now programming against an interface instead of an implementation you could easily change how the wishlist is persisted without needing to change any code that references the wishlist.
public class WishlistController : Controller {
private readonly IUserWishlist userWishlist;
public void WishlistController(IUserWishlist userWishlist) {
this.userWishlist= userWishlist;
}
public ActionResult ViewProfile()
{
...
var viewModel = new UserWishlistViewModel {
wishlist = this.userWishlist.GetWishList()
}
...
}
}
I've written a more detailed example up in a blog post that might be of interest which can be read here. I hope this helps!

working with session on zf2 (recover container)

PRECEDENTS:
using a custom hack OF ZfcUserLdap to authenticate against a LDAP server (include zfcUser too as dependency)
the hack is due the Ldap server uses a ldapc wrapper, so the bind and search process doesn't belong to Ldap standards but through a ldapc library
the login/password box works great against the Ldap server by modifying the bind and findbyuser methods
NEED:
add country selection at login step
check if the user has the permission to work with this country (so to have the country here has sense, don't need ACL, it will be check through LDAP user groups)
store the selected country to use along the whole application
WORK IN PROGRESS:
add SELECT dropdown with available countries to login box [OK]
get the country selected at the login form [OK]
-> at authenticate method on ZfcUserLdap\Authentication\Adapter\Ldap.php class I get correctly the country set at the form
PROBLEM:
how to store the country into a session variable,
-> since zfcUser has an Storage defined and the country is defined at the login step, I would like to use that Storage
I will appreciate any kind of clarification or tips to accomplish this task.
SOLUTION:
The logic is more at zfcUserLdap module, since the auth is against an LDAP Server.
I added to the Entity extended at zfcUserLdap a new property, country that is set to the Entity object along the findByUsername method.
public function findByUsername($username, $country = null)
{
$pUser = $this->ldap->findByUsername($username);
if (isObjectNotNull($pUser))
{
$this->entity->setDisplayName(getLdapUserFirstName($pUser) . ' ' . getLdapUserLastName($pUser));
$this->entity->setEmail(getLdapUserMail($pUser));
$this->entity->setId(getLdapUserUid($pUser));
$this->entity->setUsername(getLdapUserUid($pUser));
$this->entity->setLdapcObject($pUser);
$this->entity->setUserCountry($country);
return $this->entity;
}
else {
return null;
}
}
To have the country here will be useful because the authentication process might check if the username has permission to work within that country. I'll need to add that check later.
Like this, the country is part of the entity object, so I can get the country at the same way I was able to get the username.
For now, I have create a View Helper very similar to ZfcUserDisplayName. I just update the get metohd to get the country property.
$countryName = $user->getUserCountry();
I plan to create a Controller Plugin to get the country from any Controller.
ZFCUser has an authenticate event that you should leverage for this. IN your Module's main bootstrap:
$sm = $e->getApplication()->getServiceManager();
$zfcAuthEvents = $e->getApplication()->getServiceManager()->get('ZfcUser\Authentication\Adapter\AdapterChain')->getEventManager();
$zfcAuthEvents->attach( 'authenticate', function( $authEvent ) use( $sm ){
try
{
// use $authEvent->getIdentity() to get country and stick it in a session
return true;
}
catch( \Exception $x )
{
// handle it
}
});
How you store in session is up to you, there's 400 ways to skin that cat.

how to use session in grails

I am new to grails. And I have to work with session. I have seen the session documentation. But no idea where to put the code in my controller. I have a page for student creation names createStudent. Now I want that this page only be access able when the user will be in session. Now how can I do it. Should I have to set the user in a variable at the time of login. Can anyone please help me on this ?
def index() {
def user = session["user"]
if (user){
redirect(controller: 'admistratorAction', action: 'createUser')
}else{
redirect(controller: 'login', action: 'index')
}
}
You could use the session.getAttribute(key) and session.setAttribute(key, value) methods inside your controller. Alternatively, there are plugins such as the Spring Security Core Plugin that already handle this very well.
There's a good tutorial by Peter Ledbrook for the Spring Security plugin here and the plugin documentation links to at least one other tutorial.
** Edit **
As you suggested, in order to use the session directly the user would need to be set in the session at an earlier point. For example:
def setCurrentStudent() {
def aStudent = [name: "Student1"]
session["user"] = aStudent
render "Added $aStudent to the session."
}
Spring Security will do this automatically at login. Then, the current user can then be accessed at any time using the springSecurityService.
class SomeController {
def springSecurityService
def someAction = {
def user = springSecurityService.currentUser
…
}
}

grails keep a number of page under session

I am new to grails. I have recently used session in my controller. But for only one page. Now I want to use session for a number of pages. But I have no idea how to do it. Here is my code below which works for one page. Can anyone please help me on this ?
def index() {
def user = springSecurityService.currentUser
if (user){
redirect(controller: 'admistratorAction', action: 'createUser')
}else{
redirect(controller: 'login', action: 'index')
}
}
You may be new to Grails, I hope you are not new to HttpSession. :)
Session information is scoped only to the current web application
(ServletContext), so information stored in one context will not be
directly visible in another.
As long as you are in the same ServletContext you should be able to access session variable directly. Also look at Servlet API in grails.
#Alidad- Scroll back to last question from OP.
In that case you can take advantage of grails filter to do the check before execution of each action. As dmahapatro mentioned you can use session across your app to store user object and with this filter you can do a check before any action.
Something like this can help you achieve it.:
class SecurityFilters {
def filters = {
loginCheck(controller: '*', action: '*') {
before = {
if (!session.user)) {
redirect(action: 'login')
return false
}
}
}
}
}

Grails UrlMappings for a telephone number

I'd like to set it so when a user visits the application with a telephone number in the URL Grails directs the user to the specified profile, for example:
localhost:8080/Application/profile/07871216969 -> /user/show/User.findByUserTelephone(07871216969)
or preferably
localhost:8080/Application/07871216969 -> /user/show/User.findByUserTelephone(07871216969)
However, I have no idea how to reference the telephone number in the URL when calling the findByUserTelephone closure; I've noticed something like:
/profile/$telephoneNumber however I'm not entirely sure how that works out.
Also, as the /user/show action requires an id in the parameters I am not sure if the findUserByTelephone closure is any use as it returns the User as an object, and I can't seem to either getId() or .id the object to retrieve the id.
SOLVED/SOLUTION:
I solved this by creating another action in the Controller called profile, this action then had code similar to the following:
def profile = {
if(User.findByUserTelephone(params.userTelephone)) {
def userInstance = User.findByUserTelephone(params.userTelephone)
if (!userInstance) {
flash.message = "${message(code: 'default.not.found.message', args: [message(code: 'user.label', default: 'User'), params.id])}"
redirect(action: "list")
}
else {
[userInstance: userInstance]
}
} else {
render("Sorry, that user wasn't found in our database.")
}
}
I then created the following UrlMapping entry:
`"/$userTelephone"(controller: "user", action: "profile")`
Thus, when a user enters a telephone number into the system (or any string after the /) it will route the user to the user/profile action, which will attempt to find a user by their telephone number. If successful, will show the users details otherwise will show an error message.
It will probably save you some headaches later if you use a url path which is not the same as a controller name. So if you have something like:
"/p/$phoneNumber"(controller:profile, action:show)
you won't have any URL patterns that match multiple URLMapping entries which can get a little confusing. I would guess that just:
"/$phoneNumber"(controller:profile, action:show)
would work, but I would expect to end up in situations where Grails gets confused by multiple URLMappings matching the same request path unless you're very careful.

Resources