Skip to content

Instantly share code, notes, and snippets.

@s1037989
Last active June 12, 2017 18:36
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save s1037989/03960207a2b9a9befc6d5f21c0f70adc to your computer and use it in GitHub Desktop.
Save s1037989/03960207a2b9a9befc6d5f21c0f70adc to your computer and use it in GitHub Desktop.
Tiny URL clone built with Mojolicious in 1 hour
#!/usr/bin/env perl
use Mojolicious::Lite;
use Mojo::Pg;
use List::Util qw(shuffle);
# tiny.conf
# { pg => 'postgresql://a:b@c/d', };
# Get a quick and free tiny hosted Postgresql database at
# http://elephantsql.com
plugin 'Config';
helper pg => sub { state $pg = Mojo::Pg->new(shift->config('pg')) };
app->pg->migrations->from_data->migrate;
any '/' => sub {
my $c = shift;
# Check if parameters have been submitted
# and if not show the errors
my $v = $c->validation;
return $c->render unless $v->has_data;
$v->required('url')->like(qr/^https?:\/\//);
return $c->render if $v->has_error;
my $tiny;
# If someone already submitted the same URL, use the same tiny code
unless ( $tiny = $c->pg->db->query('select * from tiny where url = ?', $v->param('url'))->hash ) {
# Otherwise, store the new URL and generate a tiny code based on the shuffling of the URL
$tiny = $c->pg->db->query('insert into tiny (id, url) values (left(md5(?), 6), ?) returning *',
join('', shuffle(split //, $v->param('url'))),
$v->param('url'),
)->hash;
}
app->log->info(sprintf("Add: %s => %s", $tiny->{id}, $tiny->{url}));
# Show the same index page, but show the tiny code just created
$c->flash($tiny)->redirect_to('index');
} => 'index';
get '/:id' => sub {
my $c = shift;
# Redirect to the URL on file for the code provided, 404 otherwise
return $c->reply->not_found unless my $tiny = $c->pg->db->query('select url from tiny where id = ?', $c->param('id'))->hash;
app->log->info(sprintf("Redirect: %s => %s", $c->param('id'), $tiny->{url}));
return $c->reply->not_found unless $tiny->{url};
$c->redirect_to($tiny->{url});
} => 'tiny';
app->start or exit unless app->mode =~ /^test/;
__DATA__
@@ migrations
-- 1 up
create table tiny (id text, url text);
create unique index on tiny (id);
-- 1 down
drop table tiny;
@@ index.html.ep
% layout 'default';
% title 'Welcome';
% if ( my $id = flash 'id' ) {
Your Tiny URL is: <%= link_to url_for('tiny', {id => $id})->to_abs => begin %><%= url_for('tiny', {id => $id})->to_abs %><%= end %><br>
Which maps to: <%= flash 'url' %><br><br>
% }
%= form_for 'index', (method => 'POST') => begin
%= label_for url => 'New Tiny URL (must be a valid URL)'
<br>
%= text_field 'url', placeholder => 'Enter your URL here'
<br>
%= submit_button
%= end
@@ layouts/default.html.ep
<!DOCTYPE html>
<html>
<head>
<title><%= title %></title>
<style>
label.field-with-error { color: #dd7e5e }
input.field-with-error { background-color: #fd9e7e }
</style>
</head>
<body><%= content %></body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment