]> ruin.nu Git - ndwebbie.git/commitdiff
Login/Logout and session support with roles + convert to html 4.01.
authorMichael Andreen <harv@ruin.nu>
Tue, 17 Jun 2008 22:25:09 +0000 (00:25 +0200)
committerMichael Andreen <harv@ruin.nu>
Tue, 17 Jun 2008 22:25:09 +0000 (00:25 +0200)
Roles give a fine-grained access control. Roles can be shared by
different groups, so there is no need to check for more than one
role in most cases.

22 files changed:
ND.pm [deleted file]
NDWeb/AuthHandler.pm [deleted file]
NDWeb/Include.pm [deleted file]
NDWeb/Page.pm [deleted file]
NDWeb/XMLPage.pm [deleted file]
database/group_roles.sql [new file with mode: 0644]
lib/Catalyst/Plugin/Authentication/Store/NDWeb.pm [new file with mode: 0644]
lib/ND
lib/NDWeb.pm
lib/NDWeb/Auth/User.pm [new file with mode: 0644]
lib/NDWeb/Controller/Root.pm
lib/NDWeb/Include.pm [new file with mode: 0644]
lib/NDWeb/View/TT.pm
root/lib/config/main.tt2
root/lib/inc/targetlist.tt2 [new file with mode: 0644]
root/lib/site/html.tt2
root/lib/site/layout.tt2
root/lib/site/leftbar.tt2
root/src/access_denied.tt2 [new file with mode: 0644]
root/static/default.css
templates/NoAccess.tmpl [deleted file]
templates/targetlist.tmpl [deleted file]

