chiark / gitweb /
Properly quote various error messages
[ypp-sc-tools.web-live.git] / yarrg / CommodsWeb.pm
index 377d97b1c5c8e9794df7917e1bfb0cb3a6680a66..461a8ad49332da3d232121822012e0002ecb00dc 100644 (file)
@@ -1,26 +1,33 @@
-# This is part of ypp-sc-tools, a set of third-party tools for assisting
-# players of Yohoho Puzzle Pirates.
+# This is part of the YARRG website.  YARRG is a tool and website
+# for assisting players of Yohoho Puzzle Pirates.
 #
 # Copyright (C) 2009 Ian Jackson <ijackson@chiark.greenend.org.uk>
+# Copyright (C) 2009 Clare Boothby
+#
+#  YARRG's client code etc. is covered by the ordinary GNU GPL (v3 or later).
+#  The YARRG website is covered by the GNU Affero GPL v3 or later, which
+#   basically means that every installation of the website will let you
+#   download the source.
 #
 # 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.
+# it under the terms of the GNU Affero 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.
+# GNU Affero General Public License for more details.
 #
-# You should have received a copy of the GNU General Public License
+# You should have received a copy of the GNU Affero General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 #
 # Yohoho and Puzzle Pirates are probably trademarks of Three Rings and
 # are used without permission.  This program is not endorsed or
 # sponsored by Three Rings.
 
-# This package is used by the Mason scripts in yarrg/web/.
+
+# This Perl module is used by the Mason scripts in yarrg/web/.
 # We look for a symlink DATA to the actual data to use, so that
 # the data uploader and website displayer can use different code.
 
@@ -31,33 +38,200 @@ use warnings;
 
 use DBI;
 use POSIX;
+use JSON;
 
 use Commods;
 use CommodsDatabase;
 
-our $self_url;
-our $base_url;
-
 BEGIN {
     use Exporter ();
     our ($VERSION, @ISA, @EXPORT, @EXPORT_OK, %EXPORT_TAGS);
     $VERSION     = 1.00;
     @ISA         = qw(Exporter);
-    @EXPORT      = qw($dbh &db_setocean &db_connect &db_doall
-                     $self_url $base_url);
+    @EXPORT      = qw(&dbw_connect &dbw_filename &ocean_list &sourcebasedir
+                     &to_json_shim &to_json_protecttags
+                     &set_ctype_utf8 &webdatadir
+                     &expected_error &dbw_lookup_string
+                     &printable &tr_datarow &escerrq
+                     &prettyprint_age &meta_prettyprint_age);
     %EXPORT_TAGS = ( );
 
     @EXPORT_OK   = qw();
 }
 
