using Catalyst::Model::MenuGrinder - perl

I am trying to add a dynamic menu to my WebApp using Catalyst::Model::MenuGrinder
the documentation isn't very clear on how to configure access to via roles using this model.
has anyone implemented dynamic menu's using this Model?
I found this article in the Catalyst Advent calendar and have set it up correctly I just don't know how to configure it to restrict menu options based on roles.
Any help would be appreciated
thanks

As documented in the RequirePrivilege module, you restrict a menu entry based on privileges by adding keys like need_priv and need_user_in_realm. MenuGrinder "privileges" correspond to Catalyst authentication "roles", so if you want to require that a user has the role "admin" for a section, you just do
<item>
<label>Admin Section</label>
<need_priv>admin</need_priv>
<item>...</item>
<item>...</item>
</item>

Just take a look at your template file which generates the menu actually. Let's say for example that the "Clothes" menu should be display for admins only.
You can edit you xml file, like:
<item role="adminonly"><label>Clothes</label>...
and after that you should only check in the menuitem BLOCK if the user has the desired role:
[% BLOCK menuitem %]
<ul [%- IF menu.class %]class="[% menu.class %]"[% END %]>
[% FOREACH item = menu.item %]
[% IF item.role %]
[% IF c.user_exists && c.check_user_roles( item.role ) %]
<li [% IF item.active %]class="active"[% END %]>
[% item.label %]
[% IF item.item %]
[% PROCESS menuitem
menu = item
%]
[% END %]
</li>
[% END %]
[% END %]
[% END %]
</ul>
[% END %]
[% PROCESS menuitem %]
PS: Never tested the above code

Related

with Catalyst framework, how to check the uri path in wrapper.tt

I like to check the path in wrapper.tt, so I can dynamically include links based on the path. But I can't figure out the way to get the path in the tt file after extensive online search. For example, I can check if a user has signed in and, if yes, show the user's name as the following. Thanks.
[% IF c.user_exists %]
<h4 style="float:right;">[% c.user.username %] logout</h4>
[% ELSE %]
<h4 style="float:right;">login</h4>
[% END %]
I got the answer. c.req.path is the uri path.

Dashing - dynamically delete widgets

how can i dynamically delete widgets from a job(rb) in Dashing?
I am building the dashboard dynamically by sending a data to the erb file:
<div class="gridster">
<ul>
<% settings.servers.each do |data| %>
<li data-row="1" data-col="1" data-sizex="1" data-sizey="1">
<div data-id="<%=data['webHost']%>" data-title="<%=data['name']%>" data-version="<%=data['Version']%>" >
</li>
<% end %>
</div>
Yes. I wrote a simple example job that can do just that here:
http://www.mapledyne.com/ideas/2015/6/30/delete-a-dashing-dashboard-widget
You basically just want to manipulate the Sinatra::Application.settings.history variable, but the code in that link should get you most of the way to where you want to be.
Or skip the post and go right to the gist file:
https://gist.github.com/mapledyne/6fb671c17c3f865309f3#file-delete-widget-rb
You can also generate parts of the erb dynamically if you don't know the widgets in the first place (more complicated), but it starts with the same - leveraging that same history variable.

In TYPO3 Fluid, how do I access a variable from inside a foreach loop?

