diff options
author | Yorhel <git@yorhel.nl> | 2019-11-14 13:26:03 +0100 |
---|---|---|
committer | Yorhel <git@yorhel.nl> | 2019-11-14 13:31:15 +0100 |
commit | 389fe32c24adce3277548892b5d636c40ac35bc4 (patch) | |
tree | b739ac49edbe9670b64d310676a32310a6f69440 | |
parent | 06bacb61526f3945520dd344821d2aa7b85a5f43 (diff) |
v2rw: Convert staff pages
This is where the ExtLink module comes in handy: generating the revision
comparison thing is much easier now. Did find and fix a bunch of issues
with the new revision box generator code, but that was to be expected, I
hadn't tested that code well yet and this is its first more demanding
use.
Rest of this is a pretty direct rewrite, nothing too special.
-rw-r--r-- | lib/VNDB/DB/Staff.pm | 81 | ||||
-rw-r--r-- | lib/VNDB/ExtLinks.pm | 12 | ||||
-rw-r--r-- | lib/VNDB/Handler/Staff.pm | 165 | ||||
-rw-r--r-- | lib/VNDB/Util/CommonHTML.pm | 1 | ||||
-rw-r--r-- | lib/VNWeb/HTML.pm | 67 | ||||
-rw-r--r-- | lib/VNWeb/Prelude.pm | 2 | ||||
-rw-r--r-- | lib/VNWeb/Staff/Page.pm | 181 |
7 files changed, 256 insertions, 253 deletions
diff --git a/lib/VNDB/DB/Staff.pm b/lib/VNDB/DB/Staff.pm index 87dbef43..5a393dbb 100644 --- a/lib/VNDB/DB/Staff.pm +++ b/lib/VNDB/DB/Staff.pm @@ -5,10 +5,9 @@ use strict; use warnings; use Exporter 'import'; -our @EXPORT = qw|dbStaffGet dbStaffGetRev|; +our @EXPORT = qw|dbStaffGet |; # options: results, page, id, aid, search, exact, truename, role, gender -# what: extended changes roles aliases sub dbStaffGet { my $self = shift; my %o = ( @@ -57,7 +56,6 @@ sub dbStaffGet { ); my $select = 's.id, sa.aid, sa.name, sa.original, s.gender, s.lang'; - $select .= ', s.desc, s.l_wp, s.l_site, s.l_twitter, s.l_anidb, s.l_wikidata, s.l_pixiv, s.hidden, s.locked' if $o{what} =~ /extended/; my($order, @order) = ('sa.name'); if($o{sort} && $o{sort} eq 'search') { @@ -74,83 +72,8 @@ sub dbStaffGet { $select, \%where, @order ); - return _enrich($self, $r, $np, 0, $o{what}); -} - - -sub dbStaffGetRev { - my $self = shift; - my %o = (what => '', @_); - - $o{rev} ||= $self->dbRow('SELECT MAX(rev) AS rev FROM changes WHERE type = \'s\' AND itemid = ?', $o{id})->{rev}; - - my $select = 'c.itemid AS id, sa.aid, sa.name, sa.original, s.gender, s.lang'; - $select .= ', extract(\'epoch\' from c.added) as added, c.comments, c.rev, c.ihid, c.ilock, '.VNWeb::DB::sql_user(); - $select .= ', c.id AS cid, NOT EXISTS(SELECT 1 FROM changes c2 WHERE c2.type = c.type AND c2.itemid = c.itemid AND c2.rev = c.rev+1) AS lastrev'; - $select .= ', s.desc, s.l_wp, s.l_site, s.l_twitter, s.l_anidb, s.l_wikidata, s.l_pixiv, so.hidden, so.locked' if $o{what} =~ /extended/; - - my $r = $self->dbAll(q| - SELECT !s - FROM changes c - JOIN staff so ON so.id = c.itemid - JOIN staff_hist s ON s.chid = c.id - JOIN staff_alias_hist sa ON sa.chid = c.id AND s.aid = sa.aid - JOIN users u ON u.id = c.requester - WHERE c.type = 's' AND c.itemid = ? AND c.rev = ?|, - $select, $o{id}, $o{rev} - ); - - return _enrich($self, $r, 0, 1, $o{what}); -} - - -sub _enrich { - my($self, $r, $np, $rev, $what) = @_; - - # Role info is linked to VN revisions, so is independent of the selected staff revision - if(@$r && $what =~ /roles/) { - my %r = map { - $_->{roles} = []; - $_->{cast} = []; - ($_->{id}, $_); - } @$r; - - push @{$r{ delete $_->{id} }{roles}}, $_ for (@{$self->dbAll(q| - SELECT sa.id, sa.aid, v.id AS vid, sa.name, sa.original, v.c_released, v.title, v.original AS t_original, vs.role, vs.note - FROM vn_staff vs - JOIN vn v ON v.id = vs.id - JOIN staff_alias sa ON vs.aid = sa.aid - WHERE sa.id IN(!l) AND NOT v.hidden - ORDER BY v.c_released ASC, v.title ASC, vs.role ASC|, [ keys %r ] - )}); - push @{$r{ delete $_->{id} }{cast}}, $_ for (@{$self->dbAll(q| - SELECT sa.id, sa.aid, v.id AS vid, sa.name, sa.original, v.c_released, v.title, v.original AS t_original, c.id AS cid, c.name AS c_name, c.original AS c_original, vs.note - FROM vn_seiyuu vs - JOIN vn v ON v.id = vs.id - JOIN chars c ON c.id = vs.cid - JOIN staff_alias sa ON vs.aid = sa.aid - WHERE sa.id IN(!l) AND NOT v.hidden - ORDER BY v.c_released ASC, v.title ASC|, [ keys %r ] - )}); - } - - if(@$r && $what =~ /aliases/) { - my ($col, $hist, $colname) = $rev ? ('cid', '_hist', 'chid') : ('id', '', 'id'); - my %r = map { - $_->{aliases} = []; - ($_->{$col}, $_); - } @$r; - - push @{$r{ delete $_->{xid} }{aliases}}, $_ for (@{$self->dbAll(" - SELECT s.$colname AS xid, sa.aid, sa.name, sa.original - FROM staff_alias$hist sa - JOIN staff$hist s ON s.$colname = sa.$colname - WHERE s.$colname IN(!l) AND s.aid <> sa.aid - ORDER BY sa.name ASC", [ keys %r ] - )}); - } - return wantarray ? ($r, $np) : $r; } + 1; diff --git a/lib/VNDB/ExtLinks.pm b/lib/VNDB/ExtLinks.pm index 8e9bdf72..2280285a 100644 --- a/lib/VNDB/ExtLinks.pm +++ b/lib/VNDB/ExtLinks.pm @@ -5,7 +5,7 @@ use warnings; use VNDB::Config; use Exporter 'import'; -our @EXPORT = ('enrich_extlinks'); +our @EXPORT = ('enrich_extlinks', 'revision_extlinks'); # column name in wikidata table => \%info @@ -225,4 +225,14 @@ sub enrich_extlinks { } +# Returns a list of @fields for use in VNWeb::HTML::revision_() +sub revision_extlinks { + my($type) = @_; + map { + my($f, $p) = ($_, $LINKS{$type}{$_}); + [ $f, $p->{label}, fmt => sub { TUWF::XML::a_ href => sprintf($p->{fmt}, $_), $_; }, empty => 0 ] + } sort keys $LINKS{$type}->%* +} + + 1; diff --git a/lib/VNDB/Handler/Staff.pm b/lib/VNDB/Handler/Staff.pm index 7da42e8d..adab2be8 100644 --- a/lib/VNDB/Handler/Staff.pm +++ b/lib/VNDB/Handler/Staff.pm @@ -3,180 +3,17 @@ package VNDB::Handler::Staff; use strict; use warnings; -use TUWF qw(:html :xml uri_escape xml_escape); +use TUWF qw(:html :xml uri_escape); use VNDB::Func; use VNDB::Types; -use VNDB::ExtLinks; use List::Util qw(first); TUWF::register( - qr{s([1-9]\d*)(?:\.([1-9]\d*))?} => \&page, qr{s/([a-z0]|all)} => \&list, qr{xml/staff\.xml} => \&staffxml, ); -sub page { - my($self, $id, $rev) = @_; - - my $method = $rev ? 'dbStaffGetRev' : 'dbStaffGet'; - my $s = $self->$method( - id => $id, - what => 'extended aliases roles', - $rev ? ( rev => $rev ) : () - )->[0]; - return $self->resNotFound if !$s->{id}; - enrich_extlinks s => $s; - - my $metadata = { - 'og:title' => $s->{name}, - 'og:description' => bb2text $s->{desc}, - }; - - $self->htmlHeader(title => $s->{name}, noindex => $rev, metadata => $metadata); - $self->htmlMainTabs('s', $s) if $id; - return if $self->htmlHiddenMessage('s', $s); - - if($rev) { - my $prev = $rev && $rev > 1 && $self->dbStaffGetRev(id => $id, rev => $rev-1, what => 'extended aliases')->[0]; - $self->htmlRevision('s', $prev, $s, - [ name => 'Name (romaji)', diff => 1 ], - [ original => 'Original name', diff => 1 ], - [ gender => 'Gender', serialize => sub { $GENDER{$_[0]} } ], - [ lang => 'Language', serialize => sub { "$_[0] ($LANGUAGE{$_[0]})" } ], - [ l_site => 'Official page', diff => 1 ], - [ l_wp => 'Wikipedia link', htmlize => sub { $_[0] ? sprintf '<a href="http://en.wikipedia.org/wiki/%s">%1$s</a>', xml_escape $_[0] : '[empty]' }], - [ l_wikidata=> 'Wikidata ID', htmlize => sub { $_[0] ? sprintf '<a href="https://www.wikidata.org/wiki/Q%d">Q%1$d</a>', $_[0] : '[empty]' } ], - [ l_twitter => 'Twitter account', diff => 1 ], - [ l_anidb => 'AniDB creator ID', serialize => sub { $_[0] // '' } ], - [ l_pixiv => 'Pixiv', htmlize => sub { $_[0] ? sprintf '<a href="https://www.pixiv.net/member.php?id=%d">%1$d</a>', $_[0] : '[empty]' } ], - [ desc => 'Description', diff => qr/[ ,\n\.]/ ], - [ aliases => 'Aliases', join => '<br />', split => sub { - map xml_escape(sprintf('%s%s', $_->{name}, $_->{original} ? ' ('.$_->{original}.')' : '')), @{$_[0]}; - }], - ); - } - - div class => 'mainbox staffpage'; - $self->htmlItemMessage('s', $s); - h1 $s->{name}; - h2 class => 'alttitle', lang => $s->{lang}, $s->{original} if $s->{original}; - - # info table - table class => 'stripe'; - thead; - Tr; - td colspan => 2; - b style => 'margin-right: 10px', $s->{name}; - b class => 'grayedout', style => 'margin-right: 10px', lang => $s->{lang}, $s->{original} if $s->{original}; - cssicon "gen $s->{gender}", $GENDER{$s->{gender}} if $s->{gender} ne 'unknown'; - end; - end; - end; - Tr; - td class => 'key', 'Language'; - td $LANGUAGE{$s->{lang}}; - end; - if(@{$s->{aliases}}) { - Tr; - td class => 'key', @{$s->{aliases}} == 1 ? 'Alias' : 'Aliases'; - td; - table class => 'aliases'; - for my $alias (@{$s->{aliases}}) { - Tr class => 'nostripe'; - td $alias->{original} ? () : (colspan => 2), class => 'key'; - txt $alias->{name}; - end; - td lang => $s->{lang}, $alias->{original} if $alias->{original}; - end; - } - end; - end; - end; - } - if($s->{extlinks}->@*) { - Tr; - td class => 'key', 'Links'; - td; - for($s->{extlinks}->@*) { - a href => $_->[1], $_->[0]; - br if $_ != $s->{extlinks}[$#{$s->{extlinks}}]; - } - end; - end; - } - end 'table'; - - # description - p class => 'description'; - lit bb2html $s->{desc}, 0, 1; - end; - end; - - _roles($self, $s); - _cast($self, $s); - $self->htmlFooter; -} - - -sub _roles { - my($self, $s) = @_; - return if !@{$s->{roles}}; - - h1 class => 'boxtitle', 'Credits'; - $self->htmlBrowse( - items => $s->{roles}, - class => 'staffroles', - header => [ - [ 'Title' ], - [ 'Released' ], - [ 'Role' ], - [ 'As' ], - [ 'Note' ], - ], - row => sub { - my($r, $n, $l) = @_; - Tr; - td class => 'tc1'; a href => "/v$l->{vid}", title => $l->{t_original}||$l->{title}, shorten $l->{title}, 60; end; - td class => 'tc2'; lit fmtdatestr $l->{c_released}; end; - td class => 'tc3', $CREDIT_TYPE{$l->{role}}; - td class => 'tc4', title => $l->{original}||$l->{name}, $l->{name}; - td class => 'tc5', $l->{note}; - end; - }, - ); -} - - -sub _cast { - my($self, $s) = @_; - return if !@{$s->{cast}}; - - h1 class => 'boxtitle', sprintf 'Voiced characters (%d)', scalar @{$s->{cast}}; - $self->htmlBrowse( - items => $s->{cast}, - class => 'staffroles', - header => [ - [ 'Title' ], - [ 'Released' ], - [ 'Cast' ], - [ 'As' ], - [ 'Note' ], - ], - row => sub { - my($r, $n, $l) = @_; - Tr; - td class => 'tc1'; a href => "/v$l->{vid}", title => $l->{t_original}||$l->{title}, shorten $l->{title}, 60; end; - td class => 'tc2'; lit fmtdatestr $l->{c_released}; end; - td class => 'tc3'; a href => "/c$l->{cid}", title => $l->{c_original}, $l->{c_name}; end; - td class => 'tc4', title => $l->{original}||$l->{name}, $l->{name}; - td class => 'tc5', $l->{note}; - end; - }, - ); -} - - sub list { my ($self, $char) = @_; diff --git a/lib/VNDB/Util/CommonHTML.pm b/lib/VNDB/Util/CommonHTML.pm index b56a7c74..c6986c1c 100644 --- a/lib/VNDB/Util/CommonHTML.pm +++ b/lib/VNDB/Util/CommonHTML.pm @@ -116,7 +116,6 @@ sub htmlHiddenMessage { my $editsum = $type eq 'v' ? $self->dbVNGetRev(id => $obj->{id})->[0]{comments} : $type eq 'r' ? $self->dbReleaseGetRev(id => $obj->{id})->[0]{comments} : $type eq 'c' ? $self->dbCharGetRev(id => $obj->{id})->[0]{comments} - : $type eq 's' ? $self->dbStaffGetRev(id => $obj->{id})->[0]{comments} : $self->dbProducerGetRev(id => $obj->{id})->[0]{comments}; div class => 'mainbox'; h1 $obj->{title}||$obj->{name}; diff --git a/lib/VNWeb/HTML.pm b/lib/VNWeb/HTML.pm index 30813aac..2947041e 100644 --- a/lib/VNWeb/HTML.pm +++ b/lib/VNWeb/HTML.pm @@ -8,7 +8,7 @@ use Encode 'encode_utf8', 'decode_utf8'; use JSON::XS; use TUWF ':html5_', 'uri_escape', 'html_escape', 'mkclass'; use Exporter 'import'; -use POSIX 'ceil'; +use POSIX 'ceil', 'strftime'; use Carp 'croak'; use JSON::XS; use VNDB::Config; @@ -23,12 +23,14 @@ our @EXPORT = qw/ debug_ join_ user_ user_displayname + rdate_ elm_ framework_ revision_ paginate_ sortable_ searchbox_ + itemmsg_ editmsg_ /; @@ -93,6 +95,22 @@ sub user_displayname { } +# Display a release date. +sub rdate_ { + my $date = sprintf '%08d', shift||0; + my $future = $date > strftime '%Y%m%d', gmtime; + my($y, $m, $d) = ($1, $2, $3) if $date =~ /^([0-9]{4})([0-9]{2})([0-9]{2})$/; + + my $str = $y == 0 ? 'unknown' : + $y == 9999 ? 'TBA' : + $m == 99 ? sprintf('%04d', $y) : + $d == 99 ? sprintf('%04d-%02d', $y, $m) : + sprintf('%04d-%02d-%02d', $y, $m, $d); + + $future ? b_ class => 'future', $str : txt_ $str +} + + # Instantiate an Elm module sub elm_ { my($mod, $schema, $data, $placeholder) = @_; @@ -426,6 +444,7 @@ sub framework_ { sub _revision_header_ { my($type, $obj) = @_; b_ "Revision $obj->{chrev}"; + debug_ $obj; if(auth) { lit_ ' ('; a_ href => "/$type$obj->{id}.$obj->{chrev}/edit", $obj->{chrev} == $obj->{maxrev} ? 'edit' : 'revert to'; @@ -445,8 +464,12 @@ sub _revision_header_ { sub _revision_fmtval_ { my($opt, $val) = @_; - return i_ '[empty]' if !defined $val || !length $val; + return i_ '[empty]' if !defined $val || !length $val || (defined $opt->{empty} && $val eq $opt->{empty}); return lit_ html_escape $val if !$opt->{fmt}; + if(ref $opt->{fmt} eq 'HASH') { + my $h = $opt->{fmt}{$val}; + return txt_ ref $h eq 'HASH' ? $h->{txt} : $h || '[unknown]'; + } return txt_ $val ? 'True' : 'False' if $opt->{fmt} eq 'bool'; local $_ = $val; $opt->{fmt}->(); @@ -488,9 +511,9 @@ sub _revision_fmtcol_ { } } - } elsif(@$l > 2 && $i == 2 && ($ch eq '+' || $ch eq 'c')) { + } elsif(@$l > 1 && $i == 2 && ($ch eq '+' || $ch eq 'c')) { b_ class => 'diff_add', sub { _revision_fmtval_ $opt, $val } - } elsif(@$l > 2 && $i == 1 && ($ch eq '-' || $ch eq 'c')) { + } elsif(@$l > 1 && $i == 1 && ($ch eq '-' || $ch eq 'c')) { b_ class => 'diff_del', sub { _revision_fmtval_ $opt, $val } } elsif($ch eq 'c' || $ch eq 'u') { _revision_fmtval_ $opt, $val; @@ -500,6 +523,19 @@ sub _revision_fmtcol_ { } +# Recursively stringify scalars. This is generally a no-op, except when +# serializing the data structure to JSON this will cause all numbers to be +# formatted as strings. Not very useful for data exchange, but this allows for +# creating proper canonicalized JSON where equivalent data structures serialize +# to the same string. (TODO: Might as well write a function that hashes +# recursive data structures and use that for comparison - a little bit more +# work but less magical) +sub _stringify_scalars_rec { + defined($_[0]) && !ref $_[0] ? "$_[0]" : + ref $_[0] eq 'HASH' ? map _stringify_scalars_rec($_), values $_[0]->%* : + ref $_[0] eq 'ARRAY' ? map _stringify_scalars_rec($_), $_[0]->@* : undef; +} + sub _revision_diff_ { my($type, $old, $new, $field, $name, %opt) = @_; @@ -508,8 +544,8 @@ sub _revision_diff_ { my @old = ref $old->{$field} eq 'ARRAY' ? $old->{$field}->@* : ($old->{$field}); my @new = ref $new->{$field} eq 'ARRAY' ? $new->{$field}->@* : ($new->{$field}); - my $JS = JSON::XS->new->utf8->allow_nonref; - my $l = sdiff \@old, \@new, sub { $JS->encode($_[0]) }; + my $JS = JSON::XS->new->utf8->canonical->allow_nonref; + my $l = sdiff \@old, \@new, sub { _stringify_scalars_rec($_[0]); $JS->encode($_[0]) }; return if !grep $_->[0] ne 'u', @$l; # Now check if we should do a textual diff on the changed items. @@ -582,9 +618,13 @@ sub _revision_cmp_ { # [ field_name, display_name, %options ] # # Options: -# fmt => 'bool'||sub {$_} - Formatting function for individual values. +# fmt => 'bool'||\%HASH||sub {$_} - Formatting function for individual values. # If not given, the field is rendered as plain text and changes are highlighted with a diff. -# join => sub{} - HTML to join multi-value fields, defaults to \&br_. +# \%HASH -> Look the field up in the hash table (values should be string or {txt=>string}. +# sub($value) {$_} -> Custom formatting function, should output TUWF::XML data HTML. +# join => sub{} - HTML to join multi-value fields, defaults to \&br_. +# empty => str - What value should be considered "empty", e.g. (empty => 0) for integer fields. +# undef or empty string are always considered empty values. sub revision_ { my($type, $new, $enrich, @fields) = @_; @@ -688,6 +728,17 @@ sub searchbox_ { } +# Generate a message to display on an entry page when the entry has been locked or the user can't edit it. +sub itemmsg_ { + my($type, $obj) = @_; + if($obj->{entry_locked}) { + p_ class => 'locked', 'Locked for editing'; + } elsif(auth && !can_edit $type => $obj) { + p_ class => 'locked', 'You can not edit this page'; + } +} + + # Generate the initial mainbox when adding or editing a database entry, with a # friendly message pointing to the guidelines and stuff. # Args: $type ('v','r', etc), $obj (from db_entry(), or undef for new page), $page_title, $is_this_a_copy? diff --git a/lib/VNWeb/Prelude.pm b/lib/VNWeb/Prelude.pm index c00e9afb..10fc3b8d 100644 --- a/lib/VNWeb/Prelude.pm +++ b/lib/VNWeb/Prelude.pm @@ -14,6 +14,7 @@ # use VNDB::Types; # use VNDB::Config; # use VNDB::Func 'fmtdate', 'fmtage', 'fmtvote', 'query_encode'; +# use VNDB::ExtLinks; # use VNWeb::Auth; # use VNWeb::HTML; # use VNWeb::DB; @@ -56,6 +57,7 @@ sub import { use VNDB::Types; use VNDB::Config; use VNDB::Func 'fmtdate', 'fmtage', 'fmtvote', 'query_encode'; + use VNDB::ExtLinks; use VNWeb::Auth; use VNWeb::HTML; use VNWeb::DB; diff --git a/lib/VNWeb/Staff/Page.pm b/lib/VNWeb/Staff/Page.pm new file mode 100644 index 00000000..8a42f05f --- /dev/null +++ b/lib/VNWeb/Staff/Page.pm @@ -0,0 +1,181 @@ +package VNWeb::Staff::Page; + +use VNWeb::Prelude; +use VNWeb::Docs::Lib; + + +sub enrich_item { + my($s) = @_; + + # Add a 'main' flag to each alias + $_->{main} = $s->{aid} == $_->{aid} for $s->{alias}->@*; + + # Sort aliases by name + $s->{alias} = [ sort { $a->{name} cmp $b->{name} || ($a->{original}||'') cmp ($b->{original}||'') } $s->{alias}->@* ]; +} + + +sub _rev_ { + my($s) = @_; + revision_ s => $s, \&enrich_item, + [ alias => 'Names', fmt => sub { + txt_ $_->{name}; + txt_ " ($_->{original})" if $_->{original}; + b_ class => 'grayedout', ' (primary)' if $_->{main}; + } ], + [ gender => 'Gender', fmt => \%GENDER ], + [ lang => 'Language', fmt => \%LANGUAGE ], + [ desc => 'Description' ], + revision_extlinks 's' +} + + +sub _infotable_ { + my($main, $s) = @_; + table_ class => 'stripe', sub { + thead_ sub { tr_ sub { + td_ colspan => 2, sub { + b_ style => 'margin-right: 10px', $main->{name}; + b_ class => 'grayedout', style => 'margin-right: 10px', lang => $s->{lang}, $main->{original} if $main->{original}; + abbr_ class => "icons gen $s->{gender}", title => $GENDER{$s->{gender}}, '' if $s->{gender} ne 'unknown'; + } + } }; + + tr_ sub { + td_ class => 'key', 'Language'; + td_ $LANGUAGE{$s->{lang}}; + }; + + my @alias = grep !$_->{main}, $s->{alias}->@*; + tr_ sub { + td_ @alias == 1 ? 'Alias' : 'Aliases'; + td_ sub { + table_ class => 'aliases', sub { + tr_ class => 'nostripe', sub { + td_ class => 'key', $_->{original} ? () : (colspan => 2), $_->{name}; + td_ lang => $s->{lang}, $_->{original} if $_->{original}; + } for @alias; + }; + }; + } if @alias; + + tr_ sub { + td_ class => 'key', 'Links'; + td_ sub { + join_ \&br_, sub { a_ href => $_->[1], $_->[0] }, $s->{extlinks}->@*; + }; + } if $s->{extlinks}->@*; + }; +} + + +sub _roles_ { + my($s) = @_; + my %alias = map +($_->{aid}, $_), $s->{alias}->@*; + + my $roles = tuwf->dbAlli(q{ + SELECT v.id, vs.aid, vs.role, vs.note, v.c_released, v.title, v.original + FROM vn_staff vs + JOIN vn v ON v.id = vs.id + WHERE vs.aid IN}, [ keys %alias ], q{ + AND NOT v.hidden + ORDER BY v.c_released ASC, v.title ASC, vs.role ASC + }); + return if !@$roles; + + h1_ class => 'boxtitle', sprintf 'Credits (%d)', scalar @$roles; + div_ class => 'mainbox browse staffroles', sub { + table_ class => 'stripe', sub { + thead_ sub { tr_ sub { + td_ class => 'tc1', 'Title'; + td_ class => 'tc2', 'Released'; + td_ class => 'tc3', 'Role'; + td_ class => 'tc4', 'As'; + td_ class => 'tc5', 'Note'; + }}; + tr_ sub { + my($v, $a) = ($_, $alias{$_->{aid}}); + td_ class => 'tc1', sub { + a_ href => "/v$v->{id}", title => $v->{original}||$v->{title}, shorten $v->{title}, 60; + }; + td_ class => 'tc2', sub { rdate_ $v->{c_released} }; + td_ class => 'tc3', $CREDIT_TYPE{$v->{role}}; + td_ class => 'tc4', title => $a->{original}||$a->{name}, $a->{name}; + td_ class => 'tc5', $v->{note}; + } for @$roles; + }; + }; +} + + +sub _cast_ { + my($s) = @_; + my %alias = map +($_->{aid}, $_), $s->{alias}->@*; + + my $cast = tuwf->dbAlli(q{ + SELECT vs.aid, v.id, v.c_released, v.title, v.original, c.id AS cid, c.name AS c_name, c.original AS c_original, vs.note + FROM vn_seiyuu vs + JOIN vn v ON v.id = vs.id + JOIN chars c ON c.id = vs.cid + WHERE vs.aid IN}, [ keys %alias ], q{ + AND NOT v.hidden + AND NOT c.hidden + ORDER BY v.c_released ASC, v.title ASC + }); + return if !@$cast; + + h1_ class => 'boxtitle', sprintf 'Voiced characters (%d)', scalar @$cast; + div_ class => 'mainbox browse staffroles', sub { + table_ class => 'stripe', sub { + thead_ sub { tr_ sub { + td_ class => 'tc1', 'Title'; + td_ class => 'tc2', 'Released'; + td_ class => 'tc3', 'Cast'; + td_ class => 'tc4', 'As'; + td_ class => 'tc5', 'Note'; + }}; + tr_ sub { + my($v, $a) = ($_, $alias{$_->{aid}}); + td_ class => 'tc1', sub { + a_ href => "/v$v->{id}", title => $v->{original}||$v->{title}, shorten $v->{title}, 60; + }; + td_ class => 'tc2', sub { rdate_ $v->{c_released} }; + td_ class => 'tc3', sub { + a_ href => "/c$v->{cid}", title => $v->{c_original}||$v->{c_name}, $v->{c_name}; + }; + td_ class => 'tc4', title => $a->{original}||$a->{name}, $a->{name}; + td_ class => 'tc5', $v->{note}; + } for @$cast; + }; + }; +} + + +TUWF::get qr{/$RE{srev}} => sub { + my $s = db_entry s => tuwf->capture('id'), tuwf->capture('rev'); + return tuwf->resNotFound if !$s; + + enrich_item $s; + enrich_extlinks s => $s; + my($main) = grep $_->{aid} == $s->{aid}, $s->{alias}->@*; + + framework_ title => $main->{name}, index => 1, type => 's', dbobj => $s, hiddenmsg => 1, + og => { + description => bb2text $s->{desc} + }, + sub { + _rev_ $s if tuwf->capture('rev'); + div_ class => 'mainbox staffpage', sub { + itemmsg_ s => $s; + h1_ sub { txt_ $main->{name}; debug_ $s }; + h2_ class => 'alttitle', lang => $s->{lang}, $main->{original} if $main->{original}; + _infotable_ $main, $s; + p_ class => 'description', sub { lit_ bb2html $s->{desc} }; + }; + + _roles_ $s; + _cast_ $s; + }; +}; + +1; |