#!/usr/bin/env perl
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# ABSTRACT: Web interface for breakpad
use Mojolicious::Lite;
use Mojo::Loader qw/load_class/;
use UUID;
use lib 'lib';
use CrashTest::Models::Frame;
use CrashTest::Models::Thread;
use CrashTest::StackFilter;
app->attr(storage => sub {
my $self = shift;
my $storage_class = $self->app->config->{Storage}->{Type};
if (my $e = load_class($storage_class)) {
die ref $e ? "Exception: $e" : 'Not found!';
}
state $storage = $storage_class->new(
config => $self->app->config->{Storage},
extra_columns => $self->app->config->{WebInterface}->{ExtraColumns},
);
return $storage;
});
app->attr(decode_queue => sub {
my $self = shift;
my $decode_class = $self->app->config->{DecodeQueue}->{Type};
if (my $e = load_class($decode_class)) {
die ref $e ? "Exception: $e" : 'Not found!';
}
state $decode = $decode_class->new(
config => $self->app->config->{DecodeQueue},
dumper_config => $self->app->config->{Dumper},
storage => $self->app->storage
);
return $decode;
});
app->attr(stackfilter => sub {
my $self = shift;
state $stackfilter = CrashTest::StackFilter->new(
config => $self->app->config,
app => $self->app
);
return $stackfilter;
});
get '/' => sub {
my $self = shift;
my $page = 1;
my $crashs_per_page = 25;
if($self->req->url =~ qr{.*\.atom$}) {
$crashs_per_page = 100;
}
$self->validation->required('page')->like(qr/^[0-9]+$/);
$page = scalar $self->validation->param("page") if $self->validation->is_valid('page');
my $result = $self->app->storage->index($page, $crashs_per_page, $self->req->param('search'));
$self->stash(files => $result->{crashs});
$self->stash(pager => $result->{pager});
$self->stash(extra_columns => $self->app->config->{WebInterface}->{ExtraColumns}->{Index});
$self->render('index');
} => 'index';
get '/report/:uuid' => [ uuid => qr/[0-9a-fA-F-]+/ ] => sub {
my $self = shift;
my $data = $self->app->storage->get_processed_data($self->param('uuid'));
$self->stash(processed_data => $data);
my $crashing_thread = CrashTest::Models::Thread->new($data->{crashing_thread});
$crashing_thread = $self->app->stackfilter->apply($crashing_thread);
$self->stash(crashing_thread => $crashing_thread);
my @threads = ();
foreach my $raw_thread(@{$data->{threads}}) {
my $thread = CrashTest::Models::Thread->new($raw_thread);
$thread = $self->app->stackfilter->apply($thread);
push @threads, $thread;
}
$self->stash(threads => \@threads);
$self->render('report/crash');
} => 'report';
post '/submit' => sub {
my $self = shift;
#my @valid_params = qw/Add-ons Distributor ProductName ReleaseChannel StartupTime UserID Version BuildID CrashTime Comments/;
# save the dump in a file
my $file = $self->req->upload('upload_file_minidump');
# TODO check for authorised values ...
my %paramshash = map { $_ => $self->req->param($_) } $self->req->param;
my ($uuid, $uuidstr);
UUID::generate($uuid);
UUID::unparse($uuid, $uuidstr);
$self->render_later();
$self->app->decode_queue->decode($file, \%paramshash, $uuidstr, sub {
my $pjson = shift;
# reply
$self->render(text => $pjson->{status});
}
);
} => 'submit';
app->secrets([
'My secret passphrase here'
]);
push @{app->commands->namespaces}, 'CrashTest::Commands';
push @{app->plugins->namespaces}, 'CrashTest::Helpers';
plugin 'Config';
plugin 'bootstrap_pagination';
plugin 'CrashTestHelpers';
app->start;