diff --git a/ND.pm b/ND.pm
deleted file mode 100755 (executable)
index e9bc401..0000000
--- a/ND.pm
+++ /dev/null
@@ -1,65 +0,0 @@
-#!/usr/bin/perl -w -T
-#**************************************************************************
-#   Copyright (C) 2006 by Michael Andreen <harvATruinDOTnu>               *
-#                                                                         *
-#   This program is free software; you can redistribute it and/or modify  *
-#   it under the terms of the GNU General Public License as published by  *
-#   the Free Software Foundation; either version 2 of the License, or     *
-#   (at your option) any later version.                                   *
-#                                                                         *
-#   This program is distributed in the hope that it will be useful,       *
-#   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
-#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
-#   GNU General Public License for more details.                          *
-#                                                                         *
-#   You should have received a copy of the GNU General Public License     *
-#   along with this program; if not, write to the                         *
-#   Free Software Foundation, Inc.,                                       *
-#   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
-#**************************************************************************/
-
-package ND;
-use CGI qw/:standard/;
-use DBI;
-use DBD::Pg qw(:pg_types);
-use Apache2::Request;
-use Apache2::Response;
-use Apache2::RequestUtil;
-use ND::DB;
-use NDWeb::Page;
-use strict;
-use warnings;
-
-$SIG{__WARN__} = sub {$ND::ERROR .= p $_[0]};
-
-chdir '/var/www/ndawn';
-
-sub handler {
-       my $r = shift;
-       my $req = Apache2::Request->new($r, POST_MAX => "1M");
-       local $ND::DBH = ND::DB::DB();
-       local $ND::UID;
-       local $ND::ERROR;
-       my $page = $req->param('page');
-       $r->no_cache;
-
-       if ($ENV{'SCRIPT_NAME'} =~ /(\w+)(\.(pl|php|pm))?$/){
-               $page = $1 unless $1 eq 'index' and $3 eq 'pl';
-       }
-       $page = NDWeb::Page->new(PAGE => $page, DBH => $ND::DBH, URI => $ENV{REQUEST_URI}, USER_AGENT => $ENV{HTTP_USER_AGENT}, HTTP_ACCEPT => $ENV{HTTP_ACCEPT}, R => $r);
-       $page->render;
-
-       $ND::DBH->rollback unless $ND::DBH->{AutoCommit};
-       $ND::DBH->disconnect;
-
-       if ($page->{RETURN}){
-               if($page->{RETURN} eq 'REDIRECT'){
-                       $r->headers_out->set(Location => $page->{REDIR_LOCATION});
-                       $r->status(Apache2::Const::REDIRECT);
-                       $r->rflush;
-               }
-       }
-       return Apache2::Const::OK;
-}
-
-1;
diff --git a/NDWeb/AuthHandler.pm b/NDWeb/AuthHandler.pm
deleted file mode 100644 (file)
index 086d46b..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-#!/usr/bin/perl -w -T
-#**************************************************************************
-#   Copyright (C) 2006 by Michael Andreen <harvATruinDOTnu>               *
-#                                                                         *
-#   This program is free software; you can redistribute it and/or modify  *
-#   it under the terms of the GNU General Public License as published by  *
-#   the Free Software Foundation; either version 2 of the License, or     *
-#   (at your option) any later version.                                   *
-#                                                                         *
-#   This program is distributed in the hope that it will be useful,       *
-#   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
-#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
-#   GNU General Public License for more details.                          *
-#                                                                         *
-#   You should have received a copy of the GNU General Public License     *
-#   along with this program; if not, write to the                         *
-#   Free Software Foundation, Inc.,                                       *
-#   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
-#**************************************************************************/
-
-package NDWeb::AuthHandler;
-use strict;
-use warnings FATAL => 'all';
-
-use ND::DB;
-use Apache2::Access ();
-
-sub handler {
-       my $r = shift;
-       my($res, $sent_pw) = $r->get_basic_auth_pw;
-       return $res if $res != Apache2::Const::OK;
-
-       my $dbh = ND::DB::DB();
-       my ($username) = $dbh->selectrow_array(q{SELECT username FROM users WHERE
-               lower(username) = lower(?) AND password = MD5(?)},undef,$r->user,$sent_pw);
-       $dbh->disconnect;
-       if ($username){
-               $r->user($username);
-               return Apache2::Const::OK;
-       }
-       $r->note_basic_auth_failure();
-       return Apache2::Const::AUTH_REQUIRED;
-}
-
-1;
diff --git a/NDWeb/Include.pm b/NDWeb/Include.pm
deleted file mode 100644 (file)
index 5794b46..0000000
+++ /dev/null
@@ -1,91 +0,0 @@
-#**************************************************************************
-#   Copyright (C) 2006 by Michael Andreen <harvATruinDOTnu>               *
-#                                                                         *
-#   This program is free software; you can redistribute it and/or modify  *
-#   it under the terms of the GNU General Public License as published by  *
-#   the Free Software Foundation; either version 2 of the License, or     *
-#   (at your option) any later version.                                   *
-#                                                                         *
-#   This program is distributed in the hope that it will be useful,       *
-#   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
-#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
-#   GNU General Public License for more details.                          *
-#                                                                         *
-#   You should have received a copy of the GNU General Public License     *
-#   along with this program; if not, write to the                         *
-#   Free Software Foundation, Inc.,                                       *
-#   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
-#**************************************************************************/
-
-package NDWeb::Include;
-use strict;
-use warnings;
-use CGI qw{:standard};
-require Exporter;
-use BBCode::Parser;
-
-our @ISA = qw/Exporter/;
-
-our @EXPORT = qw/parseMarkup min max
-       alliances intelquery /;
-
-sub parseMarkup ($) {
-       my ($text) = @_;
-
-       #$text =~ s{\n}{\n<br/>}g;
-       #$text =~ s{\[B\](.*?)\[/B\]}{<b>$1</b>}gi;
-       #$text =~ s{\[I\](.*?)\[/I\]}{<i>$1</i>}gi;
-       #$text =~ s{\[url\](.*?)\[/url\]}{<a href="$1">$1</a>}gi;
-       #$text =~ s{\[PRE\](.*?)\[/PRE\]}{<pre>$1</pre>}sgi;
-       #$text =~ s{\[PRE\](.*?)\[/PRE\]}{<pre>$1</pre>}sgi;
-       #$1 =~ s{<br/>}{}g;
-
-       eval{
-               my $tree = BBCode::Parser->DEFAULT->parse($text);
-               $text = $tree->toHTML;
-       };
-       $text =~ s/\x{3}\d\d?//g; #mirc color TODO: possibly match until \x{0F} and change to [color] block
-       $text =~ s/[^\x{9}\x{A}\x{D}\x{20}-\x{D7FF}\x{E000}-\x{FFFD}\x{10000}-\x{10FFFF}]//g;
-       return $text;
-}
-
-
-sub min {
-    my ($x,$y) = @_;
-    return ($x > $y ? $y : $x);
-}
-
-sub max {
-    my ($x,$y) = @_;
-    return ($x < $y ? $y : $x);
-}
-
-
-sub alliances {
-       my ($alliance) = @_;
-       my @alliances;
-       $alliance = -1 unless defined $alliance;
-       push @alliances,{Id => -1, Name => '', Selected => not $alliance};
-       my $query = $ND::DBH->prepare(q{SELECT id,name FROM alliances ORDER BY LOWER(name)});
-       $query->execute;        
-       while (my $ally = $query->fetchrow_hashref){
-               push @alliances,{Id => $ally->{id}, Name => $ally->{name}, Selected => $alliance == $ally->{id}};
-       }
-       return @alliances;
-}
-
-sub intelquery {
-       my ($columns,$where) = @_;
-       return qq{
-SELECT $columns, i.mission, i.tick AS landingtick,MIN(i.eta) AS eta, i.amount, i.ingal, u.username
-FROM (fleets i NATURAL JOIN users u)
-       JOIN current_planet_stats t ON i.target = t.id
-       JOIN current_planet_stats o ON i.sender = o.id
-WHERE $where 
-GROUP BY i.tick,i.mission,t.x,t.y,t.z,o.x,o.y,o.z,i.amount,i.ingal,u.username,t.alliance,o.alliance,t.nick,o.nick
-ORDER BY i.tick DESC, i.mission};
-}
-
-
-
-1;
diff --git a/NDWeb/Page.pm b/NDWeb/Page.pm
deleted file mode 100644 (file)
index e5e703d..0000000
+++ /dev/null
@@ -1,119 +0,0 @@
-#**************************************************************************
-#   Copyright (C) 2006 by Michael Andreen <harvATruinDOTnu>               *
-#                                                                         *
-#   This program is free software; you can redistribute it and/or modify  *
-#   it under the terms of the GNU General Public License as published by  *
-#   the Free Software Foundation; either version 2 of the License, or     *
-#   (at your option) any later version.                                   *
-#                                                                         *
-#   This program is distributed in the hope that it will be useful,       *
-#   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
-#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
-#   GNU General Public License for more details.                          *
-#                                                                         *
-#   You should have received a copy of the GNU General Public License     *
-#   along with this program; if not, write to the                         *
-#   Free Software Foundation, Inc.,                                       *
-#   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
-#**************************************************************************/
-package NDWeb::Page;
-use strict;
-use warnings;
-use CGI qw/:standard/;
-
-our %PAGES;
-
-sub new {
-       my $invocant = shift;
-       my $class = ref($invocant) || $invocant;
-       my $self = {@_};
-       $self->{PAGE} = 'main' unless (defined $self->{PAGE} and exists $PAGES{$self->{PAGE}});
-       $class = $PAGES{$self->{PAGE}};
-       bless $self, $class;
-       $self->parse;
-       $self->initiate;
-       return $self;
-}
-
-sub initiate : method {
-       my $self = shift;
-       my $DBH = $self->{DBH};
-
-       $DBH->do(q{SET timezone = 'GMT'});
-
-       ($self->{UID},$self->{PLANET},$self->{USER}) = $DBH->selectrow_array('SELECT uid,planet,username FROM users WHERE username ILIKE ?'
-               ,undef,$ENV{'REMOTE_USER'});
-       $ND::UID = $self->{UID};
-
-       ($self->{TICK}) = $DBH->selectrow_array('SELECT tick()',undef);
-       $self->{TICK} = 0 unless defined $self->{TICK};
-
-
-       my $query = $DBH->prepare('SELECT groupname,attack,gid from groupmembers NATURAL JOIN groups WHERE uid = ?');
-       $query->execute($self->{UID});
-
-       while (my ($name,$attack,$gid) = $query->fetchrow()){
-               $self->{GROUPS}{$name} = $gid;
-               $self->{ATTACKER} = 1 if $attack;
-       }
-
-
-}
-
-sub parse : method {
-}
-
-sub render_body : method {
-       return "";
-}
-
-sub render : method {
-       my $self = shift;
-
-       print header;
-       print $self->render_body;
-}
-
-sub isInGroup ($) : method {
-       my $self = shift;
-       my $group = shift;
-       return exists $self->{GROUPS}{$group} || exists $self->{GROUPS}{Tech} || exists $self->{GROUPS}{HC};
-}
-
-sub isMember () : method {
-       my $self = shift;
-       $self->isInGroup('Members');
-}
-
-sub isHC () : method {
-       my $self = shift;
-       $self->isInGroup('HC');
-}
-
-sub isDC () : method {
-       $_[0]->isInGroup('DC');
-}
-
-sub isBC () : method {
-       $_[0]->isInGroup('BC');
-}
-
-sub isOfficer () : method {
-       $_[0]->isInGroup('Officers');
-}
-
-sub isScanner () : method {
-       $_[0]->isInGroup('Scanners');
-}
-
-sub isIntel () : method {
-       $_[0]->isInGroup('Intel');
-}
-
-sub isTech () : method {
-       $_[0]->isInGroup('Tech');
-}
-
-
-
-1;
diff --git a/NDWeb/XMLPage.pm b/NDWeb/XMLPage.pm
deleted file mode 100644 (file)
index 288bfb2..0000000
+++ /dev/null
@@ -1,141 +0,0 @@
-#**************************************************************************
-#   Copyright (C) 2006 by Michael Andreen <harvATruinDOTnu>               *
-#                                                                         *
-#   This program is free software; you can redistribute it and/or modify  *
-#   it under the terms of the GNU General Public License as published by  *
-#   the Free Software Foundation; either version 2 of the License, or     *
-#   (at your option) any later version.                                   *
-#                                                                         *
-#   This program is distributed in the hope that it will be useful,       *
-#   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
-#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
-#   GNU General Public License for more details.                          *
-#                                                                         *
-#   You should have received a copy of the GNU General Public License     *
-#   along with this program; if not, write to the                         *
-#   Free Software Foundation, Inc.,                                       *
-#   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
-#**************************************************************************/
-
-package NDWeb::XMLPage;
-use strict;
-use warnings;
-use CGI qw/:standard/;
-use HTML::Template;
-
-use ND::Include;
-use NDWeb::Page;
-use NDWeb::Include;
-
-use base qw/NDWeb::Page/;
-
-sub noAccess () {
-       HTML::Template->new(filename => 'templates/NoAccess.tmpl', global_vars => 1, cache => 1);
-};
-
-sub process : method {
-}
-
-sub listTargets () : method {
-       my $self = shift;
-       my $DBH = $self->{DBH};
-       my $query = $DBH->prepare(qq{SELECT t.id, r.id AS raid, r.tick+c.wave-1 AS landingtick, 
-               (released_coords AND old_claim(timestamp)) AS released_coords, coords(x,y,z),c.launched,c.wave,c.joinable
-FROM raid_claims c
-       JOIN raid_targets t ON c.target = t.id
-       JOIN raids r ON t.raid = r.id
-       JOIN current_planet_stats p ON t.planet = p.id
-WHERE c.uid = ? AND r.tick+c.wave > ? AND r.open AND not r.removed
-ORDER BY r.tick+c.wave,x,y,z});
-       $query->execute($ND::UID,$self->{TICK});
-       my @targets;
-       while (my $target = $query->fetchrow_hashref){
-               my $coords = "Target $target->{id}";
-               $coords = $target->{coords} if $target->{released_coords};
-               push @targets,{Coords => $coords, Launched => $target->{launched}, Raid => $target->{raid}
-                       , Target => $target->{id}, Tick => $target->{landingtick}, Wave => $target->{wave}
-                       , AJAX => $self->{AJAX}, JoinName => $target->{joinable} ? 'N' : 'J'
-                       , Joinable => $target->{joinable} ? 'FALSE' : 'TRUE', JoinableTitle => $target->{joinable} ? 'Disable join' : 'Make target joinable'};
-       }
-       my $template = HTML::Template->new(filename => "templates/targetlist.tmpl", cache => 1);
-       $template->param(Targets => \@targets);
-       return $template->output;
-}
-
-
-sub render : method {
-       my $self = shift;
-       my $DBH = $self->{DBH};
-
-
-       chdir '/var/www/ndawn/code';
-
-       my $template = HTML::Template->new(filename => 'templates/skel.tmpl', global_vars => 1, cache => 1);
-
-       my $TICK = $self->{TICK};
-       my $ATTACKER = $self->{ATTACKER};
-
-       $self->{XML} = 0;
-       $self->{AJAX} = 1;
-
-       $self->process;
-
-       my $type = 'text/html';
-       if ($self->{HTTP_ACCEPT} =~ m{application/xhtml\+xml}){
-               $type = 'application/xhtml+xml'
-       }
-       my $body;
-       if ($self->{XML}){
-               $type = 'text/xml';
-               $template = HTML::Template->new(filename => "templates/xml.tmpl", cache => 1);
-               $body = HTML::Template->new(filename => "templates/$self->{PAGE}.xml.tmpl", cache => 1);
-       }else{
-               $body = HTML::Template->new(filename => "templates/$self->{PAGE}.tmpl", global_vars => 1
-                       , cache => 1, loop_context_vars => 1, default_escape => 'HTML');
-               $body->param(PAGE => $self->{PAGE});
-       }
-
-       $body = $self->render_body($body);
-
-       unless ($body){
-               return;
-       }
-
-       unless ($self->{XML}){
-               #TODO: Need to fix this with new stuff.
-               my $fleetupdate = $DBH->selectrow_array(q{SELECT tick FROM fleets WHERE sender = ? AND mission = 'Full fleet' AND tick > tick() - 24},undef,$self->{PLANET});
-
-               $fleetupdate = 0 unless defined $fleetupdate;
-
-               my ($last_forum_visit) = $DBH->selectrow_array(q{SELECT last_forum_visit FROM users WHERE uid = $1}
-                       ,undef,$self->{UID}) or $ND::ERROR .= p($DBH->errstr);
-               my ($unread,$newposts) = $DBH->selectrow_array(unread_query(),undef,$self->{UID},$last_forum_visit)
-                       or $ND::ERROR .= p($DBH->errstr);
-               
-               $template->param(UnreadPosts => $unread);
-               $template->param(NewPosts => $newposts);
-               $template->param(Tick => $TICK);
-               $template->param(isMember => $self->isMember);
-               $template->param(Planet => $self->{PLANET});
-               $template->param(isHC => $self->isHC);
-               $template->param(isDC => $self->isDC());
-               $template->param(isBC => $self->isBC());
-               $template->param(isIntel => $self->isIntel());
-               $template->param(isAttacker => $ATTACKER && (!$self->isMember() || ((($TICK - $fleetupdate < 24) || $self->isScanner()) && $self->{PLANET})));
-               if ($ATTACKER && (!$self->isMember() || ((($TICK - $fleetupdate < 24) || $self->isScanner()) && $self->{PLANET}))){
-                       $template->param(Targets => $self->listTargets);
-               }
-               $template->param(Coords => param('coords') ? param('coords') : '1:1:1');
-               my ($css) = $DBH->selectrow_array(q{SELECT css FROM users WHERE uid = $1},undef,$ND::UID);
-               $template->param(CSS => $css);
-               $template->param(TITLE => $self->{TITLE});
-       }
-       $template->param(Error => $ND::ERROR);
-       $template->param(BODY => $body->output);
-       my $output = $template->output;
-       $output =~ s/[^\x{9}\x{A}\x{D}\x{20}-\x{D7FF}\x{E000}-\x{FFFD}\x{10000}-\x{10FFFF}]//g;
-       print header(-type=> $type, -charset => 'utf-8', -Content_Length => length $output);
-       print $output;
-};
-
-1;
diff --git a/database/group_roles.sql b/database/group_roles.sql
new file mode 100644 (file)
index 0000000..e890bb5
--- /dev/null
@@ -0,0 +1,33 @@
+CREATE TABLE roles (
+       role VARCHAR(20) UNIQUE NOT NULL
+);
+
+CREATE TABLE group_roles (
+       gid INTEGER REFERENCES groups(gid),
+       role VARCHAR(20) REFERENCES roles(role)
+);
+
+INSERT INTO roles VALUES('member_menu');
+INSERT INTO roles VALUES('hc_menu');
+INSERT INTO roles VALUES('bc_menu');
+INSERT INTO roles VALUES('dc_menu');
+INSERT INTO roles VALUES('intel_menu');
+INSERT INTO roles VALUES('attack_menu');
+INSERT INTO roles VALUES('no_fleet_update');
+
+INSERT INTO group_roles (gid,role) VALUES(2,'member_menu');
+INSERT INTO group_roles (gid,role) VALUES(2,'attack_menu');
+INSERT INTO group_roles (gid,role) VALUES(6,'dc_menu');
+INSERT INTO group_roles (gid,role) VALUES(4,'bc_menu');
+INSERT INTO group_roles (gid,role) VALUES(5,'intel_menu');
+INSERT INTO group_roles (gid,role) VALUES(8,'no_fleet_update');
+
+INSERT INTO group_roles (gid,role) VALUES(1,'dc_menu');
+INSERT INTO group_roles (gid,role) VALUES(1,'bc_menu');
+INSERT INTO group_roles (gid,role) VALUES(1,'hc_menu');
+INSERT INTO group_roles (gid,role) VALUES(1,'intel_menu');
+
+INSERT INTO group_roles (gid,role) VALUES(3,'dc_menu');
+INSERT INTO group_roles (gid,role) VALUES(3,'bc_menu');
+INSERT INTO group_roles (gid,role) VALUES(3,'hc_menu');
+INSERT INTO group_roles (gid,role) VALUES(3,'intel_menu');
diff --git a/lib/Catalyst/Plugin/Authentication/Store/NDWeb.pm b/lib/Catalyst/Plugin/Authentication/Store/NDWeb.pm
new file mode 100644 (file)
index 0000000..ff90aff
--- /dev/null
@@ -0,0 +1,77 @@
+package Catalyst::Plugin::Authentication::Store::NDWeb;
+
+use strict;
+use warnings;
+use base qw/Class::Accessor::Fast/;
+
+use NDWeb::Auth::User;
+
+our $VERSION= "0.104";
+
+
+BEGIN {
+       #__PACKAGE__->mk_accessors(qw/config/);
+}
+
+
+sub setup {
+       my $c = shift;
+
+    $c->default_auth_store(
+        Catalyst::Plugin::Authentication::Store::NDWeb->new(
+        )
+    );
+
+    $c->NEXT::setup(@_);
+
+}
+
+sub new {
+       my ( $class ) = @_;
+
+       my $self = {
+       };
+
+       bless $self, $class;
+}
+
+sub from_session {
+       my ( $self, $c, $frozenuser ) = @_;
+
+       my $user = NDWeb::Auth::User->new();
+
+       return $user->from_session($frozenuser, $c);
+}
+
+sub for_session {
+       my ($self, $c, $user) = @_;
+       return $user->for_session($c);
+}
+
+sub find_user {
+       my ( $self, $authinfo, $c ) = @_;
+
+       my $user = NDWeb::Auth::User->new();;
+
+       return $user->load($authinfo, $c);
+}
+
+sub user_supports {
+       my $self = shift;
+       # this can work as a class method on the user class
+       NDWeb::User->supports( @_ );
+}
+
+__PACKAGE__;
+
+__END__
+
+=head1 AUTHOR
+
+Michael Andreen (harv@ruin.nu)
+
+=head1 LICENSE
+
+GPL 2.0, or later.
+
+=cut
diff --git a/lib/ND b/lib/ND
index 193d9ed10fea0563da8da5f54ec42f3068547dd4..245cb3b058157d719b02be466e1b4deaa72fc986 160000 (submodule)
--- a/lib/ND
+++ b/lib/ND
@@ -1 +1 @@
-Subproject commit 193d9ed10fea0563da8da5f54ec42f3068547dd4
+Subproject commit 245cb3b058157d719b02be466e1b4deaa72fc986
index 2dbab22e755946756581e26838f19abec9883b4f..85bbf831de6fd811d83c6d571e07e635e8900e79 100644 (file)
@@ -27,10 +27,27 @@ our $VERSION = '0.01';
 # local deployment.
 
 __PACKAGE__->config( name => 'NDWeb' );
