diff options
author | Yorhel <git@yorhel.nl> | 2011-05-01 11:13:42 +0200 |
---|---|---|
committer | Yorhel <git@yorhel.nl> | 2011-05-01 11:13:42 +0200 |
commit | 2e73fe7c7a174f3349786a69684f6a70101a57c0 (patch) | |
tree | 6701c7ca4429a7f59d5d2cd08bf98d8a143aced5 /lib | |
parent | ee977448037feeb53736f35809722dd16d3d3d91 (diff) | |
parent | 2bf4818105a11abeca313b36d820c3cc397dc5b3 (diff) |
Merge branch 'beta'2.20
Conflicts:
ChangeLog
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Multi/Core.pm | 2 | ||||
-rw-r--r-- | lib/Multi/Maintenance.pm | 18 | ||||
-rw-r--r-- | lib/VNDB/DB/Affiliates.pm | 69 | ||||
-rw-r--r-- | lib/VNDB/DB/Misc.pm | 3 | ||||
-rw-r--r-- | lib/VNDB/DB/Releases.pm | 2 | ||||
-rw-r--r-- | lib/VNDB/DB/Users.pm | 4 | ||||
-rw-r--r-- | lib/VNDB/Handler/Affiliates.pm | 146 | ||||
-rw-r--r-- | lib/VNDB/Handler/Chars.pm | 12 | ||||
-rw-r--r-- | lib/VNDB/Handler/Misc.pm | 7 | ||||
-rw-r--r-- | lib/VNDB/Handler/Producers.pm | 2 | ||||
-rw-r--r-- | lib/VNDB/Handler/Releases.pm | 2 | ||||
-rw-r--r-- | lib/VNDB/Handler/Traits.pm | 6 | ||||
-rw-r--r-- | lib/VNDB/Handler/ULists.pm | 3 | ||||
-rw-r--r-- | lib/VNDB/Handler/Users.pm | 20 | ||||
-rw-r--r-- | lib/VNDB/Handler/VNEdit.pm | 64 | ||||
-rw-r--r-- | lib/VNDB/Handler/VNPage.pm | 49 | ||||
-rw-r--r-- | lib/VNDB/Util/Auth.pm | 5 | ||||
-rw-r--r-- | lib/VNDB/Util/CommonHTML.pm | 17 | ||||
-rw-r--r-- | lib/VNDB/Util/FormHTML.pm | 6 | ||||
-rw-r--r-- | lib/VNDB/Util/LayoutHTML.pm | 13 | ||||
-rw-r--r-- | lib/VNDBUtil.pm | 8 |
21 files changed, 372 insertions, 86 deletions
diff --git a/lib/Multi/Core.pm b/lib/Multi/Core.pm index 9eaa6269..3c9d8bae 100644 --- a/lib/Multi/Core.pm +++ b/lib/Multi/Core.pm @@ -98,7 +98,7 @@ sub log_msg { # msg sub log { # level, msg (my $p = eval { $_[SENDER][2]{$_[CALLER_STATE]}[0] } || '') =~ s/^Multi:://; log_msg sprintf '%s::%s: %s', $p, $_[CALLER_STATE], - $_[ARG1] ? sprintf($_[ARG0], @_[ARG1..$#_]) : $_[ARG0]; + $#_>ARG0 ? sprintf($_[ARG0], @_[ARG1..$#_]) : $_[ARG0]; } diff --git a/lib/Multi/Maintenance.pm b/lib/Multi/Maintenance.pm index 5b092d0a..33154f9b 100644 --- a/lib/Multi/Maintenance.pm +++ b/lib/Multi/Maintenance.pm @@ -18,13 +18,13 @@ sub spawn { package_states => [ $p => [qw| _start shutdown set_daily daily set_monthly monthly log_stats - vncache_inc tagcache vnpopularity vnrating cleangraphs cleansessions cleannotifications + vncache_inc tagcache traitcache vnpopularity vnrating cleangraphs cleansessions cleannotifications vncache_full usercache statscache logrotate vnsearch_check vnsearch_gettitles vnsearch_update |], ], heap => { - daily => [qw|vncache_inc tagcache vnpopularity vnrating cleangraphs cleansessions cleannotifications|], + daily => [qw|vncache_inc tagcache traitcache vnpopularity vnrating cleangraphs cleansessions cleannotifications|], monthly => [qw|vncache_full usercache statscache logrotate|], vnsearch_checkdelay => 3600, @_, @@ -46,6 +46,7 @@ sub _start { sub shutdown { $_[KERNEL]->delay('daily'); $_[KERNEL]->delay('monthly'); + $_[KERNEL]->delay('vnsearch_check'); $_[KERNEL]->alias_remove('maintenance'); } @@ -121,13 +122,19 @@ sub vncache_inc { sub tagcache { - # takes about 2 seconds max, still OK + # takes about 5 seconds max, still OK $_[KERNEL]->post(pg => do => 'SELECT tag_vn_calc()', undef, 'log_stats', 'tagcache'); } +sub traitcache { + # still takes less than a second + $_[KERNEL]->post(pg => do => 'SELECT traits_chars_calc()', undef, 'log_stats', 'traitcache'); +} + + sub vnpopularity { - # still takes at most 3 seconds. let's hope that doesn't increase... + # takes a bit more than 8 seconds, meh... $_[KERNEL]->post(pg => do => 'SELECT update_vnpopularity()', undef, 'log_stats', 'vnpopularity'); } @@ -216,6 +223,9 @@ sub statscache { q|UPDATE stats_cache SET count = (SELECT COUNT(*) FROM vn WHERE hidden = FALSE) WHERE section = 'vn'|, q|UPDATE stats_cache SET count = (SELECT COUNT(*) FROM releases WHERE hidden = FALSE) WHERE section = 'releases'|, q|UPDATE stats_cache SET count = (SELECT COUNT(*) FROM producers WHERE hidden = FALSE) WHERE section = 'producers'|, + q|UPDATE stats_cache SET count = (SELECT COUNT(*) FROM chars WHERE hidden = FALSE) WHERE section = 'chars'|, + q|UPDATE stats_cache SET count = (SELECT COUNT(*) FROM tags WHERE state = 2) WHERE section = 'tags'|, + q|UPDATE stats_cache SET count = (SELECT COUNT(*) FROM traits WHERE state = 2) WHERE section = 'traits'|, q|UPDATE stats_cache SET count = (SELECT COUNT(*) FROM threads WHERE hidden = FALSE) WHERE section = 'threads'|, q|UPDATE stats_cache SET count = (SELECT COUNT(*) FROM threads_posts WHERE hidden = FALSE AND EXISTS(SELECT 1 FROM threads WHERE threads.id = tid AND threads.hidden = FALSE)) WHERE section = 'threads_posts'| diff --git a/lib/VNDB/DB/Affiliates.pm b/lib/VNDB/DB/Affiliates.pm new file mode 100644 index 00000000..51320b47 --- /dev/null +++ b/lib/VNDB/DB/Affiliates.pm @@ -0,0 +1,69 @@ + +package VNDB::DB::Affiliates; + +use strict; +use warnings; +use POSIX 'strftime'; +use Exporter 'import'; + +our @EXPORT = qw|dbAffiliateGet dbAffiliateEdit dbAffiliateDel dbAffiliateAdd|; + + +# options: id rids affiliate hidden sort reverse +# what: release +sub dbAffiliateGet { + my($self, %o) = @_; + $o{sort} ||= 'id'; + $o{reverse} //= 0; + + my %where = ( + $o{id} ? ('id = ?' => $o{id}) : (), + $o{rids} ? ('rid IN(!l)' => [$o{rids}]) : (), + defined($o{affiliate}) ? ('affiliate = ?' => $o{affiliate}) : (), + defined($o{hidden}) ? ('!s af.hidden' => $o{hidden} ? '' : 'NOT') : (), + ); + + my $join = $o{what} ? 'JOIN releases r ON r.id = af.rid JOIN releases_rev rr ON rr.id = r.latest' : ''; + my $select = $o{what} ? ', rr.title' : ''; + + my $order = sprintf { + id => 'af.id %s', + rel => 'rr.title %s', + prio => 'af.priority %s', + url => 'af.url %s', + lastfetch => 'af.lastfetch %s', + }->{$o{sort}}, $o{reverse} ? 'DESC' : 'ASC'; + + return $self->dbAll(qq| + SELECT af.id, af.rid, af.hidden, af.priority, af.affiliate, af.url, af.version, + extract('epoch' from af.lastfetch) as lastfetch, af.price$select + FROM affiliate_links af + $join + !W + ORDER BY !s|, \%where, $order); +} + + +sub dbAffiliateDel { + my($self, $id) = @_; + $self->dbExec('DELETE FROM affiliate_links WHERE id = ?', $id); +} + + +sub dbAffiliateEdit { + my($self, $id, %ops) = @_; + my %set; + exists($ops{$_}) && ($set{"$_ = ?"} = $ops{$_}) for(qw|rid priority hidden affiliate url version|); + return if !keys %set; + $self->dbExec('UPDATE affiliate_links !H WHERE id = ?', \%set, $id); +} + +sub dbAffiliateAdd { + my($self, %ops) = @_; + $self->dbExec('INSERT INTO affiliate_links (rid, priority, hidden, affiliate, url, version) VALUES(!l)', + [@ops{qw| rid priority hidden affiliate url version|}]); +} + + +1; + diff --git a/lib/VNDB/DB/Misc.pm b/lib/VNDB/DB/Misc.pm index 2f98abe2..3155ca56 100644 --- a/lib/VNDB/DB/Misc.pm +++ b/lib/VNDB/DB/Misc.pm @@ -64,6 +64,7 @@ sub dbRevisionGet { # what types should we join? my @types = ( !$o{type} ? ('v', 'r', 'p', 'c') : + ref($o{type}) ? @{$o{type}} : $o{type} ne 'v' ? $o{type} : $o{releases} ? ('v', 'r') : 'v' ); @@ -73,7 +74,7 @@ sub dbRevisionGet { q{((h.type = 'v' AND vr.vid = ?) OR (h.type = 'r' AND h.id = ANY(ARRAY(SELECT rv.rid FROM releases_vn rv WHERE rv.vid = ?))))} => [$o{iid}, $o{iid}], ) : ( $o{type} ? ( - 'h.type = ?' => $o{type} ) : (), + 'h.type IN(!l)' => [ ref($o{type})?$o{type}:[$o{type}] ] ) : (), $o{iid} ? ( '!sr.!sid = ?' => [ $o{type}, $o{type}, $o{iid} ] ) : (), ), diff --git a/lib/VNDB/DB/Releases.pm b/lib/VNDB/DB/Releases.pm index bd2d5bd3..6f9465f8 100644 --- a/lib/VNDB/DB/Releases.pm +++ b/lib/VNDB/DB/Releases.pm @@ -12,7 +12,7 @@ our @EXPORT = qw|dbReleaseGet dbReleaseRevisionInsert|; # Options: id vid pid rev released page results what med sort reverse date_before date_after # plat lang olang type minage search resolution freeware doujin voiced ani_story ani_ero -# What: extended changes vn producers platforms media +# What: extended changes vn producers platforms media affiliates # Sort: title released minage sub dbReleaseGet { my($self, %o) = @_; diff --git a/lib/VNDB/DB/Users.pm b/lib/VNDB/DB/Users.pm index 17f360cc..abea9bec 100644 --- a/lib/VNDB/DB/Users.pm +++ b/lib/VNDB/DB/Users.pm @@ -55,7 +55,7 @@ sub dbUserGet { qw|id username c_votes c_changes c_tags|, q|extract('epoch' from registered) as registered|, $o{what} =~ /extended/ ? ( - qw|mail rank salt ign_votes|, + qw|mail perm salt ign_votes|, q|encode(passwd, 'hex') AS passwd| ) : (), $o{what} =~ /hide_list/ ? 'up.value AS hide_list' : (), @@ -118,7 +118,7 @@ sub dbUserEdit { my %h; defined $o{$_} && ($h{$_.' = ?'} = $o{$_}) - for (qw| username mail rank salt ign_votes |); + for (qw| username mail perm salt ign_votes |); $h{'passwd = decode(?, \'hex\')'} = $o{passwd} if defined $o{passwd}; diff --git a/lib/VNDB/Handler/Affiliates.pm b/lib/VNDB/Handler/Affiliates.pm new file mode 100644 index 00000000..679d6ee2 --- /dev/null +++ b/lib/VNDB/Handler/Affiliates.pm @@ -0,0 +1,146 @@ + +package VNDB::Handler::Affiliates; + +use strict; +use warnings; +use TUWF ':html'; +use VNDB::Func; + + +TUWF::register( + qr{affiliates} => \&list, + qr{affiliates/del/([1-9]\d*)} => \&linkdel, + qr{affiliates/edit/([1-9]\d*)} => \&edit, + qr{affiliates/new} => \&edit, +); + + +sub list { + my $self = shift; + + return $self->htmlDenied if !$self->authCan('affiliate'); + my $f = $self->formValidate( + { get => 'a', required => 0, enum => [ 0..$#{$self->{affiliates}} ] }, + { get => 'h', required => 0, default => 0, enum => [ -1..1 ] }, + { get => 'o', required => 0, default => 'a', enum => ['a', 'd'] }, + { get => 's', required => 0, default => 'rel', enum => [qw|rel prio url lastfetch|] }, + ); + return $self->resNotFound if $f->{_err}; + + $self->htmlHeader(title => 'Affiliate administration interface'); + div class => 'mainbox'; + h1 'Affiliate administration interface'; + p class => 'browseopts'; + a defined($f->{a}) && $f->{a} == $_ ? (class => 'optselected') : (), href => "/affiliates?a=$_", $self->{affiliates}[$_]{name} + for (grep $self->{affiliates}[$_], 0..$#{$self->{affiliates}}); + end; + if(defined $f->{a}) { + p class => 'browseopts'; + a $f->{h} == -1 ? (class => 'optselected') : (), href => "/affiliates?a=$f->{a};h=-1",'all'; + a $f->{h} == 1 ? (class => 'optselected') : (), href => "/affiliates?a=$f->{a};h=1", 'hidden'; + a $f->{h} == 0 ? (class => 'optselected') : (), href => "/affiliates?a=$f->{a};h=0", 'non-hidden'; + end; + } + end; + + if(defined $f->{a}) { + my $list = $self->dbAffiliateGet( + affiliate => $f->{a}, hidden => $f->{h}==-1?undef:$f->{h}, + what => 'release', + sort => $f->{s}, reverse => $f->{o} eq 'd' + ); + $self->htmlBrowse( + items => $list, + nextpage => 0, + options => {p=>0, %$f}, + pageurl => '', + sorturl => "/affiliates?a=$f->{a};h=$f->{h}", + header => [ + ['Release', 'rel'], + ['Version'], + ['Hid'], + ['Prio', 'prio'], + ['Price / Lastfetch', 'lastfetch'], + ['', 'url' ] + ], + row => sub { + my($s, $n, $l) = @_; + Tr $n % 2 ? (class => 'odd') : (); + td class => 'tc1'; a href => "/r$l->{rid}", shorten $l->{title}, 50; end; + td class => 'tc2', $l->{version} || '<default>'; + td class => 'tc3', $l->{hidden} ? 'YES' : 'no'; + td class => 'tc4', $l->{priority}; + td class => 'tc5', sprintf '%s / %s', $l->{price}, $l->{lastfetch} ? $self->{l10n}->age($l->{lastfetch}) : '-'; + td class => 'tc6'; + a href => $l->{url}, 'link'; + txt ' | '; + a href => "/affiliates/edit/$l->{id}", 'edit'; + txt ' | '; + a href => "/affiliates/del/$l->{id}?formcode=".$self->authGetCode("/affiliates/del/$l->{id}"), 'del'; + end; + end; + }, + ); + } + $self->htmlFooter; +} + + +sub linkdel { + my($self, $id) = @_; + return $self->htmlDenied if !$self->authCan('affiliate'); + return if !$self->authCheckCode; + my $l = $self->dbAffiliateGet(id => $id)->[0]; + return $self->resNotFound if !$l; + $self->dbAffiliateDel($id); + $self->resRedirect("/affiliates?a=$l->{affiliate}"); +} + + +sub edit { + my($self, $id) = @_; + return $self->htmlDenied if !$self->authCan('affiliate'); + + my $r = $id && $self->dbAffiliateGet(id => $id)->[0]; + return $self->resNotFound if $id && !$r; + + my $frm; + if($self->reqMethod eq 'POST') { + return if !$self->authCheckCode; + $frm = $self->formValidate( + { post => 'rid', required => 1, template => 'int' }, + { post => 'priority', required => 0, default => 0, template => 'int' }, + { post => 'hidden', required => 0, default => 0, enum => [0,1] }, + { post => 'affiliate',required => 1, enum => [0..$#{$self->{affiliates}}] }, + { post => 'url', required => 1 }, + { post => 'version', required => 0, default => '' }, + ); + if(!$frm->{_err}) { + $self->dbAffiliateEdit($id, %$frm) if $id; + $self->dbAffiliateAdd(%$frm) if !$id; + return $self->resRedirect("/affiliates?a=$frm->{affiliate}", 'post'); + } + } + + if($id) { + $frm->{$_} = $r->{$_} for(qw|rid priority hidden affiliate url version|); + } else { + $frm->{rid} = $self->reqGet('rid'); + } + + $self->htmlHeader(title => 'Edit affiliate link'); + $self->htmlForm({ frm => $frm, action => $id ? "/affiliates/edit/$id" : '/affiliates/new' }, 'blah' => [ 'Edit affiliate link', + [ input => short => 'rid', name => 'Release ID', width => 100 ], + [ input => short => 'priority', name => 'Priority', width => 50 ], + [ check => short => 'hidden', name => 'Hidden' ], + [ select => short => 'affiliate', name => 'Affiliate', options => [ map + [ $_, $self->{affiliates}[$_]{name} ], grep $self->{affiliates}[$_], 0..$#{$self->{affiliates}} ] ], + [ input => short => 'url', name => 'URL', width => 400 ], + [ input => short => 'version', name => 'Version', width => 400 ], + ]); + $self->htmlFooter; +} + + +1; + diff --git a/lib/VNDB/Handler/Chars.pm b/lib/VNDB/Handler/Chars.pm index 7968b66c..8edb6236 100644 --- a/lib/VNDB/Handler/Chars.pm +++ b/lib/VNDB/Handler/Chars.pm @@ -233,7 +233,7 @@ sub charTable { td class => 'chardesc', colspan => 2; h2 mt '_charp_description'; p; - lit bb2html $r->{desc}; + lit bb2html $r->{desc}, 0, 1; end; end; end; @@ -257,7 +257,7 @@ sub edit { $rev = undef if !$r || $r->{cid} == $r->{latest}; return $self->htmlDenied if !$self->authCan('charedit') - || $id && ($r->{locked} && !$self->authCan('lock') || $r->{hidden} && !$self->authCan('del')); + || $id && (($r->{locked} || $r->{hidden}) && !$self->authCan('dbmod')); my %b4 = !$id ? () : ( (map +($_ => $r->{$_}), qw|name original alias desc image ihid ilock s_bust s_waist s_hip height weight bloodt gender main_spoil|), @@ -331,14 +331,14 @@ sub edit { $frm->{vns} = \@vns; my $nrev = $self->dbItemEdit(c => !$copy && $id ? $r->{cid} : undef, %$frm); - - # TEMPORARY SOLUTION! I'll investigate more efficient solutions and incremental updates whenever I have more data - $self->dbExec('SELECT traits_chars_calc()'); - return $self->resRedirect("/c$nrev->{iid}.$nrev->{rev}", 'post'); } } + if(!$id) { + my $vid = $self->formValidate({ get => 'vid', required => 1, template => 'int'}); + $frm->{vns} //= "$vid->{vid}-0-0-primary" if !$vid->{_err}; + } $frm->{$_} //= $b4{$_} for keys %b4; $frm->{editsum} //= sprintf 'Reverted to revision c%d.%d', $id, $rev if !$copy && $rev; $frm->{editsum} = sprintf 'New character based on c%d.%d', $id, $r->{rev} if $copy; diff --git a/lib/VNDB/Handler/Misc.pm b/lib/VNDB/Handler/Misc.pm index 8f5b4949..643af1cf 100644 --- a/lib/VNDB/Handler/Misc.pm +++ b/lib/VNDB/Handler/Misc.pm @@ -196,7 +196,7 @@ sub history { { get => 'p', required => 0, default => 1, template => 'int' }, { get => 'm', required => 0, default => !$type, enum => [ 0, 1 ] }, { get => 'h', required => 0, default => 0, enum => [ -1..1 ] }, - { get => 't', required => 0, default => '', enum => [qw|v r p c|] }, + { get => 't', required => 0, default => '', enum => [qw|v r p c a|] }, { get => 'e', required => 0, default => 0, enum => [ -1..1 ] }, { get => 'r', required => 0, default => 0, enum => [ 0, 1 ] }, ); @@ -216,7 +216,7 @@ sub history { what => 'item user', $type && $type ne 'u' ? ( type => $type, iid => $id ) : (), $type eq 'u' ? ( uid => $id ) : (), - $f->{t} ? ( type => $f->{t} ) : (), + $f->{t} ? ( type => $f->{t} eq 'a' ? [qw|v r p|] : $f->{t} ) : (), page => $f->{p}, results => 50, auto => $f->{m}, @@ -250,7 +250,7 @@ sub history { end; } if(!$type || $type eq 'u') { - if($self->authCan('del')) { + if($self->authCan('dbmod')) { p class => 'browseopts'; a $f->{h} == 1 ? (class => 'optselected') : (), href => $u->(h => 1), mt '_hist_filter_hidedel'; a $f->{h} == -1 ? (class => 'optselected') : (), href => $u->(h => -1), mt '_hist_filter_showdel'; @@ -262,6 +262,7 @@ sub history { a $f->{t} eq 'r' ? (class => 'optselected') : (), href => $u->(t => 'r'), mt '_hist_filter_onlyreleases'; a $f->{t} eq 'p' ? (class => 'optselected') : (), href => $u->(t => 'p'), mt '_hist_filter_onlyproducers'; a $f->{t} eq 'c' ? (class => 'optselected') : (), href => $u->(t => 'c'), mt '_hist_filter_onlychars'; + a $f->{t} eq 'a' ? (class => 'optselected') : (), href => $u->(t => 'a'), mt '_hist_filter_nochars'; end; p class => 'browseopts'; a !$f->{e} ? (class => 'optselected') : (), href => $u->(e => 0), mt '_hist_filter_allactions'; diff --git a/lib/VNDB/Handler/Producers.pm b/lib/VNDB/Handler/Producers.pm index 5030c1a3..52db6edf 100644 --- a/lib/VNDB/Handler/Producers.pm +++ b/lib/VNDB/Handler/Producers.pm @@ -205,7 +205,7 @@ sub edit { $rev = undef if !$p || $p->{cid} == $p->{latest}; return $self->htmlDenied if !$self->authCan('edit') - || $pid && ($p->{locked} && !$self->authCan('lock') || $p->{hidden} && !$self->authCan('del')); + || $pid && (($p->{locked} || $p->{hidden}) && !$self->authCan('dbmod')); my %b4 = !$pid ? () : ( (map { $_ => $p->{$_} } qw|type name original lang website desc alias ihid ilock|), diff --git a/lib/VNDB/Handler/Releases.pm b/lib/VNDB/Handler/Releases.pm index 159b7c3f..dd2b278e 100644 --- a/lib/VNDB/Handler/Releases.pm +++ b/lib/VNDB/Handler/Releases.pm @@ -280,7 +280,7 @@ sub edit { return $self->resNotFound if $vid && !$v->{id}; return $self->htmlDenied if !$self->authCan('edit') - || $rid && ($r->{locked} && !$self->authCan('lock') || $r->{hidden} && !$self->authCan('del')); + || $rid && (($r->{locked} || $r->{hidden}) && !$self->authCan('dbmod')); my $vn = $rid ? $r->{vn} : [{ vid => $vid, title => $v->{title} }]; my %b4 = !$rid ? () : ( diff --git a/lib/VNDB/Handler/Traits.pm b/lib/VNDB/Handler/Traits.pm index 1f3c2872..ea599ed1 100644 --- a/lib/VNDB/Handler/Traits.pm +++ b/lib/VNDB/Handler/Traits.pm @@ -104,8 +104,7 @@ sub traitpage { if(!@$chars) { p; br; br; txt mt '_traitp_nochars'; end; } - # not really cached at the moment - # p; br; txt mt '_traitp_cached'; end; + p; br; txt mt '_traitp_cached'; end; end 'div'; @$chars && $self->charBrowseTable($chars, $np, $f, "/i$trait?m=$f->{m}"); @@ -171,9 +170,6 @@ sub traitedit { } else { $self->dbTraitEdit($trait, %opts, upddate => $frm->{state} == 2 && $t->{state} != 2) if $trait; _set_childs_group($self, $trait, $group||$trait) if ($group||0) != ($t->{group}||0); - - # TEMPORARY SOLUTION! I'll investigate more efficient solutions and incremental updates whenever I have more data - $self->dbExec('SELECT traits_chars_calc()'); } $self->resRedirect("/i$trait", 'post'); return; diff --git a/lib/VNDB/Handler/ULists.pm b/lib/VNDB/Handler/ULists.pm index 363c2262..1c82d982 100644 --- a/lib/VNDB/Handler/ULists.pm +++ b/lib/VNDB/Handler/ULists.pm @@ -239,6 +239,7 @@ sub wishlist { { post => 'sel', required => 0, default => 0, multi => 1, template => 'int' }, { post => 'batchedit', required => 1, enum => [ -1, @{$self->{wishlist_status}} ] }, ); + $frm->{sel} = [ grep $_, @{$frm->{sel}} ]; # weed out "select all" checkbox if(!$frm->{_err} && @{$frm->{sel}} && $frm->{sel}[0]) { $self->dbWishListDel($uid, $frm->{sel}) if $frm->{batchedit} == -1; $self->dbWishListAdd($frm->{sel}, $uid, $frm->{batchedit}) if $frm->{batchedit} >= 0; @@ -303,6 +304,8 @@ sub wishlist { $own ? (footer => sub { Tr; td colspan => 3; + input type => 'checkbox', class => 'checkall', name => 'sel', value => 0; + txt ' '; Select name => 'batchedit', id => 'batchedit'; option mt '_wishlist_select'; optgroup label => mt '_wishlist_changeprio'; diff --git a/lib/VNDB/Handler/Users.pm b/lib/VNDB/Handler/Users.pm index 75ddb547..dc748f75 100644 --- a/lib/VNDB/Handler/Users.pm +++ b/lib/VNDB/Handler/Users.pm @@ -301,7 +301,7 @@ sub edit { $frm = $self->formValidate( $self->authCan('usermod') ? ( { post => 'usrname', template => 'pname', minlength => 2, maxlength => 15 }, - { post => 'rank', enum => [ 1..$#{$self->{user_ranks}} ] }, + { post => 'perms', required => 0, multi => 1, enum => [ keys %{$self->{permissions}} ] }, { post => 'ign_votes', required => 0, default => 0 }, ) : (), { post => 'mail', template => 'mail' }, @@ -318,7 +318,10 @@ sub edit { $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}; + if($self->authCan('usermod')) { + $o{perm} = 0; + $o{perm} += $self->{permissions}{$_} for(@{ delete $frm->{perms} }); + } $o{mail} = $frm->{mail}; ($o{passwd}, $o{salt}) = $self->authPreparePass($frm->{usrpass}) if $frm->{usrpass}; $o{ign_votes} = $frm->{ign_votes} ? 1 : 0 if $self->authCan('usermod'); @@ -330,8 +333,9 @@ sub edit { } # fill out default values - $frm->{usrname} ||= $u->{username}; - $frm->{$_} ||= $u->{$_} for(qw|rank mail|); + $frm->{usrname} ||= $u->{username}; + $frm->{mail} ||= $u->{mail}; + $frm->{perms} ||= [ grep $u->{perm} & $self->{permissions}{$_}, keys %{$self->{permissions}} ]; $frm->{$_} //= $u->{prefs}{$_} for(qw|skin customcss show_nsfw hide_list|); $frm->{ign_votes} = $u->{ign_votes} if !defined $frm->{ign_votes}; @@ -350,8 +354,8 @@ sub edit { [ part => title => mt '_usere_geninfo' ], $self->authCan('usermod') ? ( [ input => short => 'usrname', name => mt('_usere_username') ], - [ select => short => 'rank', name => mt('_usere_rank'), options => [ - map [ $_, mt '_urank_'.$_ ], 1..$#{$self->{user_ranks}} ] ], + [ select => short => 'perms', name => mt('_usere_perm'), multi => 1, size => (scalar keys %{$self->{permissions}}), options => [ + map [ $_, $_ ], sort keys %{$self->{permissions}} ] ], [ check => short => 'ign_votes', name => mt '_usere_ignvotes' ], ) : ( [ static => label => mt('_usere_username'), content => $frm->{usrname} ], @@ -611,7 +615,7 @@ sub notifies { class => 'notifies', pageurl => "/u$uid/notifies?r=$f->{r}", header => [ - [ '<input type="checkbox" class="checkall" name="notifysel" value="0" />' ], + [ '' ], [ mt '_usern_col_type' ], [ mt '_usern_col_age' ], [ mt '_usern_col_id' ], @@ -639,6 +643,8 @@ sub notifies { footer => sub { Tr; td colspan => 5; + input type => 'checkbox', class => 'checkall', name => 'notifysel', value => 0; + txt ' '; input type => 'submit', name => 'markread', value => mt '_usern_but_markread'; input type => 'submit', name => 'remove', value => mt '_usern_but_remove'; b class => 'grayedout', ' '.mt '_usern_autodel'; diff --git a/lib/VNDB/Handler/VNEdit.pm b/lib/VNDB/Handler/VNEdit.pm index ce564fc0..d0848c09 100644 --- a/lib/VNDB/Handler/VNEdit.pm +++ b/lib/VNDB/Handler/VNEdit.pm @@ -23,12 +23,12 @@ sub edit { $rev = undef if !$vid || $v->{cid} == $v->{latest}; return $self->htmlDenied if !$self->authCan('edit') - || $vid && ($v->{locked} && !$self->authCan('lock') || $v->{hidden} && !$self->authCan('del')); + || $vid && (($v->{locked} || $v->{hidden}) && !$self->authCan('dbmod')); my $r = $v ? $self->dbReleaseGet(vid => $v->{id}) : []; my %b4 = !$vid ? () : ( - (map { $_ => $v->{$_} } qw|title original desc alias length l_wp l_encubed l_renai l_vnn img_nsfw ihid ilock|), + (map { $_ => $v->{$_} } qw|title original desc alias length l_wp l_encubed l_renai l_vnn image img_nsfw ihid ilock|), anime => join(' ', sort { $a <=> $b } map $_->{id}, @{$v->{anime}}), vnrelations => join('|||', map $_->{relation}.','.$_->{id}.','.($_->{official}?1:0).','.$_->{title}, sort { $a->{id} <=> $b->{id} } @{$v->{relations}}), screenshots => join(' ', map sprintf('%d,%d,%d', $_->{id}, $_->{nsfw}?1:0, $_->{rid}), @{$v->{screenshots}}), @@ -48,7 +48,7 @@ sub edit { { post => 'l_renai', required => 0, default => '', maxlength => 100 }, { post => 'l_vnn', required => 0, default => $b4{l_vnn}||0, template => 'int' }, { post => 'anime', required => 0, default => '' }, - { post => 'previmage', required => 0, default => 0, template => 'int' }, + { post => 'image', required => 0, default => 0, template => 'int' }, { post => 'img_nsfw', required => 0, default => 0 }, { post => 'vnrelations', required => 0, default => '', maxlength => 5000 }, { post => 'screenshots', required => 0, default => '', maxlength => 1000 }, @@ -60,7 +60,7 @@ sub edit { push @{$frm->{_err}}, 'badeditsum' if !$frm->{editsum} || lc($frm->{editsum}) eq lc($frm->{desc}); # handle image upload - my $image = _uploadimage($self, $v, $frm); + $frm->{image} = _uploadimage($self, $v, $frm); if(!$frm->{_err}) { # parse and re-sort fields that have multiple representations of the same information @@ -86,15 +86,13 @@ sub edit { # nothing changed? just redirect return $self->resRedirect("/v$vid", 'post') - if $vid && !$self->reqPost('img') && $image == $v->{image} - && !grep $frm->{$_} ne $b4{$_}, keys %b4; + if $vid && !grep $frm->{$_} ne $b4{$_}, keys %b4; # perform the edit/add my $nrev = $self->dbItemEdit(v => $vid ? $v->{cid} : undef, - (map { $_ => $frm->{$_} } qw|title original alias desc length l_wp l_encubed l_renai l_vnn editsum img_nsfw ihid ilock|), + (map { $_ => $frm->{$_} } qw|title original image alias desc length l_wp l_encubed l_renai l_vnn editsum img_nsfw ihid ilock|), anime => [ keys %$anime ], relations => $relations, - image => $image, screenshots => $screenshots, ); @@ -123,7 +121,7 @@ sub edit { sub _uploadimage { my($self, $v, $frm) = @_; - return $v ? $frm->{previmage} : 0 if $frm->{_err} || !$self->reqPost('img'); + return $v ? $frm->{image} : 0 if $frm->{_err} || !$self->reqPost('img'); # perform some elementary checks my $imgdata = $self->reqUploadRaw('img'); @@ -163,29 +161,31 @@ sub _form { [ static => content => mt '_vnedit_anime_msg' ], ], - vn_img => [ mt('_vnedit_image'), - [ hidden => short => 'previmage', value => $v ? $v->{image} : 0 ], - [ static => nolabel => 1, content => sub { - div class => 'img'; - p mt '_vnedit_image_none' if !$v || !$v->{image}; - p mt '_vnedit_image_processing' if $v && $v->{image} < 0; - img src => sprintf("%s/cv/%02d/%d.jpg", $self->{url_static}, $v->{image}%100, $v->{image}), alt => $v->{title} if $v && $v->{image} > 0; - end; - div; - - h2 mt '_vnedit_image_upload'; - input type => 'file', class => 'text', name => 'img', id => 'img'; - p mt('_vnedit_image_upload_msg'); - br; br; br; - - h2 mt '_vnedit_image_nsfw'; - input type => 'checkbox', class => 'checkbox', id => 'img_nsfw', name => 'img_nsfw', - $frm->{img_nsfw} ? (checked => 'checked') : (); - label class => 'checkbox', for => 'img_nsfw', mt '_vnedit_image_nsfw_check'; - p mt '_vnedit_image_nsfw_msg'; - end 'div'; - }], - ], + vn_img => [ mt('_vnedit_image'), [ static => nolabel => 1, content => sub { + div class => 'img'; + p mt '_vnedit_image_none' if !$v || !$v->{image}; + p mt '_vnedit_image_processing' if $v && $v->{image} < 0; + img src => sprintf("%s/cv/%02d/%d.jpg", $self->{url_static}, $v->{image}%100, $v->{image}), alt => $v->{title} if $v && $v->{image} > 0; + end; + + div; + h2 mt '_vnedit_image_id'; + input type => 'text', class => 'text', name => 'image', id => 'image', value => $frm->{image}||''; + p mt '_vnedit_image_id_msg'; + br; br; + + h2 mt '_vnedit_image_upload'; + input type => 'file', class => 'text', name => 'img', id => 'img'; + p mt('_vnedit_image_upload_msg'); + br; br; br; + + h2 mt '_vnedit_image_nsfw'; + input type => 'checkbox', class => 'checkbox', id => 'img_nsfw', name => 'img_nsfw', + $frm->{img_nsfw} ? (checked => 'checked') : (); + label class => 'checkbox', for => 'img_nsfw', mt '_vnedit_image_nsfw_check'; + p mt '_vnedit_image_nsfw_msg'; + end 'div'; + }]], vn_rel => [ mt('_vnedit_rel'), [ hidden => short => 'vnrelations' ], diff --git a/lib/VNDB/Handler/VNPage.pm b/lib/VNDB/Handler/VNPage.pm index 37efb04a..e10b4414 100644 --- a/lib/VNDB/Handler/VNPage.pm +++ b/lib/VNDB/Handler/VNPage.pm @@ -141,6 +141,7 @@ sub page { _relations($self, \$i, $v) if @{$v->{relations}}; _anime($self, \$i, $v) if @{$v->{anime}}; _useroptions($self, \$i, $v) if $self->authInfo->{id}; + _affiliate_links($self, $r); Tr; td class => 'vndesc', colspan => 2; @@ -404,11 +405,56 @@ sub _useroptions { } +sub _affiliate_links { + my($self, $r) = @_; + return if !keys @$r; + my %r = map +($_->{id}, $_), @$r; + my $links = $self->dbAffiliateGet(rids => [ keys %r ], hidden => 0); + return if !@$links; + + $links = [ sort { $b->{priority}||$self->{affiliates}[$b->{affiliate}]{default_prio} <=> $a->{priority}||$self->{affiliates}[$a->{affiliate}]{default_prio} } @$links ]; + my $en = VNDB::L10N->get_handle('en'); + + Tr; td colspan => 2, id => 'buynow'; # don't call it "affiliate", most adblock filters have that included >_> + h1; a rel => 'nofollow', href => $self->{affiliates}[$links->[0]{affiliate}]{link_format} ? $self->{affiliates}[$links->[0]{affiliate}]{link_format}->($links->[0]{url}) : $links->[0]{url}, 'Buy now!'; end; + ul; + for my $link (@$links) { + my $f = $self->{affiliates}[$link->{affiliate}]; + + my $rel = $r{$link->{rid}}; + my $plat = grep($_ eq 'win', @{$rel->{platforms}}) ? '' : ' '.join(' and ', map $en->maketext("_plat_$_"), @{$rel->{platforms}}); + my $version = join(', ', map $en->maketext("_lang_$_"), @{$rel->{languages}}).$plat.' version'; + + li; a rel => 'nofollow', href => $f->{link_format} ? $f->{link_format}->($link->{url}) : $link->{url}; + use utf8; + txt '→ '; + txt $link->{version} + || ($f->{default_version} && $f->{default_version}->($self, $link, $rel)) + || $version; + txt ' '; + acronym class => 'pricenote', title => sprintf('Last updated: %s.', $en->age($link->{lastfetch})), "for $link->{price}*" + if $link->{price}; + txt " at $f->{name}."; + end; end; + } + end; + end; end; +} + + sub _releases { my($self, $v, $r) = @_; div class => 'mainbox releases'; - a class => 'addnew', href => "/v$v->{id}/add", mt '_vnpage_rel_add'; + if($self->authCan('edit')) { + p class => 'addnew'; + if($self->authCan('charedit')) { + a href => "/c/new?vid=$v->{id}", mt '_vnpage_char_add'; + txt ' | '; + } + a href => "/v$v->{id}/add", mt '_vnpage_rel_add'; + end; + } h1 mt '_vnpage_rel'; if(!@$r) { p mt '_vnpage_rel_none'; @@ -459,6 +505,7 @@ sub _releases { } end; td class => 'tc6'; + a href => "/affiliates/new?rid=$rel->{id}", 'a' if $self->authCan('affiliate'); if($rel->{website}) { a href => $rel->{website}, rel => 'nofollow'; cssicon 'ext', mt '_vnpage_rel_extlink'; diff --git a/lib/VNDB/Util/Auth.pm b/lib/VNDB/Util/Auth.pm index 88e68edc..89807bef 100644 --- a/lib/VNDB/Util/Auth.pm +++ b/lib/VNDB/Util/Auth.pm @@ -88,8 +88,7 @@ sub authInfo { # a certain action. Argument is the action name as defined in global.pl sub authCan { my($self, $act) = @_; - my $r = $self->{_auth} ? $self->{_auth}{rank} : 0; - return scalar grep $_ eq $act, @{$self->{user_ranks}[$r]}[0..$#{$self->{user_ranks}[$r]}]; + return $self->{_auth} ? $self->{_auth}{perm} & $self->{permissions}{$act} : 0; } @@ -102,7 +101,7 @@ sub _authCheck { return 0 if !$user || length($user) > 15 || length($user) < 2 || !$pass; my $d = $self->dbUserGet(username => $user, what => 'extended notifycount')->[0]; - return 0 if !defined $d->{id} || !$d->{rank}; + return 0 if !$d->{id}; if(_authEncryptPass($self, $pass, $d->{salt}) eq $d->{passwd}) { $self->{_auth} = $d; diff --git a/lib/VNDB/Util/CommonHTML.pm b/lib/VNDB/Util/CommonHTML.pm index 41370b4b..5f2fb330 100644 --- a/lib/VNDB/Util/CommonHTML.pm +++ b/lib/VNDB/Util/CommonHTML.pm @@ -72,8 +72,8 @@ sub htmlMainTabs { } if( $type eq 'u' && ($self->authInfo->{id} && $obj->{id} == $self->authInfo->{id} || $self->authCan('usermod')) - || $type =~ /[vrp]/ && $self->authCan('edit') && (!$obj->{locked} || $self->authCan('lock')) && (!$obj->{hidden} || $self->authCan('del')) - || $type eq 'c' && $self->authCan('charedit') && (!$obj->{locked} || $self->authCan('lock')) && (!$obj->{hidden} || $self->authCan('del')) + || $type =~ /[vrp]/ && $self->authCan('edit') && ((!$obj->{locked} && !$obj->{hidden}) || $self->authCan('dbmod')) + || $type eq 'c' && $self->authCan('charedit') && ((!$obj->{locked} && !$obj->{hidden}) || $self->authCan('dbmod')) || $type =~ /[gi]/ && $self->authCan('tagmod') ) { li $sel eq 'edit' ? (class => 'tabselected') : (); @@ -143,7 +143,7 @@ sub htmlHiddenMessage { end; end; end 'div'; - return $self->htmlFooter() || 1 if !$self->authCan('del'); + return $self->htmlFooter() || 1 if !$self->authCan('dbmod'); return 0; } @@ -163,6 +163,15 @@ sub htmlRevision { div class => 'mainbox revision'; h1 mt '_revision_title', $new->{rev}; + # character information may be rather spoilerous + if($type eq 'c') { + div class => 'warning'; + h2 mt '_revision_spoil_title'; + lit mt '_revision_spoil_msg', "/c$new->{id}"; + end; + br;br; + } + # previous/next revision links a class => 'prev', href => sprintf('/%s%d.%d', $type, $new->{id}, $new->{rev}-1), '<- '.mt '_revision_previous' if $new->{rev} > 1; @@ -174,7 +183,7 @@ sub htmlRevision { # no previous revision, just show info about the revision itself if(!$old) { - div; + div class => 'rev'; revheader($self, $type, $new); br; b mt '_revision_new_summary'; diff --git a/lib/VNDB/Util/FormHTML.pm b/lib/VNDB/Util/FormHTML.pm index 68b6a101..805467f6 100644 --- a/lib/VNDB/Util/FormHTML.pm +++ b/lib/VNDB/Util/FormHTML.pm @@ -214,15 +214,11 @@ sub htmlForm { fieldset class => 'submit'; if($options->{editsum}) { # hidden / locked checkbox - if($self->authCan('del')) { + if($self->authCan('dbmod')) { input type => 'checkbox', name => 'ihid', id => 'ihid', value => 1, $options->{frm}{ihid} ? (checked => 'checked') : (); label for => 'ihid', mt '_form_ihid'; - } - if($self->authCan('lock')) { input type => 'checkbox', name => 'ilock', id => 'ilock', value => 1, $options->{frm}{ilock} ? (checked => 'checked') : (); label for => 'ilock', mt '_form_ilock'; - } - if($self->authCan('lock') || $self->authCan('del')) { br; txt mt('_form_hidlock_note'); br; } diff --git a/lib/VNDB/Util/LayoutHTML.pm b/lib/VNDB/Util/LayoutHTML.pm index 22052a75..752f6728 100644 --- a/lib/VNDB/Util/LayoutHTML.pm +++ b/lib/VNDB/Util/LayoutHTML.pm @@ -89,7 +89,6 @@ sub _menu { my $nc = $self->authInfo->{notifycount}; h2; a href => $uid, ucfirst $self->authInfo->{username}; - txt ' ('.mt('_urank_'.$self->authInfo->{rank}).')'; end; div; a href => "$uid/edit", mt '_menu_myprofile'; br; @@ -100,9 +99,13 @@ sub _menu { a href => "$uid/hist", mt '_menu_mychanges'; br; a href => '/g/links?u='.$self->authInfo->{id}, mt '_menu_mytags'; br; br; - a href => '/v/new', mt '_menu_addvn'; br; - a href => '/p/new', mt '_menu_addproducer'; br; - a href => '/c/new', mt '_menu_addcharacter'; br; + if($self->authCan('edit')) { + a href => '/v/new', mt '_menu_addvn'; br; + a href => '/p/new', mt '_menu_addproducer'; br; + } + if($self->authCan('charedit')) { + a href => '/c/new', mt '_menu_addcharacter'; br; + } br; a href => "$uid/logout", mt '_menu_logout'; end; @@ -130,7 +133,7 @@ sub _menu { h2 mt '_menu_dbstats'; div; dl; - for (qw|vn releases producers users threads posts|) { + for (qw|vn releases producers chars tags traits users threads posts|) { dt mt "_menu_stat_$_"; dd $self->{stats}{$_}; } diff --git a/lib/VNDBUtil.pm b/lib/VNDBUtil.pm index a0469a1c..76290013 100644 --- a/lib/VNDBUtil.pm +++ b/lib/VNDBUtil.pm @@ -27,8 +27,7 @@ sub shorten { # v+, v+.+ # http://../ sub bb2html { - my $raw = shift; - my $maxlength = shift; + my($raw, $maxlength, $charspoil) = @_; $raw =~ s/\r//g; return '' if !$raw && $raw ne "0"; @@ -76,7 +75,8 @@ sub bb2html { next; } elsif($tag eq '[spoiler]') { push @open, 'spoiler'; - $result .= '<b class="spoiler">'; + $result .= !$charspoil ? '<b class="spoiler">' + : '<b class="grayedout charspoil charspoil_-1"><hidden by spoiler settings></b><span class="charspoil charspoil_2 hidden">'; next; } elsif($tag eq '[quote]') { push @open, 'quote'; @@ -89,7 +89,7 @@ sub bb2html { $rmnewline = 1; next; } elsif($tag eq '[/spoiler]' && $open[$#open] eq 'spoiler') { - $result .= '</b>'; + $result .= !$charspoil ? '</b>' : '</span>'; pop @open; next; } elsif($tag eq '[/quote]' && $open[$#open] eq 'quote') { |