I am building a navigation with the VHS Menu ViewHelper. Below is the entire code.
My question is probably very basic fluid though.
Inside a scope, how do I access a variable that exists outside that scope - or how do I pass it into that scope?
EDIT: I've updated my code to not use dashes in variable names as well as assigned different names to v:page.menu with as="menuLevel0".
The full code:
{namespace v=Tx_Vhs_ViewHelpers}
<ul id="nav" class="grid-full classic">
<v:page.menu as="menuLevel0" expandAll="1" useShortcutData="1" levels="4" classHasSubpages="parent" classFirst="first" classLast="last">
<f:for each="{menuLevel0}" as="itemLevel0" iteration="iterLevel0">
<li class="{itemLevel0.class} level0 nav-{iterLevel0.cycle} level-top">
<a href='{itemLevel0.link}' class='level-top'><span>
<f:if condition="{itemLevel0.nav_title}"><f:then>{itemLevel0.nav_title}</f:then><f:else>{itemLevel0.title}</f:else></f:if>
nav-{iterLevel0.cycle}</span>
</a>
<f:if condition="{itemLevel0.hasSubPages}">
<f:then>
<v:page.menu as="menuLevel1" expandAll="1" classHasSubpages="parent" classFirst="first" classLast="last">
<ul class="level0">
<f:for each="{menuLevel1}" as="itemLevel1" iteration="iterLevel1">
<li class="{itemLevel1.class} level1 nav-{iterLevel0.cycle}-{iterLevel1.cycle}">
<a href='{itemLevel1.link}' class='level-top'><span>
<f:if condition="{itemLevel1.nav_title}"><f:then>{itemLevel1.nav_title}</f:then><f:else>{itemLevel1.title}</f:else></f:if>
nav-{menuLevel0.iterLevel0.cycle}-{iterLevel1.cycle}
</span></a>
</li>
</f:for>
</ul>
</v:page.menu>
</f:then>
</f:if>
</li>
</f:for>
</v:page.menu>
</ul>
In fluid, variables are and should be scoped to the blocks you are using.
While you are using our v:page.menu ViewHelpers, you need to understand the scoping a bit further:
Use different names for variables in nested scopes: {levelOneIterator} and {levelTwoIterator} are good examples for such behaviour
As a rule of thumb: Use lowerCamelCased variable names. It prevents fluid from parsing your var-names wrong.
The reason why your code is not working:
You assign a {iter} variable. Therefore fluid doesn't parse the dash-ified variable name as it detects the undashified identifier first. Dashes have special meaning in fluid and you can run into kind-of race conditions there.
To take this a bit further:
```
{foo-bar} // echos "baz"
{foo-bar} // echos "bing", as the bar vaiable is read first, and "foo-" isnt a variable in the current scope
```
Update:
Accessing variables from a parent scope doesnt require prefixing your var-call. In a child for-loop, you can access the parent iteration by simply calling the var.
<f:for each="{iterable}" as="iterableItem iteration="iteratorRoot">
{iteratorRoot.index} <!-- Echoes the current, zero-indexed iteration -->
<f:for each="{iterableItem}" as="subItem" iteration="iterationChild">
<!-- STILL echoes the current, zero-indexed iteration -->
{iteratorRoot.index}
<!-- Echoes the current, zero-indexed sub iteration -->
{iterationChild.index}
</f:for>
</f:for>
As long as you give different names to the iterators, you can access them in any scope by their originating name. Same goes for the aliased (as="name") named variables.
Try not using "-" in the variable-name! Use CamelCase instead:
<f:render section="layer2" arguments="{uid: curPage.uid, parentIter: iter.cycle}" />
In Controller
public function listAction() {
$events = $this->eventsRepository->getEventsList();
$this->view->assign('eventsList', $events);
}
In View File you can access like this.
<f:for each="{eventsList}" as="events">
<tr>
<td> {events.event_id} </td>
<td> <f:link.external uri="{events.event_link}" target="_blank">{events.event_link}</f:link.external></td>
<td><f:format.date format="d-m-Y">{events.event_date}</f:format.date></td>
</tr>
</f:for>
Have you tried not to use the same varibale name for the iterators in both of your foreach loops?

Email travel package info from user (CMS Made Simple, CGECommerce, Cart, Products, etc.)

I am using CMS Made Simple along with all of Calguy's plugins for e-commerce(Products, Orders, Cart, etc.)I can't quite figure out how to make what I need. How can I make a form with items from the Products module and checkboxes for each, and at the end a total and lost for the checked items is sent to the owner of the site? Any pointers would be appreciated much, I can figure out the rest.
If you use the Cart Module you could try customizing a viewcart template under "Viewcart Form Templates".
Once products are selected you can use another template to put the contents of the cart in an email. Something like this can be used to create a really basic list + total listing:
{if !isset($cartitems) || count($cartitems) == 0 }
<p>No products in the cart.</p>
{else}
<ul>
{foreach from=$cartitems item='oneitem'}
<li>
{$oneitem->quantity}x {$oneitem->summary} ({$currencysymbol}{$oneitem->item_total|number_format:2})
{if $oneitem->quantity > 1}
({$currencysymbol}{$oneitem->base_price|number_format:2} each)
{/if}
</li>
{/foreach}
</ul>
{$total_text}: {$currencysymbol}{$carttotal|number_format:2}
{/if}
You can always temporarily insert {$cartitems|print_r} into your template to view the attributes that are available for use in the smarty code.

What's the right way to display a DBIx::Class ResultSet in my Catalyst project that uses Template Toolkit?

Given a DBIx::Class resultset, for example:
my $rs = $c->model("DB::Card")->search({family_name => "Smith"});
the tutorials I've read use the stash to pass an arrayref of rows:
$c->stash->{cards} = [$rs->all];
This results in the query getting executed at this point, and the resulting objects stuffed into the stash, so they can be used in TemplateToolkit as:
[% FOREACH card IN cards %]
[% card.given_name %] [% card.family_name %]
[%END%]
Is there a proper way to have TT iterate over the rows as they get fetched from the DB?
Sure. You can pass the result set directly to TT and iterate over it in the template.
$c->stash->{cards} = $rs;
...and then:
[% WHILE (card = cards.next) %]
[% card.given_name %] [% card.family_name %]
[% END %]
Or, even better:
$c->stash(cards => $rs);
...in TT template:
[% FOREACH card = cards %]
[% card.given_name %] [% card.family_name %]
[% END %]
I do:
#{$c->stash->{cards}} = $rs->all;
In the template:
[% FOREACH card IN cards %]
[% card.given_name %] [% card.family_name %]
[% END %]
I WAS doing exactly the same thing as the author.
In trying to create a more strict MVC approach, I'm now processing the DBIC objects in the controller and passing a very simple stash for the template to display. (Key benefit being the code is reusable by other scripts instead of just the web interface.)
I'm curious if anyone knows if this is more efficient or not, processing or memory-wise. I would think the first method results in less processing time but holds onto memory longer. I'd guess my new approach takes a bit more processing and a bit more memory temporarily, but the potentially large result set object doesn't live as long.