diff options
author | morkt <> | 2014-12-22 11:14:18 +0100 |
---|---|---|
committer | Yorhel <git@yorhel.nl> | 2014-12-22 11:20:39 +0100 |
commit | ac784a64d0f74f9e04ac41890075c411e50ca823 (patch) | |
tree | f527926f531975751563e3d9286ce02212152850 /lib | |
parent | df383d117908160d1a84ce4519edc0c9bcf08c3b (diff) |
Initial implementation of a staff/seiyuu database
Diffstat (limited to 'lib')
-rw-r--r-- | lib/VNDB/DB/Chars.pm | 16 | ||||
-rw-r--r-- | lib/VNDB/DB/Misc.pm | 13 | ||||
-rw-r--r-- | lib/VNDB/DB/Staff.pm | 141 | ||||
-rw-r--r-- | lib/VNDB/DB/VN.pm | 18 | ||||
-rw-r--r-- | lib/VNDB/Handler/Chars.pm | 16 | ||||
-rw-r--r-- | lib/VNDB/Handler/Misc.pm | 3 | ||||
-rw-r--r-- | lib/VNDB/Handler/Staff.pm | 412 | ||||
-rw-r--r-- | lib/VNDB/Handler/VNPage.pm | 61 | ||||
-rw-r--r-- | lib/VNDB/Util/CommonHTML.pm | 9 | ||||
-rw-r--r-- | lib/VNDB/Util/LayoutHTML.pm | 2 |
10 files changed, 669 insertions, 22 deletions
diff --git a/lib/VNDB/DB/Chars.pm b/lib/VNDB/DB/Chars.pm index 86b3a859..272f9610 100644 --- a/lib/VNDB/DB/Chars.pm +++ b/lib/VNDB/DB/Chars.pm @@ -76,10 +76,11 @@ sub dbCharGet { join(', ', @select), join(' ', @join), \%where ); - if(@$r && $o{what} =~ /(vns|traits)/) { + if(@$r && $o{what} =~ /vns|traits|seiyuu/) { my %r = map { $_->{traits} = []; $_->{vns} = []; + $_->{seiyuu} = []; ($_->{cid}, $_) } @$r; @@ -107,6 +108,19 @@ sub dbCharGet { { 'cv.cid IN(!l)' => [[keys %r]], $1 ? ('cv.vid = ?', $1) : () } )}); } + + if($o{what} =~ /seiyuu/) { + push @{$r{ delete $_->{cid} }{seiyuu}}, $_ for (@{$self->dbAll(q| + SELECT cs.cid, sr.sid, sa.name, sa.original, cs.note + FROM chars_seiyuu cs + JOIN staff_alias sa ON sa.id = cs.aid + JOIN staff_rev sr ON sr.id = sa.rid + JOIN staff s ON sr.id = s.latest + !W + ORDER BY sa.name|, + { 'cs.cid IN(!l)' => [[ keys %r ]], $o{vid} ? ('vid = ?' => $o{vid}) : () } + )}); + } } return wantarray ? ($r, $np) : $r; } diff --git a/lib/VNDB/DB/Misc.pm b/lib/VNDB/DB/Misc.pm index 3155ca56..8927e1ec 100644 --- a/lib/VNDB/DB/Misc.pm +++ b/lib/VNDB/DB/Misc.pm @@ -27,7 +27,7 @@ sub dbStats { sub dbItemEdit { my($self, $type, $oid, %o) = @_; - my $fun = {qw|v vn r release p producer c char|}->{$type}; + my $fun = {qw|v vn r release p producer c char s staff|}->{$type}; $self->dbExec('SELECT edit_!s_init(?)', $fun, $oid); $self->dbExec('UPDATE edit_revision !H', { 'requester = ?' => $o{uid}||$self->authInfo->{id}, @@ -41,6 +41,7 @@ sub dbItemEdit { $self->dbProducerRevisionInsert(\%o) if $type eq 'p'; $self->dbReleaseRevisionInsert( \%o) if $type eq 'r'; $self->dbCharRevisionInsert( \%o) if $type eq 'c'; + $self->dbStaffRevisionInsert( \%o) if $type eq 's'; return $self->dbRow('SELECT * FROM edit_!s_commit()', $fun); } @@ -60,10 +61,10 @@ sub dbRevisionGet { $o{what} ||= ''; $o{releases} = 0 if !$o{type} || $o{type} ne 'v' || !$o{iid}; - my %tables = qw|v vn r releases p producers c chars|; + my %tables = qw|v vn r releases p producers c chars s staff|; # what types should we join? my @types = ( - !$o{type} ? ('v', 'r', 'p', 'c') : + !$o{type} ? qw(v r p c s) : ref($o{type}) ? @{$o{type}} : $o{type} ne 'v' ? $o{type} : $o{releases} ? ('v', 'r') : 'v' @@ -97,15 +98,17 @@ sub dbRevisionGet { ) : (), $o{what} =~ /user/ ? 'JOIN users u ON h.requester = u.id' : (), ); + push @join, 'LEFT JOIN staff_alias sa ON sa.rid = sr.id AND sa.id = sr.aid' if grep /s/, @types; + my %tcolumns = qw(v vr.title r rr.title p pr.name c cr.name s sa.name); my @select = ( qw|h.id h.type h.requester h.comments h.rev|, q|extract('epoch' from h.added) as added|, $o{what} =~ /user/ ? 'u.username' : (), $o{what} =~ /item/ ? ( 'COALESCE('.join(', ', map "${_}r.${_}id", @types).') AS iid', - 'COALESCE('.join(', ', map /[pc]/ ? "${_}r.name" : "${_}r.title", @types).') AS ititle', - 'COALESCE('.join(', ', map "${_}r.original", @types).') AS ioriginal', + 'COALESCE('.join(', ', map $tcolumns{$_}, @types).') AS ititle', + 'COALESCE('.join(', ', map /s/ ? 'sa.original' : "${_}r.original", @types).') AS ioriginal', ) : (), ); diff --git a/lib/VNDB/DB/Staff.pm b/lib/VNDB/DB/Staff.pm new file mode 100644 index 00000000..7a732c4d --- /dev/null +++ b/lib/VNDB/DB/Staff.pm @@ -0,0 +1,141 @@ + +package VNDB::DB::Staff; + +use strict; +use warnings; +use Exporter 'import'; + +our @EXPORT = qw|dbStaffGet dbStaffRevisionInsert|; + +# options: results, page, id, aid, vid, search, rev +# what: extended changes roles aliases +sub dbStaffGet { + my $self = shift; + my %o = ( + results => 10, + page => 1, + what => '', + @_ + ); + + $o{search} =~ s/%//g if $o{search}; + + my %where = ( + !$o{id} && !$o{rev} ? ( 's.hidden = FALSE' => 1 ) : (), + $o{id} ? ( ref $o{id} ? ('s.id IN(!l)' => [$o{id}]) : ('s.id = ?' => $o{id}) ) : (), + $o{aid} ? ( ref $o{aid} ? ('sa.id IN(!l)' => [$o{aid}]) : ('sa.id = ?' => $o{aid}) ) : (), + $o{vid} ? ( 'vr.vid = ?' => $o{vid}) : (), + $o{search} ? + ( '(sa.name ILIKE ? OR sa.original ILIKE ?)', [ map '%%'.$o{search}.'%%', 1..2 ] ) : (), + $o{char} ? ( 'LOWER(SUBSTR(sa.name, 1, 1)) = ?' => $o{char} ) : (), + defined $o{char} && !$o{char} ? + ( '(ASCII(sa.name) < 97 OR ASCII(sa.name) > 122) AND (ASCII(sa.name) < 65 OR ASCII(sa.name) > 90)' => 1 ) : (), + $o{rev} ? ( 'c.rev = ?' => $o{rev} ) : (), + ); + + my @join; + push @join, 'JOIN staff s ON '.($o{rev} ? 's.id = sr.sid' : 'sr.id = s.latest'); + push @join, 'JOIN staff_alias sa ON sa.rid = sr.id'.($o{id}?' AND sa.id = sr.aid':''); + push @join, 'JOIN changes c ON c.id = sr.id' if $o{what} =~ /changes/ || $o{rev}; + push @join, 'JOIN users u ON u.id = c.requester' if $o{what} =~ /changes/; + push @join, + 'JOIN vn_staff vs ON vs.aid = sa.id', + 'JOIN vn_rev vr ON vs.vid = vr.id', + 'JOIN vn v ON vr.id = v.latest' if $o{vid}; +# fetch both staff and seiyuu in one query +# push @join, q| +# LEFT JOIN vn_staff vs ON vs.aid = sa.id +# LEFT JOIN (chars_seiyuu cs JOIN chars c ON cs.cid = c.latest) +# ON cs.aid = sa.id +# JOIN (vn_rev vr JOIN vn v ON vr.id = v.latest) +# ON vs.vid = vr.id OR cs.vid = v.id +# | if $o{vid}; + + my $select = 's.id, sr.aid, sa.name, sa.original, sr.gender, sr.lang, sr.id AS cid'; + $select .= ', sr.desc, sr.l_wp, s.hidden, s.locked' if $o{what} =~ /extended/; + $select .= q|, extract('epoch' from c.added) as added, c.requester, c.comments, s.latest, u.username, c.rev, c.ihid, c.ilock| if $o{what} =~ /changes/; + $select .= ', vs.role, vs.note' if $o{vid}; + + my $order = $o{vid} ? 'ORDER BY vs.role ASC, sa.name ASC' : 'ORDER BY sa.name ASC'; + + my($r, $np) = $self->dbPage(\%o, q| + SELECT !s + FROM staff_rev sr + !s + !W + !s|, + $select, join(' ', @join), \%where, $order + ); + + if (@$r && $o{what} =~ /roles|aliases/) { + my %r = map { + $_->{roles} = []; + $_->{cast} = []; + $_->{aliases} = []; + ($_->{cid}, $_); + } @$r; + if ($o{what} =~ /roles/) { + push @{$r{ delete $_->{rid} }{roles}}, $_ for (@{$self->dbAll(q| + SELECT sa.rid, vr.vid, sa.name, v.c_released, vr.title, vr.original AS t_original, vs.role, vs.note + FROM vn_staff vs + JOIN vn_rev vr ON vr.id = vs.vid + JOIN vn v ON v.latest = vr.id + JOIN staff_alias sa ON vs.aid = sa.id + WHERE sa.rid IN(!l) + ORDER BY v.c_released ASC, vr.title ASC, vs.role ASC|, [ keys %r ] + )}); + push @{$r{ delete $_->{rid} }{cast}}, $_ for (@{$self->dbAll(q| + SELECT sa.rid, vr.vid, sa.name, v.c_released, vr.title, vr.original AS t_original, cr.cid, cr.name AS c_name, cs.note + FROM chars_seiyuu cs + JOIN chars_rev cr ON cr.id = cs.cid + JOIN vn v ON v.id = cs.vid + JOIN vn_rev vr ON v.latest = vr.id + JOIN staff_alias sa ON cs.aid = sa.id + WHERE sa.rid IN(!l) + ORDER BY v.c_released ASC, vr.title ASC|, [ keys %r ] + )}); + } + if ($o{what} =~ /aliases/) { + push @{$r{ delete $_->{rid} }{aliases}}, $_ for (@{$self->dbAll(q| + SELECT sa.id, sa.rid, sa.name, sa.original + FROM staff_alias sa + JOIN staff_rev sr ON sr.id = sa.rid + WHERE sr.id IN(!l) AND sr.aid <> sa.id + ORDER BY sa.name ASC|, [ keys %r ] + )}); + } + } + + return wantarray ? ($r, $np) : $r; +} + +# Updates the edit_* tables, used from dbItemEdit() +# Arguments: { columns in staff_rev and staff_alias}, +sub dbStaffRevisionInsert { + my($self, $o) = @_; + + $self->dbExec('DELETE FROM edit_staff_aliases'); + if ($o->{aid}) { + $self->dbExec(q| + INSERT INTO edit_staff_aliases (id, name, original) VALUES (?, ?, ?)|, + $o->{aid}, $o->{name}, $o->{original}); + } else { + $o->{aid} = $self->dbRow(q| + INSERT INTO edit_staff_aliases (name, original) VALUES (?, ?) RETURNING id|, + $o->{name}, $o->{original})->{id}; + } + + my %staff = map exists($o->{$_}) ? (qq|"$_" = ?|, $o->{$_}) : (), + qw|aid image gender lang desc l_wp|; + $self->dbExec('UPDATE edit_staff !H', \%staff) if %staff; + for my $alias (@{$o->{aliases}}) { + if ($alias->[0]) { + $self->dbExec('INSERT INTO edit_staff_aliases (id, name, original) VALUES (!l)', $alias); + } else { + $self->dbExec('INSERT INTO edit_staff_aliases (name, original) VALUES (?, ?)', + $alias->[1], $alias->[2]); + } + } +} + +1; diff --git a/lib/VNDB/DB/VN.pm b/lib/VNDB/DB/VN.pm index 090f9ecb..f6635c07 100644 --- a/lib/VNDB/DB/VN.pm +++ b/lib/VNDB/DB/VN.pm @@ -7,7 +7,7 @@ use Exporter 'import'; use VNDB::Func 'gtintype', 'normalize_query'; use Encode 'decode_utf8'; -our @EXPORT = qw|dbVNGet dbVNRevisionInsert dbVNImageId dbScreenshotAdd dbScreenshotGet dbScreenshotRandom dbVNHasChar|; +our @EXPORT = qw|dbVNGet dbVNRevisionInsert dbVNImageId dbScreenshotAdd dbScreenshotGet dbScreenshotRandom dbVNHasChar dbVNHasStaff|; # Options: id, rev, char, search, length, lang, olang, plat, tag_inc, tag_exc, tagspoil, @@ -225,6 +225,13 @@ sub dbVNRevisionInsert { my $q = join ',', map '(?)', @{$o->{anime}}; $self->dbExec("INSERT INTO edit_vn_anime (aid) VALUES $q", @{$o->{anime}}) if @{$o->{anime}}; } + + if($o->{credits}) { + $self->dbExec('DELETE FROM edit_vn_staff'); + my $q = join ',', ('(?, ?, ?)') x @{$o->{credits}}; + my @val = map @{$_}[0..2], @{$o->{credits}}; + $self->dbExec("INSERT INTO edit_vn_staff (aid, role, note) VALUES $q", @val) if @val; + } } @@ -290,5 +297,14 @@ sub dbVNHasChar { )->{exists}; } + +sub dbVNHasStaff { + my($self, $vid) = @_; + return $self->dbRow( + 'SELECT 1 AS exists FROM vn v JOIN vn_staff vs ON v.latest = vs.vid WHERE v.id = ?', $vid + )->{exists}; +} + + 1; diff --git a/lib/VNDB/Handler/Chars.pm b/lib/VNDB/Handler/Chars.pm index 7ae95e43..cb829e4c 100644 --- a/lib/VNDB/Handler/Chars.pm +++ b/lib/VNDB/Handler/Chars.pm @@ -22,7 +22,7 @@ sub page { my $r = $self->dbCharGet( id => $id, - what => 'extended traits vns'.($rev ? ' changes' : ''), + what => 'extended traits vns seiyuu'.($rev ? ' changes' : ''), $rev ? ( rev => $rev ) : () )->[0]; return $self->resNotFound if !$r->{id}; @@ -61,6 +61,9 @@ sub page { $_->{rid}?sprintf('[<a href="/r%d">r%d</a>]', $_->{rid}, $_->{rid}):'', mt("_charrole_$_->{role}"), mt("_spoil_$_->{spoil}")), @{$_[0]}; }], + [ seiyuu => join => '<br />', split => sub { + map sprintf('<a href="/s%d">%s</a>', $_->{sid}, $_->{name}), @{$_[0]} + }], ); } @@ -226,6 +229,17 @@ sub charTable { end; } + if (@{$r->{seiyuu}}) { + Tr; + td class => 'key', mt '_charp_voice'; + td; + for my $s (@{$r->{seiyuu}}) { + a href => "/s$s->{sid}", $s->{name}; br; + } + end; + end; + } + # description if($r->{desc}) { Tr class => 'nostripe'; diff --git a/lib/VNDB/Handler/Misc.pm b/lib/VNDB/Handler/Misc.pm index 357779bc..1540c5fe 100644 --- a/lib/VNDB/Handler/Misc.pm +++ b/lib/VNDB/Handler/Misc.pm @@ -11,7 +11,7 @@ use POSIX 'strftime'; TUWF::register( qr{}, \&homepage, - qr{(?:([upvrc])([1-9]\d*)/)?hist}, \&history, + qr{(?:([upvrcs])([1-9]\d*)/)?hist},\&history, qr{d([1-9]\d*)}, \&docpage, qr{setlang}, \&setlang, qr{nospam}, \&nospam, @@ -206,6 +206,7 @@ sub history { $type eq 'p' ? $self->dbProducerGet(id => $id)->[0] : $type eq 'r' ? $self->dbReleaseGet(id => $id)->[0] : $type eq 'c' ? $self->dbCharGet(id => $id)->[0] : + $type eq 's' ? $self->dbStaffGet(id => $id)->[0] : $type eq 'v' ? $self->dbVNGet(id => $id)->[0] : undef; my $title = mt $type ? ('_hist_title_item', $obj->{title} || $obj->{name} || $obj->{username}) : '_hist_title'; return $self->resNotFound if $type && !$obj->{id}; diff --git a/lib/VNDB/Handler/Staff.pm b/lib/VNDB/Handler/Staff.pm new file mode 100644 index 00000000..14f0b53d --- /dev/null +++ b/lib/VNDB/Handler/Staff.pm @@ -0,0 +1,412 @@ + +package VNDB::Handler::Staff; + +use strict; +use warnings; +use TUWF qw(:html :xml xml_escape); +use VNDB::Func; + +TUWF::register( + qr{s([1-9]\d*)(?:\.([1-9]\d*))?} => \&page, + qr{s(?:([1-9]\d*)(?:\.([1-9]\d*))?/edit|/new)} + => \&edit, + qr{s/([a-z0]|all)} => \&list, + qr{v([1-9]\d*)/staff/edit} => \&vn_edit, + qr{xml/staff.xml} => \&staffxml, +); + +sub page { + my($self, $id, $rev) = @_; + + my $s = $self->dbStaffGet( + id => $id, + what => 'extended aliases roles'.($rev ? ' changes' : ''), + $rev ? ( rev => $rev ) : () + )->[0]; + return $self->resNotFound if !$s->{id}; + + $self->htmlHeader(title => $s->{name}, noindex => $rev); + $self->htmlMainTabs('s', $s) if $id; + return if $self->htmlHiddenMessage('s', $s); + + if($rev) { + my $prev = $rev && $rev > 1 && $self->dbStaffGet(id => $id, rev => $rev-1, what => 'changes extended aliases')->[0]; + $self->htmlRevision('s', $prev, $s, + [ name => diff => 1 ], + [ original => diff => 1 ], + [ gender => serialize => sub { mt "_gender_$_[0]" } ], + [ lang => serialize => sub { "$_[0] (".mt("_lang_$_[0]").')' } ], + [ l_wp => htmlize => sub { + $_[0] ? sprintf '<a href="http://en.wikipedia.org/wiki/%s">%1$s</a>', xml_escape $_[0] : mt '_revision_nolink' + }], + [ desc => diff => qr/[ ,\n\.]/ ], +# [ image => htmlize => sub { +# return $_[0] ? sprintf '<img src="%s" />', imgurl(ch => $_[0]) : mt '_stdiff_image_none'; +# }], + [ aliases => join => '<br />', split => sub { + map sprintf('%s%s', $_->{name}, $_->{original} ? ' ('.$_->{original}.')' : ''), @{$_[0]}; + }], + ); + } + + div class => 'mainbox'; + $self->htmlItemMessage('s', $s); + div class => 'staffinfo'; + h1 $s->{name}; + h2 class => 'alttitle'; + cssicon "gen $s->{gender}", mt "_gender_$s->{gender}" if $s->{gender} ne 'unknown'; + txt $s->{original} if $s->{original}; + end; + + # info table + table class => 'stripe'; + +# Tr; +# td class => 'key', mt '_staff_gender'; +# td mt "_gender_$s->{gender}"; +# end; + Tr; + td class => 'key', mt '_staff_language'; + td mt "_lang_$s->{lang}"; + end; + if (@{$s->{aliases}}) { + Tr; + td class => 'key', mt '_staff_aliases'; + td; + p; + foreach my $alias (@{$s->{aliases}}) { + txt $alias->{name}; + txt ' ('.$alias->{original}.')' if $alias->{original}; + br; + } + end; + end; + end; + } + if ($s->{l_wp}) { + Tr; + td colspan => 2; + a href => "http://en.wikipedia.org/wiki/$s->{l_wp}", mt '_staff_l_wp'; + end; + end; + } + end 'table'; + end; + + # description + if($s->{desc}) { + div class => 'staffdesc'; + h2 mt '_staff_bio'; + p; + lit bb2html $s->{desc}, 0, 1; + end; + end; + } + + if (@{$s->{roles}} || @{$s->{cast}}) { + div class => 'staffroles'; + table class => 'stripe'; + thead; + Tr; + td class => 'tc1', mt '_staff_col_role'; + td class => 'tc2', mt '_staff_col_title'; + td class => 'tc3', mt '_staff_col_released'; + td class => 'tc4', mt '_staff_col_note'; + end; + end; + foreach my $r (@{$s->{roles}}) { + Tr; + td class => 'tc1', mt '_credit_'.$r->{role}; + td class => 'tc2'; a href => "/v$r->{vid}", title => $r->{t_original}, $r->{title}; end; + td class => 'tc3'; lit $self->{l10n}->datestr($r->{c_released}); end; + td class => 'tc4'; + lit '('.mt('_staff_as').$r->{name}.') ' if $r->{name} ne $s->{name}; + lit $r->{note}; + end; + end; + } + if (@{$s->{cast}}) { + Tr; + td class => 'tc1', colspan => 4; b mt '_staff_col_cast'; end; + end; + } + foreach my $r (@{$s->{cast}}) { + Tr; + td class => 'tc1'; a href => "/c$r->{cid}", $r->{c_name}; end; + td class => 'tc2'; a href => "/v$r->{vid}", title => $r->{t_original}, $r->{title}; end; + td class => 'tc3'; lit $self->{l10n}->datestr($r->{c_released}); end; + td class => 'tc4'; + lit '('.mt('_staff_as').$r->{name}.') ' if $r->{name} ne $s->{name}; + lit $r->{note}; + end; + end; + } + end 'table'; + end + } + clearfloat; + end; + + $self->htmlFooter; +} + + +sub edit { + my($self, $sid, $rev) = @_; + + my $s = $sid && $self->dbStaffGet(id => $sid, what => 'changes extended aliases', $rev ? (rev => $rev) : ())->[0]; + return $self->resNotFound if $sid && !$s->{id}; + $rev = undef if !$s || $s->{cid} == $s->{latest}; + + return $self->htmlDenied if !$self->authCan('edit') + || $sid && (($s->{locked} || $s->{hidden}) && !$self->authCan('dbmod')); + + my %b4 = !$sid ? () : ( + (map { $_ => $s->{$_} } qw|aid name original gender lang desc l_wp ihid ilock|), + aliases => join('|||', map sprintf('%d,%s,%s', $_->{id}, $_->{name}, $_->{original}), + sort { $a->{name} <=> $b->{name} } @{$s->{aliases}}), + ); + my $frm; + + if ($self->reqMethod eq 'POST') { + return if !$self->authCheckCode; + $frm = $self->formValidate ( + { post => 'aid', required => 0, template => 'int' }, + { post => 'name', maxlength => 200 }, + { post => 'original', required => 0, maxlength => 200, default => '' }, + { post => 'desc', required => 0, maxlength => 5000, default => '' }, + { post => 'gender', required => 0, default => 'unknown', enum => [qw|unknown m f|] }, + { post => 'lang', enum => $self->{languages} }, + { post => 'l_wp', required => 0, maxlength => 150, default => '' }, + { post => 'image', required => 0, default => 0, template => 'int' }, + { post => 'aliases', required => 0, maxlength => 5000, default => '' }, + { post => 'editsum', required => 0, maxlength => 5000 }, + { post => 'ihid', required => 0 }, + { post => 'ilock', required => 0 }, + ); + push @{$frm->{_err}}, 'badeditsum' if !$frm->{editsum} || lc($frm->{editsum}) eq lc($frm->{desc}); + my @aliases = map { /^(\d+),([^,]*),(.*)$/ ? [ $1, $2, $3 ]: () } split /\|\|\|/, $frm->{aliases}; + if (!$frm->{_err}) { + # parse and normalize + $frm->{aliases} = join('|||', map sprintf('%d,%s,%s', @$_), @aliases); + $frm->{ihid} = $frm->{ihid} ?1:0; + $frm->{ilock} = $frm->{ilock}?1:0; + + return $self->resRedirect("/s$sid", 'post') + if $sid && !grep $frm->{$_} ne $b4{$_}, keys %b4; + } + if(!$frm->{_err}) { + $frm->{aliases} = \@aliases; + my $nrev = $self->dbItemEdit ('s' => $sid ? $s->{cid} : undef, %$frm); + return $self->resRedirect("/s$nrev->{iid}.$nrev->{rev}", 'post'); + } + } + + $frm->{$_} //= $b4{$_} for keys %b4; + $frm->{editsum} //= sprintf 'Reverted to revision s%d.%d', $sid, $rev if $rev; + $frm->{lang} = 'ja' if !$sid && !defined $frm->{lang}; + + my $title = mt $s ? ('_staffe_title_edit', $s->{name}) : '_staffe_title_add'; + $self->htmlHeader(title => $title, noindex => 1); + $self->htmlMainTabs('s', $s, 'edit') if $s; + $self->htmlEditMessage('s', $s, $title); + $self->htmlForm({ frm => $frm, action => $s ? "/s$sid/edit" : '/s/new', editsum => 1, upload => 1 }, + staffe_geninfo => [ mt('_staffe_form_generalinfo'), + [ hidden => short => 'aid' ], + [ input => name => mt('_staffe_form_name'), short => 'name' ], + [ input => name => mt('_staffe_form_original'), short => 'original' ], + [ static => content => mt('_staffe_form_original_note') ], + [ text => name => mt('_staffe_form_note').'<br /><b class="standout">'.mt('_inenglish').'</b>', short => 'desc', rows => 4 ], + [ select => name => mt('_staffe_form_gender'),short => 'gender', options => [ + map [ $_, mt("_gender_$_") ], qw(unknown m f) ] ], + [ select => name => mt('_staffe_form_lang'), short => 'lang', + options => [ map [ $_, "$_ (".mt("_lang_$_").')' ], sort @{$self->{languages}} ] ], + [ input => name => mt('_staffe_form_wikipedia'), short => 'l_wp', pre => 'http://en.wikipedia.org/wiki/' ], + [ static => content => '<br />' ], + ], + + staffe_aliases => [ mt('_staffe_aliases'), + [ hidden => short => 'aliases' ], + [ static => nolabel => 1, content => sub { + table; + thead; Tr; + td class => 'tc_name', mt '_staffe_form_alias'; + td class => 'tc_original', mt '_staffe_form_original_alias'; td; end; + end; end; + tbody id => 'alias_tbl'; + # filled with javascript + end; + end; + h2 mt '_staffe_aliases_add'; + table; Tr id => 'alias_new'; + td class => 'tc_name'; + input id => 'alias_name', type => 'text', class => 'text'; end; + td class => 'tc_original'; + input id => 'alias_original', type => 'text', class => 'text'; end; + td class => 'tc_add'; + a href => '#', mt '_js_add'; end; + end; end; + }], + ]); + + $self->htmlFooter; +} + + +sub vn_edit { + my($self, $vid) = @_; + + my $v = $self->dbVNGet(id => $vid, what => 'changes')->[0]; + return $self->resNotFound if !$v->{id}; + + return $self->htmlDenied if !$self->authCan('edit') + || (($v->{locked} || $v->{hidden}) && !$self->authCan('dbmod')); + + my $s = $self->dbStaffGet(vid => $vid); + + my %b4 = ( + vid => $vid, + credits => join('|||', map sprintf('%d-%s-%s', $_->{aid}, $_->{role}, $_->{note}), @$s), + ); + my $frm; + if ($self->reqMethod eq 'POST') { + return if !$self->authCheckCode; + $frm = $self->formValidate ( + { post => 'vid', required => 1, template => 'int' }, + { post => 'credits', required => 0, maxlength => 5000, default => '' }, + ); + my @credits = map { /^(\d+)-([^-]+)-(.*)$/ ? [ $1, $2, $3 ]: () } split /\|\|\|/, $frm->{credits}; + if (!$frm->{_err}) { + # parse and normalize + $frm->{credits} = join('|||', map sprintf('%d-%s-%s', @$_), @credits); + + return $self->resRedirect("/v$vid/staff#staff", 'post') + if !grep $frm->{$_} ne $b4{$_}, keys %b4; + + $frm->{credits} = \@credits; + $frm->{editsum} = 'Edit staff'; + my $nrev = $self->dbItemEdit ('v' => $v->{cid}, %$frm); + return $self->resRedirect("/v$nrev->{iid}.$nrev->{rev}", 'post'); + } + } + $frm->{$_} //= $b4{$_} for keys %b4; + + my $title = mt ('_vnstaff_edit_title', $v->{title}); + $self->htmlHeader(title => $title, noindex => 1); + $self->htmlMainTabs('v', $v, 'edit'); + $self->htmlEditMessage('v', $v, $title); + + $self->htmlForm({ frm => $frm, action => "/v$vid/staff/edit" }, + vnstaffe_credits => [ mt('_vnstaff_edit_credits'), + [ hidden => short => 'vid' ], + [ hidden => short => 'credits' ], + [ static => nolabel => 1, content => sub { + table; tbody id => 'credits_tbl'; + Tr id => 'credits_loading'; td colspan => '4', mt('_js_loading'); end; + end; end; + h2 mt '_vnstaffe_add'; + table; Tr; + td class => 'tc_staff'; + input id => 'credit_input', type => 'text', class => 'text'; end; + td colspan => 3, ''; + end; end; + }], + ]); + + $self->htmlFooter; +} + + +sub list { + my ($self, $char) = @_; + + my $f = $self->formValidate( + { get => 'p', required => 0, default => 1, template => 'int' }, + { get => 'q', required => 0, default => '' }, + ); + return $self->resNotFound if $f->{_err}; + + my ($list, $np) = $self->dbStaffGet( + $char ne 'all' ? ( char => $char ) : (), + $f->{q} ? ( search => $f->{q} ) : (), + results => 150, + page => $f->{p} + ); + + return $self->resRedirect('/s'.$list->[0]{id}, 'temp') + if $f->{q} && @$list == 1 && $f->{p} == 1; + + $self->htmlHeader(title => mt '_sbrowse_title'); + + div class => 'mainbox'; + h1 mt '_sbrowse_title'; + form action => '/s/all', 'accept-charset' => 'UTF-8', method => 'get'; + $self->htmlSearchBox('s', $f->{q}); + end; + p class => 'browseopts'; + for ('all', 'a'..'z', 0) { + a href => "/s/$_", $_ eq $char ? (class => 'optselected') : (), $_ eq 'all' ? mt('_char_all') : $_ ? uc $_ : '#'; + } + end; + end; + + my $pageurl = "/s/$char" . ($f->{q} ? "?q=$f->{q}" : ''); + $self->htmlBrowseNavigate($pageurl, $f->{p}, $np, 't'); + div class => 'mainbox staffbrowse'; + h1 mt $f->{q} ? '_sbrowse_searchres' : '_sbrowse_list'; + if(!@$list) { + p mt '_sbrowse_noresults'; + } else { + # spread the results over 3 equivalent-sized lists + my $perlist = @$list/3 < 1 ? 1 : @$list/3; + for my $c (0..(@$list < 3 ? $#$list : 2)) { + ul; + for ($perlist*$c..($perlist*($c+1))-1) { + li; + my $gender = $list->[$_]{gender}; + cssicon "gen $gender", mt "_gender_$gender" if $gender ne 'unknown'; +# cssicon 'lang '.$list->[$_]{lang}, mt "_lang_$list->[$_]{lang}"; + a href => "/s$list->[$_]{id}", + title => $list->[$_]{original}, $list->[$_]{name}; + end; + } + end; + } + } + clearfloat; + end 'div'; + $self->htmlBrowseNavigate($pageurl, $f->{p}, $np, 'b'); + $self->htmlFooter; +} + + +sub staffxml { + my $self = shift; + + my $q = $self->formValidate( + { get => 'a', required => 0, multi => 1, template => 'int' }, + { get => 's', required => 0, multi => 1, template => 'int' }, + { get => 'q', required => 0, maxlength => 500 }, + ); + return $self->resNotFound if $q->{_err} || !(@{$q->{s}} || @{$q->{a}} || $q->{q}); + + my($list, $np) = $self->dbStaffGet( + @{$q->{s}} ? (id => $q->{s}) : + @{$q->{a}} ? (aid => $q->{a}) : + $q->{q} =~ /^s([1-9]\d*)/ ? (id => $1) : + (search => $q->{q}), + results => 10, + page => 1, + ); + + $self->resHeader('Content-type' => 'text/xml; charset=UTF-8'); + xml; + tag 'staff', more => $np ? 'yes' : 'no'; + for(@$list) { + tag 'item', id => $_->{id}, aid => $_->{aid}, $_->{name}; + } + end; +} + +1; +__END__ diff --git a/lib/VNDB/Handler/VNPage.pm b/lib/VNDB/Handler/VNPage.pm index 7d170ce8..be3f8a4c 100644 --- a/lib/VNDB/Handler/VNPage.pm +++ b/lib/VNDB/Handler/VNPage.pm @@ -13,7 +13,7 @@ TUWF::register( qr{v/rand} => \&rand, qr{v([1-9]\d*)/rg} => \&rg, qr{v([1-9]\d*)/releases} => \&releases, - qr{v([1-9]\d*)/(chars)} => \&page, + qr{v([1-9]\d*)/(chars|staff)} => \&page, qr{v([1-9]\d*)(?:\.([1-9]\d*))?} => \&page, ); @@ -513,7 +513,8 @@ sub page { my($self, $vid, $rev) = @_; my $char = $rev && $rev eq 'chars'; - $rev = undef if $char; + my $staff = $rev && $rev eq 'staff'; + $rev = undef if $char || $staff; my $v = $self->dbVNGet( id => $vid, @@ -646,25 +647,38 @@ sub page { end 'div'; # /mainbox my $haschar = $self->dbVNHasChar($v->{id}); - if($haschar || $self->authCan('edit')) { + my $hasstaff = $self->dbVNHasStaff($v->{id}); + if($haschar || $hasstaff || $self->authCan('edit')) { ul class => 'maintabs notfirst'; - if($haschar) { - li class => 'left '.(!$char ? ' tabselected' : ''); a href => "/v$v->{id}#main", name => 'main', mt '_vnpage_tab_main'; end; - li class => 'left '.( $char ? ' tabselected' : ''); a href => "/v$v->{id}/chars#chars", name => 'chars', mt '_vnpage_tab_chars'; end; + if($haschar || $hasstaff) { + li class => 'left '.(!($char || $staff) && ' tabselected'); a href => "/v$v->{id}#main", name => 'main', mt '_vnpage_tab_main'; end; + if ($haschar) { + li class => 'left '.($char && ' tabselected'); a href => "/v$v->{id}/chars#chars", name => 'chars', mt '_vnpage_tab_chars'; end; + } + if ($hasstaff) { + li class => 'left '.($staff && ' tabselected'); a href => "/v$v->{id}/staff#staff", name => 'staff', mt '_vnpage_tab_staff'; end; + } } if($self->authCan('edit')) { li; a href => "/c/new?vid=$v->{id}", mt '_vnpage_char_add'; end; + if(!$v->{locked}) { + li; + a href => "/v$v->{id}/staff/edit", mt $hasstaff ? '_vnpage_staff_edit' : '_vnpage_staff_add'; + end; + } li; a href => "/v$v->{id}/add", mt '_vnpage_rel_add'; end; } end; } - if(!$char) { + if($char) { + _chars($self, $haschar, $v); + } elsif ($staff) { + _staff($self, $hasstaff, $v); + } else { _releases($self, $v, $r); _stats($self, $v); _screenshots($self, $v, $r) if @{$v->{screenshots}}; - } else { - _chars($self, $haschar, $v); } $self->htmlFooter; @@ -1070,5 +1084,34 @@ sub _chars { } +sub _staff { + my ($self, $has, $v) = @_; + my $l = $has && $self->dbStaffGet(vid => $v->{id}, results => 100); + return if !$has; + div class => 'mainbox'; + table class => 'stripe'; + thead; + Tr; + td class => 'tc1', mt '_staff_col_role'; + td class => 'tc2', mt '_staff_col_credit'; + td class => 'tc3', mt '_staff_col_note'; + end; + end; + my $last_role = ''; + for my $s (@$l) { + Tr; + td class => 'tc1', $s->{role} ne $last_role ? mt '_credit_'.$s->{role} : ''; + td class => 'tc2'; + a href => "/s$s->{id}", title => $s->{original}||$s->{name}, $s->{name}; + end; + td class => 'tc3', $s->{note}; + end; + $last_role = $s->{role}; + } + end 'table'; + end; +} + + 1; diff --git a/lib/VNDB/Util/CommonHTML.pm b/lib/VNDB/Util/CommonHTML.pm index d4bba99f..8474f9c7 100644 --- a/lib/VNDB/Util/CommonHTML.pm +++ b/lib/VNDB/Util/CommonHTML.pm @@ -27,7 +27,7 @@ sub htmlMainTabs { return if $type eq 'g' && !$self->authCan('tagmod'); ul class => 'maintabs'; - if($type =~ /[uvrpc]/) { + if($type =~ /[uvrpcs]/) { li $sel eq 'hist' ? (class => 'tabselected') : (); a href => "/$id/hist", mt '_mtabs_hist'; end; @@ -73,7 +73,7 @@ sub htmlMainTabs { } if( $type eq 'u' && ($self->authInfo->{id} && $obj->{id} == $self->authInfo->{id} || $self->authCan('usermod')) - || $type =~ /[vrpc]/ && $self->authCan('edit') && ((!$obj->{locked} && !$obj->{hidden}) || $self->authCan('dbmod')) + || $type =~ /[vrpcs]/ && $self->authCan('edit') && ((!$obj->{locked} && !$obj->{hidden}) || $self->authCan('dbmod')) || $type =~ /[gi]/ && $self->authCan('tagmod') ) { li $sel eq 'edit' ? (class => 'tabselected') : (); @@ -284,8 +284,8 @@ sub revdiff { # Arguments: v/r/p, obj sub htmlEditMessage { my($self, $type, $obj, $title, $copy) = @_; - my $num = {v => 0, r => 1, p => 2, c => 3}->{$type}; - my $guidelines = {v => 2, r => 3, p => 4, c => 12}->{$type}; + my $num = {v => 0, r => 1, p => 2, c => 3, 's' => 4}->{$type}; + my $guidelines = {v => 2, r => 3, p => 4, c => 12, 's' => 16}->{$type}; div class => 'mainbox'; h1 $title; @@ -423,6 +423,7 @@ sub htmlSearchBox { a href => '/v/all', $sel eq 'v' ? (class => 'sel') : (), mt '_searchbox_vn'; a href => '/r', $sel eq 'r' ? (class => 'sel') : (), mt '_searchbox_releases'; a href => '/p/all', $sel eq 'p' ? (class => 'sel') : (), mt '_searchbox_producers'; + a href => '/s/all', $sel eq 's' ? (class => 'sel') : (), mt '_searchbox_staff'; a href => '/c/all', $sel eq 'c' ? (class => 'sel') : (), mt '_searchbox_chars'; a href => '/g', $sel eq 'g' ? (class => 'sel') : (), mt '_searchbox_tags'; a href => '/i', $sel eq 'i' ? (class => 'sel') : (), mt '_searchbox_traits'; diff --git a/lib/VNDB/Util/LayoutHTML.pm b/lib/VNDB/Util/LayoutHTML.pm index 7de7f709..128a18c7 100644 --- a/lib/VNDB/Util/LayoutHTML.pm +++ b/lib/VNDB/Util/LayoutHTML.pm @@ -66,6 +66,7 @@ sub _menu { b class => 'grayedout', '> '; a href => '/g', mt '_menu_tags'; br; a href => '/r', mt '_menu_releases'; br; a href => '/p/all', mt '_menu_producers'; br; + a href => '/s/all', mt '_menu_staff'; br; a href => '/c/all', mt '_menu_characters'; br; b class => 'grayedout', '> '; a href => '/i', mt '_menu_traits'; br; a href => '/u/all', mt '_menu_users'; br; @@ -102,6 +103,7 @@ sub _menu { if($self->authCan('edit')) { a href => '/v/add', mt '_menu_addvn'; br; a href => '/p/new', mt '_menu_addproducer'; br; + a href => '/s/new', mt '_menu_addstaff'; br; a href => '/c/new', mt '_menu_addcharacter'; br; } br; |