+__PACKAGE__->config->{'Plugin::Authentication'}{'use_session'} = 1;
+
 
-# Start the application
-__PACKAGE__->setup(qw/-Debug ConfigLoader Static::Simple/);
 
+# Start the application
+__PACKAGE__->setup(qw/
+       -Debug
+       ConfigLoader
+       Static::Simple
+
+       Authentication
+       Authentication::Store::NDWeb
+       Authentication::Credential::Password
+
+       Authorization::Roles
+       Authorization::ACL
+       
+       Session
+       Session::Store::File
+       Session::State::Cookie
+       /);
 
 =head1 NAME
 
diff --git a/lib/NDWeb/Auth/User.pm b/lib/NDWeb/Auth/User.pm
new file mode 100644 (file)
index 0000000..490f188
--- /dev/null
@@ -0,0 +1,127 @@
+package NDWeb::Auth::User;
+
+use strict;
+use warnings;
+use Data::Dumper;
+use base qw/Catalyst::Authentication::User/;
+use base qw/Class::Accessor::Fast/;
+
+BEGIN {
+       __PACKAGE__->mk_accessors(qw//);
+       __PACKAGE__->mk_ro_accessors(qw/username id css planet _roles/);
+};
+
+sub new {
+       my ( $class ) = @_;
+       my $self = {
+               _roles => undef,
+               username => undef,
+               id => undef,
+               c => undef,
+       };
+       bless $self, $class;
+       return $self;
+}
+
+
+
+sub load {
+       my ($self, $authinfo, $c) = @_;
+       $self->{c} = $c;
+       my $dbh = $c->model;
+
+       if (exists $authinfo->{id}){
+               $self->{id} = $dbh->selectrow_array(q{
+                       SELECT uid FROM users WHERE lower(username) = lower(?)
+               },undef,$authinfo->{id});
+       }elsif (exists $authinfo->{uid}){
+               $self->{id} = $authinfo->{uid};
+       }
+       unless($self->{id}){
+               $c->logout;
+               return $self
+       }
+
+       ($self->{planet},$self->{username},$self->{css}) = $dbh->selectrow_array(q{
+               SELECT planet,username,css FROM users WHERE uid = ?
+               },undef,$self->{id}) or die $dbh->errstr;
+
+       return $self;
+}
+
+sub supported_features {
+       my $self = shift;
+
+       return {
+               password => {
+                       self_check => 1,
+               },
+               session         => 1,
+               roles           => 1,
+       };
+}
+
+
+sub roles {
+       my ( $self ) = shift;
+
+    ## shortcut if we have already retrieved them
+       if (ref $self->_roles eq 'ARRAY') {
+               return(@{$self->_roles});
+       }
+       my $dbh = $self->{c}->model;
+
+       my $query = $dbh->prepare(q{SELECT role FROM group_roles
+               WHERE gid IN (SELECT gid FROM groupmembers WHERE uid = $1)
+               }) or die $dbh->errstr;
+
+       my @roles = ();
+       $query->execute($self->id);
+       while (my $group = $query->fetchrow_hashref){
+               push @roles,$group->{role};
+       }
+       $self->{_roles} = \@roles;
+
+       return @{$self->_roles};
+}
+
+sub for_session {
+       my $self = shift;
+
+       my $userdata = {
+               uid => $self->id
+       };
+       return $userdata;
+}
+
+sub from_session {
+       my ($self, $frozenuser, $c) = @_;
+
+       return $self->load($frozenuser, $c);
+}
+
+sub check_password {
+       my ( $self, $password ) = @_;
+       my $query = $self->{c}->model->prepare(q{
+               SELECT uid FROM users WHERE uid = ? AND password = md5(?)
+       });
+       $query->execute($self->id,$password);
+       if ($query->rows == 1){
+               return $self;
+       }
+       return;
+}
+
+
+1;
+__END__
+
+=head1 AUTHOR
+
+Michael Andreen (harv@ruin.nu)
+
+=head1 LICENSE
+
+GPL 2, or later.
+
+=cut
index 0a41059c7bc3e7188202c6caf050c12cdb61d464..6685c8537c812e0a41624c6808c24de5dd6625f0 100644 (file)
@@ -4,6 +4,8 @@ use strict;
 use warnings;
 use parent 'Catalyst::Controller';
 
+use ND::Include;
+
 #
 # Sets the actions in this controller to be registered with no prefix
 # so they function identically to actions created in MyApp.pm
@@ -27,25 +29,84 @@ NDWeb::Controller::Root - Root Controller for NDWeb
 =cut
 
 sub index : Local Path Args(0) {
-    my ( $self, $c ) = @_;
-
-       $c->stash(abc => $c->req->base);
+       my ( $self, $c ) = @_;
 }
 
 sub default : Path {
-    my ( $self, $c ) = @_;
+       my ( $self, $c ) = @_;
        $c->res->body( 'Page not found' );
-    $c->response->status(404);
-    
+       $c->response->status(404);
 }
 
-sub auto : Private {
+sub login : Local {
+       my ($self, $c) = @_;
+       if ($c->login){
+               $c->res->redirect($c->uri_for('index'));
+               return;
+       }
+
+       $c->stash(error => 'Bad password');
+       $c->stash(template => 'index.tt2');
+       $c->forward('index');
+}
+
+sub logout : Local {
+       my ($self, $c) = @_;
+       $c->logout;
+       $c->res->redirect($c->uri_for('index'));
+}
+
+#sub begin : private {
+#}
+
+sub listTargets : Private {
        my ($self, $c) = @_;
 
        my $dbh = $c ->model;
+
+       my $query = $dbh->prepare(q{SELECT t.id, r.id AS raid, r.tick+c.wave-1 AS landingtick, 
+               (released_coords AND old_claim(timestamp)) AS released_coords, coords(x,y,z),c.launched,c.wave,c.joinable
+FROM raid_claims c
+       JOIN raid_targets t ON c.target = t.id
+       JOIN raids r ON t.raid = r.id
+       JOIN current_planet_stats p ON t.planet = p.id
+WHERE c.uid = $1 AND r.tick+c.wave > tick() AND r.open AND not r.removed
+ORDER BY r.tick+c.wave,x,y,z});
+       $query->execute($c->user->id) or die $dbh->errstr;
+       my @targets;
+       while (my $target = $query->fetchrow_hashref){
+               push @targets, $target;
+       }
+
+       $c->stash(targets => \@targets);
+}
+
+sub auto : Private {
+       my ($self, $c) = @_;
+       my $dbh = $c ->model;
+
        $c->stash(dbh => $dbh);
 
-       $c->stash->{game}->{tick} = $dbh->selectrow_array('SELECT tick()',undef);
+       $dbh->do(q{SET timezone = 'GMT'});
+
+       $c->stash(TICK =>$dbh->selectrow_array('SELECT tick()',undef));
+       $c->stash->{game}->{tick} = $c->stash->{TICK};
+
+       if ($c->user_exists){
+               $c->stash(UID => $c->user->id);
+       }else{
+               $c->stash(UID => -4);
+       }
+
+}
+
+sub access_denied : Private {
+       my ($self, $c, $action) = @_;
+
+       $c->log->debug('moo' . $action);
+
+       # Set the error message
+       $c->stash->{template} = 'access_denied.tt2';
 
 }
 
@@ -55,16 +116,44 @@ Attempt to render a view, if needed.
 
 =cut 
 
-sub end : ActionClass('RenderView') {}
+sub end : ActionClass('RenderView') {
+       my ($self, $c) = @_;
+
+       my $dbh = $c ->model;
+
+       if ($c->user_exists && $c->res->status == 200){
+               my $fleetupdate = 0;
+               if ($c->check_user_roles(qw/member_menu/)){
+                       $fleetupdate = $dbh->selectrow_array(q{SELECT tick FROM fleets WHERE sender = ?
+                               AND mission = 'Full fleet' AND tick > tick() - 24
+                               },undef,$c->user->planet);
+                       $fleetupdate = 0 unless defined $fleetupdate;
+               }
+
+               my ($unread,$newposts) = $dbh->selectrow_array(unread_query,undef,$c->user->id) or die $dbh->errstr;
+
+               $c->stash(user => {
+                       id => $c->user->id,
+                       name => $c->user->username,
+                       css => $c->user->css,
+                       newposts => $newposts,
+                       unreadposts => $unread
+               });
+               $c->stash->{user}->{attacker} = $c->check_user_roles(qw/attack_menu/)
+                       && (!$c->check_user_roles(qw/member_menu/)
+                               || ($c->user->planet && (($c->stash->{TICK} - $fleetupdate < 24)
+                                       || $c->check_user_roles(qw/no_fleet_update/)))),
+               $c->forward('listTargets');
+       }
+}
 
 =head1 AUTHOR
 
-Catalyst developer
+Michael Andreen        (harv@ruin.nu)
 
 =head1 LICENSE
 
-This library is free software, you can redistribute it and/or modify
-it under the same terms as Perl itself.
+GPL 2, or later.
 
 =cut
 
diff --git a/lib/NDWeb/Include.pm b/lib/NDWeb/Include.pm
new file mode 100644 (file)
index 0000000..e35567a
--- /dev/null
@@ -0,0 +1,90 @@
+#**************************************************************************
+#   Copyright (C) 2006 by Michael Andreen <harvATruinDOTnu>               *
+#                                                                         *
+#   This program is free software; you can redistribute it and/or modify  *
+#   it under the terms of the GNU General Public License as published by  *
+#   the Free Software Foundation; either version 2 of the License, or     *
+#   (at your option) any later version.                                   *
+#                                                                         *
+#   This program is distributed in the hope that it will be useful,       *
+#   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+#   GNU General Public License for more details.                          *
+#                                                                         *
+#   You should have received a copy of the GNU General Public License     *
+#   along with this program; if not, write to the                         *
+#   Free Software Foundation, Inc.,                                       *
+#   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
+#**************************************************************************/
+
+package NDWeb::Include;
+use strict;
+use warnings;
+require Exporter;
+use BBCode::Parser;
+
+our @ISA = qw/Exporter/;
+
+our @EXPORT = qw/parseMarkup min max
+       alliances intelquery /;
+
+sub parseMarkup ($) {
+       my ($text) = @_;
+
+       #$text =~ s{\n}{\n<br/>}g;
+       #$text =~ s{\[B\](.*?)\[/B\]}{<b>$1</b>}gi;
+       #$text =~ s{\[I\](.*?)\[/I\]}{<i>$1</i>}gi;
+       #$text =~ s{\[url\](.*?)\[/url\]}{<a href="$1">$1</a>}gi;
+       #$text =~ s{\[PRE\](.*?)\[/PRE\]}{<pre>$1</pre>}sgi;
+       #$text =~ s{\[PRE\](.*?)\[/PRE\]}{<pre>$1</pre>}sgi;
+       #$1 =~ s{<br/>}{}g;
+
+       eval{
+               my $tree = BBCode::Parser->DEFAULT->parse($text);
+               $text = $tree->toHTML;
+       };
+       $text =~ s/\x{3}\d\d?//g; #mirc color TODO: possibly match until \x{0F} and change to [color] block
+       $text =~ s/[^\x{9}\x{A}\x{D}\x{20}-\x{D7FF}\x{E000}-\x{FFFD}\x{10000}-\x{10FFFF}]//g;
+       return $text;
+}
+
+
+sub min {
+    my ($x,$y) = @_;
+    return ($x > $y ? $y : $x);
+}
+
+sub max {
+    my ($x,$y) = @_;
+    return ($x < $y ? $y : $x);
+}
+
+
+sub alliances {
+       my ($alliance) = @_;
+       my @alliances;
+       $alliance = -1 unless defined $alliance;
+       push @alliances,{Id => -1, Name => '', Selected => not $alliance};
+       my $query = $ND::DBH->prepare(q{SELECT id,name FROM alliances ORDER BY LOWER(name)});
+       $query->execute;        
+       while (my $ally = $query->fetchrow_hashref){
+               push @alliances,{Id => $ally->{id}, Name => $ally->{name}, Selected => $alliance == $ally->{id}};
+       }
+       return @alliances;
+}
+
+sub intelquery {
+       my ($columns,$where) = @_;
+       return qq{
+SELECT $columns, i.mission, i.tick AS landingtick,MIN(i.eta) AS eta, i.amount, i.ingal, u.username
+FROM (fleets i NATURAL JOIN users u)
+       JOIN current_planet_stats t ON i.target = t.id
+       JOIN current_planet_stats o ON i.sender = o.id
+WHERE $where 
+GROUP BY i.tick,i.mission,t.x,t.y,t.z,o.x,o.y,o.z,i.amount,i.ingal,u.username,t.alliance,o.alliance,t.nick,o.nick
+ORDER BY i.tick DESC, i.mission};
+}
+
+
+
+1;
index fc22bae70bb1033e9e32a7330dc174215cb625c7..b0f85713f1d4e164c066f9d1b32af65f88f5e6e6 100644 (file)
@@ -14,6 +14,7 @@ __PACKAGE__->config({
        TIMER        => 0,
        #DEBUG        => 'undef',
        TEMPLATE_EXTENSION => '.tt2',
+       #CACHE_SIZE => 256,
 });
 
 =head1 NAME
index 2e9bcfde325026d8f0c0cbc1e099985eaccfd61f..5b30aa452386a478c37b593d1e0e514e80cc5d56 100644 (file)
@@ -7,7 +7,7 @@
 
    IF c.debug;
      # define a debug() macro directed to Catalyst's log
-     MACRO debug(message) CALL Catalyst.log.debug(message);
+     MACRO debug(message) CALL c.log.debug(message);
    END;
 
    # define a data structure to hold sitewide data
diff --git a/root/lib/inc/targetlist.tt2 b/root/lib/inc/targetlist.tt2
new file mode 100644 (file)
index 0000000..4b1890f
--- /dev/null
@@ -0,0 +1,20 @@
+[% IF targets%]
+<table>
+       <tr><th>Target</th><th>Tick</th></tr>
+       [% FOR target IN targets %]
+       <tr>
+               <td><a href="[% target.released_coords and c.uri_for('/check',target.coords)%]">
+                       [% target.released_coords and target.coords%][% IF target.launched%]*[% END %]</a></td>
+               <td><a href="[% c.uri_for('/raid',target.raid)%]#target[% target.id %]">
+                       [% target.landingtick %]</a></td>
+               <td>
+                       <input title="Unclaim target" type="button" value="U" class="small" onclick = 
+                       "claim('/raids?xml=1&amp;raid=[% target.raid %]',[% target.id %],[% target.wave %],'Unclaim')" />
+                       <input title="[% IF target.joinable %]Disable joinable[% ELSE %]Make target joinable[% END %]"
+                               type="button" class="small" value="[% IF target.joinable %]N[% ELSE %]J[% END %]" onclick = 
+                       "claim('/raids?xml=1&amp;raid=[% target.raid %]',[% target.id %],[% target.wave %],'set&amp;joinable=[% target.joinable %]')" />
+               </td>
+       </tr>
+       [% END %]
+</table>
+[% END %]
index 8cccb3f53f58b5f26e335ca37721b18bac904171..91fbff06fa4b668e26e37a4b880cad39c56b3644 100644 (file)
@@ -1,17 +1,15 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
-  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html  xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
 <head>
        <title>[% site.title %]: [% template.title %]</title>
-       <meta http-equiv="Content-Type" content="application/xhtml+xml;charset=UTF-8"/>
-       <link rel="stylesheet" type="text/css" href="/static/default.css"/>
-       <link rel="stylesheet" type="text/css" href="/static/css/[% user.css or "black" %].css"/>
-       <link rel="icon" type="image/ico" href="/favicon.ico"/>
+       <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
+       <link rel="stylesheet" type="text/css" href="/static/default.css">
+       <link rel="stylesheet" type="text/css" href="/static/css/[% user.css or "black" %].css">
+       <link rel="icon" type="image/ico" href="/favicon.ico">
        <script type="text/javascript" src="/static/js/raid.js"></script>
        <script type="text/javascript" src="/static/js/misc.js"></script>
-       <TMPL_VAR NAME=HEADER>
 </head>
  <body>
 [% content %]
 </body>
+</html>
index ec17e5f2bc7c861fbc42e7f085bbd65fe4107313..2c11d74416d421d21928d7a4062e611cd1f2bba8 100644 (file)
@@ -2,6 +2,11 @@
 <div id="header">[%# PROCESS site/header.tt2 %]</div>
 
 <div id="body">
+[% IF error %]
+       <div id="error">
+       [% error %]
+       </div>
+[% END %]
 [% content %]
 </div>
 
index 371428510805976e22f915feb7f44ab57e9201c2..e69075e7661c97a12c761aac2f13a855ad8a94cb 100644 (file)
@@ -1,14 +1,25 @@
 <ul class="linkbar">
        <li><a href="/index">Main page</a></li>
-       <li><a href="/settings">Settings</a></li>
        <li><a href="/forum">Forum</a></li>
+       <li><a href="/forum/search">Forum search</a></li>
 [% IF user %]
-       <li><a href="/forum/allUnread">New posts [% IF user.forum.unread %](<span class="[% user.newposts or "unreadposts"%]">[% user.forum.unread %]</span>)[% END %]</a></li>
+       <li><a href="/forum/allUnread">New posts [% IF user.unreadposts %](<span class="[% IF user.newposts %]newposts[% ELSE %]unreadposts[% END %]">[% user.unreadposts %]</span>)[% END %]</a></li>
+       <li><a href="/settings">Settings</a></li>
+       <li><a href="/logout">Log out ([% c.user.username %])</a></li>
+[% ELSE %]
+       <li>
+       <form action="/login" method="post">
+               <p>
+               Username: <input type="text" name="user" value="">
+               Password: <input type="password" name="password" value="">
+               <input type="submit" value="Login">
+               </p>
+       </form>
+       </li>
 [% END %]
-       <li><a href="/forum/search">Forum search</a></li>
 </ul>  <p>Tick: [% game.tick %]</p>
-[% IF user.isMember %]
-       [% IF user.isAttacker %]
+[% IF c.check_user_roles("member_menu") %]
+       [% IF user.attacker %]
 <p>Member menu</p>
 <ul class="linkbar">
        <li><a href="/points">Top members</a></li>
        <li><a href="/defrequest">Request defense</a></li>
 </ul>
        [% ELSE %]
-               [% IF user.planet %]
+               [% IF c.user.planet %]
        <p><b>Update your fleet to see member menu</b></p>
                [% ELSE %]
-       <form action="/main" method="post">
+       <form action="/main/setcoords" method="post">
                <p>We need your planet's coordinates: 
-               <input type="text" name="planet" value=""/>
-               <input type="submit" value="Submit"/>
+               <input type="text" name="planet" value="">
+               <input type="submit" value="Submit">
                </p>
        </form>
                [% END %]
        [% END %]
 [% END %]
-[% IF user.isAttacker %]
+[% IF user.attacker %]
 <p>Attack menu</p>
 <ul class="linkbar">
        <li><form action="/check" method="post"><p>
-               <input type="hidden" name="page" value="check"/>
-               <input class="coordsinput" type="text" name="coords" value="<TMPL_VAR NAME=Coords>"/>
-               <input class="coordsbutton" type="submit" value="Check"/>
+               <input class="coordsinput" type="text" name="coords" value="[% cords or '1:1:1' %]">
+               <input class="coordsinput" type="submit" value="Check">
                </p></form></li>
        <li><a href="/raids">Web raids</a></li>
 </ul>
-<div id="targets"><TMPL_VAR NAME=Targets></div>
+<p><input type="button" value="Update target list"
+               onclick = "listTargets('/jsrpc/targetList')">
+</p>
+<div id="targets">[% PROCESS inc/targetlist.tt2 %]</div>
 [% END %]
-[% IF user.isBC %]
+[% IF c.check_user_roles("bc_menu") %]
 <p>BC menu</p>
 <ul class="linkbar">
        <li><a href="/editRaid">Create raid</a></li>
 </ul>
 [% END %]
-[% IF user.isDC %]
+[% IF c.check_user_roles("dc_menu") %]
 <p>DC menu</p>
 <ul class="linkbar">
        <li><a href="/defLeeches">Def Leeches</a></li>
        <li><a href="/calls?show=all">All calls</a></li>
 </ul>
 [% END %]
-[% IF user.isHC %]
+[% IF c.check_user_roles("intel_menu") %]
+<p>Intel menu</p>
+<ul class="linkbar">
+       <li><a href="intel">Intel</a></li>
+</ul>
+[% END %]
+[% IF c.check_user_roles("hc_menu") %]
 <p>HC menu</p>
 <ul class="linkbar">
        <li><a href="/users">List users</a></li>
-       <li><a href="/intel">Intel</a></li>
        <li><a href="/alliances">Alliances</a></li>
        <li><a href="/hostileAlliances">Hostile Alliances</a></li>
        <li><a href="/memberIntel">Member Intel</a></li>
        <li><a href="/planetNaps">Planet Naps</a></li>
        <li><a href="/mail">Mail</a></li>
 </ul>
-[% ELSE %]
-       [% IF user.isIntel %]
-<p>Intel menu</p>
-<ul class="linkbar">
-       <li><a href="intel">Intel</a></li>
-</ul>
-       [% END %]
 [% END %]
diff --git a/root/src/access_denied.tt2 b/root/src/access_denied.tt2
new file mode 100644 (file)
index 0000000..df5bbdb
--- /dev/null
@@ -0,0 +1 @@
+<h1>Access Denied</h1>
index 9349e084bf000c361f143b78a9828a70f5fcccb0..3275e9f11cc2098815a0d9710f10313234f245ca 100644 (file)
@@ -94,8 +94,11 @@ ul.linkbar a {
        width: 100%;
        display: block;
 }
-input.coordsinput {
-       width: 4em;
+ul.linkbar input {
+       width: 12em;
+}
+ul.linkbar input.coordsinput {
+       width: 5em;
 }
 input.small {
        width: 1.7em;
diff --git a/templates/NoAccess.tmpl b/templates/NoAccess.tmpl
deleted file mode 100644 (file)
index df5bbdb..0000000
+++ /dev/null
@@ -1 +0,0 @@
-<h1>Access Denied</h1>
diff --git a/templates/targetlist.tmpl b/templates/targetlist.tmpl
deleted file mode 100644 (file)
index 3a2e6e0..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-<p><input type="button" value="Update target list"
-               onclick = "listTargets('raids?xml=1')"/>
-</p>
-<TMPL_IF Targets>
-<table>
-       <tr><th>Target</th><th>Tick</th></tr>
-       <TMPL_LOOP Targets>
-       <tr>
-               <td><a href="/check?coords=<TMPL_VAR NAME=Coords>"><TMPL_VAR NAME=Coords><TMPL_IF Launched>*</TMPL_IF></a></td>
-               <td><a href="/raids?raid=<TMPL_VAR NAME=Raid>#target<TMPL_VAR NAME=Target>">
-                       <TMPL_VAR NAME=Tick></a></td>
-               <td><TMPL_UNLESS AJAX><a href="raids?raid=<TMPL_VAR NAME=Raid>&amp;cmd=Unclaim&amp;target=<TMPL_VAR NAME=Target>&amp;wave=<TMPL_VAR NAME=Wave>" >U</a>
-                       <TMPL_ELSE>
-                               <input title="Unclaim target" type="button" value="U" class="small" onclick = 
-                               "claim('/raids?xml=1&amp;raid=<TMPL_VAR NAME=Raid>',<TMPL_VAR NAME=Target>,<TMPL_VAR NAME=Wave>,'Unclaim')"/>
-                               <input title="<TMPL_VAR NAME=JoinableTitle>" type="button" class="small" value="<TMPL_VAR NAME=JoinName>" onclick = 
-                               "claim('/raids?xml=1&amp;raid=<TMPL_VAR NAME=Raid>',<TMPL_VAR NAME=Target>,<TMPL_VAR NAME=Wave>,'set&amp;joinable=<TMPL_VAR NAME=Joinable>')"/>
-                       </TMPL_UNLESS>
-               </td>
-       </tr>
-       </TMPL_LOOP>
-</table>
-</TMPL_IF>