I am doing a two level menu and I want to show some entries if the user has certain permissions.
I dont want to show the first level of the menu if the user doesn't have permissions to any other submenu because it would display an empty list of results.
I'll put some code to explain it better. This could be an example of the menu:
<ul>
<shiro:hasPermission permission="foo">
<li> foo</li>
</shiro:hasPermission>
<shiro:hasPermission permission="bar">
<li> bar</li>
</shiro:hasPermission>
</ul>
Is it there a way to wrap the <ul> somehow to ask if the user has foo or bar permission?
I'm using Grails 2.4.4 and Shiro plugin 1.2.1
UPDATE WITH SOLUTION:
Finally I've created a new tagLib that extends the ShiroTagLib and has the desired function:
class ShiroTagLib extends org.apache.shiro.grails.ShiroTagLib {
/**
* This tag only writes its body to the output if the current user
* have any of the given permissions provided in a separated comma String.
*/
def hasAnyPermission = { attrs, body ->
def permissions = attrs["permissions"]
if (!permissions){
throwTagError("Tag [hasAnyPermission] must have [permissions] attribute")
}
def permissionsList = permissions.split(',')
for (permission in permissionsList) {
if (checkPermission([permission: permission], "hasPermission")) {
// Output the body text.
out << body()
return out
}
}
}
}
with this you can do <shiro:hasAnyPermission permissions="foo,bar">
There are several ways to approach this but the hasAnyRole tag from the Shiro plugin is likely the easiest way.
<shiro:hasAnyRole in="foo,bar">
<ul>
<shiro:hasPermission permission="foo">
<li> foo</li>
</shiro:hasPermission>
<shiro:hasPermission permission="bar">
<li> bar</li>
</shiro:hasPermission>
</ul>
</shiro:hasAnyRole>
You can take a look at the source code for the tag library for more information.
Update
Based on the comment provided there is another option which is based on permissions.
<g:set var="hasSomePermission" value="${false}" />
<shiro:hasPermission permission="foo">
<g:set var="hasSomePermission" value="${true}" />
</shiro:hasPermission>
<shiro:hasPermission permission="bar">
<g:set var="hasSomePermission" value="${true}" />
</shiro:hasPermission>
...
<g:if test="${hasSomePermission}">
...
</g:if>
The Shiro plugin doesn't provide a logical OR tag for permissions like it does with roles, so the above is another approach. Using this same idea you could DRY it up with your own tag library.
Related
In a Grails 3.3 application, I'm trying to create a menu configuration and I'd like to use application.groovy for that.
application.groovy:
mainmenuconfig {
menuitem_1 {
id = 'menuitem-1'
name='Home'
sub=null
}
menuitem_2 {
id ='menuitem-2'
name='Stammdaten'
sub = submenuitem_2 {
menuitem_2_1 {
id = 'menuitem-2-1'
name ='Stamm-A'
sub=null
}
}}
}
Retrieving the config via grailsApplication.config.get('mainmenuconfig') would give me the following:
[menuitem_1:[id:menuitem-1, name:Home, sub:null], menuitem_2:[id:menuitem-2, name:Stammdaten, submenuitem_2:[menuitem_2_1:[id:menuitem-2-1, name:Stamm-A]], sub:null]]
If I look at getClass() it says it's a org.grails.config.NavigableMap
Now, for my understanding, generating an <UL> ... <LI> tree should be done inside the View layer. For iterating through that structure, I will need recursion, because it can be n levels deep.
If I'm looking from main.gsp, I know the spot where I want to insert the menu tree, but how do I bring the data there and where do I do that recursion? Will I need a menu controller that is being called from the GSP? IMHO the GSP shouldn't do such calls. And on the other side, no controller should generate <UL> ... <LI> trees. I need the glue piece.
This sounds like a good use for an interceptor. You can have it add to your model after every action is finished. Then your view will have access to menu in its model and can build out the menu. It's fine to do recursion in your view if it's for display purposes.
class NavigationMenuInterceptor {
NavigationMenuInterceptor() {
matchAll()
}
boolean after() {
model.menu = grailsApplication.config.getProperty('mainmenuconfig', Map)
true
}
}
To render your menu, you can use a template that recursively renders itself. Depending on your desired HTML output it might be something like below.
In the main body:
<ul>
<g:each in="${menu}" var="menuitem">
<g:render template="menuitem" model="[menuitem: menuitem]"/>
</g:each>
</ul>
In your template _menuitem.gsp:
<li id="${menuitem.id}">
${menuitem.name}
</li>
<g:if test="${menuitem.sub}">
<li>
<ul>
<g:render template="menuitem" model="[menuitem: menuitem.sub]"/>
</ul>
</li>
</g:if>
I'm using Grails 2.2.3 and Fields plugin 1.3.
I want to customize fields to manage one-to-many relationships using select tag.
In views/_fields/oneToMany/_input.gsp I have:
<g:select name="${property}.id" from="${type.list()}" optionKey="id" value="${value}" class="form-control one-to-many" noSelection="['null': "${label}"]" />
But type is a set, so I can't use list function.
How can I retrieve target domain class?
As long as you use a Map to declare the relationship, for example:
static hasMany = [ books: Book ]
You can get the list of the referenced domain, which is the key from the hasMany property of the bean, so the from attribute should change to
from="${bean.hasMany[property].list()}"
Alternatively you can pass the list to the _input.gsp template prefixing the variable name with input-, e.g.
<f:field property="books" input-domainList="${bookInstaceList}" />
In the _input.gsp template you can use the variable as follows:
from="${domainList}"
or mixing both methods:
from"${domainList ?: bean.hasMany[property].list()}"
I found this solution for the problem, this code work fine with one to many and one to one
<div class="input-group">
<g:select name="${persistentProperty.toString().contains('one-to-many')?property:property+'.id'}" value="${value?.id}" required="${required}"
noSelection="${['null':'Escriba...']}" class="select2 col-md-6"
multiple="${persistentProperty.toString().contains('one-to-many')?true:false}" from="${grailsApplication.getDomainClass(persistentProperty.properties['associatedEntity'].toString()).clazz.list()}"
optionKey="id"></g:select>
</div>
This solution can be helpful. I found in the documentacion of Fields Plugin, the persistentProperty is a class type DomainProperty but their methods doesn't works and I found the correct class is org.grails.datastore.mapping.model.MappingFactory
you can use .toArray() method on your Set instead of .list().
ale
You can use the code below to identify the Element of your collection
def className = bean.hasMany[property].properties.typeName
See my "views/_fields/oneToMany/_input.gsp" implementation:
<%# page defaultCodec="html" %>
<%
def className = bean.hasMany[property].properties.typeName
def simpleName = Class.forName(className).simpleName
def beanSimpleName = bean.class.simpleName
def createUri = "/${simpleName.toLowerCase()}/create?${beanSimpleName.toLowerCase()}.id=${bean.id}"
%>
<a id="add${simpleName}" name="add${simpleName}" href="${createLink(uri: "${createUri}")}">
Add ${simpleName}
</a>
<ul>
<g:each var="item" in="${value}">
<li>
${item}
</li>
</g:each>
</ul>
I want to know the usage and implementation of the bread crumbs in grails.
i have some gsp(view) pages ,Home page is default i have 6 categories and in that 6 sub pages i need to show the navigation path in my pageslike
home/grocery/sub grocery....
home/finance/subfinance...
i need to show the page navigation.
<div id="heder_content">
<g:if test="${session.user }">
<div id="bread_crumbs"style="position:absolute;top:0px;left:474px;height:80px;width:800px">
</div>
</div>
</g:if>
What would you like to achieve exactly? You can try creating a taglib where you read the controller name and the action, and passing some parameters you can display the name of your product for example.
I mean something like this:
<g:breadcrumb title="${product.name}" />
and in your taglib file:
class BreadCrumbTagLib {
def breadcrumb = { attrs ->
def title=attrs.remove('title')
out << '''<div id="bread_crumbs"style="position:absolute;top:0px;left:474px;height:80px;width:800px">${controllerName} / ${actionName} / ${title} </div>'''
}
}
My example is very simple, but I hope you get the idea! If you need something more complex, I suggest you to get a look at: http://adityakalia.wordpress.com/2011/01/10/breadcrumbs-framework-for-grails/
edit-
I am trying to return a list of portfolios, along with the last 5 publications attached to each portfolio from my 2 domain classes. I am getting the last total 5 publications back and each list displays all 5. The query is not returning that particular instances own publications. Kellys great ideas put back into another track.
I have created the method in the portfolio controller which is the hasMany side to the publications which belongsTo the portfolio domain class.
I just cant seem to get the portfolios to list their own publications. If I change the eq portfolios, it all works fine, except each portfolio list shows the same publications.
How do I load each portfolio and list the last 5 publications. This is rendered from the portfolio/list page as a partial.Is this the issue maybe. Should I just render it from a new view which is not associated with the portfolio list action??
Newbie to grails and have read and read the doc's, just cant seem to get the params query to return correctly. Help
def _webList (){
//def per = Portfolio.properties
def portfolios = Portfolio.list(params.id)
def results = Publication.withCriteria {
eq('published', 'Yes')
order('lastUpdated', 'desc')
maxResults(5)
}
def reportscount = Publication.count()
[ portfolios: portfolios, results: results, reportscount: reportscount]
}
I can show the the sql log if needed.
EDIT
The following code is the entire partial from file _webList.gsp. The top div -alert loads on the page, but the content within the div property-list portfolio fails to load. Using Kelly's hibernate criteria produces the query in the sql log but not results or styles or anything are return to the view??. weird.!
<div class="alert alert-info" xmlns="http://www.w3.org/1999/html">Permissions apply to <strong>editing</strong> publications.<br>
<div style="display: inline;"><p>Click portfolio name to read or edit publications. Total number of sites: <strong>${rsNumb}</strong> | Total number of publications: <strong>${reportscount}</strong> </p>
</div>
</div>
<div class="property-list portfolio">
<g:each in="${portfolios}" var="portfolioInstance">
<div class="site-listing">
<div><span class="label">Site Name:</span><g:link action="show" id="${portfolioInstance?.id }">${portfolioInstance?.portfolioName?.encodeAsHTML()}</g:link></div>
<div><span class="label">Site Description: </span>${portfolioInstance?.portdescrip?.encodeAsHTML() }</div> <br>
<div><span class="label">Site Administrator: </span>${portfolioInstance?.profile?.portfolioAdmin?.encodeAsHTML() }</div> <br>
<div><span class="label"> Total publications:</span><span class="badge badge-success"> ${portfolioInstance?.publications?.size()}</span> </div>
<!-- whatever else you need here -->
<!-- now iterate through the pubs -->
<g:if test="${portfolioInstance?.publications}">
<g:set var="publicationInstance" />
<ul class="site-publication">
<li class="fieldcontain">
<span id="publications-label" class="property-label"><g:message code="portfolio.publications.label" default="Last 5 published publications:" /></span>
<g:each in="${portfolioInstance.publications}" var="publicationInstance">
${publicationInstance?.id}
<span class="property-value" aria-labelledby="publications-label"><g:link controller="publication" action="show" id="${publicationInstance.id}">${publicationInstance?.encodeAsHTML()}</g:link></span>
<!-- and again whatever else you need here -->
</g:each>
</g:if>
</g:each>
</div>
EDIT - sql log below
Hibernate: select this_.id as id5_1_, this_.version as version5_1_, this_.date_created as date3_5_1_, this_.last_updated as last4_5_1_,
this_.portdescrip as portdesc5_5_1_, this_.portfolio_name as portfolio6_5_1_, this_.portpublished as portpubl7_5_1_, this_.profile_id as profile8_5_1_,
this_.status as status5_1_,
publicatio1_.portfolio_id as portfolio5_5_3_,
publicatio1_.id as id3_, publicatio1_.id as id2_0_,
publicatio1_.version as version2_0_,
publicatio1_.date_created as date3_2_0_,
publicatio1_.last_updated as last4_2_0_,
publicatio1_.portfolio_id as portfolio5_2_0_,
publicatio1_.publication_content as publicat6_2_0_,
publicatio1_.publication_name as publicat7_2_0_,
publicatio1_.published as published2_0_,
publicatio1_.publisheddate as publishe9_2_0_,
publicatio1_.publishedemail as publish10_2_0_,
publicatio1_.pubproduct_id as pubproduct11_2_0_
from portfolio this_ left outer join publication publicatio1_
on this_.id=publicatio1_.portfolio_id where (this_.status=?)
and (publicatio1_.published=?) order by publicatio1_.last_updated desc
You are getting the java.lang.ClassCastException because portfolios is a list and portfolio in the Publication class (probably) isn't, it's probably an id (long); can't cast a list in any meaningful way to compare to a long in eq ('portfolio', portfolios)
You should not need two separate queries since the domain classes are related.
--EDIT--
Editing to not use separate action and just use list action. I've not been able to get the include to work either, but below is pretty much what I've in dozens of cases. If there is some reason you can't do this then maybe a new question on just using the include mechanism might generate some attention.
I'm not sure what your current list action looks like. This is how I would code a list method to get ALL Portfolios and their last 5 Publications. No need for any parameters because I'm returning ALL portfolios.
//PortfolioController
def list (){
def portfolios = Portfolio.createCriteria().list {
//if you needed to filter the list by for example portfolio status or something you could add that here
or {
eq('status','ACTIVE')
eq('status','PENDING')
}
publications(org.hibernate.criterion.CriteriaSpecification.LEFT_JOIN) {
eq("published", "Yes")
order("lastUpdated", "desc")
firstResult(5)
}
}
[portfolios: portfolios, portfolioCount:portfolios.size()]
}
Now the Publications come pre-attached to their Portfolio.
The LEFT_JOIN part of the above insures you get back a list of portfolios with ONLY those Publications attached that meet the criteria; if you leave that out it defaults to an inner join and when you iterate you will get ALL of the Publications for that Portfolio (even if they don't meet the criteria).
Then in your gsp iterate through the portfolios - it can either be directly in the list.gsp or in a template rendered in list.gsp. If you put it in a template called _webList.gsp you would render it in the list.gsp as
<g:render template="weblist" model="['portfolios': portfolios]" />
This is either in list.gsp or _webList.gsp - I would start with it directly in list.gsp to make sure it's all working.
<g:each in="${portfolios}" var="portfolioInstance" status="i">
${portfolioInstance?.portfolioName?.encodeAsHTML()
<!-- whatever else you need here -->
<!-- now iterate through the pubs -->
<g:each in="${portfolioInstance.publications"} var="publicationInstance" status="j">
${publicationInstance.id}
<!-- and again whatever else you need here -->
</g:each>
</g:each>
--EDIT--
firstResult(5) seems to do the trick.
--EDIT--
You'll notice I have the maxResults(5) commented in there - I'm having trouble getting that to work correctly. It seems to control the number of portfolios that are returned even though it is in the association block. Maybe someone else will see this and add that piece of the puzzle - or tinker with it yourself. I'll keep trying and update if I figure it out.
I am currently developing a web app in Grails and I am looking for a way to hide a menu based on the current user logged into the solution.
To give you a bit of background this is what I have setup
A web app with a User Model and Roles model that are mapped
Login functionality that restricts certain controllers based on the users access.
I have menus that are display on each of the pages.
I know how to restrict a controller to only allow users with access to view it but I want to now restrict a menu like the one below from being seen unless the right user is logged in, how can I do this? Does it have something to do with rendering that element from the controller??
<div class="nav">
<ul class"nav">
<li>
<g:link class="Tester" controller="Testing" action="test">
<g:message code="Tester" args"[entityName]" />
</g:link>
</li>
<li>
<g:link class="Tester2" controller="Testing" action="test2">
<g:message code="Tester2" args"[entityName]" />
</g:link>
</li>
</ul>
</div>
The spring-security-core plugin provides a taglib that may help you here
<sec:ifAnyGranted roles="ROLE_TESTER">
<div class="nav">
...
</div>
</sec:ifAnyGranted>
Ian answered your question well but we should add here to secure the server side controller/actions as well such as:
// At the controller level
#Secured(["hasRole('User')"])
class Testing
// action specific
#Secured(["hasAnyRole('SuperUser', 'Support', 'InternalUser')"])
def test() {
...
}
Otherwise the links are just hidden from view but could still be executed by anyone.
HTH
If you are not using spring-security-core plugin following can be implemented
<g:if test="${userHaveRightRole}">
<div class="nav">
...
</div>
</g:if>