summaryrefslogtreecommitdiff
path: root/lib/VNDB/Handler/Tags.pm
diff options
context:
space:
mode:
Diffstat (limited to 'lib/VNDB/Handler/Tags.pm')
-rw-r--r--lib/VNDB/Handler/Tags.pm193
1 files changed, 122 insertions, 71 deletions
diff --git a/lib/VNDB/Handler/Tags.pm b/lib/VNDB/Handler/Tags.pm
index ad736027..6a4cb760 100644
--- a/lib/VNDB/Handler/Tags.pm
+++ b/lib/VNDB/Handler/Tags.pm
@@ -4,11 +4,11 @@ package VNDB::Handler::Tags;
use strict;
use warnings;
-use YAWF ':html', ':xml';
+use TUWF ':html', ':xml', 'xml_escape';
use VNDB::Func;
-YAWF::register(
+TUWF::register(
qr{g([1-9]\d*)}, \&tagpage,
qr{g([1-9]\d*)/(edit)}, \&tagedit,
qr{g([1-9]\d*)/(add)}, \&tagedit,
@@ -27,16 +27,16 @@ sub tagpage {
my($self, $tag) = @_;
my $t = $self->dbTagGet(id => $tag, what => 'parents(0) childs(2) aliases')->[0];
- return 404 if !$t;
+ return $self->resNotFound if !$t;
my $f = $self->formValidate(
- { name => 's', required => 0, default => 'tagscore', enum => [ qw|title rel pop tagscore rating| ] },
- { name => 'o', required => 0, default => 'd', enum => [ 'a','d' ] },
- { name => 'p', required => 0, default => 1, template => 'int' },
- { name => 'm', required => 0, default => -1, enum => [qw|0 1 2|] },
+ { get => 's', required => 0, default => 'tagscore', enum => [ qw|title rel pop tagscore rating| ] },
+ { get => 'o', required => 0, default => 'd', enum => [ 'a','d' ] },
+ { get => 'p', required => 0, default => 1, template => 'int' },
+ { get => 'm', required => 0, default => -1, enum => [qw|0 1 2|] },
);
- return 404 if $f->{_err};
- my $tagspoil = $self->reqCookie($self->{cookie_prefix}.'tagspoil');
+ return $self->resNotFound if $f->{_err};
+ my $tagspoil = $self->reqCookie('tagspoil');
$f->{m} = $tagspoil =~ /^[0-2]$/ ? $tagspoil : 0 if $f->{m} == -1;
my($list, $np) = $t->{meta} || $t->{state} != 2 ? ([],0) : $self->filFetchDB(vn => undef, undef, {
@@ -69,7 +69,7 @@ sub tagpage {
p mt '_tagp_pending_msg';
end;
}
- end;
+ end 'div';
}
div class => 'mainbox';
@@ -84,9 +84,10 @@ sub tagpage {
txt ' > ';
a href => "/g$_->{id}", $_->{name};
}
- txt " > $t->{name}\n";
+ txt " > $t->{name}";
+ br;
}
- end;
+ end 'p';
if($t->{description}) {
p class => 'description';
@@ -95,11 +96,12 @@ sub tagpage {
}
if(@{$t->{aliases}}) {
p class => 'center';
- b mt('_tagp_aliases')."\n";
- txt "$_\n" for (@{$t->{aliases}});
+ b mt('_tagp_aliases');
+ br;
+ lit xml_escape($_).'<br />' for (@{$t->{aliases}});
end;
}
- end;
+ end 'div';
_childtags($self, $t) if @{$t->{childs}};
@@ -112,9 +114,11 @@ sub tagpage {
a href => "/g$t->{id}?m=1", $f->{m} == 1 ? (class => 'optselected') : (), onclick => "setCookie('tagspoil', 1);return true;", mt '_tagp_spoil1';
a href => "/g$t->{id}?m=2", $f->{m} == 2 ? (class => 'optselected') : (), onclick => "setCookie('tagspoil', 2);return true;", mt '_tagp_spoil2';
end;
- p "\n\n".mt '_tagp_novn' if !@$list;
- p "\n".mt '_tagp_cached';
- end;
+ if(!@$list) {
+ p; br; br; txt mt '_tagp_novn'; end;
+ }
+ p; br; txt mt '_tagp_cached'; end;
+ end 'div';
$self->htmlBrowseVN($list, $f, $np, "/g$t->{id}?m=$f->{m}", 1) if @$list;
}
@@ -164,12 +168,12 @@ sub _childtags {
end;
}
end;
- end;
+ end 'li';
}
- end;
+ end 'ul';
clearfloat;
br;
- end;
+ end 'div';
}
@@ -179,7 +183,7 @@ sub tagedit {
my($frm, $par);
if($act && $act eq 'add') {
$par = $self->dbTagGet(id => $tag)->[0];
- return 404 if !$par;
+ return $self->resNotFound if !$par;
$frm->{parents} = $par->{name};
$tag = undef;
}
@@ -187,18 +191,18 @@ sub tagedit {
return $self->htmlDenied if !$self->authCan('tag') || $tag && !$self->authCan('tagmod');
my $t = $tag && $self->dbTagGet(id => $tag, what => 'parents(1) aliases addedby')->[0];
- return 404 if $tag && !$t;
+ return $self->resNotFound if $tag && !$t;
if($self->reqMethod eq 'POST') {
return if !$self->authCheckCode;
$frm = $self->formValidate(
- { name => 'name', required => 1, maxlength => 250, regex => [ qr/^[^,]+$/, 'A comma is not allowed in tag names' ] },
- { name => 'state', required => 0, default => 0, enum => [ 0..2 ] },
- { name => 'meta', required => 0, default => 0 },
- { name => 'alias', required => 0, maxlength => 1024, default => '', regex => [ qr/^[^,]+$/s, 'No comma allowed in aliases' ] },
- { name => 'description', required => 0, maxlength => 10240, default => '' },
- { name => 'parents', required => !$self->authCan('tagmod'), default => '' },
- { name => 'merge', required => 0, default => '' },
+ { post => 'name', required => 1, maxlength => 250, regex => [ qr/^[^,]+$/, 'A comma is not allowed in tag names' ] },
+ { post => 'state', required => 0, default => 0, enum => [ 0..2 ] },
+ { post => 'meta', required => 0, default => 0 },
+ { post => 'alias', required => 0, maxlength => 1024, default => '', regex => [ qr/^[^,]+$/s, 'No comma allowed in aliases' ] },
+ { post => 'description', required => 0, maxlength => 10240, default => '' },
+ { post => 'parents', required => !$self->authCan('tagmod'), default => '' },
+ { post => 'merge', required => 0, default => '' },
);
my @aliases = split /[\t\s]*\n[\t\s]*/, $frm->{alias};
my @parents = split /[\t\s]*,[\t\s]*/, $frm->{parents};
@@ -289,13 +293,13 @@ sub taglist {
my $self = shift;
my $f = $self->formValidate(
- { name => 's', required => 0, default => 'name', enum => ['added', 'name'] },
- { name => 'o', required => 0, default => 'a', enum => ['a', 'd'] },
- { name => 'p', required => 0, default => 1, template => 'int' },
- { name => 't', required => 0, default => -1, enum => [ -1..2 ] },
- { name => 'q', required => 0, default => '' },
+ { get => 's', required => 0, default => 'name', enum => ['added', 'name'] },
+ { get => 'o', required => 0, default => 'a', enum => ['a', 'd'] },
+ { get => 'p', required => 0, default => 1, template => 'int' },
+ { get => 't', required => 0, default => -1, enum => [ -1..2 ] },
+ { get => 'q', required => 0, default => '' },
);
- return 404 if $f->{_err};
+ return $self->resNotFound if $f->{_err};
my($t, $np) = $self->dbTagGet(
sort => $f->{s}, reverse => $f->{o} eq 'd',
@@ -321,7 +325,7 @@ sub taglist {
if(!@$t) {
p mt '_tagb_noresults';
}
- end;
+ end 'div';
if(@$t) {
$self->htmlBrowse(
class => 'taglist',
@@ -345,7 +349,7 @@ sub taglist {
b class => 'grayedout', ' '.mt '_tagb_note_del' if $l->{state} == 1;
}
end;
- end;
+ end 'tr';
}
);
}
@@ -357,14 +361,14 @@ sub taglinks {
my $self = shift;
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 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' },
+ { get => 'p', required => 0, default => 1, template => 'int' },
+ { get => 'o', required => 0, default => 'd', enum => ['a', 'd'] },
+ { get => 's', required => 0, default => 'date', enum => [qw|date tag|] },
+ { get => 'v', required => 0, default => 0, template => 'int' },
+ { get => 'u', required => 0, default => 0, template => 'int' },
+ { get => 't', required => 0, default => 0, template => 'int' },
);
- return 404 if $f->{_err} || $f->{p} > 100;
+ return $self->resNotFound if $f->{_err} || $f->{p} > 100;
my($list, $np) = $self->dbTagLinks(
what => 'details',
@@ -420,10 +424,10 @@ sub taglinks {
a href => "/v$o->{id}", $o->{title};
end;
}
- end;
+ end 'ul';
}
p mt '_taglink_fil_add' unless $f->{v} && $f->{u} && $f->{t};
- end;
+ end 'div';
$self->htmlBrowse(
class => 'taglinks',
@@ -450,7 +454,7 @@ sub taglinks {
a href => $url->(u=>$l->{uid}), class => 'setfil', '> ' if !$f->{u};
a href => "/u$l->{uid}", $l->{username};
end;
- td class => 'tc3';
+ td class => 'tc3'.($l->{ignore}?' ignored':'');
tagscore $l->{vote};
end;
td class => 'tc4';
@@ -473,23 +477,61 @@ sub vntagmod {
my($self, $vid) = @_;
my $v = $self->dbVNGet(id => $vid)->[0];
- return 404 if !$v || $v->{hidden};
+ return $self->resNotFound if !$v || $v->{hidden};
return $self->htmlDenied if !$self->authCan('tag');
+ my $tags = $self->dbTagStats(vid => $vid, results => 9999);
+ my $my = $self->dbTagLinks(vid => $vid, uid => $self->authInfo->{id});
+
if($self->reqMethod eq 'POST') {
return if !$self->authCheckCode;
my $frm = $self->formValidate(
- { name => 'taglinks', required => 0, default => '', maxlength => 10240, regex => [ qr/^[1-9][0-9]*,-?[1-3],-?[0-2]( [1-9][0-9]*,-?[1-3],-?[0-2])*$/, 'meh' ] }
+ { post => 'taglinks', required => 0, default => '', maxlength => 10240, regex => [ qr/^[1-9][0-9]*,-?[1-3],-?[0-2]( [1-9][0-9]*,-?[1-3],-?[0-2])*$/, 'meh' ] },
+ { post => 'overrule', required => 0, multi => 1, template => 'int' },
);
- return 404 if $frm->{_err};
- $self->dbTagLinkEdit($self->authInfo->{id}, $vid, [ map [ split /,/ ], split / /, $frm->{taglinks}]);
- }
+ return $self->resNotFound if $frm->{_err};
+
+ # convert some data in a more convenient structure for faster lookup
+ my %tags = map +($_->{id} => $_), @$tags;
+ my %old = map +($_->{tag} => $_), @$my;
+ my %new = map { my($tag, $vote, $spoiler) = split /,/; ($tag => [ $vote, $spoiler ]) } split / /, $frm->{taglinks};
+ my %over = !$self->authCan('tagmod') || !$frm->{overrule}[0] ? () : (map $new{$_} ? ($_ => 1) : (), @{$frm->{overrule}});
+
+ # hashes which need to be filled, indicating what should be changed to the DB
+ my %delete; # tag => 1
+ my %update; # tag => [ vote, spoiler ] (ignore flag is untouched)
+ my %insert; # tag => [ vote, spoiler, ignore ]
+ my %overrule; # tag => 0/1
+
+ for my $t (keys %old, keys %new) {
+ my $prev_over = $old{$t} && !$old{$t}{ignore} && $tags{$t}{overruled};
+
+ # overrule checkbox has changed? make sure to (de-)overrule the tag votes
+ $overrule{$t} = $over{$t}?1:0 if (!$prev_over && $over{$t}) || ($prev_over && !$over{$t});
+
+ # tag deleted?
+ if($old{$t} && !$new{$t}) {
+ $delete{$t} = 1;
+ next;
+ }
- my $my = $self->dbTagLinks(vid => $vid, uid => $self->authInfo->{id});
- my $tags = $self->dbTagStats(vid => $vid, results => 9999);
+ # and insert or update the vote
+ if(!$old{$t} && $new{$t}) {
+ # determine whether this vote is going to be ignored or not
+ my $ign = $tags{$t}{overruled} && !$prev_over && !$over{$t};
+ $insert{$t} = [ $new{$t}[0], $new{$t}[1], $ign ];
+ } elsif($old{$t}{vote} != $new{$t}[0] || (defined $old{$t}{spoiler} ? $old{$t}{spoiler} : -1) != $new{$t}[1]) {
+ $update{$t} = [ $new{$t}[0], $new{$t}[1] ];
+ }
+ }
+ $self->dbTagLinkEdit($self->authInfo->{id}, $vid, \%insert, \%update, \%delete, \%overrule);
+
+ # need to re-fetch the tags and tag links, as these have been modified
+ $tags = $self->dbTagStats(vid => $vid, results => 9999);
+ $my = $self->dbTagLinks(vid => $vid, uid => $self->authInfo->{id});
+ }
- my $frm;
my $title = mt '_tagv_title', $v->{title};
$self->htmlHeader(title => $title, noindex => 1);
@@ -504,26 +546,27 @@ sub vntagmod {
li mt '_tagv_msg_cache';
end;
end;
- end;
- $self->htmlForm({ frm => $frm, action => "/v$vid/tagmod", nosubmit => 1 }, tagmod => [ mt('_tagv_frm_title'),
+ end 'div';
+ $self->htmlForm({ action => "/v$vid/tagmod", nosubmit => 1 }, tagmod => [ mt('_tagv_frm_title'),
[ hidden => short => 'taglinks', value => '' ],
[ static => nolabel => 1, content => sub {
table class => 'tgl';
thead;
Tr;
td '';
- td colspan => 2, class => 'tc_you', mt '_tagv_col_you';
+ td colspan => $self->authCan('tagmod') ? 3 : 2, class => 'tc_you', mt '_tagv_col_you';
td colspan => 3, class => 'tc_others', mt '_tagv_col_others';
end;
Tr;
td class => 'tc_tagname', mt '_tagv_col_tag';
td class => 'tc_myvote', mt '_tagv_col_rating';
+ td class => 'tc_myover', 'O' if $self->authCan('tagmod');
td class => 'tc_myspoil', mt '_tagv_col_spoiler';
td class => 'tc_allvote', mt '_tagv_col_rating';
td class => 'tc_allspoil', mt '_tagv_col_spoiler';
td class => 'tc_allwho', '';
end;
- end;
+ end 'thead';
tfoot; Tr;
td colspan => 6;
input type => 'submit', class => 'submit', value => mt('_tagv_save'), style => 'float: right';
@@ -534,17 +577,25 @@ sub vntagmod {
lit mt '_tagv_addmsg';
end;
end;
- end; end;
+ end; end 'tfoot';
tbody id => 'tagtable';
for my $t (sort { $a->{name} cmp $b->{name} } @$tags) {
my $m = (grep $_->{tag} == $t->{id}, @$my)[0] || {};
Tr id => "tgl_$t->{id}";
td class => 'tc_tagname'; a href => "/g$t->{id}", $t->{name}; end;
td class => 'tc_myvote', $m->{vote}||0;
+ if($self->authCan('tagmod')) {
+ td class => 'tc_myover';
+ input type => 'checkbox', name => 'overrule', value => $t->{id},
+ $m->{vote} && !$m->{ignore} && $t->{overruled} ? (checked => 'checked') : ()
+ if $t->{cnt} > 1;
+ end;
+ }
td class => 'tc_myspoil', defined $m->{spoiler} ? $m->{spoiler} : -1;
td class => 'tc_allvote';
- tagscore !$m->{vote} ? $t->{rating} : $t->{cnt} == 1 ? 0 : ($t->{rating}*$t->{cnt} - $m->{vote}) / ($t->{cnt}-1);
- i ' ('.($t->{cnt} - ($m->{vote} ? 1 : 0)).')';
+ tagscore $t->{rating};
+ i $t->{overruled} ? (class => 'grayedout') : (), " ($t->{cnt})";
+ b class => 'standout', style => 'font-weight: bold', ' !' if $t->{overruled};
end;
td class => 'tc_allspoil', sprintf '%.2f', $t->{spoiler};
td class => 'tc_allwho';
@@ -552,8 +603,8 @@ sub vntagmod {
end;
end;
}
- end;
- end;
+ end 'tbody';
+ end 'table';
} ],
]);
$self->htmlFooter;
@@ -623,7 +674,7 @@ sub tagindex {
end;
}
li;
- txt "\n";
+ br;
a href => '/g/list?t=0;o=d;s=added', mt '_tagidx_queue_link';
txt ' - ';
a href => '/g/list?t=1;o=d;s=added', mt '_tagidx_denied';
@@ -631,8 +682,8 @@ sub tagindex {
end;
end;
- end; # /tr
- end; # /table
+ end 'tr';
+ end 'table';
$self->htmlFooter;
}
@@ -671,10 +722,10 @@ sub tagxml {
my $self = shift;
my $f = $self->formValidate(
- { name => 'q', required => 0, maxlength => 500 },
- { name => 'id', required => 0, multi => 1, template => 'int' },
+ { get => 'q', required => 0, maxlength => 500 },
+ { get => 'id', required => 0, multi => 1, template => 'int' },
);
- return 404 if $f->{_err} || (!$f->{q} && !$f->{id} && !$f->{id}[0]);
+ return $self->resNotFound if $f->{_err} || (!$f->{q} && !$f->{id} && !$f->{id}[0]);
my($list, $np) = $self->dbTagGet(
!$f->{q} ? () : $f->{q} =~ /^g([1-9]\d*)/ ? (id => $1) : $f->{q} =~ /^name:(.+)$/ ? (name => $1) : (search => $f->{q}),