Route to static file in Mojo - perl

I have small app based on mojolicious. And I have index.html in public dir. I want to have route to this file when user asks for '/'.
I wrote two solution, but I don't like them.
First solution - add simple controller.
sub stratup {
//...
$r->get('/')->to('general#index_html');
//...
}
package MyPackage::General;
use Mojo::Base 'Mojolicious::Controller';
use strict;
use warnings;
sub index_html {
my $self = shift;
$self->render_static('index.html');
return;
}
1;
Second solution - add hook
sub startup {
my $self = shift;
$self->hook(before_dispatch => sub {
my $self = shift;
if ($self->req->url eq '/') {
$self->req->url( Mojo::URL->new('/index.html') );
}
});
What I want:
$r->get('/')->to('/index.html');
or something like that.
P.S. I know, than usualy nginx/apache do it, but I use morbo to run code.

You want:
$r->get('...')->to(cb => sub {
my $c = shift;
$c->reply->static('index.html')
});
(As long as you're after Mojolicous 5.45 2014-09-26)

By far the simplest way is
get "/" => "index";

I'll dig this up from the graveyard, why not.
I found myself similarly trying to serve a static html file in a docker container that I had using to serve both a Mojolicious REST API and a Vue.js front end. After searching around and piecing sporadic information together, this is what seems to work for me.
** disclaimer: I have not fully tested this with Vue routing and other aspects as yet.
My directory structure:
/app
/app/script
/app/modules/ui
/app/modules/ui/dist
From the command line the app directory, using morbo to test:
morbo script/ui.pl
ui.pl script
#!/usr/bin/env perl
use Mojolicious::Lite -signatures;
use Mojo::File qw(curfile);
use v5.25;
my $app = app;
my $static = $app->static;
push #{$static->paths}, curfile->dirname->sibling('modules/ui/dist')->to_string;
any '/' => sub {
my $c = shift;
my $content = $static->file("/index.html")->slurp;
$c->render(text => $content);
};
$app->start;
Using a combo of information from https://metacpan.org/pod/Mojolicious::Static and basic routing information at https://docs.mojolicious.org/Mojolicious/Lite, I could get the vue.js index page to render as expected.
** UPDATED A DAY LATER **
As it turns out, there is an easier way, though not clearly documented. If you place the static files inside your public folder, you can use the default helpers included with Mojolicious to render the files. The documentation refers to it here, https://docs.mojolicious.org/Mojolicious/Guides/Rendering#Serving-static-files, but it's not very clear on how to make it happen.
I tooled around some, but it took browsing the code of Controller.pm of for Mojolicious to sort it out. This section of the POD led me to determine how to get the reply object:
=head2 helpers
my $helpers = $c->helpers;
Return a proxy object containing the current controller object and on which helpers provided by /app can be called. This includes all helpers from Mojolicious::Plugin::DefaultHelpers and Mojolicious::Plugin::TagHelpers.
# Make sure to use the "title" helper and not the controller method
$c->helpers->title('Welcome!');
# Use a nested helper instead of the "reply" controller method
$c->helpers->reply->not_found;
Based on this, I can drop my files into the public folder:
/app/public/index.html
Then modify my controller to match:
# https://docs.mojolicious.org/Mojolicious/Guides/Rendering#Serving-static-files
any '/' => sub {
my $c = shift;
$c->helpers->reply->static('index.html');
};

Related

param info for mojolicious routing using under

I'm using the under method in Mojolicious routing to handle some route permissions. I was hoping to handle nearly all routes by passing to a common controller function, however it doesn't appear that under captures all of the params that I need. Here's a MWE:
package Test;
use Mojo::Base 'Mojolicious', -signatures;
sub startup ($app) {
my $config = $app->plugin('NotYAMLConfig');
$app->secrets($config->{secrets});
$app->routes->under('/api')->to('Permission#allow')->get('/users/:user_id')->to('User#getUser');
$app->routes->under('/api/other/users/:user_id')->to('Permission#allow')->get('/')->to('User#getUser');
}
1;
with the module Permission as:
package Test::Controller::Permission;
use Mojo::Base 'Mojolicious::Controller', -signatures;
sub allow ($c) {
print $c->dumper($c->stash->{'mojo.captures'});
return 1;
}
1;
and module User.pm is:
package Test::Controller::User;
use Mojo::Base 'Mojolicious::Controller', -signatures;
sub getUser ($c) {
$c->render(text => 'The user_id is: ' . $c->param('user_id'));
}
1;
There is a basic script called test that was created with the mojo generate and running script/test /api/users/3 shows that the user_id is not available as a $c->param('user_id') in the Permission#allow sub, however is in the User#getUser sub.
Running script/test /api/other/users/3 does show that now Permission#allow has user_id available as a param.
This is clearly the difference in defining the under part of the route. My question is do I need to defined all of the under in my routes (I have about 20 in my full app), or is there another way to capture the params in a more general way.
I have noticed that the allow sub has the url of the full route (with the route params).

Perl Mojolicious Model

I am creating a
Mojolicious
application but I can't understand the documentation for creating a model.
Could someone provide an example of how to create a model, run a raw SQL query and get the results in a controller to pass to the view?
I am thinking of something like this:
Model
package LS::Model::Dt;
use Mojo::Base;
use DBI;
# Here is what I don't understand
# Do I need to create a subroutine that connects to the database like this?
sub connect_db {
my $user = 'user_sql';
my $pass = 'pass_sql';
my $connection = "dbi:Sybase:server=db.sql-srv.com;database=Adventure";
my $dbh = DBI->connect($connection, $user, $pass) or die 'Cannot connect';
}
sub queries{
my $query_selectall = "select * from foo";
my $all_query = $dbh->selectall_arrayref($query_selectall, {Slice => {}});
}
Controller
package LS::Controller::Home;
use Mojo::Base 'Mojolicious::Controller';
use LS::Model::Dt
sub home {
my $self = shift;
# Somehow get the query results here
my $query_res = #somehow get the query results here
$self->render(res=>$query_res);
}
1;
Later edit: I have managed somehow via this tutorial:
http://oliverguenther.de/2014/04/applications-with-mojolicious-part-four-database-schemas-with-dbixclass/
Github code for when you are now sure where the author is creating a file is available here:
https://github.com/oliverguenther/Moblo
If you encounter problems also check this:
Mojolicious Deploying database schema

mojolicious helper storing an elasticsearch connection

i'm experimenting with elasticsearch within mojolicious.
I'm reasonably new at both.
I wanted to create a helper to store the ES connection and I was hoping to pass the helper configuration relating to ES (for example the node info, trace_on file etc).
If I write the following very simple helper, it works;
has elasticsearch => sub {
return Search::Elasticsearch->new( nodes => '192.168.56.21:9200', trace_to => ['File','/tmp/elasticsearch.log'] );
};
and then in startup
$self->helper(es => sub { $self->app->elasticsearch() });
however if I try to extend that to take config - like the following -
it fails. I get an error "cannot find index on package" when the application calls $self->es->index
has elasticsearch => sub {
my $config = shift;
my $params->{nodes} = '192.168.56.21:' . $config->{port};
$params->{trace_to} = $config->{trace_to} if $config->{trace_to};
my $es = Search::Elasticsearch->new( $params );
return $es;
};
and in startup
$self->helper(es => sub { $self->app->elasticsearch($self->config->{es}) });
I assume I'm simply misunderstanding helpers or config or both - can someone enlighten me?
Just fyi, in a separate controller file I use the helper as follows;
$self->es->index(
index => $self->_create_index_name($index),
type => 'crawl_data',
id => $esid,
body => {
content => encode_json $data,
}
);
that works fine if I create the helper using the simple (1st) form above.
I hope this is sufficient info? please let me know if anything else is required?
First of all, has and helper are not the same. has is a lazily built instance attribute. The only argument to an attribute constructor is the instance. For an app, it would look like:
package MyApp;
has elasticsearch => sub {
my $app = shift;
Search::ElasticSearch->new($app->config->{es});
};
sub startup {
my $app = shift;
...
}
This instance is then persistent for the life of the application after first use. I'm not sure if S::ES has any reconnect-on-drop logic, so you might need to think about it a permanent object is really what you want.
In contrast a helper is just a method, available to the app, all controllers and all templates (in the latter case, as a function). The first argument to a helper is a controller instance, whether the current one or a new one, depending on context. Therefore you need to build your helper like:
has (elasticsearch => sub {
my ($c, $config) = #_;
$config ||= $c->app->config->{es};
Search::ElasticSearch->new($config);
});
This mechanism will build the instance on demand and can accept pass-in arguments, perhaps for optional configuration override as I have shown in that example.
I hope this answers your questions.

Base url in Mojolicious template rendering

Is there a way to have urls such as /foo/bar replaced bay baseurl/foo/bar for each template rendering?
Absolutely. You can do this with the before_dispatch hook (or maybe the before_routes hook) in the Mojolicious::App object.
app->hook( before_dispatch => sub {
my $c = shift;
unless ($c->req->url->path->to_route =~ m#/baseurl#) {
$c->req->url->path( "/baseurl" . $c->req->url->path->to_string);
}
} );
...
app->start;
I can't add comments yet but I just wanted to add that mob is correct - the example code using hooks is the recommended approach for URL rewriting:
http://mojolicio.us/perldoc/Mojolicious/Guides/Cookbook#Rewriting

How to debug Bugzilla extension that doesn't appear to run?

I need some help getting a bugzilla extension off the ground.
I want to hook into bug_format_comment (FWIW: to change some plain text automatically added as a comment when I commit to SVN to links to the respective SCM commit.)
Right now, nothing seems to happen when I manually add a comment to a bug.
Is there anything special I need to do to make the extension run, besides putting it in the /extensions/my-ext-name/ dir ?
How can I test if the extension is called at all?
I use an old version of Bugzilla (3.2.x). Is that hook even supported? (I can't find that info in the documentation).
Here's my complete Extension.pm file (I have no experience in Perl. I took the example of the hook from the example extension and ran from there)
package Bugzilla::Extension::Websvn-scmbug-autolink;
use strict;
use base qw(Bugzilla::Extension);
# This code for this is in ./extensions/Websvn-scmbug-autolink/lib/Util.pm
use Bugzilla::Extension::Websvn-scmbug-autolink::Util;
use URI::Escape;
our $VERSION = '0.01';
# See the documentation of Bugzilla::Hook ("perldoc Bugzilla::Hook"
# in the bugzilla directory) for a list of all available hooks.
sub install_update_db {
my ($self, $args) = #_;
}
sub bug_format_comment {
my ($self, $args) = #_;
my $regexes = $args->{'regexes'};
# push(#$regexes, { match => qr/\bfoo\b/, replace => 'bar' });
# 6665 --> 6666
# CTUFramework:trunk/CTUCsharpRuntime/CtuFramework/text1-renamed.txt
#my $bar_match = qr/\b(bar)\b/;
my $bar_match = qr/(?:^|\r|\n)(\d+|NONE) (-->) (\d+|NONE)[ \r\n\t]+([^:]+):(.*?)[\r\n]/s; #/s - treat as single line
push(#$regexes, { match => $bar_match, replace => \&_replace_bar });
my $scm_match2 = qr/(?:^|\r|\n)(\d+|NONE) (-->) (\d+|NONE)[ \r\n\t]+([^:]+):(.*?)[\r\n]/s; #/s - treat as single line
push(#$regexes, { match => $scm_match2, replace => \&_replace_bar });
}
# Used by bug_format_comment--see its code for an explanation.
sub _replace_bar {
my $args = shift;
my $scmFromVer = $args->{matches}->[0];
my $scmToVer = $args->{matches}->[1];
my $scmArrow = $args->{matches}->[2];
my $scmProject = $args->{matches}->[3];
my $scmFile = $args->{matches}->[4];
# Remember, you have to HTML-escape any data that you are returning!
my $websvnRoot = "http://devlinux/websvn";
my $websvnRepo = uri_escape($scmProject); #maybe do a mapping
my $websvnFilePath = uri_escape("/".$scmFile);
my $fromRevUrl = sprintf("%s/revision.php?repname=%s&rev=%s",
$websvnRoot, $websvnRepo, $scmFromVer);
my $toRevUrl = sprintf("%s/revision.php?repname=%s&rev=%s",
$websvnRoot, $websvnRepo, $scmToVer);
my $diffUrl = sprintf("%s/diff.php?repname=%s&path=%s&rev=%s",
$websvnRoot, $websvnRepo, $websvnFilePath, $scmToVer);
my $fileUrl = sprintf("%s/filedetails.php?repname=%s&path=%s&rev=%s",
$websvnRoot, $websvnRepo, $websvnFilePath, $scmToVer);
# TODO no link for 'NONE'
my $fromRevLink = sprintf(qq{%s}, $fromRevUrl, $scmFromVer);
my $toRevLink = sprintf(qq{%s}, $toRevUrl, $scmToVer);
my $diffLink = sprintf(qq{%s}, $diffUrl, $scmArrow);
my $fileLink = sprintf(qq{%s}, $fileUrl, $scmFilePath);
# $match = html_quote($match);
return "$fromRevLink $diffLink $toRevLink:$fileLink";
};
__PACKAGE__->NAME;
As written, your extension won't even load: dashes are not valid in Perl package names.
Change the name from Websvn-scmbug-autolink to Websvn_scmbug_autolink.
I searched the Bugzilla sources, and found that the hook is simply not supported in version 3.2.x. The hook was introduced in Bugzilla 3.6: http://bzr.mozilla.org/bugzilla/3.6/revision/6762
PS. I hacked the regex replaces right in the template script for comments. Hacky, but it works.