diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/VNDB/DB/Traits.pm | 138 | ||||
-rw-r--r-- | lib/VNDB/Func.pm | 71 | ||||
-rw-r--r-- | lib/VNDB/Handler/Tags.pm | 68 | ||||
-rw-r--r-- | lib/VNDB/Handler/Traits.pm | 82 |
4 files changed, 293 insertions, 66 deletions
diff --git a/lib/VNDB/DB/Traits.pm b/lib/VNDB/DB/Traits.pm new file mode 100644 index 00000000..81ac95e1 --- /dev/null +++ b/lib/VNDB/DB/Traits.pm @@ -0,0 +1,138 @@ + +package VNDB::DB::Traits; + +# This module is for a large part a copy of VNDB::DB::Tags. I could have chosen +# to modify that module to work for both traits and tags but that would have +# complicated the code, so I chose to maintain two versions with similar +# functionality instead. + +use strict; +use warnings; +use Exporter 'import'; + +our @EXPORT = qw|dbTraitGet dbTraitTree dbTraitEdit dbTraitAdd|; + + +# Options: id what results page sort reverse +# what: parents childs(n) aliases addedby +# sort: id name added +sub dbTraitGet { + my $self = shift; + my %o = ( + page => 1, + results => 10, + what => '', + @_, + ); + + my %where = ( + $o{id} ? ('t.id = ?' => $o{id}) : (), + ); + + my @select = ( + qw|t.id t.meta t.name t.description t.state|, + q|extract('epoch' from t.added) as added|, + $o{what} =~ /addedby/ ? ('t.addedby', 'u.username') : (), + ); + my @join = $o{what} =~ /addedby/ ? 'JOIN users u ON u.id = t.addedby' : (); + + my $order = sprintf { + id => 't.id %s', + name => 't.name %s', + added => 't.added %s', + }->{ $o{sort}||'id' }, $o{reverse} ? 'DESC' : 'ASC'; + + my($r, $np) = $self->dbPage(\%o, q| + SELECT !s + FROM traits t + !s + !W + ORDER BY !s|, + join(', ', @select), join(' ', @join), \%where, $order + ); + + if(@$r && $o{what} =~ /aliases/) { + my %r = map { + $_->{aliases} = []; + ($_->{id}, $_->{aliases}) + } @$r; + + push @{$r{$_->{trait}}}, $_->{alias} for (@{$self->dbAll(q| + SELECT trait, alias FROM traits_aliases WHERE trait IN(!l)|, [ keys %r ] + )}); + } + + if($o{what} =~ /parents\((\d+)\)/) { + $_->{parents} = $self->dbTraitTree($_->{id}, $1, 1) for(@$r); + } + + if($o{what} =~ /childs\((\d+)\)/) { + $_->{childs} = $self->dbTraitTree($_->{id}, $1) for(@$r); + } + + return wantarray ? ($r, $np) : $r; +} + + +# almost much equivalent to dbTagTree +sub dbTraitTree { + my($self, $id, $lvl, $back) = @_; + $lvl ||= 15; + my $r = $self->dbAll(q| + WITH RECURSIVE traittree(lvl, id, parent, name) AS ( + SELECT ?::integer, id, 0, name + FROM traits + !W + UNION ALL + SELECT tt.lvl-1, t.id, tt.id, t.name + FROM traittree tt + JOIN traits_parents tp ON !s + JOIN traits t ON !s + WHERE tt.lvl > 0 + AND t.state = 2 + ) SELECT DISTINCT id, parent, name FROM traittree ORDER BY name|, $lvl, + $id ? {'id = ?' => $id} : {'NOT EXISTS(SELECT 1 FROM traits_parents WHERE trait = id)' => 1, 'state = 2' => 1}, + !$back ? ('tp.parent = tt.id', 't.id = tp.trait') : ('tp.trait = tt.id', 't.id = tp.parent') + ); + for my $i (@$r) { + $i->{'sub'} = [ grep $_->{parent} == $i->{id}, @$r ]; + } + my @r = grep !delete($_->{parent}), @$r; + return $id ? $r[0]{'sub'} : \@r; +} + + +# args: trait id, %options->{ columns in the traits table + parents + aliases } +sub dbTraitEdit { + my($self, $id, %o) = @_; + + $self->dbExec('UPDATE traits !H WHERE id = ?', { + $o{upddate} ? ('added = NOW()' => 1) : (), + map exists($o{$_}) ? ("$_ = ?" => $o{$_}) : (), qw|name meta description state| + }, $id); + if($o{aliases}) { + $self->dbExec('DELETE FROM traits_aliases WHERE trait = ?', $id); + $self->dbExec('INSERT INTO traits_aliases (trait, alias) VALUES (?, ?)', $id, $_) for (@{$o{aliases}}); + } + if($o{parents}) { + $self->dbExec('DELETE FROM traits_parents WHERE trait = ?', $id); + $self->dbExec('INSERT INTO traits_parents (trait, parent) VALUES (?, ?)', $id, $_) for(@{$o{parents}}); + } +} + + +# same args as dbTraitEdit, without the first trait id +# returns the id of the new trait +sub dbTraitAdd { + my($self, %o) = @_; + my $id = $self->dbRow('INSERT INTO traits (name, meta, description, state, addedby) VALUES (!l, ?) RETURNING id', + [ map $o{$_}, qw|name meta description state| ], $o{addedby}||$self->authInfo->{id} + )->{id}; + $self->dbExec('INSERT INTO traits_parents (trait, parent) VALUES (?, ?)', $id, $_) for(@{$o{parents}}); + $self->dbExec('INSERT INTO traits_aliases (trait, alias) VALUES (?, ?)', $id, $_) for (@{$o{aliases}}); + return $id; +} + + +1; + diff --git a/lib/VNDB/Func.pm b/lib/VNDB/Func.pm index 435f0fec..20ade586 100644 --- a/lib/VNDB/Func.pm +++ b/lib/VNDB/Func.pm @@ -7,7 +7,7 @@ use TUWF ':html'; use Exporter 'import'; use POSIX 'strftime', 'ceil', 'floor'; use VNDBUtil; -our @EXPORT = (@VNDBUtil::EXPORT, qw| clearfloat cssicon tagscore mt minage fil_parse fil_serialize |); +our @EXPORT = (@VNDBUtil::EXPORT, qw| clearfloat cssicon tagscore mt minage fil_parse fil_serialize parenttags childtags |); # three ways to represent the same information @@ -105,5 +105,74 @@ sub fil_serialize { } grep defined($fil->{$_}), keys %$fil; } + +# generates a parent tags/traits listing +sub parenttags { + my($t, $index, $type) = @_; + p; + my @p = _parenttags(@{$t->{parents}}); + for my $p (@p ? @p : []) { + a href => "/$type", $index; #mt '_tagp_indexlink'; + for (reverse @$p) { + txt ' > '; + a href => "/$type$_->{id}", $_->{name}; + } + txt " > $t->{name}"; + br; + } + end 'p'; +} + +# arg: tag/trait hashref +# returns: [ [ tag1, tag2, tag3 ], [ tag1, tag2, tag5 ] ] +sub _parenttags { + my @r; + for my $t (@_) { + for (@{$t->{'sub'}}) { + push @r, [ $t, @$_ ] for _parenttags($_); + } + push @r, [$t] if !@{$t->{'sub'}}; + } + return @r; +} + + +# a child tags/traits box +sub childtags { + my($self, $title, $type, $t) = @_; + + div class => 'mainbox'; + h1 $title; + ul class => 'tagtree'; + for my $p (sort { @{$b->{'sub'}} <=> @{$a->{'sub'}} } @{$t->{childs}}) { + li; + a href => "/$type$p->{id}", $p->{name}; + b class => 'grayedout', " ($p->{c_vns})" if $type eq 'g' && $p->{c_vns}; + end, next if !@{$p->{'sub'}}; + ul; + for (0..$#{$p->{'sub'}}) { + last if $_ >= 5 && @{$p->{'sub'}} > 6; + li; + txt '> '; + a href => "/$type$p->{sub}[$_]{id}", $p->{'sub'}[$_]{name}; + b class => 'grayedout', " ($p->{sub}[$_]{c_vns})" if $type eq 'g' && $p->{'sub'}[$_]{c_vns}; + end; + } + if(@{$p->{'sub'}} > 6) { + li; + txt '> '; + a href => "/$type$p->{id}", style => 'font-style: italic', mt $type eq 'g' ? '_tagp_moretags' : '_traitp_more', @{$p->{'sub'}}-5; + end; + } + end; + end 'li'; + } + end 'ul'; + clearfloat; + br; + end 'div'; +} + + 1; diff --git a/lib/VNDB/Handler/Tags.pm b/lib/VNDB/Handler/Tags.pm index cff5d980..6e48cc26 100644 --- a/lib/VNDB/Handler/Tags.pm +++ b/lib/VNDB/Handler/Tags.pm @@ -78,18 +78,7 @@ sub tagpage { a class => 'addnew', href => "/g$tag/add", mt '_tagp_addchild' if $self->authCan('tag') && $t->{state} != 1; h1 $title; - p; - my @p = _parenttags(@{$t->{parents}}); - for my $p (@p ? @p : []) { - a href => '/g', mt '_tagp_indexlink'; - for (reverse @$p) { - txt ' > '; - a href => "/g$_->{id}", $_->{name}; - } - txt " > $t->{name}"; - br; - } - end 'p'; + parenttags($t, mt('_tagp_indexlink'), 'g'); if($t->{description}) { p class => 'description'; @@ -110,7 +99,7 @@ sub tagpage { } end 'div'; - _childtags($self, $t) if @{$t->{childs}}; + childtags($self, mt('_tagp_childs'), 'g', $t) if @{$t->{childs}}; if(!$t->{meta} && $t->{state} == 2) { form action => "/g$t->{id}", 'accept-charset' => 'UTF-8', method => 'get'; @@ -142,57 +131,6 @@ sub tagpage { } -# arg: tag hashref -# returns: [ [ tag1, tag2, tag3 ], [ tag1, tag2, tag5 ] ] -sub _parenttags { - my @r; - for my $t (@_) { - for (@{$t->{'sub'}}) { - push @r, [ $t, @$_ ] for _parenttags($_); - } - push @r, [$t] if !@{$t->{'sub'}}; - } - return @r; -} - - -# used for on both /g and /g+ -sub _childtags { - my($self, $t, $index) = @_; - - div class => 'mainbox'; - h1 mt $index ? '_tagp_tree' : '_tagp_childs'; - ul class => 'tagtree'; - for my $p (sort { @{$b->{'sub'}} <=> @{$a->{'sub'}} } @{$t->{childs}}) { - li; - a href => "/g$p->{id}", $p->{name}; - b class => 'grayedout', " ($p->{c_vns})" if $p->{c_vns}; - end, next if !@{$p->{'sub'}}; - ul; - for (0..$#{$p->{'sub'}}) { - last if $_ >= 5 && @{$p->{'sub'}} > 6; - li; - txt '> '; - a href => "/g$p->{sub}[$_]{id}", $p->{'sub'}[$_]{name}; - b class => 'grayedout', " ($p->{sub}[$_]{c_vns})" if $p->{'sub'}[$_]{c_vns}; - end; - } - if(@{$p->{'sub'}} > 6) { - li; - txt '> '; - a href => "/g$p->{id}", style => 'font-style: italic', mt '_tagp_moretags', @{$p->{'sub'}}-5; - end; - } - end; - end 'li'; - } - end 'ul'; - clearfloat; - br; - end 'div'; -} - - sub tagedit { my($self, $tag, $act) = @_; @@ -687,7 +625,7 @@ sub tagindex { end; my $t = $self->dbTagTree(0, 2); - _childtags($self, {childs => $t}, 1); + childtags($self, mt('_tagp_tree'), 'g', {childs => $t}); table class => 'mainbox threelayout'; Tr; diff --git a/lib/VNDB/Handler/Traits.pm b/lib/VNDB/Handler/Traits.pm new file mode 100644 index 00000000..640af81e --- /dev/null +++ b/lib/VNDB/Handler/Traits.pm @@ -0,0 +1,82 @@ + +package VNDB::Handler::Traits; + +use strict; +use warnings; +use TUWF ':html'; +use VNDB::Func; + + +TUWF::register( + qr{i([1-9]\d*)}, \&traitpage, +); + + +sub traitpage { + my($self, $trait) = @_; + + my $t = $self->dbTraitGet(id => $trait, what => 'parents(0) childs(2) aliases')->[0]; + return $self->resNotFound if !$t; + + my $title = mt '_traitp_title', $t->{meta}?0:1, $t->{name}; + $self->htmlHeader(title => $title, noindex => $t->{state} != 2); + + if($t->{state} != 2) { + div class => 'mainbox'; + h1 $title; + if($t->{state} == 1) { + div class => 'warning'; + h2 mt '_traitp_del_title'; + p; + lit mt '_traitp_del_msg'; + end; + end; + } else { + div class => 'notice'; + h2 mt '_traitp_pending_title'; + p mt '_traitp_pending_msg'; + end; + } + end 'div'; + } + + div class => 'mainbox'; + h1 $title; + + parenttags($t, mt('_traitp_indexlink'), 'i'); + + if($t->{description}) { + p class => 'description'; + lit bb2html $t->{description}; + end; + } + if(@{$t->{aliases}}) { + p class => 'center'; + b mt('_traitp_aliases'); + br; + lit xml_escape($_).'<br />' for (@{$t->{aliases}}); + end; + } + end 'div'; + + childtags($self, mt('_traitp_childs'), 'i', $t) if @{$t->{childs}}; + + # TODO: list of characters + + $self->htmlFooter; +} + + +1; + +__END__ + +Simple test database: + + INSERT INTO traits (name, description, state, meta, addedby) VALUES + ('Blood Type', 'Describes the blood type of the character', 2, true, 2), + ('Blood Type O', '', 2, true, 2), + ('Blood Type B', '', 2, true, 2); + INSERT INTO traits_parents (trait, parent) VALUES (2, 1), (3, 1); + + |