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

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.

Related

How can I find a specific piece of a webpage using MOJO::Dom?

Below I put an extract from an IMDb page, I purposely kept it short. My end goal is to get the 2 links. But I can't even figure out how to get a specific div with an id. Because obviously the class below is spread out all over the page. I've Googled, looking for an example using class and id, but still can't find he solution.
p.s. The only reason I have Dumper in there is so when I run it, I can instantly see how I still haven't got it.
my $ua = Mojo::UserAgent->new( max_redirects=>3, timeout => 30 );
my $dom = $ua->get($newrip)->result->dom;
my $module_list = $dom->find('div.article');
print Dumper $module_list;
exit;
<div class="article" id="titleDetails">
<span class=rightcornerlink>
Edit
</span>
<h2>Details</h2>
<div class="txt-block">
<h4 class="inline">Official Sites:</h4>
<a href="/offsite/?page-action=offsite-facebook&token=BCYtlGRCvvzcjTOrSRBQqjTPuEUBGkxbnkfQjRYZi0XJxm-A-A4vf0mzJF5WqH6HYLt2TZCuVR7c%0D%0A209QQMCwUe-51EwtDDYbNczYCnFRIRzctUhoXJCF2gsQJw6m050sV9g0sTJJEfiGP37rfeIIoXMS%0D%0ACfj2qgUNCaL2YaP_FeWVGCg39Bw-3dRsP5cB1Wk9FfobPd5tG8Q4WjVbUR2pTOvE0Pkc5QUK5E7U%0D%0AX7O9awNb0Kw%0D%0A&ref_=tt_pdt_ofs_offsite_0"
rel="nofollow">Official Facebook</a>
<span class="ghost">|</span>
Official site
<span class="see-more inline"></span>
</div>

EJS includes not working

I have an EJS file called 'test.ejs', which contains:
<p>This is a test statement</p>
Then, I have another file called 'index.ejs' which is in the same folder as the other EJS file. Index.ejs contains:
<%- include ("test") %>
<p>Hello world</p>
However, when I load the page, I do not get any output. Instead, the page just loads endlessly.
My routes in Express are being handled properly and my controllers are working too. All this is tested.
Also, can someone refer me to good EJS documentation?
Try this:
<% include ./test %>
<p>Hello world</p>
try: <% include /pathname/test %>
Documentation is sparse but the official one works
http://www.embeddedjs.com/
or
http://ejs.co/

Trouble pinpointing child elements while using Mojo::DOM

I'm trying to extract text from an old vBulletin forum using WWW::Mechanize and Mojo::DOM.
vBulletin doesn't use HTML and CSS for semantic markup, and I'm having trouble using Mojo::DOM->children to get at certain elements.
These vBulletin posts are structured differently depending on their content.
Single message:
<div id="postid_12345">The quick brown fox jumps over the lazy dog.<div>
Single message quoting another user:
<div id="postid_12345">
<div>
<table>
<tr>
<td>
<div>Quote originally posted by Bob</div>
<div>Everyone knows the sky is blue.</div>
</td>
</tr>
</table>
</div>
I disagree with you, Bob. It's obviously green.
</div>
Single message with spoilers:
<div id="postid_12345">
<div class="spoiler">Yoda is Luke's father!</div>
</div>
Single message quoting another user, with spoilers:
<div id="postid_12345">
<div>
<table>
<tr>
<td>
<div>Quote originally posted by Fred</div>
<div class="spoiler">Yoda is Luke's father!</div>
</td>
</tr>
</table>
</div>
<div class="spoiler">No waaaaay!</div>
</div>
Assuming the above HTML and an array packed with the necessary post IDs:
for (#post_ids) {
$mech->get($full_url_of_specific_forum_post);
my $dom = Mojo::DOM->new($mech->content);
my $div_id = 'postid_' . $_;
say $dom->at($div_id)->children('div')->first;
say $dom->at($div_id)->text;
}
Using $dom->at($div_id)->all_text gives me everything in an unbroken line, which makes it difficult to tell what's quoted and what's original in the post.
Using $dom->at($div_id)->text skips all of the child elements, so quoted text and spoilers are not picked up.
I've tried variations of $dom->at($div_id)->children('div')->first, but this gives me everything, including the HTML.
Ideally, I'd like to be able to pick up all the text in each post, with each child element on its own line, e.g.
POSTID12345:
+ Quote originally posted by Bob
+ Everyone knows the sky is blue.
I disagree with you, Bob. It's obviously green.
I'm new to Mojo and rusty with Perl. I wanted to solve this on my own, but after looking over the documentation and fiddling with it for a few hours, my brain is mush and I'm at a loss. I'm just not getting how Mojo::DOM and Mojo::Collections work.
Any help will be greatly appreciated.
Looking at the source of Mojo::DOM, basically the all_text method recursively walks the DOM and extracts all text. Use that source to write your own walking the DOM function. Its recursive function depends on returning a single string, in yours you might have it return an array with whatever context you need.
EDIT:
After some discussion on IRC, the web scraping example has been updated, it might help you guide you. http://mojolicio.us/perldoc/Mojolicious/Guides/Cookbook#Web_scraping
There is a module to flattern HTML tree, HTML::Linear.
The explanation of purpose for flatterning HTML tree is a bit long and boring, so here's a picture showing the output of the xpathify tool, bound with that module:
As you see, HTML tree nodes become single key/value list, where the key is the XPath for that node, and the value is the node's text attribute.
In a few keystrokes, this is how you use HTML::Linear:
#!/usr/bin/env perl
use strict;
use utf8;
use warnings;
use Data::Printer;
use HTML::Linear;
my $hl = HTML::Linear->new;
$hl->parse_file(q(vboard.html));
for my $el ($hl->as_list) {
my $hash = $el->as_hash;
next unless keys %{$hash};
p $hash;
}

using Catalyst::Model::MenuGrinder

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

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.