summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/VNDB/DB/Traits.pm138
-rw-r--r--lib/VNDB/Func.pm71
-rw-r--r--lib/VNDB/Handler/Tags.pm68
-rw-r--r--lib/VNDB/Handler/Traits.pm82
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);
+
+