Catalyst Models Intermission—MyApp source code browser

Published · Saturday, 18 July 2009 (Updated · 7 March 2010)

We have begun linking and obliquely mentioning a source browser in the example code and templates. It’s not actually covered in the articles and it’s not super-easy to explain so we’re just gonna drop it here. You can wait for the final code distribution to be able to use it if you prefer. You just won’t be able to browse your application source in a web client.

It requires Path::Class but that was already installed along with Catalyst so you shouldn’t have to install anything for this.

I do you hope you’ll note again how short the code is to do a nice nested list browser of all the files in a controlled way with Catalyst. For example, you cannot see the myapp_local.yml file with it. In this case because I have my real Amazon developer keys in there for personal tests so I know it works and I don’t want to surface them because some of the services are for pay. Yikes!

Path::Class and Alloy/TT2 are what really make it tight.

Controller

emacs lib/MyApp/Controller/Src.pm
package MyApp::Controller::Src;
use strict;
use warnings;
use parent 'Catalyst::Controller';

sub index :Path {
    my ( $self, $c ) = @_;
    unless ( $self->{enabled} )
    {
        $c->response->body(<<"MessageInAhereDoc");
Set "enabled" for this package in config to use the source browser. E.g.-
<pre>Controller::Src:
  enabled: 1</pre>
MessageInAhereDoc
        $c->detach();
    }
    $c->stash
        ( disallowed_file => '\b(?:\.svn|[#~]|etc|img/title|blib|inc|myapp_local|t|script)\b',
          disallowed_dir => '[.#~]|/\b(?:etc|img/title|blib|inc|t|script|static)\b'
        );
}

sub view :Path Args(1) {
    my ( $self, $c, $file ) = @_;
    ( my $path = $c->path_to($file) ) =~ s/[^[:print:]]+//g;
    die "No such file..." unless -f $path;
    die "No way, sucka!" if $path =~ /myapp_local/;
    $c->response->content_type("text/plain; charset=utf-8");
    $c->response->body( scalar $path->slurp );
}

1;

Template

emacs root/alloy/src/index.tt
<h1>[% c.config.name | html  %] source browser</h1>

<div>
This feature is a security risk in a live, production application. To
disable this feature remove the <code>enabled</code> setting from
<code>Controller::Src</code>&rsquo;s entry in <a href="[%
c.uri_for("/src").path %]/myapp.yml">the configuration file</a>.
</div>

[%-MACRO real_list_dirs(file_dir) BLOCK-%]
[% root ||= file_dir %]
[% IF file_dir.is_dir %]
[% NEXT IF file_dir.stringify.match(disallowed_dir) %]
  <li>[% file_dir.relative(root) == "." ? file_dir.relative(root.parent) : file_dir.relative(root) %]
    <ul>[% FOR item IN file_dir.children %]
      [% real_list_dirs(item,root) %]
    [% END %]</ul>
</li>
  [% ELSE %]
[% NEXT IF file_dir.stringify.match(disallowed_file) %]
<li>
  <a href="[% c.uri_for("/src").path %]/[% file_dir.relative(root).stringify | uri %]">[% file_dir.basename %]</a>
</li>
  [% END %]
[%-END-%]

<ul>[% real_list_dirs( c.path_to() ) %]</ul>

Configuration addition

emacs myapp.yml
Controller::Src:
  enabled: 1


digg stumbleupon del.icio.us reddit Fark Technorati Faves

« Catalyst Model #5: Stock quotes · Catalyst Model #6: Log file model–Apache access log »
« 10 Catalyst models in 10 days1 »