summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/VNDB/Func.pm2
-rw-r--r--lib/VNDB/Handler/Releases.pm42
-rw-r--r--lib/VNDB/Handler/VNBrowse.pm49
-rw-r--r--lib/VNDB/Util/Misc.pm100
4 files changed, 135 insertions, 58 deletions
diff --git a/lib/VNDB/Func.pm b/lib/VNDB/Func.pm
index bb8ad775..17d69cd5 100644
--- a/lib/VNDB/Func.pm
+++ b/lib/VNDB/Func.pm
@@ -103,7 +103,7 @@ sub fil_serialize {
my @v = ref $fil->{$_} ? @{$fil->{$_}} : ($fil->{$_});
s/$e/_$fil_escape{$1}/g for(@v);
$_.'-'.join '~', @v
- } keys %$fil;
+ } grep defined($fil->{$_}), keys %$fil;
}
1;
diff --git a/lib/VNDB/Handler/Releases.pm b/lib/VNDB/Handler/Releases.pm
index 6163e1f2..9422a836 100644
--- a/lib/VNDB/Handler/Releases.pm
+++ b/lib/VNDB/Handler/Releases.pm
@@ -488,18 +488,14 @@ sub browse {
);
return 404 if $f->{_err};
- my $fil = fil_parse $f->{fil}, qw|type patch freeware doujin date_before date_after minage lang olang resolution plat med voiced ani_story ani_ero|;
- _fil_compat($self, $fil);
- $f->{fil} = fil_serialize($fil);
-
- my($list, $np) = !$f->{q} && !keys %$fil ? ([], 0) : $self->dbReleaseGet(
+ my %compat = _fil_compat($self);
+ my($list, $np) = !$f->{q} && !$f->{fil} && !keys %compat ? ([], 0) : $self->filFetchDB(release => $f->{fil}, \%compat, {
sort => $f->{s}, reverse => $f->{o} eq 'd',
page => $f->{p},
results => 50,
what => 'platforms',
$f->{q} ? ( search => $f->{q} ) : (),
- %$fil
- );
+ });
$self->htmlHeader(title => mt('_rbrowse_title'));
@@ -546,7 +542,7 @@ sub browse {
end;
},
) if @$list;
- if(($f->{q} || keys %$fil) && !@$list) {
+ if(($f->{q} || $f->{fil}) && !@$list) {
div class => 'mainbox';
h1 mt '_rbrowse_noresults_title';
div class => 'notice';
@@ -558,9 +554,10 @@ sub browse {
}
-# provide compatibility with old filter URLs
+# provide compatibility with old URLs
sub _fil_compat {
- my($self, $fil) = @_;
+ my $self = shift;
+ my %c;
my $f = $self->formValidate(
{ name => 'ln', required => 0, multi => 1, default => '', enum => $self->{languages} },
{ name => 'pl', required => 0, multi => 1, default => '', enum => $self->{platforms} },
@@ -575,18 +572,19 @@ sub _fil_compat {
{ name => 'ma', required => 0, default => 99999999, template => 'int' },
{ name => 're', required => 0, multi => 1, default => 0, enum => [ 1..$#{$self->{resolutions}} ] },
);
- return if $f->{_err};
- $fil->{minage} //= [ grep $_ >= 0 && ($f->{ma_m} ? $f->{ma_a} >= $_ : $f->{ma_a} <= $_), @{$self->{age_ratings}} ] if $f->{ma_a} || $f->{ma_m};
- $fil->{date_after} //= $f->{mi} if $f->{mi};
- $fil->{date_before} //= $f->{ma} if $f->{ma} < 99990000;
- $fil->{plat} //= $f->{pl} if $f->{pl}[0];
- $fil->{lang} //= $f->{ln} if $f->{ln}[0];
- $fil->{med} //= $f->{me} if $f->{me}[0];
- $fil->{resolution} //= $f->{re} if $f->{re}[0];
- $fil->{type} //= $f->{tp} if $f->{tp};
- $fil->{patch} //= $f->{pa} == 2 ? 0 : 1 if $f->{pa};
- $fil->{freeware} //= $f->{fw} == 2 ? 0 : 1 if $f->{fw};
- $fil->{doujin} //= $f->{do} == 2 ? 0 : 1 if $f->{do};
+ return () if $f->{_err};
+ $c{minage} = [ grep $_ >= 0 && ($f->{ma_m} ? $f->{ma_a} >= $_ : $f->{ma_a} <= $_), @{$self->{age_ratings}} ] if $f->{ma_a} || $f->{ma_m};
+ $c{date_after} = $f->{mi} if $f->{mi};
+ $c{date_before} = $f->{ma} if $f->{ma} < 99990000;
+ $c{plat} = $f->{pl} if $f->{pl}[0];
+ $c{lang} = $f->{ln} if $f->{ln}[0];
+ $c{med} = $f->{me} if $f->{me}[0];
+ $c{resolution} = $f->{re} if $f->{re}[0];
+ $c{type} = $f->{tp} if $f->{tp};
+ $c{patch} = $f->{pa} == 2 ? 0 : 1 if $f->{pa};
+ $c{freeware} = $f->{fw} == 2 ? 0 : 1 if $f->{fw};
+ $c{doujin} = $f->{do} == 2 ? 0 : 1 if $f->{do};
+ return %c;
}
diff --git a/lib/VNDB/Handler/VNBrowse.pm b/lib/VNDB/Handler/VNBrowse.pm
index 25166717..15407076 100644
--- a/lib/VNDB/Handler/VNBrowse.pm
+++ b/lib/VNDB/Handler/VNBrowse.pm
@@ -25,32 +25,22 @@ sub list {
);
return 404 if $f->{_err};
$f->{q} ||= $f->{sq};
- my $fil = fil_parse $f->{fil}, qw|length hasani tag_inc tag_exc taginc tagexc tagspoil lang olang plat|;
- _fil_compat($self, $fil);
+ my %compat = _fil_compat($self);
- if($f->{q}) {
- return $self->resRedirect('/'.$1.$2.(!$3 ? '' : $1 eq 'd' ? '#'.$3 : '.'.$3), 'temp')
- if $f->{q} =~ /^([gvrptud])([0-9]+)(?:\.([0-9]+))?$/;
+ return $self->resRedirect('/'.$1.$2.(!$3 ? '' : $1 eq 'd' ? '#'.$3 : '.'.$3), 'temp')
+ if $f->{q} && $f->{q} =~ /^([gvrptud])([0-9]+)(?:\.([0-9]+))?$/;
- # for URL compatibilty with older versions (ugly hack to get English strings)
- my @lang;
- $f->{q} =~ s/\s*$VNDB::L10N::en::Lexicon{"_lang_$_"}\s*//&&push @lang, $_ for (@{$self->{languages}});
- $fil->{lang} = $fil->{lang} ? [ ref($fil->{lang}) ? @{$fil->{lang}} : $fil->{lang}, @lang ] : \@lang if @lang;
- }
- $f->{fil} = fil_serialize $fil;
-
- $f->{s} = 'title' if !$fil->{tag_inc} && $f->{s} eq 'tagscore';
+ $f->{s} = 'title' if $f->{fil} !~ /tag_inc-/ && $f->{s} eq 'tagscore';
$f->{o} = $f->{s} eq 'tagscore' ? 'd' : 'a' if !$f->{o};
- my($list, $np) = $self->dbVNGet(
+ my($list, $np) = $self->filFetchDB(vn => $f->{fil}, \%compat, {
what => 'rating',
$char ne 'all' ? ( char => $char ) : (),
$f->{q} ? ( search => $f->{q} ) : (),
results => 50,
page => $f->{p},
sort => $f->{s}, reverse => $f->{o} eq 'd',
- %$fil
- );
+ });
$self->resRedirect('/v'.$list->[0]{id}, 'temp')
if $f->{q} && @$list == 1 && $f->{p} == 1;
@@ -74,35 +64,24 @@ sub list {
end;
end; # /form
- $self->htmlBrowseVN($list, $f, $np, "/v/$char?q=$f->{q};fil=$f->{fil}", $fil->{tag_inc});
+ $self->htmlBrowseVN($list, $f, $np, "/v/$char?q=$f->{q};fil=$f->{fil}", $f->{fil} =~ /tag_inc-/);
$self->htmlFooter;
}
sub _fil_compat {
- my($self, $fil) = @_;
+ my $self = shift;
+ my %c;
my $f = $self->formValidate(
{ name => 'ln', required => 0, multi => 1, enum => $self->{languages}, default => '' },
{ name => 'pl', required => 0, multi => 1, enum => $self->{platforms}, default => '' },
- { name => 'ti', required => 0, default => '', maxlength => 200 },
- { name => 'te', required => 0, default => '', maxlength => 200 },
{ name => 'sp', required => 0, default => $self->reqCookie($self->{cookie_prefix}.'tagspoil') =~ /^([0-2])$/ ? $1 : 0, enum => [0..2] },
);
- $fil->{lang} //= $f->{ln} if $f->{ln}[0];
- $fil->{plat} //= $f->{pl} if $f->{pl}[0];
- $fil->{taginc} //= $f->{ti} if $f->{ti};
- $fil->{tagexc} //= $f->{te} if $f->{te};
- $fil->{tagspoil} //= $f->{sp};
-
- # older tag specification (by name rather than ID)
- my $tagfind = sub {
- return map {
- my $i = $self->dbTagGet(name => $_)->[0];
- $i && !$i->{meta} ? $i->{id} : ();
- } grep $_, ref $_[0] ? @{$_[0]} : ($_[0]||'')
- };
- $fil->{tag_inc} //= [ $tagfind->(delete $fil->{taginc}) ] if $fil->{taginc};
- $fil->{tag_exc} //= [ $tagfind->(delete $fil->{tagexc}) ] if $fil->{tagexc};
+ return () if $f->{_err};
+ $c{lang} //= $f->{ln} if $f->{ln}[0];
+ $c{plat} //= $f->{pl} if $f->{pl}[0];
+ $c{tagspoil} //= $f->{sp};
+ return %c;
}
diff --git a/lib/VNDB/Util/Misc.pm b/lib/VNDB/Util/Misc.pm
new file mode 100644
index 00000000..2d1554ab
--- /dev/null
+++ b/lib/VNDB/Util/Misc.pm
@@ -0,0 +1,100 @@
+
+package VNDB::Util::Misc;
+
+use strict;
+use warnings;
+use Exporter 'import';
+use VNDB::Func;
+
+our @EXPORT = qw|filFetchDB|;
+
+
+my %filfields = (
+ vn => [qw|length hasani tag_inc tag_exc taginc tagexc tagspoil lang olang plat|],
+ release => [qw|type patch freeware doujin date_before date_after minage lang olang resolution plat med voiced ani_story ani_ero|],
+);
+
+
+# Arguments:
+# type ('vn' or 'release'),
+# filter overwrite (string or undef),
+# when defined and not '', these filters will be used instead of the preferences,
+# must point to a variable, will be modified in-place with the actually used filters
+# options to pass to db*Get() before the filters (hashref or undef)
+# these options can be overwritten by the filters or the next option
+# options to pass to db*Get() after the filters (hashref or undef)
+# these options overwrite all other options (pre-options and filters)
+
+sub filFetchDB {
+ my($self, $type, $overwrite, $pre, $post) = @_;
+ $pre = {} if !$pre;
+ $post = {} if !$post;
+ my $dbfunc = $self->can($type eq 'vn' ? 'dbVNGet' : 'dbReleaseGet');
+ my $prefname = 'fil_'.$type;
+ my $pref = $self->authPref($prefname);
+
+ # simply call the DB if we're not applying filters
+ return $dbfunc->($self, %$pre, %$post) if !$pref && !$overwrite;
+
+ my $filters = fil_parse $overwrite || $pref, @{$filfields{$type}};
+
+ # compatibility
+ $self->authPref($prefname => fil_serialize $filters)
+ if $type eq 'vn' && _fil_vn_compat($self, $filters) && !$overwrite;
+
+ # write the definite filter string in $overwrite
+ $_[2] = fil_serialize({map +(
+ exists($post->{$_}) ? ($_ => $post->{$_}) :
+ exists($filters->{$_}) ? ($_ => $filters->{$_}) :
+ exists($pre->{$_}) ? ($_ => $pre->{$_}) : (),
+ ), @{$filfields{$type}}}) if defined $overwrite;
+
+ return $dbfunc->($self, %$pre, %$filters, %$post) if $overwrite;
+
+ # since incorrect filters can throw a database error, we have to special-case
+ # filters that originate from a preference setting, so that in case these are
+ # the cause of an error, they are removed. Not doing this will result in VNDB
+ # throwing 500's even for non-browse pages. We have to do some low-level
+ # PostgreSQL stuff with savepoints to ensure that an error won't affect our
+ # existing transaction.
+ my $dbh = $self->{_YAWF}{DB}{sql};
+ $dbh->pg_savepoint('filter');
+ my($r, $np);
+ my $OK = eval {
+ ($r, $np) = $dbfunc->($self, %$pre, %$filters, %$post);
+ 1;
+ };
+ $dbh->pg_rollback_to('filter') if !$OK;
+ $dbh->pg_release('filter');
+
+ # error occured, let's try again without filters. if that succeeds we know
+ # it's the fault of the filter preference, and we should remove it.
+ if(!$OK) {
+ ($r, $np) = $dbfunc->($self, %$pre, %$post);
+ # if we're here, it means the previous function didn't die() (duh!)
+ $self->authPref($prefname => '');
+ warn sprintf "Reset filter preference for userid %d. Old: %s\n", $self->authInfo->{id}||0, $pref;
+ }
+ return wantarray ? ($r, $np) : $r;
+}
+
+
+sub _fil_vn_compat {
+ my($self, $fil) = @_;
+
+ # older tag specification (by name rather than ID)
+ if($fil->{taginc} || $fil->{tagexc}) {
+ my $tagfind = sub {
+ return map {
+ my $i = $self->dbTagGet(name => $_)->[0];
+ $i && !$i->{meta} ? $i->{id} : ();
+ } grep $_, ref $_[0] ? @{$_[0]} : ($_[0]||'')
+ };
+ $fil->{tag_inc} //= [ $tagfind->(delete $fil->{taginc}) ] if $fil->{taginc};
+ $fil->{tag_exc} //= [ $tagfind->(delete $fil->{tagexc}) ] if $fil->{tagexc};
+ return 1;
+ }
+
+ return 0;
+}
+