summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorYorhel <git@yorhel.nl>2011-01-02 14:17:57 +0100
committerYorhel <git@yorhel.nl>2011-01-02 14:17:57 +0100
commitb4e3c35620916852a6028ab5f6644382553408f9 (patch)
tree303248a812f6a7dc9c25bec0d8af5836c87fec3f /lib
parent632df9599de8dbb25707b0bf8caea075c55cfa3f (diff)
parent98f4725013b6d7a65e1fd07f7f02785b12e8a9bd (diff)
Merge branch 'beta'2.16
Conflicts: ChangeLog lib/VNDB/Handler/ULists.pm
Diffstat (limited to 'lib')
-rw-r--r--lib/Multi/API.pm2
-rw-r--r--lib/VNDB/DB/Releases.pm11
-rw-r--r--lib/VNDB/DB/Tags.pm2
-rw-r--r--lib/VNDB/DB/ULists.pm138
-rw-r--r--lib/VNDB/DB/Users.pm39
-rw-r--r--lib/VNDB/DB/VN.pm47
-rw-r--r--lib/VNDB/Func.pm21
-rw-r--r--lib/VNDB/Handler/Discussions.pm6
-rw-r--r--lib/VNDB/Handler/Misc.pm46
-rw-r--r--lib/VNDB/Handler/Producers.pm5
-rw-r--r--lib/VNDB/Handler/Releases.pm89
-rw-r--r--lib/VNDB/Handler/Tags.pm29
-rw-r--r--lib/VNDB/Handler/ULists.pm237
-rw-r--r--lib/VNDB/Handler/Users.pm72
-rw-r--r--lib/VNDB/Handler/VNBrowse.pm73
-rw-r--r--lib/VNDB/Handler/VNEdit.pm4
-rw-r--r--lib/VNDB/Handler/VNPage.pm32
-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
23 files changed, 676 insertions, 369 deletions
diff --git a/lib/Multi/API.pm b/lib/Multi/API.pm
index 4872acf9..3f1b24c4 100644
--- a/lib/Multi/API.pm
+++ b/lib/Multi/API.pm
@@ -648,7 +648,7 @@ sub get_release_res {
if(grep /details/, @{$get->{info}}) {
$_->{website} ||= undef;
$_->{notes} ||= undef;
- $_->{minage} *= 1 if defined $_->{minage};
+ $_->{minage} = $_->{minage} < 0 ? undef : $_->{minage}*1;
$_->{gtin} ||= undef;
$_->{catalog} ||= undef;
}
diff --git a/lib/VNDB/DB/Releases.pm b/lib/VNDB/DB/Releases.pm
index b0fb9a89..ffffb2a6 100644
--- a/lib/VNDB/DB/Releases.pm
+++ b/lib/VNDB/DB/Releases.pm
@@ -32,6 +32,7 @@ sub dbReleaseGet {
defined $o{type} ? ( 'rr.type = ?' => $o{type} ) : (),
defined $o{date_before} ? ( 'rr.released <= ?' => $o{date_before} ) : (),
defined $o{date_after} ? ( 'rr.released >= ?' => $o{date_after} ) : (),
+ defined $o{minage} ? ( 'rr.minage IN(!l)' => [ ref $o{minage} ? $o{minage} : [$o{minage}] ] ) : (),
defined $o{resolution} ? ( 'rr.resolution IN(!l)' => [ ref $o{resolution} ? $o{resolution} : [$o{resolution}] ] ) : (),
defined $o{voiced} ? ( 'rr.voiced IN(!l)' => [ ref $o{voiced} ? $o{voiced} : [$o{voiced}] ] ) : (),
defined $o{ani_story} ? ( 'rr.ani_story IN(!l)' => [ ref $o{ani_story} ? $o{ani_story} : [$o{ani_story}] ] ) : (),
@@ -47,16 +48,6 @@ sub dbReleaseGet {
'rr.id IN(SELECT irm.rid FROM releases_media irm JOIN releases ir ON ir.latest = irm.rid WHERE irm.medium IN(!l))' => [ ref $o{med} ? $o{med} : [ $o{med} ] ] ) : (),
);
- # TODO: don't allow NULL for rr.minage after all, since this could be a lot easier...
- if(exists $o{minage}) {
- my @m = ref $o{minage} ? @{$o{minage}} : ($o{minage});
- my @w = (
- grep(!defined $_ || $_ == -1, @m) ? 'rr.minage IS NULL' : (),
- grep(defined $_ && $_ != -1, @m) ? 'rr.minage IN(!s)' : ()
- );
- push @where, '('.join(' OR ', @w).')', [ grep defined $_ && $_ != -1, @m ];
- }
-
if($o{search}) {
for (split /[ -,._]/, $o{search}) {
s/%//g;
diff --git a/lib/VNDB/DB/Tags.pm b/lib/VNDB/DB/Tags.pm
index 4a87713b..b3e16960 100644
--- a/lib/VNDB/DB/Tags.pm
+++ b/lib/VNDB/DB/Tags.pm
@@ -24,7 +24,7 @@ sub dbTagGet {
my %where = (
$o{id} ? (
- 't.id = ?' => $o{id} ) : (),
+ 't.id IN(!l)' => [ ref $o{id} ? $o{id} : [$o{id}] ] ) : (),
$o{noid} ? (
't.id <> ?' => $o{noid} ) : (),
$o{name} ? (
diff --git a/lib/VNDB/DB/ULists.pm b/lib/VNDB/DB/ULists.pm
index e52cbf37..e6b6419a 100644
--- a/lib/VNDB/DB/ULists.pm
+++ b/lib/VNDB/DB/ULists.pm
@@ -7,56 +7,62 @@ use Exporter 'import';
our @EXPORT = qw|
- dbVNListGet dbVNListList dbVNListAdd dbVNListDel
+ dbRListGet dbVNListGet dbVNListList dbVNListAdd dbVNListDel dbRListAdd dbRListDel
dbVoteGet dbVoteStats dbVoteAdd dbVoteDel
dbWishListGet dbWishListAdd dbWishListDel
|;
-# Simpler and more efficient version of dbVNListList below
-# %options->{ uid rid }
-sub dbVNListGet {
+# Options: uid rid
+sub dbRListGet {
my($self, %o) = @_;
my %where = (
'uid = ?' => $o{uid},
- $o{rid} && !ref $o{rid} ? (
- 'rid = ?' => $o{rid} ) : (),
- $o{rid} && ref $o{rid} ? (
- 'rid IN(!l)' => [$o{rid}] ) : (),
+ $o{rid} ? ('rid IN(!l)' => [ ref $o{rid} ? $o{rid} : [$o{rid}] ]) : (),
);
return $self->dbAll(q|
- SELECT uid, rid, rstat, vstat
+ SELECT uid, rid, status
FROM rlists
!W|,
\%where
);
}
+# Options: uid vid
+sub dbVNListGet {
+ my($self, %o) = @_;
-# %options->{ uid char voted page results sort reverse }
+ my %where = (
+ 'uid = ?' => $o{uid},
+ $o{vid} ? ('vid IN(!l)' => [ ref $o{vid} ? $o{vid} : [$o{vid}] ]) : (),
+ );
+
+ return $self->dbAll(q|
+ SELECT uid, vid, status
+ FROM vnlists
+ !W|,
+ \%where
+ );
+}
+
+
+# Options: uid char voted page results sort reverse
# sort: title vote
-# NOTE: this function is mostly copied from 1.x, may need some rewriting...
sub dbVNListList {
my($self, %o) = @_;
-
$o{results} ||= 50;
$o{page} ||= 1;
- $o{voted} ||= 0; # -1: only non-voted, 0: all, 1: only voted
-
- # construct the global WHERE clause
- my $where = $o{voted} != -1 ? 'vo.vote IS NOT NULL' : '';
- $where .= ($where?' OR ':'').q|v.id = ANY(ARRAY(
- SELECT irv.vid
- FROM rlists irl
- JOIN releases ir ON ir.id = irl.rid
- JOIN releases_vn irv ON irv.rid = ir.latest
- WHERE uid = ?
- ))| if $o{voted} != 1;
- $where = '('.$where.') AND LOWER(SUBSTR(vr.title, 1, 1)) = \''.$o{char}.'\'' if $o{char};
- $where = '('.$where.') AND (ASCII(vr.title) < 97 OR ASCII(vr.title) > 122) AND (ASCII(vr.title) < 65 OR ASCII(vr.title) > 90)' if defined $o{char} && !$o{char};
- $where = '('.$where.') AND vo.vote IS NULL' if $o{voted} == -1;
+
+ my %where = (
+ 'vl.uid = ?' => $o{uid},
+ defined($o{voted}) ? ('vo.vote !s NULL' => $o{voted} ? 'IS NOT' : 'IS') : (),
+ defined($o{status})? ('vl.status = ?' => $o{status}) : (),
+ $o{char} ? ('LOWER(SUBSTR(vr.title, 1, 1)) = ?' => $o{char} ) : (),
+ defined $o{char} && !$o{char} ? (
+ '(ASCII(vr.title) < 97 OR ASCII(vr.title) > 122) AND (ASCII(vr.title) < 65 OR ASCII(vr.title) > 90)' => 1 ) : (),
+ );
my $order = sprintf {
title => 'vr.title %s',
@@ -65,14 +71,14 @@ sub dbVNListList {
# execute query
my($r, $np) = $self->dbPage(\%o, qq|
- SELECT vr.vid, vr.title, vr.original, COALESCE(vo.vote, 0) AS vote
- FROM vn v
+ SELECT vr.vid, vr.title, vr.original, vl.status, vl.notes, COALESCE(vo.vote, 0) AS vote
+ FROM vnlists vl
+ JOIN vn v ON v.id = vl.vid
JOIN vn_rev vr ON vr.id = v.latest
- !s JOIN votes vo ON vo.vid = v.id AND vo.uid = ?
- WHERE $where
+ LEFT JOIN votes vo ON vo.vid = vl.vid AND vo.uid = vl.uid
+ !W
ORDER BY !s|,
- $o{voted} == 1 ? '' : 'LEFT', $o{uid}, # JOIN if we only want votes, LEFT JOIN if we also want rlist items
- $o{voted} != 1 ? $o{uid} : (), $order
+ \%where, $order
);
# fetch releases and link to VNs
@@ -83,7 +89,7 @@ sub dbVNListList {
} @$r;
my $rel = $self->dbAll(q|
- SELECT rv.vid, rr.rid, r.latest, rr.title, rr.original, rr.released, rr.type, rl.rstat, rl.vstat
+ SELECT rv.vid, rr.rid, r.latest, rr.title, rr.original, rr.released, rr.type, rl.status
FROM rlists rl
JOIN releases r ON rl.rid = r.id
JOIN releases_rev rr ON rr.id = r.latest
@@ -114,35 +120,57 @@ sub dbVNListList {
}
-# %options->{ uid rid rstat vstat }
+# Arguments: uid vid status notes
+# vid can be an arrayref only when the rows are already present, in which case an update is done
+# status and notes can be undef when an update is done, in which case these fields aren't updated
sub dbVNListAdd {
- my($self, %o) = @_;
+ my($self, $uid, $vid, $stat, $notes) = @_;
+ $self->dbExec(
+ 'UPDATE vnlists !H WHERE uid = ? AND vid IN(!l)',
+ {defined($stat) ? ('status = ?' => $stat ):(),
+ defined($notes)? ('notes = ?' => $notes):()},
+ $uid, ref($vid) ? $vid : [ $vid ]
+ )
+ ||
+ $self->dbExec(
+ 'INSERT INTO vnlists (uid, vid, status, notes) VALUES(?, ?, ?, ?)',
+ $uid, $vid, $stat||0, $notes||''
+ );
+}
- my %s = (
- defined $o{rstat} ? ( 'rstat = ?', $o{rstat} ) : (),
- defined $o{vstat} ? ( 'vstat = ?', $o{vstat} ) : (),
+
+# Arguments: uid, vid
+sub dbVNListDel {
+ my($self, $uid, $vid) = @_;
+ $self->dbExec(
+ 'DELETE FROM vnlists WHERE uid = ? AND vid IN(!l)',
+ $uid, ref($vid) ? $vid : [ $vid ]
);
- $o{rstat}||=0;
- $o{vstat}||=0;
+}
+
+# Arguments: uid rid status
+# rid can be an arrayref only when the rows are already present, in which case an update is done
+sub dbRListAdd {
+ my($self, $uid, $rid, $stat) = @_;
$self->dbExec(
- 'UPDATE rlists !H WHERE uid = ? AND rid IN(!l)',
- \%s, $o{uid}, ref($o{rid}) eq 'ARRAY' ? $o{rid} : [ $o{rid} ]
+ 'UPDATE rlists SET status = ? WHERE uid = ? AND rid IN(!l)',
+ $stat, $uid, ref($rid) ? $rid : [ $rid ]
)
||
$self->dbExec(
- 'INSERT INTO rlists (uid, rid, rstat, vstat) VALUES(!l)',
- [@o{qw| uid rid rstat vstat |}]
+ 'INSERT INTO rlists (uid, rid, status) VALUES(?, ?, ?)',
+ $uid, $rid, $stat
);
}
# Arguments: uid, rid
-sub dbVNListDel {
+sub dbRListDel {
my($self, $uid, $rid) = @_;
$self->dbExec(
'DELETE FROM rlists WHERE uid = ? AND rid IN(!l)',
- $uid, ref($rid) eq 'ARRAY' ? $rid : [ $rid ]
+ $uid, ref($rid) ? $rid : [ $rid ]
);
}
@@ -160,8 +188,14 @@ sub dbVoteGet {
my %where = (
$o{uid} ? ( 'n.uid = ?' => $o{uid} ) : (),
$o{vid} ? ( 'n.vid = ?' => $o{vid} ) : (),
- $o{hide} ? ( 'u.show_list = TRUE' => 1 ) : (),
+ $o{hide} ? ( 'NOT EXISTS(SELECT 1 FROM users_prefs WHERE uid = n.uid AND key = \'hide_list\')' => 1 ) : (),
$o{hide_ign} ? ( '(NOT u.ign_votes OR u.id = ?)' => $self->authInfo->{id}||0 ) : (),
+ $o{vn_char} ? ( 'LOWER(SUBSTR(vr.title, 1, 1)) = ?' => $o{vn_char} ) : (),
+ defined $o{vn_char} && !$o{vn_char} ? (
+ '(ASCII(vr.title) < 97 OR ASCII(vr.title) > 122) AND (ASCII(vr.title) < 65 OR ASCII(vr.title) > 90)' => 1 ) : (),
+ $o{user_char} ? ( 'LOWER(SUBSTR(u.username, 1, 1)) = ?' => $o{user_char} ) : (),
+ defined $o{user_char} && !$o{user_char} ? (
+ '(ASCII(u.username) < 97 OR ASCII(u.username) > 122) AND (ASCII(u.username) < 65 OR ASCII(u.username) > 90)' => 1 ) : (),
);
my @select = (
@@ -221,14 +255,15 @@ sub dbVoteStats {
# Adds a new vote or updates an existing one
# Arguments: vid, uid, vote
+# vid can be an arrayref only when the rows are already present, in which case an update is done
sub dbVoteAdd {
my($self, $vid, $uid, $vote) = @_;
$self->dbExec(q|
UPDATE votes
- SET vote = ?
- WHERE vid = ?
+ SET vote = ?, date = NOW()
+ WHERE vid IN(!l)
AND uid = ?|,
- $vote, $vid, $uid
+ $vote, ref($vid) ? $vid : [$vid], $uid
) || $self->dbExec(q|
INSERT INTO votes
(vid, uid, vote)
@@ -239,10 +274,11 @@ sub dbVoteAdd {
# Arguments: uid, vid
+# vid can be an arrayref
sub dbVoteDel {
my($self, $uid, $vid) = @_;
$self->dbExec('DELETE FROM votes !W',
- { 'vid = ?' => $vid, 'uid = ?' => $uid }
+ { 'vid IN(!l)' => [ref($vid)?$vid:[$vid]], 'uid = ?' => $uid }
);
}
diff --git a/lib/VNDB/DB/Users.pm b/lib/VNDB/DB/Users.pm
index 7440f495..bd7db201 100644
--- a/lib/VNDB/DB/Users.pm
+++ b/lib/VNDB/DB/Users.pm
@@ -6,14 +6,14 @@ use warnings;
use Exporter 'import';
our @EXPORT = qw|
- dbUserGet dbUserEdit dbUserAdd dbUserDel
+ dbUserGet dbUserEdit dbUserAdd dbUserDel dbUserPrefSet
dbSessionAdd dbSessionDel dbSessionUpdateLastUsed
dbNotifyGet dbNotifyMarkRead dbNotifyRemove
|;
# %options->{ username passwd mail session uid ip registered search results page what sort reverse }
-# what: notifycount stats extended
+# what: notifycount stats extended prefs hide_list
# sort: username registered votes changes tags
sub dbUserGet {
my $s = shift;
@@ -21,6 +21,7 @@ sub dbUserGet {
page => 1,
results => 10,
what => '',
+ sort => '',
@_
);
@@ -51,12 +52,13 @@ sub dbUserGet {
);
my @select = (
- qw|id username c_votes c_changes show_list c_tags|,
+ qw|id username c_votes c_changes c_tags|,
q|extract('epoch' from registered) as registered|,
$o{what} =~ /extended/ ? (
- qw|mail rank salt skin customcss show_nsfw ign_votes notify_dbedit notify_announce|,
+ qw|mail rank salt ign_votes|,
q|encode(passwd, 'hex') AS passwd|
) : (),
+ $o{what} =~ /hide_list/ ? 'up.value AS hide_list' : (),
$o{what} =~ /notifycount/ ?
'(SELECT COUNT(*) FROM notifications WHERE uid = u.id AND read IS NULL) AS notifycount' : (),
$o{what} =~ /stats/ ? (
@@ -72,12 +74,14 @@ sub dbUserGet {
my @join = (
$o{session} ? 'JOIN sessions s ON s.uid = u.id' : (),
+ $o{what} =~ /hide_list/ || $o{sort} eq 'votes' ?
+ "LEFT JOIN users_prefs up ON up.uid = u.id AND up.key = 'hide_list'" : (),
);
my $order = sprintf {
username => 'u.username %s',
registered => 'u.registered %s',
- votes => 'NOT u.show_list, u.c_votes %s',
+ votes => 'up.value NULLS FIRST, u.c_votes %s',
changes => 'u.c_changes %s',
tags => 'u.c_tags %s',
}->{ $o{sort}||'username' }, $o{reverse} ? 'DESC' : 'ASC';
@@ -90,6 +94,20 @@ sub dbUserGet {
ORDER BY !s|,
join(', ', @select), join(' ', @join), \%where, $order
);
+
+ if(@$r && $o{what} =~ /prefs/) {
+ my %r = map {
+ $r->[$_]{prefs} = {};
+ ($r->[$_]{id}, $r->[$_])
+ } 0..$#$r;
+
+ $r{$_->{uid}}{prefs}{$_->{key}} = $_->{value} for (@{$s->dbAll(q|
+ SELECT uid, key, value
+ FROM users_prefs
+ WHERE uid IN(!l)|,
+ [ keys %r ]
+ )});
+ }
return wantarray ? ($r, $np) : $r;
}
@@ -100,7 +118,7 @@ sub dbUserEdit {
my %h;
defined $o{$_} && ($h{$_.' = ?'} = $o{$_})
- for (qw| username mail rank show_nsfw show_list skin customcss salt ign_votes notify_dbedit notify_announce |);
+ for (qw| username mail rank salt ign_votes |);
$h{'passwd = decode(?, \'hex\')'} = $o{passwd}
if defined $o{passwd};
@@ -127,6 +145,15 @@ sub dbUserDel {
}
+# uid, key, val
+sub dbUserPrefSet {
+ my($s, $uid, $key, $val) = @_;
+ !$val ? $s->dbExec('DELETE FROM users_prefs WHERE uid = ? AND key = ?', $uid, $key)
+ : $s->dbExec('UPDATE users_prefs SET value = ? WHERE uid = ? AND key = ?', $val, $uid, $key)
+ || $s->dbExec('INSERT INTO users_prefs (uid, key, value) VALUES (?, ?, ?)', $uid, $key, $val);
+}
+
+
# Adds a session to the database
# uid, 40 character session token
sub dbSessionAdd {
diff --git a/lib/VNDB/DB/VN.pm b/lib/VNDB/DB/VN.pm
index d25a5796..2a7f2477 100644
--- a/lib/VNDB/DB/VN.pm
+++ b/lib/VNDB/DB/VN.pm
@@ -10,7 +10,8 @@ use Encode 'decode_utf8';
our @EXPORT = qw|dbVNGet dbVNRevisionInsert dbVNImageId dbScreenshotAdd dbScreenshotGet dbScreenshotRandom|;
-# Options: id, rev, char, search, length, lang, olang, plat, tags_include, tags_exclude, hasani, results, page, what, sort, reverse
+# Options: id, rev, char, search, length, lang, olang, plat, tag_inc, tag_exc, tagspoil,
+# hasani, hasshot, results, page, what, sort, reverse
# What: extended anime relations screenshots relgraph rating ranking changes
# Sort: id rel pop rating title tagscore rand
sub dbVNGet {
@@ -19,6 +20,12 @@ sub dbVNGet {
$o{page} ||= 1;
$o{what} ||= '';
$o{sort} ||= 'title';
+ $o{tagspoil} //= 2;
+
+ # user input that is literally added to the query should be checked...
+ die "Invalid input for tagspoil or tag_inc at dbVNGet()\n" if
+ grep !defined($_) || $_!~/^\d+$/, $o{tagspoil},
+ !$o{tag_inc} ? () : (ref($o{tag_inc}) ? @{$o{tag_inc}} : $o{tag_inc});
my @where = (
$o{id} ? (
@@ -39,19 +46,20 @@ sub dbVNGet {
'('.join(' OR ', map "v.c_platforms ILIKE '%%$_%%'", ref $o{plat} ? @{$o{plat}} : $o{plat}).')' => 1 ) : (),
defined $o{hasani} ? (
'!sEXISTS(SELECT 1 FROM vn_anime va WHERE va.vid = vr.id)' => [ $o{hasani} ? '' : 'NOT ' ]) : (),
- $o{tags_include} && @{$o{tags_include}} ? (
+ defined $o{hasshot} ? (
+ '!sEXISTS(SELECT 1 FROM vn_screenshots vs WHERE vs.vid = vr.id)' => [ $o{hasshot} ? '' : 'NOT ' ]) : (),
+ $o{tag_inc} ? (
'v.id IN(SELECT vid FROM tags_vn_inherit WHERE tag IN(!l) AND spoiler <= ? GROUP BY vid HAVING COUNT(tag) = ?)',
- [ $o{tags_include}[1], $o{tags_include}[0], $#{$o{tags_include}[1]}+1 ]
- ) : (),
- $o{tags_exclude} && @{$o{tags_exclude}} ? (
- 'v.id NOT IN(SELECT vid FROM tags_vn_inherit WHERE tag IN(!l))' => [ $o{tags_exclude} ] ) : (),
+ [ ref $o{tag_inc} ? $o{tag_inc} : [$o{tag_inc}], $o{tagspoil}, ref $o{tag_inc} ? $#{$o{tag_inc}}+1 : 1 ]) : (),
+ $o{tag_exc} ? (
+ 'v.id NOT IN(SELECT vid FROM tags_vn_inherit WHERE tag IN(!l))' => [ ref $o{tag_exc} ? $o{tag_exc} : [$o{tag_exc}] ] ) : (),
$o{search} ? (
map +('v.c_search like ?', "%$_%"), normalize_query($o{search})) : (),
# don't fetch hidden items unless we ask for an ID
!$o{id} && !$o{rev} ? (
'v.hidden = FALSE' => 0 ) : (),
# optimize fetching random entries (only when there are no other filters present, otherwise this won't work well)
- $o{sort} eq 'rand' && $o{results} <= 10 && !grep(!/^(?:results|page|what|sort)$/, keys %o) ? (
+ $o{sort} eq 'rand' && $o{results} <= 10 && !grep(!/^(?:results|page|what|sort|tagspoil)$/, keys %o) ? (
sprintf 'v.id IN(SELECT floor(random() * last_value)::integer
FROM generate_series(1,20), (SELECT last_value FROM vn_id_seq) s1
LIMIT 20)' ) : (),
@@ -69,7 +77,7 @@ sub dbVNGet {
'JOIN relgraphs vg ON vg.id = v.rgraph' : (),
);
- my $tag_ids = $o{tags_include} && join ',', @{$o{tags_include}[1]};
+ my $tag_ids = $o{tag_inc} && join ',', ref $o{tag_inc} ? @{$o{tag_inc}} : $o{tag_inc};
my @select = ( # see https://rt.cpan.org/Ticket/Display.html?id=54224 for the cast on c_languages
qw|v.id v.locked v.hidden v.c_released v.c_languages::text[] v.c_platforms vr.title vr.original v.rgraph|, 'vr.id AS cid',
$o{what} =~ /extended/ ? (
@@ -84,7 +92,7 @@ sub dbVNGet {
) : (),
# TODO: optimize this, as it will be very slow when the selected tags match a lot of VNs (>1000)
$tag_ids ?
- qq|(SELECT AVG(tvh.rating) FROM tags_vn_inherit tvh WHERE tvh.tag IN($tag_ids) AND tvh.vid = v.id AND spoiler <= $o{tags_include}[0] GROUP BY tvh.vid) AS tagscore| : (),
+ qq|(SELECT AVG(tvh.rating) FROM tags_vn_inherit tvh WHERE tvh.tag IN($tag_ids) AND tvh.vid = v.id AND spoiler <= $o{tagspoil} GROUP BY tvh.vid) AS tagscore| : (),
);
my $order = sprintf {
@@ -216,8 +224,10 @@ sub dbScreenshotGet {
# Fetch random VN + screenshots
+# if any arguments are given, it will return one random screenshot for each VN
sub dbScreenshotRandom {
- return shift->dbAll(q|
+ my($self, @vids) = @_;
+ return $self->dbAll(q|
SELECT s.id AS scr, s.width, s.height, vr.vid, vr.title
FROM screenshots s
JOIN vn_screenshots vs ON vs.scr = s.id
@@ -230,7 +240,22 @@ sub dbScreenshotRandom {
LIMIT 20
)
LIMIT 4|
- );
+ ) if !@vids;
+ # this query is faster than it looks
+ return $self->dbAll(join(' UNION ALL ', map
+ q|SELECT s.id AS scr, s.width, s.height, vr.vid, vr.title, RANDOM() AS position
+ FROM vn v
+ JOIN vn_rev vr ON vr.id = v.latest
+ JOIN vn_screenshots vs ON vs.vid = v.latest
+ JOIN screenshots s ON s.id = vs.scr
+ WHERE v.id = ? AND s.id = (
+ SELECT vs2.scr
+ FROM vn_screenshots vs2
+ JOIN vn v2 ON v2.latest = vs2.vid
+ WHERE v2.id = v.id
+ ORDER BY RANDOM()
+ LIMIT 1
+ )|, @vids).' ORDER BY position', @vids);
}
diff --git a/lib/VNDB/Func.pm b/lib/VNDB/Func.pm
index 65b66f9e..17d69cd5 100644
--- a/lib/VNDB/Func.pm
+++ b/lib/VNDB/Func.pm
@@ -7,7 +7,7 @@ use YAWF ':html';
use Exporter 'import';
use POSIX 'strftime', 'ceil', 'floor';
use VNDBUtil;
-our @EXPORT = (@VNDBUtil::EXPORT, qw| liststat clearfloat cssicon tagscore mt minage fil_parse fil_serialize |);
+our @EXPORT = (@VNDBUtil::EXPORT, qw| clearfloat cssicon tagscore mt minage fil_parse fil_serialize |);
# three ways to represent the same information
@@ -16,21 +16,6 @@ our @fil_escape = split //, $fil_escape;
our %fil_escape = map +($fil_escape[$_], sprintf '%02d', $_), 0..$#fil_escape;
-# Argument: hashref with rstat and vstat
-# Returns: empty string if not in list, otherwise colour-encoded list status
-sub liststat {
- my $l = shift;
- return '' if !$l;
- my $rs = mt('_rlst_rstat_'.$l->{rstat});
- $rs = qq|<b class="done">$rs</b>| if $l->{rstat} == 2; # Obtained
- $rs = qq|<b class="todo">$rs</b>| if $l->{rstat} < 2; # Unknown/pending
- my $vs = mt('_rlst_vstat_'.$l->{vstat});
- $vs = qq|<b class="done">$vs</b>| if $l->{vstat} == 2; # Finished
- $vs = qq|<b class="todo">$vs</b>| if $l->{vstat} == 0 || $l->{vstat} == 4; # Unknown/dropped
- return "$rs / $vs";
-}
-
-
# Clears a float, to make sure boxes always have the correct height
sub clearfloat {
div class => 'clearfloat', '';
@@ -82,7 +67,7 @@ sub mt {
sub minage {
my($a, $ex) = @_;
- my $str = !defined($a) ? mt '_minage_null' : !$a ? mt '_minage_all' : mt '_minage_age', $a;
+ my $str = $a == -1 ? mt '_minage_null' : !$a ? mt '_minage_all' : mt '_minage_age', $a;
$ex = !defined($a) ? '' : {
0 => 'CERO A',
12 => 'CERO B',
@@ -118,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/Discussions.pm b/lib/VNDB/Handler/Discussions.pm
index d9974b00..0b5daa6c 100644
--- a/lib/VNDB/Handler/Discussions.pm
+++ b/lib/VNDB/Handler/Discussions.pm
@@ -48,7 +48,7 @@ sub thread {
end;
end;
- $self->htmlBrowseNavigate("/t$tid/", $page, $t->{count} > $page*25, 't', 1);
+ $self->htmlBrowseNavigate("/t$tid/", $page, [ $t->{count}, 25 ], 't', 1);
div class => 'mainbox thread';
table;
for my $i (0..$#$p) {
@@ -83,7 +83,7 @@ sub thread {
}
end;
end;
- $self->htmlBrowseNavigate("/t$tid/", $page, $t->{count} > $page*25, 'b', 1);
+ $self->htmlBrowseNavigate("/t$tid/", $page, [ $t->{count}, 25 ], 'b', 1);
if($t->{locked}) {
div class => 'mainbox';
@@ -278,7 +278,7 @@ sub board {
return 404 if $f->{_err};
my $obj = !$iid ? undef :
- $type eq 'u' ? $self->dbUserGet(uid => $iid)->[0] :
+ $type eq 'u' ? $self->dbUserGet(uid => $iid, what => 'hide_list')->[0] :
$type eq 'p' ? $self->dbProducerGet(id => $iid)->[0] :
$self->dbVNGet(id => $iid)->[0];
return 404 if $iid && !$obj;
diff --git a/lib/VNDB/Handler/Misc.pm b/lib/VNDB/Handler/Misc.pm
index 88e08f68..90a457aa 100644
--- a/lib/VNDB/Handler/Misc.pm
+++ b/lib/VNDB/Handler/Misc.pm
@@ -16,6 +16,7 @@ YAWF::register(
qr{setlang}, \&setlang,
qr{nospam}, \&nospam,
qr{we-dont-like-ie}, \&iemessage,
+ qr{xml/prefs\.xml}, \&prefs,
qr{opensearch\.xml}, \&opensearch,
# redirects for old URLs
@@ -44,7 +45,13 @@ sub homepage {
lit mt '_home_intro';
end;
- my $scr = $self->dbScreenshotRandom;
+ # with filters applied it's signifcantly slower, so special-code the situations with and without filters
+ my @vns;
+ if($self->authPref('filter_vn')) {
+ my $r = $self->filFetchDB(vn => undef, undef, {hasshot => 1, results => 4, order => 'rand'});
+ @vns = map $_->{id}, @$r;
+ }
+ my $scr = $self->dbScreenshotRandom(@vns);
p class => 'screenshots';
for (@$scr) {
my($w, $h) = imgsize($_->{width}, $_->{height}, @{$self->{scr_size}});
@@ -124,7 +131,7 @@ sub homepage {
h1;
a href => '/v/rand', mt '_home_randomvn';
end;
- my $random = $self->dbVNGet(results => 10, sort => 'rand');
+ my $random = $self->filFetchDB(vn => undef, undef, {results => 10, sort => 'rand'});
ul;
for (@$random) {
li;
@@ -139,7 +146,7 @@ sub homepage {
h1;
a href => strftime('/r?fil=date_after-%Y%m%d;o=a;s=released', gmtime), mt '_home_upcoming';
end;
- my $upcoming = $self->dbReleaseGet(results => 10, unreleased => 1, what => 'platforms');
+ my $upcoming = $self->filFetchDB(release => undef, undef, {results => 10, unreleased => 1, what => 'platforms'});
ul;
for (@$upcoming) {
li;
@@ -159,7 +166,7 @@ sub homepage {
h1;
a href => strftime('/r?fil=date_before-%Y%m%d;o=d;s=released', gmtime), mt '_home_justreleased';
end;
- my $justrel = $self->dbReleaseGet(results => 10, sort => 'released', reverse => 1, unreleased => 0, what => 'platforms');
+ my $justrel = $self->filFetchDB(release => undef, undef, {results => 10, sort => 'released', reverse => 1, unreleased => 0, what => 'platforms'});
ul;
for (@$justrel) {
li;
@@ -197,7 +204,7 @@ sub history {
return 404 if $f->{_err};
# get item object and title
- my $obj = $type eq 'u' ? $self->dbUserGet(uid => $id)->[0] :
+ my $obj = $type eq 'u' ? $self->dbUserGet(uid => $id, what => 'hide_list')->[0] :
$type eq 'p' ? $self->dbProducerGet(id => $id)->[0] :
$type eq 'r' ? $self->dbReleaseGet(id => $id)->[0] :
$type eq 'v' ? $self->dbVNGet(id => $id)->[0] : undef;
@@ -340,10 +347,17 @@ sub setlang {
return 404 if $lang->{_err};
$lang = $lang->{lang};
+ my $browser = VNDB::L10N->get_handle()->language_tag();
+
(my $ref = $self->reqHeader('Referer')||'/') =~ s/^\Q$self->{url}//;
$self->resRedirect($ref, 'post');
- $self->resHeader('Set-Cookie', "l10n=$lang; expires=Sat, 01-Jan-2030 00:00:00 GMT; path=/; domain=$self->{cookie_domain}")
- if $lang ne $self->{l10n}->language_tag();
+ if($lang ne $self->{l10n}->language_tag()) {
+ $self->authInfo->{id}
+ ? $self->authPref(l10n => $lang eq $browser ? undef : $lang)
+ : $self->resHeader('Set-Cookie', sprintf 'l10n=%s; expires=%s; path=/; domain=%s',
+ $lang, $lang eq $browser ? 'Sat, 01-Jan-2000 00:00:00 GMT' : 'Sat, 01-Jan-2030 00:00:00 GMT',
+ $self->{cookie_domain});
+ }
}
@@ -405,6 +419,24 @@ sub iemessage {
}
+sub prefs {
+ my $self = shift;
+ return if !$self->authCheckCode;
+ return 404 if !$self->authInfo->{id};
+ my $f = $self->formValidate(
+ { name => 'key', enum => [qw|filter_vn filter_release|] },
+ { name => 'value', required => 0, maxlength => 2000 },
+ );
+ return 404 if $f->{_err};
+ $self->authPref($f->{key}, $f->{value});
+
+ # doesn't really matter what we return, as long as it's XML
+ $self->resHeader('Content-type' => 'text/xml');
+ xml;
+ tag 'done', '';
+}
+
+
sub opensearch {
my $self = shift;
$self->resHeader('Content-Type' => 'application/opensearchdescription+xml');
diff --git a/lib/VNDB/Handler/Producers.pm b/lib/VNDB/Handler/Producers.pm
index 6e11e829..f7a46c2d 100644
--- a/lib/VNDB/Handler/Producers.pm
+++ b/lib/VNDB/Handler/Producers.pm
@@ -162,7 +162,7 @@ sub _releases {
for my $rel (@{$vn{$v->{vid}}}) {
Tr class => 'rel';
td class => 'tc1'; lit $self->{l10n}->datestr($rel->{released}); end;
- td class => 'tc2', !defined($rel->{minage}) ? '' : minage $rel->{minage};
+ td class => 'tc2', $rel->{minage} < 0 ? '' : minage $rel->{minage};
td class => 'tc3';
for (sort @{$rel->{platforms}}) {
next if $_ eq 'oth';
@@ -225,10 +225,11 @@ sub edit {
{ name => 'l_wp', required => 0, maxlength => 150, default => '' },
{ name => 'desc', required => 0, maxlength => 5000, default => '' },
{ name => 'prodrelations', required => 0, maxlength => 5000, default => '' },
- { name => 'editsum', maxlength => 5000 },
+ { name => 'editsum', required => 0, maxlength => 5000 },
{ name => 'ihid', required => 0 },
{ name => 'ilock', required => 0 },
);
+ push @{$frm->{_err}}, 'badeditsum' if !$frm->{editsum} || lc($frm->{editsum}) eq lc($frm->{desc});
if(!$frm->{_err}) {
# parse
my $relations = [ map { /^([a-z]+),([0-9]+),(.+)$/ && (!$pid || $2 != $pid) ? [ $1, $2, $3 ] : () } split /\|\|\|/, $frm->{prodrelations} ];
diff --git a/lib/VNDB/Handler/Releases.pm b/lib/VNDB/Handler/Releases.pm
index ce5c62c2..06dcfd0a 100644
--- a/lib/VNDB/Handler/Releases.pm
+++ b/lib/VNDB/Handler/Releases.pm
@@ -56,7 +56,7 @@ sub page {
[ media => join => ', ', split => sub {
map $self->{media}{$_->{medium}} ? $_->{qty}.' '.mt("_med_$_->{medium}", $_->{qty}) : mt("_med_$_->{medium}",1), @{$_[0]}
} ],
- [ resolution => serialize => sub { $self->{resolutions}[$_[0]][0] } ],
+ [ resolution => serialize => sub { my $r = $self->{resolutions}[$_[0]][0]; $r =~ /^_/ ? mt($r) : $r } ],
[ voiced => serialize => sub { mt '_voiced_'.$_[0] } ],
[ ani_story => serialize => sub { mt '_animated_'.$_[0] } ],
[ ani_ero => serialize => sub { mt '_animated_'.$_[0] } ],
@@ -190,7 +190,7 @@ sub _infotable {
end;
end;
- if(defined $r->{minage}) {
+ if($r->{minage} >= 0) {
Tr ++$i % 2 ? (class => 'odd') : ();
td mt '_relinfo_minage';
td minage $r->{minage};
@@ -236,22 +236,18 @@ sub _infotable {
}
if($self->authInfo->{id}) {
- my $rl = $self->dbVNListGet(uid => $self->authInfo->{id}, rid => $r->{id})->[0];
+ my $rl = $self->dbRListGet(uid => $self->authInfo->{id}, rid => $r->{id})->[0];
Tr ++$i % 2 ? (class => 'odd') : ();
td mt '_relinfo_user';
td;
Select id => 'listsel', name => $self->authGetCode("/r$r->{id}/list");
- option mt !$rl ? '_relinfo_user_notlist' :
- ('_relinfo_user_inlist', mt('_rlst_rstat_'.$rl->{rstat}), mt('_rlst_vstat_'.$rl->{vstat}));
- optgroup label => mt '_relinfo_user_setr';
- option value => "r$_", mt '_rlst_rstat_'.$_
- for (@{$self->{rlst_rstat}});
+ option value => -2,
+ mt !$rl ? '_relinfo_user_notlist' : ('_relinfo_user_inlist', mt('_rlist_status_'.$rl->{status}));
+ optgroup label => mt '_relinfo_user_setstatus';
+ option value => $_, mt '_rlist_status_'.$_
+ for (@{$self->{rlist_status}});
end;
- optgroup label => mt '_relinfo_user_setv';
- option value => "v$_", mt '_rlst_vstat_'.$_
- for (@{$self->{rlst_vstat}});
- end;
- option value => 'del', mt '_relinfo_user_del' if $rl;
+ option value => -1, mt '_relinfo_user_del' if $rl;
end;
end;
end;
@@ -287,9 +283,8 @@ sub edit {
my $vn = $rid ? $r->{vn} : [{ vid => $vid, title => $v->{title} }];
my %b4 = !$rid ? () : (
- (map { $_ => $r->{$_} } qw|type title original gtin catalog languages website released
+ (map { $_ => $r->{$_} } qw|type title original gtin catalog languages website released minage
notes platforms patch resolution voiced freeware doujin ani_story ani_ero ihid ilock|),
- minage => defined($r->{minage}) ? $r->{minage} : -1,
media => join(',', sort map "$_->{medium} $_->{qty}", @{$r->{media}}),
producers => join('|||', map
sprintf('%d,%d,%s', $_->{id}, ($_->{developer}?1:0)+($_->{publisher}?2:0), $_->{name}),
@@ -315,7 +310,7 @@ sub edit {
{ name => 'languages', multi => 1, enum => $self->{languages} },
{ name => 'website', required => 0, default => '', maxlength => 250, template => 'url' },
{ name => 'released', required => 0, default => 0, template => 'int' },
- { name => 'minage' , required => 0, default => -1, enum => [map !defined($_)?-1:$_, @{$self->{age_ratings}}] },
+ { name => 'minage' , required => 0, default => -1, enum => $self->{age_ratings} },
{ name => 'notes', required => 0, default => '', maxlength => 10240 },
{ name => 'platforms', required => 0, default => '', multi => 1, enum => $self->{platforms} },
{ name => 'media', required => 0, default => '' },
@@ -325,11 +320,12 @@ sub edit {
{ name => 'ani_ero', required => 0, default => 0, enum => $self->{animated} },
{ name => 'producers', required => 0, default => '' },
{ name => 'vn', maxlength => 5000 },
- { name => 'editsum', maxlength => 5000 },
+ { name => 'editsum', required => 0, maxlength => 5000 },
{ name => 'ihid', required => 0 },
{ name => 'ilock', required => 0 },
);
+ push @{$frm->{_err}}, 'badeditsum' if !$frm->{editsum} || lc($frm->{editsum}) eq lc($frm->{notes});
push @{$frm->{_err}}, [ 'released', 'required', 1 ] if !$frm->{released};
my($media, $producers, $new_vn);
@@ -356,9 +352,8 @@ sub edit {
if(!$frm->{_err}) {
my $nrev = $self->dbItemEdit(r => !$copy && $rid ? $r->{cid} : undef,
- (map { $_ => $frm->{$_} } qw| type title original gtin catalog languages website released
+ (map { $_ => $frm->{$_} } qw| type title original gtin catalog languages website released minage
notes platforms resolution editsum patch voiced freeware doujin ani_story ani_ero ihid ilock|),
- minage => $frm->{minage} < 0 ? undef : $frm->{minage},
vn => $new_vn,
producers => $producers,
media => $media,
@@ -406,7 +401,7 @@ sub _form {
[ date => short => 'released', name => mt('_redit_form_released') ],
[ static => content => mt('_redit_form_released_note') ],
[ select => short => 'minage', name => mt('_redit_form_minage'),
- options => [ map [ !defined($_)?-1:$_, minage $_, 1 ], @{$self->{age_ratings}} ] ],
+ options => [ map [ $_, minage $_, 1 ], @{$self->{age_ratings}} ] ],
[ textarea => short => 'notes', name => mt('_redit_form_notes').'<br /><b class="standout">'.mt('_inenglish').'</b>' ],
[ static => content => mt('_redit_form_notes_note') ],
],
@@ -492,19 +487,16 @@ sub browse {
{ name => 'fil',required => 0, default => '' },
);
return 404 if $f->{_err};
+ $f->{fil} = $self->authPref('filter_release') if !grep $_ eq 'fil', $self->reqParam();
- 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'));
@@ -519,13 +511,14 @@ sub browse {
end;
end;
+ my $uri = sprintf '/r?q=%s;fil=%s', uri_escape($f->{q}), $f->{fil};
$self->htmlBrowse(
class => 'relbrowse',
items => $list,
options => $f,
nextpage => $np,
- pageurl => "/r?q=$f->{q};fil=$f->{fil};s=$f->{s};o=$f->{o}",
- sorturl => "/r?q=$f->{q};fil=$f->{fil}",
+ pageurl => "$uri;s=$f->{s};o=$f->{o}",
+ sorturl => $uri,
header => [
[ mt('_rbrowse_col_released'), 'released' ],
[ mt('_rbrowse_col_minage'), 'minage' ],
@@ -538,7 +531,7 @@ sub browse {
td class => 'tc1';
lit $self->{l10n}->datestr($l->{released});
end;
- td class => 'tc2', !defined($l->{minage}) ? '' : minage $l->{minage};
+ td class => 'tc2', $l->{minage} < 0 ? '' : minage $l->{minage};
td class => 'tc3';
$_ ne 'oth' && cssicon $_, mt "_plat_$_" for (@{$l->{platforms}});
cssicon "lang $_", mt "_lang_$_" for (@{$l->{languages}});
@@ -551,7 +544,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';
@@ -559,13 +552,14 @@ sub browse {
end;
end;
}
- $self->htmlFooter;
+ $self->htmlFooter(prefs => [qw|filter_release|]);
}
-# 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,23 +569,24 @@ sub _fil_compat {
{ name => 'fw', required => 0, default => 0, enum => [ 0..2 ] },
{ name => 'do', required => 0, default => 0, enum => [ 0..2 ] },
{ name => 'ma_m', required => 0, default => 0, enum => [ 0, 1 ] },
- { name => 'ma_a', required => 0, default => 0, enum => [ grep defined($_), @{$self->{age_ratings}} ] },
+ { name => 'ma_a', required => 0, default => 0, enum => $self->{age_ratings} },
{ name => 'mi', required => 0, default => 0, template => 'int' },
{ 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 defined($_) && $f->{ma_m} ? $f->{ma_a} >= $_ : defined ($_) && $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/Tags.pm b/lib/VNDB/Handler/Tags.pm
index 0567bff6..ad736027 100644
--- a/lib/VNDB/Handler/Tags.pm
+++ b/lib/VNDB/Handler/Tags.pm
@@ -39,13 +39,15 @@ sub tagpage {
my $tagspoil = $self->reqCookie($self->{cookie_prefix}.'tagspoil');
$f->{m} = $tagspoil =~ /^[0-2]$/ ? $tagspoil : 0 if $f->{m} == -1;
- my($list, $np) = $t->{meta} || $t->{state} != 2 ? ([],0) : $self->dbVNGet(
+ my($list, $np) = $t->{meta} || $t->{state} != 2 ? ([],0) : $self->filFetchDB(vn => undef, undef, {
what => 'rating',
results => 50,
page => $f->{p},
sort => $f->{s}, reverse => $f->{o} eq 'd',
- tags_include => [ $f->{m}, [$tag ]],
- );
+ tagspoil => $f->{m},
+ tag_inc => $tag,
+ tag_exc => undef,
+ });
my $title = mt '_tagp_title', $t->{meta}?0:1, $t->{name};
$self->htmlHeader(title => $title, noindex => $t->{state} != 2);
@@ -357,12 +359,12 @@ sub taglinks {
my $f = $self->formValidate(
{ name => 'p', required => 0, default => 1, template => 'int' },
{ name => 'o', required => 0, default => 'd', enum => ['a', 'd'] },
- { name => 's', required => 0, default => 'date', enum => [qw|date username title tag|] },
+ { name => 's', required => 0, default => 'date', enum => [qw|date tag|] },
{ name => 'v', required => 0, default => 0, template => 'int' },
{ name => 'u', required => 0, default => 0, template => 'int' },
{ name => 't', required => 0, default => 0, template => 'int' },
);
- return 404 if $f->{_err};
+ return 404 if $f->{_err} || $f->{p} > 100;
my($list, $np) = $self->dbTagLinks(
what => 'details',
@@ -432,11 +434,11 @@ sub taglinks {
sorturl => $url->(s=>0,o=>0),
header => [
[ mt('_taglink_col_date'), 'date' ],
- [ mt('_taglink_col_user'), 'username' ],
+ [ mt('_taglink_col_user') ],
[ mt('_taglink_col_rating') ],
[ mt('_taglink_col_tag'), 'tag' ],
[ mt('_taglink_col_spoiler') ],
- [ mt('_taglink_col_vn'), 'title' ],
+ [ mt('_taglink_col_vn'), ],
],
row => sub {
my($s, $n, $l) = @_;
@@ -668,19 +670,22 @@ sub fulltree {
sub tagxml {
my $self = shift;
- my $q = $self->formValidate({ name => 'q', maxlength => 500 });
- return 404 if $q->{_err};
- $q = $q->{q};
+ my $f = $self->formValidate(
+ { name => 'q', required => 0, maxlength => 500 },
+ { name => 'id', required => 0, multi => 1, template => 'int' },
+ );
+ return 404 if $f->{_err} || (!$f->{q} && !$f->{id} && !$f->{id}[0]);
my($list, $np) = $self->dbTagGet(
- $q =~ /^g([1-9]\d*)/ ? (id => $1) : $q =~ /^name:(.+)$/ ? (name => $1) : (search => $q),
+ !$f->{q} ? () : $f->{q} =~ /^g([1-9]\d*)/ ? (id => $1) : $f->{q} =~ /^name:(.+)$/ ? (name => $1) : (search => $f->{q}),
+ $f->{id} && $f->{id}[0] ? (id => $f->{id}) : (),
results => 15,
page => 1,
);
$self->resHeader('Content-type' => 'text/xml; charset=UTF-8');
xml;
- tag 'tags', more => $np ? 'yes' : 'no', query => $q;
+ tag 'tags', more => $np ? 'yes' : 'no', $f->{q} ? (query => $f->{q}) : ();
for(@$list) {
tag 'item', id => $_->{id}, meta => $_->{meta} ? 'yes' : 'no', state => $_->{state}, $_->{name};
}
diff --git a/lib/VNDB/Handler/ULists.pm b/lib/VNDB/Handler/ULists.pm
index 6efb0a13..403b391d 100644
--- a/lib/VNDB/Handler/ULists.pm
+++ b/lib/VNDB/Handler/ULists.pm
@@ -10,8 +10,9 @@ use VNDB::Func;
YAWF::register(
qr{v([1-9]\d*)/vote}, \&vnvote,
qr{v([1-9]\d*)/wish}, \&vnwish,
- qr{r([1-9]\d*)/list}, \&rlist,
- qr{xml/rlist.xml}, \&rlist,
+ qr{v([1-9]\d*)/list}, \&vnlist_e,
+ qr{r([1-9]\d*)/list}, \&rlist_e,
+ qr{xml/rlist.xml}, \&rlist_e,
qr{([uv])([1-9]\d*)/votes}, \&votelist,
qr{u([1-9]\d*)/wish}, \&wishlist,
qr{u([1-9]\d*)/list}, \&vnlist,
@@ -56,7 +57,26 @@ sub vnwish {
}
-sub rlist {
+sub vnlist_e {
+ my($self, $id) = @_;
+
+ my $uid = $self->authInfo->{id};
+ return $self->htmlDenied() if !$uid;
+
+ return if !$self->authCheckCode;
+ my $f = $self->formValidate(
+ { name => 'e', enum => [ -1, @{$self->{vnlist_status}} ] }
+ );
+ return 404 if $f->{_err};
+
+ $self->dbVNListDel($uid, $id) if $f->{e} == -1;
+ $self->dbVNListAdd($uid, $id, $f->{e}) if $f->{e} != -1;
+
+ $self->resRedirect('/v'.$id, 'temp');
+}
+
+
+sub rlist_e {
my($self, $id) = @_;
my $rid = $id;
@@ -73,27 +93,21 @@ sub rlist {
return if !$self->authCheckCode;
my $f = $self->formValidate(
- { name => 'e', required => 1, enum => [ 'del', map("r$_", @{$self->{rlst_rstat}}), map("v$_", @{$self->{rlst_vstat}}) ] },
+ { name => 'e', required => 1, enum => [ -1, @{$self->{rlist_status}} ] }
);
return 404 if $f->{_err};
- $self->dbVNListDel($uid, $rid) if $f->{e} eq 'del';
- $self->dbVNListAdd(
- rid => $rid,
- uid => $uid,
- $f->{e} =~ /^([rv])(\d+)$/ && $1 eq 'r' ? (rstat => $2) : (vstat => $2)
- ) if $f->{e} ne 'del';
+ $self->dbRListDel($uid, $rid) if $f->{e} == -1;
+ $self->dbRListAdd($uid, $rid, $f->{e}) if $f->{e} >= 0;
if($id) {
(my $ref = $self->reqHeader('Referer')||"/r$id") =~ s/^\Q$self->{url}//;
$self->resRedirect($ref, 'temp');
} else {
+ # doesn't really matter what we return, as long as it's XML
$self->resHeader('Content-type' => 'text/xml');
- my $st = $self->dbVNListGet(uid => $self->authInfo->{id}, rid => [$rid])->[0];
xml;
- tag 'rlist', uid => $self->authInfo->{id}, rid => $rid;
- txt $st ? liststat $st : '--';
- end;
+ tag 'done', '';
}
}
@@ -101,17 +115,32 @@ sub rlist {
sub votelist {
my($self, $type, $id) = @_;
- my $obj = $type eq 'v' ? $self->dbVNGet(id => $id)->[0] : $self->dbUserGet(uid => $id)->[0];
+ my $obj = $type eq 'v' ? $self->dbVNGet(id => $id)->[0] : $self->dbUserGet(uid => $id, what => 'hide_list')->[0];
return 404 if !$obj->{id};
my $own = $type eq 'u' && $self->authInfo->{id} && $self->authInfo->{id} == $id;
- return 404 if $type eq 'u' && !$own && !($obj->{show_list} || $self->authCan('usermod'));
+ return 404 if $type eq 'u' && !$own && !(!$obj->{hide_list} || $self->authCan('usermod'));
my $f = $self->formValidate(
{ name => 'p', required => 0, default => 1, template => 'int' },
{ name => 'o', required => 0, default => 'd', enum => ['a', 'd'] },
{ name => 's', required => 0, default => 'date', enum => [qw|date title vote|] },
+ { name => 'c', required => 0, default => 'all', enum => [ 'all', 'a'..'z', 0 ] },
);
+ return 404 if $f->{_err};
+
+ if($own && $self->reqMethod eq 'POST') {
+ return if !$self->authCheckCode;
+ my $frm = $self->formValidate(
+ { name => 'vid', required => 1, multi => 1, template => 'int' },
+ { name => 'batchedit', required => 1, enum => [ -2, -1, 1..10 ] },
+ );
+ my @vid = grep $_ > 0, @{$frm->{vid}};
+ if(!$frm->{_err} && @vid && $frm->{batchedit} > -2) {
+ $self->dbVoteDel($id, \@vid) if $frm->{batchedit} == -1;
+ $self->dbVoteAdd(\@vid, $id, $frm->{batchedit}) if $frm->{batchedit} >= 0;
+ }
+ }
my($list, $np) = $self->dbVoteGet(
$type.'id' => $id,
@@ -121,24 +150,35 @@ sub votelist {
sort => $f->{s} eq 'title' && $type eq 'v' ? 'username' : $f->{s},
reverse => $f->{o} eq 'd',
results => 50,
- page => $f->{p}
+ page => $f->{p},
+ $f->{c} ne 'all' ? ($type eq 'u' ? 'vn_char' : 'user_char', $f->{c}) : (),
);
- return 404 if !@$list;
my $title = mt $type eq 'v' ? '_votelist_title_vn' : '_votelist_title_user', $obj->{title} || $obj->{username};
$self->htmlHeader(noindex => 1, title => $title);
$self->htmlMainTabs($type => $obj, 'votes');
div class => 'mainbox';
h1 $title;
+ p class => 'browseopts';
+ for ('all', 'a'..'z', 0) {
+ a href => "/$type$id/votes?c=$_", $_ eq $f->{c} ? (class => 'optselected') : (), $_ eq 'all' ? mt('_char_all') : $_ ? uc $_ : '#';
+ }
+ end;
+ p mt '_votelist_novotes' if !@$list;
end;
- $self->htmlBrowse(
+ if($own) {
+ my $code = $self->authGetCode("/u$id/votes");
+ form action => "/u$id/votes?formcode=$code;c=$f->{c};s=$f->{s};p=$f->{p}", method => 'post';
+ }
+
+ @$list && $self->htmlBrowse(
class => 'votelist',
items => $list,
options => $f,
nextpage => $np,
- pageurl => "/$type$id/votes?o=$f->{o};s=$f->{s}",
- sorturl => "/$type$id/votes",
+ pageurl => "/$type$id/votes?c=$f->{c};o=$f->{o};s=$f->{s}",
+ sorturl => "/$type$id/votes?c=$f->{c}",
header => [
[ mt('_votelist_col_date'), 'date' ],
[ mt('_votelist_col_vote'), 'vote' ],
@@ -147,15 +187,33 @@ sub votelist {
row => sub {
my($s, $n, $l) = @_;
Tr $n % 2 ? (class => 'odd') : ();
- td class => 'tc1', $self->{l10n}->date($l->{date});
+ td class => 'tc1';
+ input type => 'checkbox', name => 'vid', value => $l->{vid} if $own;
+ txt ' '.$self->{l10n}->date($l->{date});
+ end;
td class => 'tc2', $l->{vote};
td class => 'tc3';
a href => $type eq 'v' ? ("/u$l->{uid}", $l->{username}) : ("/v$l->{vid}", shorten $l->{title}, 100);
end;
end;
},
+ $own ? (footer => sub {
+ Tr;
+ td colspan => 3, class => 'tc1';
+ input type => 'checkbox', class => 'checkall', name => 'vid', value => -1;
+ txt ' ';
+ Select name => 'batchedit', id => 'batchedit';
+ option value => -2, '-- with selected --';
+ optgroup label => 'Change vote';
+ option value => $_, "$_ (".mt("_vote_$_").')' for (reverse 1..10);
+ end;
+ option value => -1, 'revoke';
+ end;
+ end;
+ end;
+ }) : (),
);
-
+ end if $own;
$self->htmlFooter;
}
@@ -164,8 +222,8 @@ sub wishlist {
my($self, $uid) = @_;
my $own = $self->authInfo->{id} && $self->authInfo->{id} == $uid;
- my $u = $self->dbUserGet(uid => $uid)->[0];
- return 404 if !$u || !$own && !($u->{show_list} || $self->authCan('usermod'));
+ my $u = $self->dbUserGet(uid => $uid, what => 'hide_list')->[0];
+ return 404 if !$u || !$own && !(!$u->{hide_list} || $self->authCan('usermod'));
my $f = $self->formValidate(
{ name => 'p', required => 0, default => 1, template => 'int' },
@@ -266,8 +324,8 @@ sub vnlist {
my($self, $uid) = @_;
my $own = $self->authInfo->{id} && $self->authInfo->{id} == $uid;
- my $u = $self->dbUserGet(uid => $uid)->[0];
- return 404 if !$u || !$own && !($u->{show_list} || $self->authCan('usermod'));
+ my $u = $self->dbUserGet(uid => $uid, what => 'hide_list')->[0];
+ return 404 if !$u || !$own && !(!$u->{hide_list} || $self->authCan('usermod'));
my $f = $self->formValidate(
{ name => 'p', required => 0, default => 1, template => 'int' },
@@ -275,33 +333,40 @@ sub vnlist {
{ name => 's', required => 0, default => 'title', enum => [ 'title', 'vote' ] },
{ name => 'c', required => 0, default => 'all', enum => [ 'all', 'a'..'z', 0 ] },
{ name => 'v', required => 0, default => 0, enum => [ -1..1 ] },
+ { name => 't', required => 0, default => -1, enum => [ -1, @{$self->{vnlist_status}} ] },
);
return 404 if $f->{_err};
if($own && $self->reqMethod eq 'POST') {
return if !$self->authCheckCode;
my $frm = $self->formValidate(
- { name => 'sel', required => 0, default => 0, multi => 1, template => 'int' },
- { name => 'batchedit', required => 1, enum => [ 'del', map("r$_", @{$self->{rlst_rstat}}), map("v$_", @{$self->{rlst_vstat}}) ] },
+ { name => 'vid', required => 0, default => 0, multi => 1, template => 'int' },
+ { name => 'rid', required => 0, default => 0, multi => 1, template => 'int' },
+ { name => 'not', required => 0, default => '', maxlength => 2000 },
+ { name => 'vns', required => 1, enum => [ -2, -1, @{$self->{vnlist_status}}, 999 ] },
+ { name => 'rel', required => 1, enum => [ -2, -1, @{$self->{rlist_status}} ] },
);
- if(!$frm->{_err} && @{$frm->{sel}} && $frm->{sel}[0]) {
- $self->dbVNListDel($uid, $frm->{sel}) if $frm->{batchedit} eq 'del';
- $self->dbVNListAdd(
- rid => $frm->{sel},
- uid => $uid,
- $frm->{batchedit} =~ /^([rv])(\d+)$/ && $1 eq 'r' ? (rstat => $2) : (vstat => $2)
- ) if $frm->{batchedit} ne 'del';
+ my @vid = grep $_ > 0, @{$frm->{vid}};
+ my @rid = grep $_ > 0, @{$frm->{rid}};
+ if(!$frm->{_err} && @vid && $frm->{vns} > -2) {
+ $self->dbVNListDel($uid, \@vid) if $frm->{vns} == -1;
+ $self->dbVNListAdd($uid, \@vid, $frm->{vns}) if $frm->{vns} >= 0 && $frm->{vns} < 999;
+ $self->dbVNListAdd($uid, \@vid, undef, $frm->{not}) if $frm->{vns} == 999;
+ }
+ if(!$frm->{_err} && @rid && $frm->{rel} > -2) {
+ $self->dbRListDel($uid, \@rid) if $frm->{rel} == -1;
+ $self->dbRListAdd($uid, \@rid, $frm->{rel}) if $frm->{rel} >= 0;
}
}
-
my($list, $np) = $self->dbVNListList(
uid => $uid,
results => 50,
page => $f->{p},
sort => $f->{s}, reverse => $f->{o} eq 'd',
- voted => $f->{v},
+ voted => $f->{v} == 0 ? undef : $f->{v} < 0 ? 0 : $f->{v},
$f->{c} ne 'all' ? (char => $f->{c}) : (),
+ $f->{t} >= 0 ? (status => $f->{t}) : (),
);
my $title = $own ? mt '_rlist_title_my' : mt '_rlist_title_other', $u->{username};
@@ -315,6 +380,7 @@ sub vnlist {
local $_ = "/u$uid/list";
$_ .= '?c='.($n eq 'c' ? $v : $f->{c});
$_ .= ';v='.($n eq 'v' ? $v : $f->{v});
+ $_ .= ';t='.($n eq 't' ? $v : $f->{t});
if($n eq 'page') {
$_ .= ';o='.($n eq 'o' ? $v : $f->{o});
$_ .= ';s='.($n eq 's' ? $v : $f->{s});
@@ -330,10 +396,14 @@ sub vnlist {
}
end;
p class => 'browseopts';
- a href => $url->(v => 0), 0 == $f->{v} ? (class => 'optselected') : (), mt '_rlist_voted_all';
+ a href => $url->(v => 0), 0 == $f->{v} ? (class => 'optselected') : (), mt '_rlist_all';
a href => $url->(v => 1), 1 == $f->{v} ? (class => 'optselected') : (), mt '_rlist_voted_only';
a href => $url->(v => -1), -1 == $f->{v} ? (class => 'optselected') : (), mt '_rlist_voted_none';
end;
+ p class => 'browseopts';
+ a href => $url->(t => -1), -1 == $f->{t} ? (class => 'optselected') : (), mt '_rlist_all';
+ a href => $url->(t => $_), $_ == $f->{t} ? (class => 'optselected') : (), mt '_vnlist_status_'.$_ for @{$self->{vnlist_status}};
+ end;
end;
_vnlist_browse($self, $own, $list, $np, $f, $url, $uid);
@@ -343,8 +413,11 @@ sub vnlist {
sub _vnlist_browse {
my($self, $own, $list, $np, $f, $url, $uid) = @_;
- form action => $url->().';formcode='.$self->authGetCode("/u$uid/list"), method => 'post'
- if $own;
+ if($own) {
+ form action => $url->(), method => 'post';
+ input type => 'hidden', class => 'hidden', name => 'not', id => 'not', value => '';
+ input type => 'hidden', class => 'hidden', name => 'formcode', id => 'formcode', value => $self->authGetCode("/u$uid/list");
+ }
$self->htmlBrowse(
class => 'rlist',
@@ -354,66 +427,84 @@ sub _vnlist_browse {
sorturl => $url->(),
pageurl => $url->('page'),
header => [
- [ mt('_rlist_col_title') => 'title', 3 ],
- sub { td class => 'tc2', id => 'expandall'; lit '<i>&#9656;</i>'.mt('_rlist_col_releases').'*'; end; },
+ [ '' ],
+ sub { td class => 'tc2', id => 'expandall'; lit '&#9656;'; end; },
+ [ mt('_rlist_col_title') => 'title' ],
+ [ '' ], [ '' ],
+ [ mt('_rlist_col_status') ],
+ [ mt('_rlist_col_releases').'*' ],
[ mt('_rlist_col_vote') => 'vote' ],
],
row => sub {
my($s, $n, $i) = @_;
Tr $n % 2 == 0 ? (class => 'odd') : ();
- td class => 'tc1', colspan => 3;
+ td class => 'tc1'; input type => 'checkbox', name => 'vid', value => $i->{vid} if $own; end;
+ if(@{$i->{rels}}) {
+ td class => 'tc2 collapse_but', id => "vid$i->{vid}"; lit '&#9656;'; end;
+ } else {
+ td class => 'tc2', '';
+ }
+ td class => 'tc3_5', colspan => 3;
a href => "/v$i->{vid}", title => $i->{original}||$i->{title}, shorten $i->{title}, 70;
+ b class => 'grayedout', $i->{notes} if $i->{notes};
end;
- td class => 'tc2'.(@{$i->{rels}} ? ' collapse_but' : ''), id => 'vid'.$i->{vid};
- lit '<i>&#9656;</i>';
- my $obtained = grep $_->{rstat}==2, @{$i->{rels}};
- my $finished = grep $_->{vstat}==2, @{$i->{rels}};
- my $txt = sprintf '%d/%d/%d', $obtained, $finished, scalar @{$i->{rels}};
- $txt = qq|<b class="done">$txt</b>| if $finished > $obtained || $finished && $finished == $obtained;
- $txt = qq|<b class="todo">$txt</b>| if $obtained > $finished;
+ td class => 'tc6', $i->{status} ? mt '_vnlist_status_'.$i->{status} : '';
+ td class => 'tc7';
+ my $obtained = grep $_->{status}==2, @{$i->{rels}};
+ my $total = scalar @{$i->{rels}};
+ my $txt = sprintf '%d/%d', $obtained, $total;
+ $txt = qq|<b class="done">$txt</b>| if $total && $obtained == $total;
+ $txt = qq|<b class="todo">$txt</b>| if $obtained < $total;
lit $txt;
end;
- td class => 'tc3', $i->{vote} || '-';
+ td class => 'tc8', $i->{vote} || '-';
end;
for (@{$i->{rels}}) {
- Tr class => "collapse relhid collapse_vid$i->{vid}";
- td class => 'tc1'.($own ? ' own' : '');
- input type => 'checkbox', name => 'sel', value => $_->{rid}
- if $own;
- lit $self->{l10n}->datestr($_->{released});
- end;
+ Tr class => "collapse relhid collapse_vid$i->{vid}".($n%2 ? '':' odd');
+ td class => 'tc1', '';
td class => 'tc2';
+ input type => 'checkbox', name => 'rid', value => $_->{rid} if $own;
+ end;
+ td class => 'tc3', $self->{l10n}->datestr($_->{released});
+ td class => 'tc4';
cssicon "lang $_", mt "_lang_$_" for @{$_->{languages}};
cssicon "rt$_->{type}", mt "_rtype_$_->{type}";
end;
- td class => 'tc3';
+ td class => 'tc5';
a href => "/r$_->{rid}", title => $_->{original}||$_->{title}, shorten $_->{title}, 50;
end;
- td colspan => 2, class => 'tc4';
- lit liststat($_);
- end;
+ td class => 'tc6', $_->{status} ? mt '_rlist_status_'.$_->{status} : '';
+ td class => 'tc7_8', colspan => 2, '';
end;
}
},
$own ? (footer => sub {
Tr;
- td class => 'tc1', colspan => 3;
- Select id => 'batchedit', name => 'batchedit';
- option mt '_rlist_selection';
- optgroup label => mt '_rlist_changerel';
- option value => "r$_", mt "_rlst_rstat_$_"
- for (@{$self->{rlst_rstat}});
+ td class => 'tc1'; input type => 'checkbox', name => 'vid', value => -1, class => 'checkall'; end;
+ td class => 'tc2'; input type => 'checkbox', name => 'rid', value => -1, class => 'checkall'; end;
+ td class => 'tc3_6', colspan => 4;
+ Select id => 'vns', name => 'vns';
+ option value => -2, mt '_rlist_withvn';
+ optgroup label => mt '_rlist_changestat';
+ option value => $_, mt "_vnlist_status_$_"
+ for (@{$self->{vnlist_status}});
end;
- optgroup label => mt '_rlist_changeplay';
- option value => "v$_", mt "_rlst_vstat_$_"
- for (@{$self->{rlst_vstat}});
+ option value => 999, mt '_rlist_setnote';
+ option value => -1, mt '_rlist_del';
+ end;
+ Select id => 'rel', name => 'rel';
+ option value => -2, mt '_rlist_withrel';
+ optgroup label => mt '_rlist_changestat';
+ option value => $_, mt "_rlist_status_$_"
+ for (@{$self->{rlist_status}});
end;
- option value => 'del', mt '_rlist_del';
+ option value => -1, mt '_rlist_del';
end;
+ input type => 'submit', value => mt '_rlist_update';
end;
- td class => 'tc2', colspan => 2, mt '_rlist_releasenote';
+ td class => 'tc7_8', colspan => 2, mt '_rlist_releasenote';
end;
}) : (),
);
diff --git a/lib/VNDB/Handler/Users.pm b/lib/VNDB/Handler/Users.pm
index 3e2a1aef..044c72b2 100644
--- a/lib/VNDB/Handler/Users.pm
+++ b/lib/VNDB/Handler/Users.pm
@@ -27,7 +27,7 @@ YAWF::register(
sub userpage {
my($self, $uid) = @_;
- my $u = $self->dbUserGet(uid => $uid, what => 'stats')->[0];
+ my $u = $self->dbUserGet(uid => $uid, what => 'stats hide_list')->[0];
return 404 if !$u->{id};
my $votes = $u->{c_votes} && $self->dbVoteStats(uid => $uid);
@@ -69,7 +69,7 @@ sub userpage {
Tr ++$i % 2 ? (class => 'odd') : ();
td mt '_userpage_votes';
td;
- if(!$u->{show_list}) {
+ if($u->{hide_list}) {
txt mt '_userpage_hidden';
} elsif($votes) {
my($total, $count) = (0, 0);
@@ -99,7 +99,7 @@ sub userpage {
Tr ++$i % 2 ? (class => 'odd') : ();
td mt '_userpage_list';
- td !$u->{show_list} ? mt('_userpage_hidden') :
+ td $u->{hide_list} ? mt('_userpage_hidden') :
mt('_userpage_list_item', $u->{releasecount}, $u->{vncount});
end;
@@ -116,7 +116,7 @@ sub userpage {
end;
end;
- if($u->{show_list} && $votes) {
+ if(!$u->{hide_list} && $votes) {
div class => 'mainbox';
h1 mt '_userpage_votestats';
$self->htmlVoteStats(u => $u, $votes);
@@ -291,7 +291,7 @@ sub edit {
return $self->htmlDenied if !$self->authInfo->{id} || $self->authInfo->{id} != $uid && !$self->authCan('usermod');
# fetch user info (cached if uid == loggedin uid)
- my $u = $self->authInfo->{id} == $uid ? $self->authInfo : $self->dbUserGet(uid => $uid, what => 'extended')->[0];
+ my $u = $self->authInfo->{id} == $uid ? $self->authInfo : $self->dbUserGet(uid => $uid, what => 'extended prefs')->[0];
return 404 if !$u->{id};
# check POST data
@@ -300,30 +300,27 @@ sub edit {
return if !$self->authCheckCode;
$frm = $self->formValidate(
$self->authCan('usermod') ? (
- { name => 'usrname', template => 'pname', minlength => 2, maxlength => 15 },
- { name => 'rank', enum => [ 1..$#{$self->{user_ranks}} ] },
+ { name => 'usrname', template => 'pname', minlength => 2, maxlength => 15 },
+ { name => 'rank', enum => [ 1..$#{$self->{user_ranks}} ] },
{ name => 'ign_votes', required => 0, default => 0 },
) : (),
- { name => 'mail', template => 'mail' },
- { name => 'usrpass', required => 0, minlength => 4, maxlength => 64, template => 'asciiprint' },
- { name => 'usrpass2', required => 0, minlength => 4, maxlength => 64, template => 'asciiprint' },
- { name => 'flags_list', required => 0, default => 0 },
- { name => 'flags_nsfw', required => 0, default => 0 },
- { name => 'skin', enum => [ '', keys %{$self->{skins}} ], required => 0, default => '' },
- { name => 'customcss', required => 0, maxlength => 2000, default => '' },
+ { name => 'mail', template => 'mail' },
+ { name => 'usrpass', required => 0, minlength => 4, maxlength => 64, template => 'asciiprint' },
+ { name => 'usrpass2', required => 0, minlength => 4, maxlength => 64, template => 'asciiprint' },
+ { name => 'hide_list', required => 0, default => 0, enum => [0,1] },
+ { name => 'show_nsfw', required => 0, default => 0, enum => [0,1] },
+ { name => 'skin', required => 0, default => '', enum => [ '', keys %{$self->{skins}} ] },
+ { name => 'customcss', required => 0, maxlength => 2000, default => '' },
);
push @{$frm->{_err}}, 'passmatch'
if ($frm->{usrpass} || $frm->{usrpass2}) && (!$frm->{usrpass} || !$frm->{usrpass2} || $frm->{usrpass} ne $frm->{usrpass2});
if(!$frm->{_err}) {
+ $self->dbUserPrefSet($uid, $_ => $frm->{$_}) for (qw|skin customcss show_nsfw hide_list |);
my %o;
$o{username} = $frm->{usrname} if $frm->{usrname};
$o{rank} = $frm->{rank} if $frm->{rank};
$o{mail} = $frm->{mail};
- $o{skin} = $frm->{skin};
- $o{customcss} = $frm->{customcss};
($o{passwd}, $o{salt}) = $self->authPreparePass($frm->{usrpass}) if $frm->{usrpass};
- $o{show_list} = $frm->{flags_list} ? 1 : 0;
- $o{show_nsfw} = $frm->{flags_nsfw} ? 1 : 0;
$o{ign_votes} = $frm->{ign_votes} ? 1 : 0 if $self->authCan('usermod');
$self->dbUserEdit($uid, %o);
$self->dbSessionDel($uid) if $frm->{usrpass};
@@ -334,9 +331,8 @@ sub edit {
# fill out default values
$frm->{usrname} ||= $u->{username};
- $frm->{$_} ||= $u->{$_} for(qw|rank mail skin customcss|);
- $frm->{flags_list} = $u->{show_list} if !defined $frm->{flags_list};
- $frm->{flags_nsfw} = $u->{show_nsfw} if !defined $frm->{flags_nsfw};
+ $frm->{$_} ||= $u->{$_} for(qw|rank mail|);
+ $frm->{$_} //= $u->{prefs}{$_} for(qw|skin customcss show_nsfw hide_list|);
$frm->{ign_votes} = $u->{ign_votes} if !defined $frm->{ign_votes};
# create the page
@@ -368,8 +364,8 @@ sub edit {
[ passwd => short => 'usrpass2', name => mt '_usere_confirm' ],
[ part => title => mt '_usere_options' ],
- [ check => short => 'flags_list', name => mt '_usere_flist', "/u$uid/list", "/u$uid/wish" ],
- [ check => short => 'flags_nsfw', name => mt '_usere_fnsfw' ],
+ [ check => short => 'hide_list', name => mt '_usere_flist', "/u$uid/list", "/u$uid/votes", "/u$uid/wish" ],
+ [ check => short => 'show_nsfw', name => mt '_usere_fnsfw' ],
[ select => short => 'skin', name => mt('_usere_skin'), width => 300, options => [
map [ $_ eq $self->{skin_default} ? '' : $_, $self->{skins}{$_}[0].($self->debug?" [$_]":'') ], sort { $self->{skins}{$a}[0] cmp $self->{skins}{$b}[0] } keys %{$self->{skins}} ] ],
[ textarea => short => 'customcss', name => mt '_usere_css' ],
@@ -382,7 +378,7 @@ sub posts {
my($self, $uid) = @_;
# fetch user info (cached if uid == loggedin uid)
- my $u = $self->authInfo->{id} && $self->authInfo->{id} == $uid ? $self->authInfo : $self->dbUserGet(uid => $uid)->[0];
+ my $u = $self->authInfo->{id} && $self->authInfo->{id} == $uid ? $self->authInfo : $self->dbUserGet(uid => $uid, what => 'hide_list')->[0];
return 404 if !$u->{id};
my $f = $self->formValidate(
@@ -439,7 +435,7 @@ sub delete {
# confirm
if(!$act) {
my $code = $self->authGetCode("/u$uid/del/o");
- my $u = $self->dbUserGet(uid => $uid)->[0];
+ my $u = $self->dbUserGet(uid => $uid, what => 'hide_list')->[0];
return 404 if !$u->{id};
$self->htmlHeader(title => 'Delete user', noindex => 1);
$self->htmlMainTabs('u', $u, 'del');
@@ -500,6 +496,7 @@ sub list {
my($list, $np) = $self->dbUserGet(
sort => $f->{s}, reverse => $f->{o} eq 'd',
+ what => 'hide_list',
$char ne 'all' ? (
firstchar => $char ) : (),
results => 50,
@@ -527,8 +524,8 @@ sub list {
a href => '/u'.$l->{id}, $l->{username};
end;
td class => 'tc2', $self->{l10n}->date($l->{registered});
- td class => 'tc3'.(!$l->{show_list} && $self->authCan('usermod') ? ' linethrough' : '');
- lit !$l->{show_list} && !$self->authCan('usermod') ? '-' : !$l->{c_votes} ? 0 :
+ td class => 'tc3'.($l->{hide_list} && $self->authCan('usermod') ? ' linethrough' : '');
+ lit $l->{hide_list} && !$self->authCan('usermod') ? '-' : !$l->{c_votes} ? 0 :
qq|<a href="/u$l->{id}/votes">$l->{c_votes}</a>|;
end;
td class => 'tc4';
@@ -546,9 +543,9 @@ sub list {
sub notifies {
my($self, $uid) = @_;
- return $self->htmlDenied if !$self->authInfo->{id} || $uid != $self->authInfo->{id};
- my $u = $self->dbUserGet(uid => $uid)->[0];
+ my $u = $self->authInfo;
+ return $self->htmlDenied if !$u->{id} || $uid != $u->{id};
my $f = $self->formValidate(
{ name => 'p', required => 0, default => 1, template => 'int' },
@@ -562,15 +559,11 @@ sub notifies {
if($self->reqMethod() eq 'POST' && $self->reqParam('set')) {
return if !$self->authCheckCode;
my $frm = $self->formValidate(
- { name => 'notify_dbedit', required => 0 },
- { name => 'notify_announce', required => 0 }
+ { name => 'notify_nodbedit', required => 0, default => 1, enum => [0,1] },
+ { name => 'notify_announce', required => 0, default => 0, enum => [0,1] }
);
return 404 if $frm->{_err};
- for ('notify_dbedit', 'notify_announce') {
- $frm->{$_} = $frm->{$_} ? 1 : 0;
- $self->authInfo->{$_} = $frm->{$_};
- }
- $self->dbUserEdit($uid, %$frm);
+ $self->authPref($_, $frm->{$_}) for ('notify_nodbedit', 'notify_announce');
$saved = 1;
# updating notifications
@@ -661,9 +654,10 @@ sub notifies {
h1 mt '_usern_set_title';
div class => 'notice', mt '_usern_set_saved' if $saved;
p;
- for('dbedit', 'announce') {
- input type => 'checkbox', name => "notify_$_", id => "notify_$_", value => 1,
- $self->authInfo->{"notify_$_"} ? (checked => 'checked') : ();
+ for('nodbedit', 'announce') {
+ my $def = $_ eq 'nodbedit'? 0 : 1;
+ input type => 'checkbox', name => "notify_$_", id => "notify_$_", value => $def,
+ ($self->authPref("notify_$_")||0) == $def ? (checked => 'checked') : ();
label for => "notify_$_", ' '.mt("_usern_set_$_");
br;
}
diff --git a/lib/VNDB/Handler/VNBrowse.pm b/lib/VNDB/Handler/VNBrowse.pm
index 8e30da99..8a63b79b 100644
--- a/lib/VNDB/Handler/VNBrowse.pm
+++ b/lib/VNDB/Handler/VNBrowse.pm
@@ -25,72 +25,40 @@ sub list {
);
return 404 if $f->{_err};
$f->{q} ||= $f->{sq};
- my $fil = fil_parse $f->{fil}, qw|length hasani taginc tagexc tagspoil lang olang plat|;
- _fil_compat($self, $fil);
-
- if($f->{q}) {
- return $self->resRedirect('/'.$1.$2.(!$3 ? '' : $1 eq 'd' ? '#'.$3 : '.'.$3), 'temp')
- if $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;
-
- # TODO: this should be moved to dbVNGet() in order for savable VN filters to be useful
- my @ignored;
- my $tagfind = sub {
- return map {
- my $i = $self->dbTagGet(name => $_)->[0];
- push @ignored, [$_, 0] if !$i;
- push @ignored, [$_, 1] if $i && $i->{meta};
- $i && !$i->{meta} ? $i->{id} : ();
- } grep $_, ref $_[0] ? @{$_[0]} : ($_[0]||'')
- };
- my @ti = $tagfind->(delete $fil->{taginc});
- my @te = $tagfind->(delete $fil->{tagexc});
-
- $f->{s} = 'title' if !@ti && $f->{s} eq 'tagscore';
+ $f->{fil} = $self->authPref('filter_vn') if !grep $_ eq 'fil', $self->reqParam();
+ my %compat = _fil_compat($self);
+
+ return $self->resRedirect('/'.$1.$2.(!$3 ? '' : $1 eq 'd' ? '#'.$3 : '.'.$3), 'temp')
+ if $f->{q} && $f->{q} =~ /^([gvrptud])([0-9]+)(?:\.([0-9]+))?$/;
+
+ $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',
- @ti ? (tags_include => [ delete $fil->{tagspoil}, \@ti ]) : (),
- @te ? (tags_exclude => \@te) : (),
- %$fil
- );
+ });
$self->resRedirect('/v'.$list->[0]{id}, 'temp')
if $f->{q} && @$list == 1 && $f->{p} == 1;
$self->htmlHeader(title => mt('_vnbrowse_title'), search => $f->{q});
+ my $quri = uri_escape($f->{q});
form action => '/v/all', 'accept-charset' => 'UTF-8', method => 'get';
div class => 'mainbox';
h1 mt '_vnbrowse_title';
$self->htmlSearchBox('v', $f->{q});
p class => 'browseopts';
for ('all', 'a'..'z', 0) {
- a href => "/v/$_?q=$f->{q};fil=$f->{fil}", $_ eq $char ? (class => 'optselected') : (), $_ eq 'all' ? mt('_char_all') : $_ ? uc $_ : '#';
+ a href => "/v/$_?q=$quri;fil=$f->{fil}", $_ eq $char ? (class => 'optselected') : (), $_ eq 'all' ? mt('_char_all') : $_ ? uc $_ : '#';
}
end;
- if(@ignored) {
- div class => 'warning';
- h2 mt '_vnbrowse_tagign_title';
- ul;
- li $_->[0].' ('.mt('_vnbrowse_tagign_'.($_->[1]?'meta':'notfound')).')' for @ignored;
- end;
- end;
- }
-
a id => 'filselect', href => '#v';
lit '<i>&#9656;</i> '.mt('_rbrowse_filters').'<i></i>'; # TODO: it's not *r*browse
end;
@@ -98,25 +66,24 @@ sub list {
end;
end; # /form
- $self->htmlBrowseVN($list, $f, $np, "/v/$char?q=$f->{q};fil=$f->{fil}", scalar @ti);
- $self->htmlFooter;
+ $self->htmlBrowseVN($list, $f, $np, "/v/$char?q=$quri;fil=$f->{fil}", $f->{fil} =~ /tag_inc-/);
+ $self->htmlFooter(prefs => ['filter_vn']);
}
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};
+ 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/Handler/VNEdit.pm b/lib/VNDB/Handler/VNEdit.pm
index 8ee104af..b93c544d 100644
--- a/lib/VNDB/Handler/VNEdit.pm
+++ b/lib/VNDB/Handler/VNEdit.pm
@@ -52,11 +52,13 @@ sub edit {
{ name => 'img_nsfw', required => 0, default => 0 },
{ name => 'vnrelations', required => 0, default => '', maxlength => 5000 },
{ name => 'screenshots', required => 0, default => '', maxlength => 1000 },
- { name => 'editsum', maxlength => 5000 },
+ { name => 'editsum', required => 0, maxlength => 5000 },
{ name => 'ihid', required => 0 },
{ name => 'ilock', required => 0 },
);
+ push @{$frm->{_err}}, 'badeditsum' if !$frm->{editsum} || lc($frm->{editsum}) eq lc($frm->{desc});
+
# handle image upload
my $image = _uploadimage($self, $v, $frm);
diff --git a/lib/VNDB/Handler/VNPage.pm b/lib/VNDB/Handler/VNPage.pm
index 1a3eb514..5e024424 100644
--- a/lib/VNDB/Handler/VNPage.pm
+++ b/lib/VNDB/Handler/VNPage.pm
@@ -16,7 +16,7 @@ YAWF::register(
sub rand {
my $self = shift;
- $self->resRedirect('/v'.$self->dbVNGet(results => 1, sort => 'rand')->[0]{id}, 'temp');
+ $self->resRedirect('/v'.$self->filFetchDB(vn => undef, undef, {results => 1, sort => 'rand'})->[0]{id}, 'temp');
}
@@ -74,12 +74,12 @@ sub page {
} elsif($v->{image} < 0) {
p mt '_vnpage_imgproc';
} else {
- p $v->{img_nsfw} ? (id => 'nsfw_hid', style => $self->authInfo->{show_nsfw} ? 'display: block' : '') : ();
+ p $v->{img_nsfw} ? (id => 'nsfw_hid', style => $self->authPref('show_nsfw') ? 'display: block' : '') : ();
img src => sprintf("%s/cv/%02d/%d.jpg", $self->{url_static}, $v->{image}%100, $v->{image}), alt => $v->{title};
i mt '_vnpage_imgnsfw_foot' if $v->{img_nsfw};
end;
if($v->{img_nsfw}) {
- p id => 'nsfw_show', $self->authInfo->{show_nsfw} ? (style => 'display: none') : ();
+ p id => 'nsfw_show', $self->authPref('show_nsfw') ? (style => 'display: none') : ();
txt mt('_vnpage_imgnsfw_msg')."\n\n";
a href => '#', mt '_vnpage_imgnsfw_show';
txt "\n\n".mt '_vnpage_imgnsfw_note';
@@ -225,7 +225,7 @@ sub _revision {
[ image => htmlize => sub {
my $url = sprintf "%s/cv/%02d/%d.jpg", $self->{url_static}, $_[0]%100, $_[0];
if($_[0] > 0) {
- return $_[1]->{img_nsfw} && !$self->authInfo->{show_nsfw} ? "<a href=\"$url\">".mt('_vndiff_image_nsfw').'</a>' : "<img src=\"$url\" />";
+ return $_[1]->{img_nsfw} && !$self->authPref('show_nsfw') ? "<a href=\"$url\">".mt('_vndiff_image_nsfw').'</a>' : "<img src=\"$url\" />";
} else {
return mt $_[0] < 0 ? '_vndiff_image_proc' : '_vndiff_image_none';
}
@@ -343,6 +343,7 @@ sub _useroptions {
my($self, $i, $v) = @_;
my $vote = $self->dbVoteGet(uid => $self->authInfo->{id}, vid => $v->{id})->[0];
+ my $list = $self->dbVNListGet(uid => $self->authInfo->{id}, vid => $v->{id})->[0];
my $wish = $self->dbWishListGet(uid => $self->authInfo->{id}, vid => $v->{id})->[0];
Tr ++$$i % 2 ? (class => 'odd') : ();
@@ -358,6 +359,16 @@ sub _useroptions {
end;
br;
}
+
+ Select id => 'listsel', name => $self->authGetCode("/v$v->{id}/list");
+ option $list ? mt '_vnpage_uopt_vnlisted', mt '_vnlist_status_'.$list->{status} : mt '_vnpage_uopt_novn';
+ optgroup label => $list ? mt '_vnpage_uopt_changevn' : mt '_vnpage_uopt_addvn';
+ option value => $_, mt "_vnlist_status_$_" for (@{$self->{rlist_status}});
+ end;
+ option value => -1, mt '_vnpage_uopt_delvn' if $list;
+ end;
+ br;
+
if(!$vote || $wish) {
Select id => 'wishsel', name => $self->authGetCode("/v$v->{id}/wish");
option $wish ? mt '_vnpage_uopt_wishlisted', mt '_wish_'.$wish->{wstat} : mt '_vnpage_uopt_nowish';
@@ -385,7 +396,7 @@ sub _releases {
}
if($self->authInfo->{id}) {
- my $l = $self->dbVNListGet(uid => $self->authInfo->{id}, rid => [map $_->{id}, @$r]);
+ my $l = $self->dbRListGet(uid => $self->authInfo->{id}, rid => [map $_->{id}, @$r]);
for my $i (@$l) {
[grep $i->{rid} == $_->{id}, @$r]->[0]{ulist} = $i;
}
@@ -406,7 +417,7 @@ sub _releases {
for my $rel (grep grep($_ eq $l, @{$_->{languages}}), @$r) {
Tr;
td class => 'tc1'; lit $self->{l10n}->datestr($rel->{released}); end;
- td class => 'tc2', !defined($rel->{minage}) ? '' : minage $rel->{minage};
+ td class => 'tc2', $rel->{minage} < 0 ? '' : minage $rel->{minage};
td class => 'tc3';
for (sort @{$rel->{platforms}}) {
next if $_ eq 'oth';
@@ -420,9 +431,8 @@ sub _releases {
end;
td class => 'tc5';
if($self->authInfo->{id}) {
- a href => "/r$rel->{id}", id => "rlsel_$rel->{id}", class => 'vnrlsel';
- lit $rel->{ulist} ? liststat $rel->{ulist} : '--';
- end;
+ a href => "/r$rel->{id}", id => "rlsel_$rel->{id}", class => 'vnrlsel',
+ $rel->{ulist} ? mt '_rlist_status_'.$rel->{ulist}{status} : '--';
} else {
txt ' ';
}
@@ -451,7 +461,7 @@ sub _screenshots {
if(grep $_->{nsfw}, @{$v->{screenshots}}) {
p class => 'nsfwtoggle';
lit mt '_vnpage_scr_showing',
- sprintf('<i id="nsfwshown">%d</i>', $self->authInfo->{show_nsfw} ? scalar @{$v->{screenshots}} : scalar grep(!$_->{nsfw}, @{$v->{screenshots}})),
+ sprintf('<i id="nsfwshown">%d</i>', $self->authPref('show_nsfw') ? scalar @{$v->{screenshots}} : scalar grep(!$_->{nsfw}, @{$v->{screenshots}})),
scalar @{$v->{screenshots}};
txt " ";
a href => '#', id => "nsfwhide", mt '_vnpage_scr_nsfwhide';
@@ -471,7 +481,7 @@ sub _screenshots {
for (@scr) {
my($w, $h) = imgsize($_->{width}, $_->{height}, @{$self->{scr_size}});
a href => sprintf('%s/sf/%02d/%d.jpg', $self->{url_static}, $_->{id}%100, $_->{id}),
- class => sprintf('scrlnk%s%s', $_->{nsfw} ? ' nsfw':'', $_->{nsfw}&&!$self->authInfo->{show_nsfw}?' hidden':''),
+ class => sprintf('scrlnk%s%s', $_->{nsfw} ? ' nsfw':'', $_->{nsfw}&&!$self->authPref('show_nsfw')?' hidden':''),
rel => "iv:$_->{width}x$_->{height}:scr";
img src => sprintf('%s/st/%02d/%d.jpg', $self->{url_static}, $_->{id}%100, $_->{id}),
width => $w, height => $h, alt => mt '_vnpage_scr_num', $_->{id};
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;
+}
+