summaryrefslogtreecommitdiff
path: root/lib/VNDB/Util
diff options
context:
space:
mode:
Diffstat (limited to 'lib/VNDB/Util')
-rw-r--r--lib/VNDB/Util/Auth.pm17
-rw-r--r--lib/VNDB/Util/BrowseHTML.pm43
-rw-r--r--lib/VNDB/Util/CommonHTML.pm6
-rw-r--r--lib/VNDB/Util/FormHTML.pm4
-rw-r--r--lib/VNDB/Util/LayoutHTML.pm22
-rw-r--r--lib/VNDB/Util/Misc.pm100
6 files changed, 169 insertions, 23 deletions
diff --git a/lib/VNDB/Util/Auth.pm b/lib/VNDB/Util/Auth.pm
index 24e316ce..9ad76894 100644
--- a/lib/VNDB/Util/Auth.pm
+++ b/lib/VNDB/Util/Auth.pm
@@ -14,7 +14,7 @@ use YAWF ':html';
use VNDB::Func;
-our @EXPORT = qw| authInit authLogin authLogout authInfo authCan authPreparePass authGetCode authCheckCode |;
+our @EXPORT = qw| authInit authLogin authLogout authInfo authCan authPreparePass authGetCode authCheckCode authPref |;
# initializes authentication information and checks the vndb_auth cookie
@@ -27,7 +27,7 @@ sub authInit {
return _rmcookie($self) if length($cookie) < 41;
my $token = substr($cookie, 0, 40);
my $uid = substr($cookie, 40);
- $self->{_auth} = $uid =~ /^\d+$/ && $self->dbUserGet(uid => $uid, session => $token, what => 'extended notifycount')->[0];
+ $self->{_auth} = $uid =~ /^\d+$/ && $self->dbUserGet(uid => $uid, session => $token, what => 'extended notifycount prefs')->[0];
# update the sessions.lastused column if lastused < now()'6 hours'
$self->dbSessionUpdateLastUsed($uid, $token) if $self->{_auth} && $self->{_auth}{session_lastused} < time()-6*3600;
return _rmcookie($self) if !$self->{_auth};
@@ -70,6 +70,10 @@ sub authLogout {
$self->resRedirect('/', 'temp');
_rmcookie($self);
+
+ # set l10n cookie if the user has a preferred language set
+ my $l10n = $self->authPref('l10n');
+ $self->resHeader('Set-Cookie', "l10n=$l10n; expires=Sat, 01-Jan-2030 00:00:00 GMT; path=/; domain=$self->{cookie_domain}") if $l10n;
}
@@ -196,5 +200,14 @@ sub _incorrectcode {
}
+sub authPref {
+ my($self, $key, $val) = @_;
+ my $nfo = $self->authInfo;
+ return '' if !$nfo->{id};
+ return $nfo->{prefs}{$key}||'' if @_ == 2;
+ $nfo->{prefs}{$key} = $val;
+ $self->dbUserPrefSet($nfo->{id}, $key, $val);
+}
+
1;
diff --git a/lib/VNDB/Util/BrowseHTML.pm b/lib/VNDB/Util/BrowseHTML.pm
index 139ff1b0..62e01fd1 100644
--- a/lib/VNDB/Util/BrowseHTML.pm
+++ b/lib/VNDB/Util/BrowseHTML.pm
@@ -6,6 +6,7 @@ use warnings;
use YAWF ':html', 'xml_escape';
use Exporter 'import';
use VNDB::Func;
+use POSIX 'ceil';
our @EXPORT = qw| htmlBrowse htmlBrowseNavigate htmlBrowseHist htmlBrowseVN |;
@@ -83,23 +84,39 @@ sub htmlBrowse {
# creates next/previous buttons (tabs), if needed
-# Arguments: page url, current page (1..n), nextpage (0/1), alignment (t/b), noappend (0/1)
+# Arguments: page url, current page (1..n), nextpage (0/1 or [$total, $perpage]), alignment (t/b), noappend (0/1)
sub htmlBrowseNavigate {
my($self, $url, $p, $np, $al, $na) = @_;
- return if $p == 1 && !$np;
+ my($cnt, $pp) = ref($np) ? @$np : ($p+$np, 1);
+ return if $p == 1 && $cnt <= $pp;
$url .= $url =~ /\?/ ? ';p=' : '?p=' unless $na;
- ul class => 'maintabs ' . ($al eq 't' ? 'notfirst' : 'bottom');
- if($p > 1) {
- li class => 'left';
- a href => $url.($p-1), '<- '.mt '_browse_previous';
- end;
- }
- if($np) {
- li;
- a href => $url.($p+1), mt('_browse_next').' ->';
- end;
- }
+
+ my $tab = sub {
+ my($left, $page, $label) = @_;
+ li $left ? (class => 'left') : ();
+ a href => $url.$page; lit $label; end;
+ end;
+ };
+ my $ell = sub {
+ use utf8;
+ li class => 'ellipsis'.(shift() ? ' left' : '');
+ b '⋯';
+ end;
+ };
+ my $nc = 5; # max. number of buttons on each side
+
+ ul class => 'maintabs browsetabs ' . ($al eq 't' ? 'notfirst' : 'bottom');
+ $p > 2 and ref $np and $tab->(1, 1, '&laquo; '.mt '_browse_first');
+ $p > $nc+1 and ref $np and $ell->(1);
+ $p > $_ and ref $np and $tab->(1, $p-$_, $p-$_) for (reverse 2..($nc>$p-2?$p-2:$nc-1));
+ $p > 1 and $tab->(1, $p-1, '&lsaquo; '.mt '_browse_previous');
+
+ my $l = ceil($cnt/$pp)-$p+1;
+ $l > 2 and $tab->(0, $l+$p-1, mt('_browse_last').' &raquo;');
+ $l > $nc+1 and $ell->(0);
+ $l > $_ and $tab->(0, $p+$_, $p+$_) for (reverse 2..($nc>$l-2?$l-2:$nc-1));
+ $l > 1 and $tab->(0, $p+1, mt('_browse_next').' &rsaquo;');
end;
}
diff --git a/lib/VNDB/Util/CommonHTML.pm b/lib/VNDB/Util/CommonHTML.pm
index c7d67647..a412949a 100644
--- a/lib/VNDB/Util/CommonHTML.pm
+++ b/lib/VNDB/Util/CommonHTML.pm
@@ -45,11 +45,15 @@ sub htmlMainTabs {
end;
}
- if($type eq 'u' && ($obj->{show_list} || $self->authCan('usermod'))) {
+ if($type eq 'u' && (!($obj->{hide_list} || $obj->{prefs}{hide_list}) || ($self->authInfo->{id} && $self->authInfo->{id} == $obj->{id}) || $self->authCan('usermod'))) {
li $sel eq 'wish' ? (class => 'tabselected') : ();
a href => "/$id/wish", mt '_mtabs_wishlist';
end;
+ li $sel eq 'votes' ? (class => 'tabselected') : ();
+ a href => "/$id/votes", mt '_mtabs_votes';
+ end;
+
li $sel eq 'list' ? (class => 'tabselected') : ();
a href => "/$id/list", mt '_mtabs_list';
end;
diff --git a/lib/VNDB/Util/FormHTML.pm b/lib/VNDB/Util/FormHTML.pm
index d619754a..41ee0ccc 100644
--- a/lib/VNDB/Util/FormHTML.pm
+++ b/lib/VNDB/Util/FormHTML.pm
@@ -27,7 +27,7 @@ sub htmlFormError {
ul;
for my $e (@{$frm->{_err}}) {
if(!ref $e) {
- li mt '_formerr_e_'.$e;
+ li; lit mt '_formerr_e_'.$e; end;
next;
}
my($field, $type, $rule) = @$e;
@@ -89,7 +89,7 @@ sub htmlFormPart {
end;
td class => 'field';
input type => 'checkbox', name => $o{short}, id => $o{short},
- value => $o{value}||'true', $frm->{$o{short}} ? ( checked => 'checked' ) : ();
+ value => $o{value}||1, ($frm->{$o{short}}||0) eq ($o{value}||1) ? ( checked => 'checked' ) : ();
label for => $o{short};
lit $o{name};
end;
diff --git a/lib/VNDB/Util/LayoutHTML.pm b/lib/VNDB/Util/LayoutHTML.pm
index f1a6dc2d..cc34b874 100644
--- a/lib/VNDB/Util/LayoutHTML.pm
+++ b/lib/VNDB/Util/LayoutHTML.pm
@@ -12,7 +12,7 @@ our @EXPORT = qw|htmlHeader htmlFooter|;
sub htmlHeader { # %options->{ title, noindex, search, feeds }
my($self, %o) = @_;
- my $skin = $self->reqParam('skin') || $self->authInfo->{skin} || $self->{skin_default};
+ my $skin = $self->reqParam('skin') || $self->authPref('skin') || $self->{skin_default};
$skin = $self->{skin_default} if !$self->{skins}{$skin} || !-d "$VNDB::ROOT/static/s/$skin";
# heading
@@ -22,8 +22,8 @@ sub htmlHeader { # %options->{ title, noindex, search, feeds }
Link rel => 'shortcut icon', href => '/favicon.ico', type => 'image/x-icon';
Link rel => 'stylesheet', href => $self->{url_static}.'/s/'.$skin.'/style.css?'.$self->{version}, type => 'text/css', media => 'all';
Link rel => 'search', type => 'application/opensearchdescription+xml', title => 'VNDB VN Search', href => $self->{url}.'/opensearch.xml';
- if($self->authInfo->{customcss}) {
- (my $css = $self->authInfo->{customcss}) =~ s/\n/ /g;
+ if($self->authPref('customcss')) {
+ (my $css = $self->authPref('customcss')) =~ s/\n/ /g;
style type => 'text/css', $css;
}
Link rel => 'alternate', type => 'application/atom+xml', href => "/feeds/$_.atom", title => $self->{atom_feeds}{$_}[1]
@@ -88,6 +88,7 @@ sub _menu {
div;
a href => "$uid/edit", mt '_menu_myprofile'; br;
a href => "$uid/list", mt '_menu_myvnlist'; br;
+ a href => "$uid/votes",mt '_menu_myvotes'; br;
a href => "$uid/wish", mt '_menu_mywishlist'; br;
a href => "$uid/notifies", $nc ? (class => 'notifyget') : (), mt('_menu_mynotifications').($nc?" ($nc)":''); br;
a href => "$uid/hist", mt '_menu_mychanges'; br;
@@ -134,8 +135,8 @@ sub _menu {
}
-sub htmlFooter {
- my $self = shift;
+sub htmlFooter { # %options => { prefs => [pref1,..] }
+ my($self, %o) = @_;
div id => 'footer';
my $q = $self->dbRandomQuote;
@@ -155,6 +156,17 @@ sub htmlFooter {
a href => $self->{source_url}, mt '_footer_source';
end;
end; # /div maincontent
+
+ # insert users' preference data when required by JS
+ if($o{prefs}) {
+ script type => 'text/javascript';
+ txt sprintf "PREF_CODE='%s';", $self->authInfo->{id} ? $self->authGetCode('/xml/prefs.xml') : '';
+ txt 'PREFS={';
+ # assumes the preference value doesn't contain a '
+ txt join ',', map sprintf("'%s':'%s'", $_, $self->authPref($_)), @{$o{prefs}};
+ txt '};';
+ end;
+ }
script type => 'text/javascript', src => $self->{url_static}.'/f/js/'.$self->{l10n}->language_tag().'.js?'.$self->{version}, '';
end; # /body
end; # /html
diff --git a/lib/VNDB/Util/Misc.pm b/lib/VNDB/Util/Misc.pm
new file mode 100644
index 00000000..71aca7a8
--- /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, 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 = 'filter_'.$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) && !defined $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 defined $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;
+}
+