]> ruin.nu Git - ndwebbie.git/blobdiff - lib/NDWeb/Controller/Wiki.pm
Implemented a basic Wiki.
[ndwebbie.git] / lib / NDWeb / Controller / Wiki.pm
diff --git a/lib/NDWeb/Controller/Wiki.pm b/lib/NDWeb/Controller/Wiki.pm
new file mode 100644 (file)
index 0000000..d15c609
--- /dev/null
@@ -0,0 +1,222 @@
+package NDWeb::Controller::Wiki;
+
+use strict;
+use warnings;
+use parent 'Catalyst::Controller';
+
+use Text::MediawikiFormat prefix => '/wiki/';
+
+=head1 NAME
+
+NDWeb::Controller::Wiki - Catalyst Controller
+
+=head1 DESCRIPTION
+
+Catalyst Controller.
+
+=head1 METHODS
+
+=cut
+
+
+=head2 index
+
+=cut
+
+sub auto : Priate {
+       my ( $self, $c ) = @_;
+
+       $c->stash(wikiformat => \&wikiformat);
+}
+
+sub index :Path :Args(0) {
+       my ( $self, $c ) = @_;
+
+       push @{$c->req->captures}, ('Info','Main');
+       $c->forward('page');
+       $c->stash(template => 'wiki/page.tt2');
+}
+
+sub page : LocalRegex(^(?:([A-Z]\w*)(?::|%3A))?([A-Z]\w*)$) {
+       my ( $self, $c ) = @_;
+       my $dbh = $c->model;
+
+       $c->forward('findPage');
+       $c->acl_access_denied('test',$c->action,'No edit access for this page')
+               if defined $c->stash->{page}->{view} && !$c->stash->{page}->{view};
+       $c->forward('loadText');
+
+       unless ($c->stash->{page}->{wpid}){
+               $c->stash->{page}->{namespace} = $c->req->captures->[0];
+               $c->stash->{page}->{name} = $c->req->captures->[1];
+               $c->stash->{page}->{fullname} = ($c->stash->{page}->{namespace} ? $c->stash->{page}->{namespace}.':' : '')
+                       . $c->stash->{page}->{name};
+               $c->stash->{page}->{post} = $dbh->selectrow_array(q{SELECT post
+                               FROM wiki_namespace_access
+                               WHERE namespace = COALESCE($1,'') AND post AND gid IN (SELECT groups($2))
+                       },undef,$c->stash->{page}->{namespace}, $c->stash->{UID});
+       }
+       $c->stash(title => $c->stash->{page}->{fullname});
+}
+
+sub edit : LocalRegex(^edit/(?:([A-Z]\w*)(?::|%3A))?([A-Z]\w*)$) {
+       my ( $self, $c ) = @_;
+       my $dbh = $c->model;
+
+       $c->forward('findPage');
+       $c->acl_access_denied('test',$c->action,'No edit access for this page')
+               if defined $c->stash->{page}->{edit} && !$c->stash->{page}->{edit};
+       $c->forward('loadText');
+       $c->forward('findNamespaces');
+
+       unless ($c->stash->{page}->{wpid}){
+               $c->acl_access_denied('test',$c->action,'No edit access for this page')
+                       unless @{$c->stash->{namespaces}};
+               $c->stash->{page}->{namespace} = $c->req->captures->[0];
+               $c->stash->{page}->{name} = $c->req->captures->[1];
+       }
+}
+
+sub history : LocalRegex(^history/(?:([A-Z]\w*)(?::|%3A))?([A-Z]\w*)$) {
+       my ( $self, $c ) = @_;
+       my $dbh = $c->model;
+
+       $c->forward('findPage');
+
+       my $query = $dbh->prepare(q{SELECT wprev,time,username,comment
+               FROM wiki_page_revisions JOIN users u USING (uid)
+               WHERE wpid = $1
+               ORDER BY time DESC
+               });
+       $query->execute($c->stash->{page}->{wpid});
+       $c->stash(revisions => $query->fetchall_arrayref({}) );
+       $c->stash(title => 'History for ' . $c->stash->{page}->{fullname});
+}
+
+sub postedit : Local {
+       my ( $self, $c, $p ) = @_;
+       my $dbh = $c->model;
+
+       eval {
+               $dbh->begin_work;
+
+               my $wpid = $c->req->param('wpid');
+               if ( $wpid eq 'new'){
+                       my $namespace = $dbh->selectrow_array(q{SELECT namespace
+                               FROM wiki_namespace_access
+                               WHERE namespace = $1 AND post AND gid IN (SELECT groups($2))
+                       },undef,$c->req->param('namespace'), $c->stash->{UID});
+
+                       my $query = $dbh->prepare(q{INSERT INTO wiki_pages (namespace,name) VALUES($1,$2) RETURNING wpid});
+                       $query->execute($namespace,$c->req->param('name'));
+                       $wpid = $query->fetchrow;
+               }
+               $c->forward('findPage',[$wpid]);
+               $c->acl_access_denied('test',$c->action,'No edit access for this page')
+                       if defined $c->stash->{page}->{edit} && !$c->stash->{page}->{edit};
+
+               my $query = $dbh->prepare(q{INSERT INTO wiki_page_revisions
+                       (wpid,parent,text,comment,uid) VALUES($1,$2,$3,$4,$5)
+                       RETURNING wprev
+                       });
+               $c->req->params->{parent}||= undef;
+               $query->execute($wpid,$c->req->param('parent'),$c->req->param('text')
+                       ,$c->req->param('comment'),$c->stash->{UID});
+               my $rev = $query->fetchrow;
+               $dbh->do(q{UPDATE wiki_pages SET wprev = $1 WHERE wpid = $2}
+                       ,undef,$rev,$wpid);
+
+               $dbh->commit;
+               $c->res->redirect($c->uri_for($c->stash->{page}->{fullname}));
+               return;
+       } if ($c->req->param('cmd') eq 'Submit');
+
+       if ($@){
+               if ($@ =~ /duplicate key value violates unique constraint "wiki_pages_namespace_key"/){
+                       $c->stash(error => "Page does already exist");
+               }elsif ($@ =~ /value too long for type character varying\(255\)/){
+                       $c->stash(error => 'The name is too long, keep it to max 255 characters');
+               }else{
+                       $c->stash(error => $@);
+               }
+               $dbh->rollback;
+       }
+
+       $c->forward('findPage') if $p;
+       $c->forward('findNamespaces');
+
+       $c->stash->{page}->{namespace} = $c->req->param('namespace');
+       $c->stash->{page}->{name} = $c->req->param('name');
+
+       $c->stash(text => $c->req->param('text'));
+       $c->stash(template => 'wiki/edit.tt2');
+}
+
+sub findPage : Private {
+       my ( $self, $c, $p ) = @_;
+       my $dbh = $c->model;
+
+       my @arguments = ($c->stash->{UID});
+       my $where;
+       if ($p){
+               $where =  q{AND wpid = $2};
+               push @arguments, $p;
+       }else{
+               $where = q{AND (namespace = COALESCE($2,'') AND name = $3)};
+               push @arguments, @{$c->req->captures};
+       }
+
+       my $query = q{SELECT wpid,namespace,name,wprev
+               ,(CASE WHEN namespace <> '' THEN namespace || ':' ELSE '' END) || name AS fullname
+               ,bool_or(COALESCE(wpa.edit,wna.edit)) AS edit
+               ,bool_or(wna.post) AS post
+               ,bool_or(wpa.moderate OR wna.moderate) AS moderate
+               ,bool_or(wpa.wpid IS NOT NULL OR wna.namespace IS NOT NULL) AS view
+               FROM wiki_pages wp
+                       LEFT OUTER JOIN (SELECT * FROM wiki_namespace_access
+                               WHERE gid IN (SELECT groups($1))) wna USING (namespace)
+                       LEFT OUTER JOIN (SELECT * FROM wiki_page_access
+                               WHERE uid =  $1) wpa USING (wpid)
+               WHERE TRUE
+       } . $where . q{ GROUP BY wpid,namespace,name,wprev};
+       $query = $dbh->prepare($query);
+       $query->execute(@arguments);
+
+       my $page = $query->fetchrow_hashref;
+       $c->stash(page => $page);
+}
+
+sub loadText : Private {
+       my ( $self, $c, $p ) = @_;
+       my $dbh = $c->model;
+
+       my $text = $dbh->selectrow_array(q{SELECT text
+               FROM wiki_page_revisions WHERE wprev = $1
+               },undef,$c->stash->{page}->{wprev});
+       $c->stash(text => $text);
+}
+
+sub findNamespaces : Private {
+       my ( $self, $c, $p ) = @_;
+       my $dbh = $c->model;
+
+       my $query = $dbh->prepare(q{SELECT namespace FROM wiki_namespaces
+               WHERE namespace IN (SELECT namespace FROM wiki_namespace_access WHERE post AND gid IN (SELECT groups($1)))
+               ORDER BY namespace
+               });
+       $query->execute($c->stash->{UID});
+       $c->stash(namespaces => $query->fetchall_arrayref({}) );
+}
+
+
+=head1 AUTHOR
+
+Michael Andreen (harv@ruin.nu)
+
+=head1 LICENSE
+
+GPL 2.0, or later
+
+=cut
+
+1;