#!/usr/bin/perl
use strict;
$|++;
my $VERSION = '0.03';
#----------------------------------------------------------------------------
=head1 NAME
reports-ajax.cgi - program to return information for a CPAN distribution.
=head1 SYNOPSIS
perl reports-ajax.cgi
=head1 DESCRIPTION
Called in a CGI context, will return either the reporting statistics for a CPAN
named distribution, or will give the date a distribution version was released
to CPAN, depending upon the action requested.
=head1 ACTION MODES
There are two action modes available, 'reports' and 'uploaded', which provide
different data regarding a specific distribution version. For both modes, basic
parameters are required, while additional optional parameters are available for
each mode.
=head2 Common Functionality
In both modes the distribution name and version are required. This can be
derived from the 'distvers' or 'distpath' parameters as described below.
=head3 Required CGI parameters
act - action [required] ('reports' or 'uploaded')
distvers - distribution name and version
distpath - distribution filename or path
dist - distribution name
version - distribution version
Note that 'dist' and 'version' are required, but will be derived if you pass
'distvers' or 'distpath'
=head2 Reports Functionality
=head3 Optional Reports CGI parameters
force - force zeros [optional] (values: 1 only)
grades - grades [optional]
patches - allow patches [optional] (values: 1 only)
perlver - specific perl version required [optional]
osname - specific osname required [optional]
The 'grades' parameter is only used with the 'reports' action, and allows the
request to specify which totals are required. If no grades are specified, the
default is to return the grade totals in the following order: ALL PASS FAIL
UNKNOWN NA. Note that if no grade total is available, that grade is not
included in the returned string, unless the 'force' parameter is specified.
=head3 Reports Examples
> /cgi-bin/reports-ajax.cgi?act=reports&dist=CPAN-WWW-Testers&version=0.35
ALL (2) PASS (2)
> /cgi-bin/reports-ajax.cgi?act=reports&dist=CPAN-WWW-Testers&version=0.35&force=1
ALL (2) PASS (2) FAIL (0) UNKNOWN (0) NA (0)
> /cgi-bin/reports-ajax.cgi?act=reports&dist=CPAN-WWW-Testers&version=0.35&force=1&grades=fail,na,pass
FAIL (0) NA (0) PASS (2)
> /cgi-bin/reports-ajax.cgi?act=reports&distvers=CPAN-WWW-Testers-0.35
ALL (2) PASS (2)
> /cgi-bin/reports-ajax.cgi?act=reports&distpath=CPAN-WWW-Testers-0.35.tar.gz
ALL (2) PASS (2)
> /cgi-bin/reports-ajax.cgi?act=reports&distpath=BARBIE/CPAN-WWW-Testers-0.35.tar.gz
ALL (2) PASS (2)
Note that for the 'distpath' example you can provide just the distribution
filename or precede it with the author's PAUSE ID.
If no reports are found a blank string is returned. On error an error string
is returned.
=head2 Uploaded Functionality
=head3 Optional Uploaded CGI parameters
epoch - return time since epoch [optional]
When requesting the 'uploaded' action, the date returned is of the form:
"YYYY/MM/DD hh::mm::ss". However, by including the 'epoch' parameter the string
return will be the value of seconds since the server epoch time
("1970/01/01 00:00:00").
=head3 Uploaded Examples
> /cgi-bin/reports-ajax.cgi?act=uploaded&dist=CPAN-WWW-Testers&version=0.35
2008/09/28 15:37:50
> /cgi-bin/reports-ajax.cgi?act=uploaded&dist=CPAN-WWW-Testers&version=0.35&epoch=1
1222612670
If no entry for the distribution version is found '0' is returned if the epoch
is requested, otherwise '0000/00/00 00:00:00' is returned. On error an error
string is returned.
=head1 AJAX & HTML
The returning text is wrapped in HTML tags, as can be seen in the examples
above. However, to appropriately use the results, you will need to include the
following HTML snippet on the page:
It is recommended that you use the OpenThought javascript file, to enable the
communication between the client and server. See the L module on
CPAN for further details.
=cut
# -------------------------------------
# Library Modules
use OpenThought();
use CGI;
#use CGI::Carp qw(fatalsToBrowser);
use Config::IniFiles;
use CPAN::Testers::Common::DBUtils;
use CPAN::DistnameInfo;
# -------------------------------------
# Variables
my (%options,%cgiparams,$OT,$cgi);
my %rules = (
act => qr/^(reports|uploaded)$/i,
distvers => qr/^([-\w.]+)$/i,
distpath => qr/^([-\w.]+)$/i,
dist => qr/^([-\w.]+)$/i,
version => qr/^([-\w.]+)$/i,
grades => qr/^((?:all|pass|fail|unknown|na)(?:,(?:all|pass|fail|unknown|na))*)$/i,
force => qr/^(1)$/i,
epoch => qr/^(1)$/i,
patches => qr/^([0-1])$/i,
perlver => qr/^([\w.]+)$/i,
osname => qr/^([\w.]+)$/i
);
# -------------------------------------
# Program
init_options();
process_reports() if($cgiparams{act} eq 'reports');
process_uploaded() if($cgiparams{act} eq 'uploaded');
# -------------------------------------
# Subroutines
sub init_options {
$options{config} = 'data/settings.ini';
error("Must specific the configuration file") unless($options{config});
error("Configuration file [$options{config}] not found") unless(-f $options{config});
# load configuration
my $cfg = Config::IniFiles->new( -file => $options{config} );
# configure upload DB
for my $db (qw(CPANSTATS UPLOADS)) {
my %opts = map {$_ => $cfg->val($db,$_);} qw(driver database dbfile dbhost dbport dbuser dbpass);
$options{$db} = CPAN::Testers::Common::DBUtils->new(%opts);
error("Cannot configure '$options{$db}' database") unless($options{$db});
}
$OT = OpenThought->new();
$cgi = CGI->new;
for my $key (keys %rules) {
my $val = $cgi->param($key);
$cgiparams{$key} = $1 if($val =~ $rules{$key});
}
#$cgiparams{act} = 'reports';
#$cgiparams{distvers} = 'CPAN-WWW-Testers-0.39';
#$cgiparams{distpath} = 'CPAN-WWW-Testers-0.39.tar.gz';
if($cgiparams{distvers}) {
$cgiparams{distpath} = $cgiparams{distvers} . '.tar.gz';
}
if($cgiparams{distpath}) {
my $d = CPAN::DistnameInfo->new($cgiparams{distpath});
$cgiparams{dist} = $d->dist;
$cgiparams{version} = $d->version;
}
error("Missing variables act=[$cgiparams{act}]","No action given\n")
unless($cgiparams{act});
error("Missing variables dist=[$cgiparams{dist}], version=[$cgiparams{version}]","No distribution or version given\n")
unless($cgiparams{dist} && $cgiparams{version});
}
sub process_reports {
my $next = $options{CPANSTATS}->iterator(
'hash',
"SELECT * FROM cpanstats WHERE dist=? AND version=? AND state!='cpan'",
$cgiparams{dist},$cgiparams{version});
my %counts;
while(my $row = $next->()) {
next if(!$cgiparams{patches} && $row->{perl} =~ /patch/i);
next if( $cgiparams{perlver} && $row->{perl} !~ /$cgiparams{perlver}/i);
next if( $cgiparams{osname} && $row->{osname} !~ /$cgiparams{osname}/i);
$counts{ALL}++;
$counts{PASS}++ if($row->{state} eq 'pass');
$counts{FAIL}++ if($row->{state} eq 'fail');
$counts{UNKNOWN}++ if($row->{state} eq 'unknown');
$counts{NA}++ if($row->{state} eq 'na');
}
my $str;
my @grades = $cgiparams{grades} ? split(',',uc $cgiparams{grades}) : qw(ALL PASS FAIL UNKNOWN NA);
for(@grades) {
next unless($cgiparams{force} || $counts{$_});
$counts{$_} ||= 0;
$str .= qq!$_ ($counts{$_}) !;
}
my $html;
$html->{'report_stats'} = $str;
$OT->param( $html );
print $cgi->header;
print $OT->response();
}
sub process_uploaded {
my @rows = $options{UPLOADS}->get_query(
'hash',
"SELECT released FROM uploads WHERE dist=? AND version=?",
$cgiparams{dist},$cgiparams{version});
my $str;
if(@rows) {
if($cgiparams{epoch}) {
$str = qq!$rows[0]->{released}!;
} else {
my @dt = localtime($rows[0]->{released});
$str = sprintf '%04d/%02d/%02d %02d:%02d:%02d', $dt[5]+1900,$dt[4]+1,$dt[3],$dt[2],$dt[1],$dt[0];
}
} else {
if($cgiparams{epoch}) {
$str = '0';
} else {
$str = '0000/00/00 00:00:00';
}
}
my $html;
$html->{'report_stats'} = $str;
$OT->param( $html );
print $cgi->header;
print $OT->response();
}
sub error {
my @mess = @_;
$mess[1] ||= "Error retrieving data\n";
print STDERR $mess[0];
print $cgi->header('text/plain'), $mess[1];
exit;
}
1;
__END__
=head1 FUTUTE ENHANCEMENTS
Although every attempt has been made to provide as much useful functionality
in these scripts, it is possible that there is further information you would
want it to provide. If you have a suggestion to enhance the capability of this
script, please post it as a wishlist item to the RT queue.
=head1 BUGS, PATCHES & FIXES
There are no known bugs at the time of this release. However, if you spot a
bug or are experiencing difficulties, that is not explained within the POD
documentation, please send bug reports and patches to the RT Queue (see below).
Fixes are dependant upon their severity and my availablity. Should a fix not
be forthcoming, please feel free to (politely) remind me.
RT: http://rt.cpan.org/Public/Dist/Display.html?Name=CPAN-WWW-Testers
=head1 SEE ALSO
L
L,
L
F,
F
=head1 AUTHOR
Barbie 2008-present
=head1 COPYRIGHT AND LICENSE
Copyright (C) 2008-2009 Barbie
This module is free software; you can redistribute it and/or
modify it under the same terms as Perl itself.
=cut