-for my $dir (@INC) {
-    if ($dir =~ m/\.perl-lib$/) {
-       db_setdatadir("$dir/DATA");
-       last;
+sub dotperllibdir () {
+    my $dir;
+    
+    for my $dir (@INC) {
+       if ($dir =~ m/\.perl-lib$/) {
+           return $dir;
+       }
+    }
+    die "no appropriate dotperllib dir in @INC";
+}
+
+sub sourcebasedir () {
+    return dotperllibdir().'/..';
+}
+
+sub some_datadir ($) {
+    my ($what) = @_;
+    my $edir= $ENV{"YARRG_${what}_DIR"};
+    return $edir if defined $edir;
+    my $dir= dotperllibdir();
+    my $dirwhat= "$dir/$what";
+    if (stat $dirwhat) {
+       return $dirwhat;
+    } elsif ($!==&ENOENT) {
+       return "$dir";
+    } else {
+       die "stat $dirwhat $!";
+    }
+    return '.';
+}
+
+sub webdatadir () { return some_datadir('WEBDATA'); }
+sub datadir () { return some_datadir('DATA'); }
+
+my @ocean_list;
+
+sub ocean_list () {
+    my $datadir= datadir();
+    if (!@ocean_list) {
+       my $fn= "$datadir/source-info.txt";
+       my $f= new IO::File $fn or die "$fn $!";
+       my @r;
+       while (<$f>) {
+           next unless m/^ocean\s+(\S.*\S)\s*$/;
+           push @r, $1;
+       }
+       $f->error and die $!;
+       close $fn;
+       @ocean_list= @r;
     }
+    return @ocean_list;
+}
+
+sub dbw_filename ($) {
+    my ($ocean) = @_;
+    die "unknown ocean $ocean ?"
+       unless grep { $_ eq $ocean } ocean_list();
+    return dbr_filename(datadir(), $ocean);
+}
+
+sub dbw_connect ($) {
+    my ($ocean) = @_;
+    my $fn= dbw_filename($ocean);
+    return db_connect_core($fn);
+}
+
+sub to_json_shim ($) {
+    my ($obj) = @_;
+    # In JSON.pm 2.x, jsonToObj prints a warning to stderr which
+    # our callers don't like at all.
+    if ($JSON::VERSION >= 2.0) {
+       return to_json($obj);
+    } else {
+       return objToJson($obj);
+    }
+}
+
+sub to_json_protecttags ($) {
+    my ($v) = @_;
+    my $j= to_json_shim($v);
+    $j =~ s,/,\\/,g;
+    return $j;
 }
 
-$self_url= 'http://'.$ENV{'SERVER_NAME'}.$ENV{'SCRIPT_NAME'}.$ENV{'PATH_INFO'};
-$base_url= $self_url;  $base_url =~ s,/[^/]+,,;
+sub meta_prettyprint_age ($$$) {
+    my ($age,$floor,$plus) = @_;
+    return <<END;
+        $age < 60 ?             'less than a minute'                    :
+        $age < 60*2 ?           '1 minute'                              :
+        $age < 3600*2 ?         $floor ($age/60) $plus' minutes'        :
+        $age < 86400*2 ?        $floor ($age/3600) $plus ' hours'       :
+                                $floor ($age/86400) $plus ' days';
+END
+};
+
+BEGIN { eval '
+  sub prettyprint_age ($) {
+               my ($age) = @_;
+               '.meta_prettyprint_age('$age','floor','.').'
+  };
+  1;
+' or die "$@";
+}
+
+
+sub dbw_lookup_string ($$$$$$$$) { # => ( $emsg, @dbresults )
+    my ($each,
+       $sth, $stmt_nqs, $abbrev_initials, $maxambig,
+       $em_nomatch, $em_manyambig, $emf_ambiguous) = @_;
+    
+    $each =~ s/^\s*//;  $each =~ s/\s*$//;  $each =~ s/\s+/ /g;
+    my %m;
+    my $results;
+    my @pats= ("$each", "$each \%", "$each\%", "\%$each\%");
+    if ($abbrev_initials) {
+       push @pats, join ' ', map { "$_%" } split //, $each;
+    }
+    foreach my $pat (@pats) {
+       $sth->execute(($pat) x $stmt_nqs);
+       $results= $sth->fetchall_arrayref();
+       last if @$results==1;
+       $m{ $_->[0] }=1 for @$results;
+       $results= undef;
+    }
+    if (!$results) {
+       if (!%m) {
+           return $em_nomatch;
+       } elsif (keys(%m) > $maxambig) {
+           return $em_manyambig;
+       } else {
+           return $emf_ambiguous->($each, join(', ', sort keys %m));
+       }
+    }
+    return (undef, @{ $results->[0] });
+}
+
+sub expected_error ($) {
+    my $r= { Emsg => $_[0] };
+    bless $r, 'CommodsWeb::ExpectedError';
+    die $r;
+}
+
+sub printable ($) { # printable($m)  where $m is the Mason request object
+    my ($m) = @_;
+    my $a= scalar $m->caller_args(-1);
+    foreach my $t (qw(pdf ps html pdf2 ps2)) {
+       return $t if $a->{"printable_$t"};
+    }
+    return 0;
+}
+
+sub tr_datarow ($$) {
+    my ($m, $lineno) = @_;
+    $lineno &= 1;
+    if (!printable($m)) {
+       $m->print("<tr class=\"datarow$lineno\">");
+    } else {
+       $m->print("<tr bgcolor=\"".
+                 ($lineno ? "#ffffff" : "#e3e3e3" ).
+                 "\">");
+    }
+}
+
+sub escerrq ($) {
+    return '&#8220;'.CGI::escapeHTML($_[0]).'&#8221;';
+#    return '&#8216;'.CGI::escapeHTML($_[0]).'&#8217;';
+}
+
+package CommodsWeb::ExpectedError;
+
+sub emsg ($) {
+    my ($self) = @_;
+    return $self->{Emsg};
+}
 
 1;