diff options
-rw-r--r-- | lib/VNDB/Func.pm | 2 | ||||
-rw-r--r-- | lib/VNDB/Handler/Releases.pm | 42 | ||||
-rw-r--r-- | lib/VNDB/Handler/VNBrowse.pm | 49 | ||||
-rw-r--r-- | lib/VNDB/Util/Misc.pm | 100 |
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; +} + |