diff options
-rw-r--r-- | data/style.css | 8 | ||||
-rw-r--r-- | lib/VNDB/DB/Tags.pm | 55 | ||||
-rw-r--r-- | lib/VNDB/Handler/Tags.pm | 95 | ||||
-rw-r--r-- | util/updates/update_2.3.sql | 89 |
4 files changed, 247 insertions, 0 deletions
diff --git a/data/style.css b/data/style.css index 59ef3008..8d3cccef 100644 --- a/data/style.css +++ b/data/style.css @@ -963,6 +963,14 @@ ul#catselect li li.exc { background-position: 0px -33px; color: $statnok$; } +/***** Tag page *****/ + +.tagtree { margin-left: 20px; list-style-type: none } +.tagtree ul { margin-left: 10px; list-style-type: none } + + + + /***** Warning/Notice Box *****/ div.warning, div.notice { diff --git a/lib/VNDB/DB/Tags.pm b/lib/VNDB/DB/Tags.pm new file mode 100644 index 00000000..5d0263fb --- /dev/null +++ b/lib/VNDB/DB/Tags.pm @@ -0,0 +1,55 @@ + +package VNDB::DB::Tags; + +use strict; +use warnings; +use Exporter 'import'; + +our @EXPORT = qw|dbTagGet|; + + +# %options->{ id page results order what } +# what: parents childs(n) +sub dbTagGet { + my $self = shift; + my %o = ( + order => 't.id ASC', + page => 1, + results => 10, + what => '', + @_ + ); + + my %where = ( + $o{id} ? ( + 't.id = ?' => $o{id} ) : (), + ); + + my($r, $np) = $self->dbPage(\%o, q| + SELECT t.id, t.meta, t.name, t.aliases, t.description + FROM tags t + !W + ORDER BY !s|, + \%where, $o{order} + ); + + if($o{what} =~ /parents/) { + $_->{parents} = $self->dbAll(q|SELECT lvl, tag, name FROM tag_tree(?, -1, false)|, $_->{id}) for (@$r); + } + + if($o{what} =~ /childs\((\d+)\)/) { + $_->{childs} = $self->dbAll(q|SELECT lvl, tag, name FROM tag_tree(?, ?, true)|, $_->{id}, $1) for (@$r); + } + + #if(@$r && $o{what} =~ /(?:parents)/) { + #my %r = map { + # ($r->[$_]{id}, $_) + #} 0..$#$r; + #} + + return wantarray ? ($r, $np) : $r; +} + + +1; + diff --git a/lib/VNDB/Handler/Tags.pm b/lib/VNDB/Handler/Tags.pm new file mode 100644 index 00000000..0dfcc9bc --- /dev/null +++ b/lib/VNDB/Handler/Tags.pm @@ -0,0 +1,95 @@ + +package VNDB::Handler::Tags; + + +use strict; +use warnings; +use YAWF ':html'; +use VNDB::Func; + + +YAWF::register( + qr{g([1-9]\d*)}, \&tagpage, + qr{g}, \&tagtree, +); + + +sub tagpage { + my($self, $tag) = @_; + + # fetch tag + my $t = $self->dbTagGet(id => $tag, what => 'parents childs(2)')->[0]; + return 404 if !$t; + + my $title = ($t->{meta} ? 'Meta tag: ' : 'Tag: ').$t->{name}; + $self->htmlHeader(title => $title); + div class => 'mainbox'; + h1 $title; + h2 class => 'alttitle', 'a.k.a. '.join(', ', split /\n/, $t->{aliases}) if $t->{aliases}; + + # TODO: handle multiple parents here + p; + a href => '/g', 'Tags'; + for (sort { $a->{lvl} <=> $b->{lvl} } @{$t->{parents}}) { + txt ' > '; + a href => "/g$_->{tag}", $_->{name}; + } + txt ' > '.$t->{name}; + end; + + if($t->{description}) { + p; + lit bb2html $t->{description}; + end; + } + + if(@{$t->{childs}}) { + ul class => 'tagtree'; + li 'Child tags'; + my $lvl = $t->{childs}[0]{lvl} + 1; + for (@{$t->{childs}}) { + map ul, 1..($lvl-$_->{lvl}) if $lvl > $_->{lvl}; + map end, 1..($_->{lvl}-$lvl) if $lvl < $_->{lvl}; + $lvl = $_->{lvl}; + li; + txt ' > '; + a href => "/g$_->{tag}", $_->{name}; + end; + } + map end, 0..($t->{childs}[0]{lvl}-$lvl); + end; + } + + end; + $self->htmlFooter; +} + + +sub tagtree { + my $self = shift; + + $self->htmlHeader(title => '[DEBUG] The complete tag tree'); + div class => 'mainbox'; + h1 '[DEBUG] The complete tag tree'; + + my $t = $self->dbAll('SELECT * FROM tag_tree(0, -1, true)'); + ul class => 'tagtree'; + li "This page won't make it to the final version. (At least, not in this form)\n\n"; + my $lvl = $t->[0]{lvl} + 1; + for (@$t) { + map ul, 1..($lvl-$_->{lvl}) if $lvl > $_->{lvl}; + map end, 1..($_->{lvl}-$lvl) if $lvl < $_->{lvl}; + $lvl = $_->{lvl}; + li; + txt ' > '; + a href => "/g$_->{tag}", $_->{name}; + end; + } + map end, 0..($t->[0]{lvl}-$lvl); + end; + end; + $self->htmlFooter; +} + + +1; diff --git a/util/updates/update_2.3.sql b/util/updates/update_2.3.sql index d43718c9..9ae226df 100644 --- a/util/updates/update_2.3.sql +++ b/util/updates/update_2.3.sql @@ -9,3 +9,92 @@ CREATE TABLE quotes ( -- catalog numbers for releases ALTER TABLE releases_rev ADD COLUMN catalog varchar(50) NOT NULL DEFAULT ''; + + + + +-- tagging system + +CREATE TABLE tags ( + id SERIAL NOT NULL PRIMARY KEY, + name varchar(250) NOT NULL UNIQUE, + aliases text NOT NULL DEFAULT '', + description text NOT NULL DEFAULT '', + meta boolean NOT NULL DEFAULT FALSE +) WITHOUT OIDS; + +CREATE TABLE tags_parents ( + tag integer NOT NULL REFERENCES tags (id) DEFERRABLE INITIALLY DEFERRED, + parent integer NOT NULL REFERENCES tags (id) DEFERRABLE INITIALLY DEFERRED, + PRIMARY KEY(tag, parent) +) WITHOUT OIDS; + +CREATE TABLE tags_vn ( + tag integer NOT NULL REFERENCES tags (id) DEFERRABLE INITIALLY DEFERRED, + vid integer NOT NULL REFERENCES vn (id) DEFERRABLE INITIALLY DEFERRED, + uid integer NOT NULL REFERENCES users (id) DEFERRABLE INITIALLY DEFERRED, + vote smallint NOT NULL DEFAULT 3, -- -3..3 (0 isn't actually used...) + spoiler boolean NOT NULL DEFAULT FALSE, + PRIMARY KEY(tag, vid, uid) +) WITHOUT OIDS; + + +CREATE TYPE tag_tree_item AS (lvl smallint, tag integer, name text); + +-- tag: tag to start with, +-- lvl: recursion level +-- dir: direction, true = parent->child, false = child->parent +CREATE OR REPLACE FUNCTION tag_tree(tag integer, lvl integer, dir boolean) RETURNS SETOF tag_tree_item AS $$ +DECLARE + r tag_tree_item%rowtype; + r2 tag_tree_item%rowtype; +BEGIN + IF dir AND tag = 0 THEN + FOR r IN + SELECT lvl, t.id, t.name + FROM tags t + WHERE NOT EXISTS(SELECT 1 FROM tags_parents tp WHERE tp.tag = t.id) + ORDER BY t.name + LOOP + RETURN NEXT r; + IF lvl-1 <> 0 THEN + FOR r2 IN SELECT * FROM tag_tree(r.tag, lvl-1, dir) LOOP + RETURN NEXT r2; + END LOOP; + END IF; + END LOOP; + ELSIF dir THEN + FOR r IN + SELECT lvl, tp.tag, t.name + FROM tags_parents tp + JOIN tags t ON t.id = tp.tag + WHERE tp.parent = tag + ORDER BY t.name + LOOP + RETURN NEXT r; + IF lvl-1 <> 0 THEN + FOR r2 IN SELECT * FROM tag_tree(r.tag, lvl-1, dir) LOOP + RETURN NEXT r2; + END LOOP; + END IF; + END LOOP; + ELSE + FOR r IN + SELECT lvl, tp.parent, t.name + FROM tags_parents tp + JOIN tags t ON t.id = tp.parent + WHERE tp.tag = tag + ORDER BY t.name + LOOP + RETURN NEXT r; + IF lvl-1 <> 0 THEN + FOR r2 IN SELECT * FROM tag_tree(r.tag, lvl-1, dir) LOOP + RETURN NEXT r2; + END LOOP; + END IF; + END LOOP; + END IF; +END; +$$ LANGUAGE plpgsql; + + |