chiark / gitweb /
Properly quote various error messages
[ypp-sc-tools.db-live.git] / yarrg / CommodsWeb.pm
1 # This is part of the YARRG website.  YARRG is a tool and website
2 # for assisting players of Yohoho Puzzle Pirates.
3 #
4 # Copyright (C) 2009 Ian Jackson <ijackson@chiark.greenend.org.uk>
5 # Copyright (C) 2009 Clare Boothby
6 #
7 #  YARRG's client code etc. is covered by the ordinary GNU GPL (v3 or later).
8 #  The YARRG website is covered by the GNU Affero GPL v3 or later, which
9 #   basically means that every installation of the website will let you
10 #   download the source.
11 #
12 # This program is free software: you can redistribute it and/or modify
13 # it under the terms of the GNU Affero General Public License as
14 # published by the Free Software Foundation, either version 3 of the
15 # License, or (at your option) any later version.
16 #
17 # This program is distributed in the hope that it will be useful,
18 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20 # GNU Affero General Public License for more details.
21 #
22 # You should have received a copy of the GNU Affero General Public License
23 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
24 #
25 # Yohoho and Puzzle Pirates are probably trademarks of Three Rings and
26 # are used without permission.  This program is not endorsed or
27 # sponsored by Three Rings.
28
29
30 # This Perl module is used by the Mason scripts in yarrg/web/.
31 # We look for a symlink DATA to the actual data to use, so that
32 # the data uploader and website displayer can use different code.
33
34 package CommodsWeb;
35
36 use strict;
37 use warnings;
38
39 use DBI;
40 use POSIX;
41 use JSON;
42
43 use Commods;
44 use CommodsDatabase;
45
46 BEGIN {
47     use Exporter ();
48     our ($VERSION, @ISA, @EXPORT, @EXPORT_OK, %EXPORT_TAGS);
49     $VERSION     = 1.00;
50     @ISA         = qw(Exporter);
51     @EXPORT      = qw(&dbw_connect &dbw_filename &ocean_list &sourcebasedir
52                       &to_json_shim &to_json_protecttags
53                       &set_ctype_utf8 &webdatadir
54                       &expected_error &dbw_lookup_string
55                       &printable &tr_datarow &escerrq
56                       &prettyprint_age &meta_prettyprint_age);
57     %EXPORT_TAGS = ( );
58
59     @EXPORT_OK   = qw();
60 }
61
62 sub dotperllibdir () {
63     my $dir;
64     
65     for my $dir (@INC) {
66         if ($dir =~ m/\.perl-lib$/) {
67             return $dir;
68         }
69     }
70     die "no appropriate dotperllib dir in @INC";
71 }
72
73 sub sourcebasedir () {
74     return dotperllibdir().'/..';
75 }
76
77 sub some_datadir ($) {
78     my ($what) = @_;
79     my $edir= $ENV{"YARRG_${what}_DIR"};
80     return $edir if defined $edir;
81     my $dir= dotperllibdir();
82     my $dirwhat= "$dir/$what";
83     if (stat $dirwhat) {
84         return $dirwhat;
85     } elsif ($!==&ENOENT) {
86         return "$dir";
87     } else {
88         die "stat $dirwhat $!";
89     }
90     return '.';
91 }
92
93 sub webdatadir () { return some_datadir('WEBDATA'); }
94 sub datadir () { return some_datadir('DATA'); }
95
96 my @ocean_list;
97
98 sub ocean_list () {
99     my $datadir= datadir();
100     if (!@ocean_list) {
101         my $fn= "$datadir/source-info.txt";
102         my $f= new IO::File $fn or die "$fn $!";
103         my @r;
104         while (<$f>) {
105             next unless m/^ocean\s+(\S.*\S)\s*$/;
106             push @r, $1;
107         }
108         $f->error and die $!;
109         close $fn;
110         @ocean_list= @r;
111     }
112     return @ocean_list;
113 }
114
115 sub dbw_filename ($) {
116     my ($ocean) = @_;
117     die "unknown ocean $ocean ?"
118         unless grep { $_ eq $ocean } ocean_list();
119     return dbr_filename(datadir(), $ocean);
120 }
121
122 sub dbw_connect ($) {
123     my ($ocean) = @_;
124     my $fn= dbw_filename($ocean);
125     return db_connect_core($fn);
126 }
127
128 sub to_json_shim ($) {
129     my ($obj) = @_;
130     # In JSON.pm 2.x, jsonToObj prints a warning to stderr which
131     # our callers don't like at all.
132     if ($JSON::VERSION >= 2.0) {
133         return to_json($obj);
134     } else {
135         return objToJson($obj);
136     }
137 }
138
139 sub to_json_protecttags ($) {
140     my ($v) = @_;
141     my $j= to_json_shim($v);
142     $j =~ s,/,\\/,g;
143     return $j;
144 }
145
146 sub meta_prettyprint_age ($$$) {
147     my ($age,$floor,$plus) = @_;
148     return <<END;
149         $age < 60 ?             'less than a minute'                    :
150         $age < 60*2 ?           '1 minute'                              :
151         $age < 3600*2 ?         $floor ($age/60) $plus' minutes'        :
152         $age < 86400*2 ?        $floor ($age/3600) $plus ' hours'       :
153                                 $floor ($age/86400) $plus ' days';
154 END
155 };
156
157 BEGIN { eval '
158   sub prettyprint_age ($) {
159                 my ($age) = @_;
160                 '.meta_prettyprint_age('$age','floor','.').'
161   };
162   1;
163 ' or die "$@";
164 }
165
166
167 sub dbw_lookup_string ($$$$$$$$) { # => ( $emsg, @dbresults )
168     my ($each,
169         $sth, $stmt_nqs, $abbrev_initials, $maxambig,
170         $em_nomatch, $em_manyambig, $emf_ambiguous) = @_;
171     
172     $each =~ s/^\s*//;  $each =~ s/\s*$//;  $each =~ s/\s+/ /g;
173     my %m;
174     my $results;
175     my @pats= ("$each", "$each \%", "$each\%", "\%$each\%");
176     if ($abbrev_initials) {
177         push @pats, join ' ', map { "$_%" } split //, $each;
178     }
179     foreach my $pat (@pats) {
180         $sth->execute(($pat) x $stmt_nqs);
181         $results= $sth->fetchall_arrayref();
182         last if @$results==1;
183         $m{ $_->[0] }=1 for @$results;
184         $results= undef;
185     }
186     if (!$results) {
187         if (!%m) {
188             return $em_nomatch;
189         } elsif (keys(%m) > $maxambig) {
190             return $em_manyambig;
191         } else {
192             return $emf_ambiguous->($each, join(', ', sort keys %m));
193         }
194     }
195     return (undef, @{ $results->[0] });
196 }
197
198 sub expected_error ($) {
199     my $r= { Emsg => $_[0] };
200     bless $r, 'CommodsWeb::ExpectedError';
201     die $r;
202 }
203
204 sub printable ($) { # printable($m)  where $m is the Mason request object
205     my ($m) = @_;
206     my $a= scalar $m->caller_args(-1);
207     foreach my $t (qw(pdf ps html pdf2 ps2)) {
208         return $t if $a->{"printable_$t"};
209     }
210     return 0;
211 }
212
213 sub tr_datarow ($$) {
214     my ($m, $lineno) = @_;
215     $lineno &= 1;
216     if (!printable($m)) {
217         $m->print("<tr class=\"datarow$lineno\">");
218     } else {
219         $m->print("<tr bgcolor=\"".
220                   ($lineno ? "#ffffff" : "#e3e3e3" ).
221                   "\">");
222     }
223 }
224
225 sub escerrq ($) {
226     return '&#8220;'.CGI::escapeHTML($_[0]).'&#8221;';
227 #    return '&#8216;'.CGI::escapeHTML($_[0]).'&#8217;';
228 }
229
230 package CommodsWeb::ExpectedError;
231
232 sub emsg ($) {
233     my ($self) = @_;
234     return $self->{Emsg};
235 }
236
237 1;