]> ruin.nu Git - ndwebbie.git/blob - lib/NDWeb/Controller/Wiki.pm
1c3ea8714e3f48fa1b23da4320447318210bdfe9
[ndwebbie.git] / lib / NDWeb / Controller / Wiki.pm
1 package NDWeb::Controller::Wiki;
2
3 use strict;
4 use warnings;
5 use parent 'Catalyst::Controller';
6
7 use Text::MediawikiFormat prefix => '/wiki/';
8
9 =head1 NAME
10
11 NDWeb::Controller::Wiki - Catalyst Controller
12
13 =head1 DESCRIPTION
14
15 Catalyst Controller.
16
17 =head1 METHODS
18
19 =cut
20
21
22 =head2 index
23
24 =cut
25
26 sub auto : Priate {
27         my ( $self, $c ) = @_;
28
29         $c->stash(wikiformat => \&wikiformat);
30 }
31
32 sub index :Path :Args(0) {
33         my ( $self, $c ) = @_;
34
35         push @{$c->req->captures}, ('Info','Main');
36         $c->forward('page');
37         $c->stash(template => 'wiki/page.tt2');
38 }
39
40 sub page : LocalRegex(^(?:([A-Z]\w*)(?::|%3A))?([A-Z]\w*)$) {
41         my ( $self, $c ) = @_;
42         my $dbh = $c->model;
43
44         $c->forward('findPage');
45         $c->acl_access_denied('test',$c->action,'No edit access for this page')
46                 if defined $c->stash->{page}->{view} && !$c->stash->{page}->{view};
47         $c->forward('loadText');
48
49         unless ($c->stash->{page}->{wpid}){
50                 $c->stash->{page}->{namespace} = $c->req->captures->[0];
51                 $c->stash->{page}->{name} = $c->req->captures->[1];
52                 $c->stash->{page}->{fullname} = ($c->stash->{page}->{namespace} ? $c->stash->{page}->{namespace}.':' : '')
53                         . $c->stash->{page}->{name};
54                 $c->stash->{page}->{post} = $dbh->selectrow_array(q{SELECT post
55                                 FROM wiki_namespace_access
56                                 WHERE namespace = COALESCE($1,'') AND post AND gid IN (SELECT groups($2))
57                         },undef,$c->stash->{page}->{namespace}, $c->stash->{UID});
58         }
59         $c->stash(title => $c->stash->{page}->{fullname});
60 }
61
62 sub edit : LocalRegex(^edit/(?:([A-Z]\w*)(?::|%3A))?([A-Z]\w*)$) {
63         my ( $self, $c ) = @_;
64         my $dbh = $c->model;
65
66         $c->forward('findPage');
67         $c->acl_access_denied('test',$c->action,'No edit access for this page')
68                 if defined $c->stash->{page}->{edit} && !$c->stash->{page}->{edit};
69         $c->forward('loadText');
70         $c->forward('findNamespaces');
71
72         unless ($c->stash->{page}->{wpid}){
73                 $c->acl_access_denied('test',$c->action,'No edit access for this page')
74                         unless @{$c->stash->{namespaces}};
75                 $c->stash->{page}->{namespace} = $c->req->captures->[0];
76                 $c->stash->{page}->{name} = $c->req->captures->[1];
77         }
78 }
79
80 sub history : LocalRegex(^history/(?:([A-Z]\w*)(?::|%3A))?([A-Z]\w*)$) {
81         my ( $self, $c ) = @_;
82         my $dbh = $c->model;
83
84         $c->forward('findPage');
85
86         my $query = $dbh->prepare(q{SELECT wprev,time,username,comment
87                 FROM wiki_page_revisions JOIN users u USING (uid)
88                 WHERE wpid = $1
89                 ORDER BY time DESC
90                 });
91         $query->execute($c->stash->{page}->{wpid});
92         $c->stash(revisions => $query->fetchall_arrayref({}) );
93         $c->stash(title => 'History for ' . $c->stash->{page}->{fullname});
94 }
95
96 sub postedit : Local {
97         my ( $self, $c, $p ) = @_;
98         my $dbh = $c->model;
99
100         eval {
101                 $dbh->begin_work;
102
103                 my $wpid = $c->req->param('wpid');
104                 if ( $wpid eq 'new'){
105                         unless ($c->req->param('name') =~ /^([A-Z]\w*)$/){
106                                 die 'The name is not valid, start with a capital letter and only use alphanumerical characters or _ for the rest';
107                         }
108                         my $namespace = $dbh->selectrow_array(q{SELECT namespace
109                                 FROM wiki_namespace_access
110                                 WHERE namespace = $1 AND post AND gid IN (SELECT groups($2))
111                         },undef,$c->req->param('namespace'), $c->stash->{UID});
112
113                         my $query = $dbh->prepare(q{INSERT INTO wiki_pages (namespace,name) VALUES($1,$2) RETURNING wpid});
114                         $query->execute($namespace,$c->req->param('name'));
115                         $wpid = $query->fetchrow;
116                 }
117                 $c->forward('findPage',[$wpid]);
118                 $c->acl_access_denied('test',$c->action,'No edit access for this page')
119                         if defined $c->stash->{page}->{edit} && !$c->stash->{page}->{edit};
120
121                 my $query = $dbh->prepare(q{INSERT INTO wiki_page_revisions
122                         (wpid,parent,text,comment,uid) VALUES($1,$2,$3,$4,$5)
123                         RETURNING wprev
124                         });
125                 $c->req->params->{parent}||= undef;
126                 $query->execute($wpid,$c->req->param('parent'),$c->req->param('text')
127                         ,$c->req->param('comment'),$c->stash->{UID});
128                 my $rev = $query->fetchrow;
129                 $dbh->do(q{UPDATE wiki_pages SET wprev = $1 WHERE wpid = $2}
130                         ,undef,$rev,$wpid);
131
132                 $dbh->commit;
133                 $c->res->redirect($c->uri_for($c->stash->{page}->{fullname}));
134                 return;
135         } if ($c->req->param('cmd') eq 'Submit');
136
137         if ($@){
138                 if ($@ =~ /duplicate key value violates unique constraint "wiki_pages_namespace_key"/){
139                         $c->stash(error => "Page does already exist");
140                 }elsif ($@ =~ /value too long for type character varying\(255\)/){
141                         $c->stash(error => 'The name is too long, keep it to max 255 characters');
142                 }else{
143                         $c->stash(error => $@);
144                 }
145                 $dbh->rollback;
146         }
147
148         $c->forward('findPage') if $p;
149         $c->forward('findNamespaces');
150
151         $c->stash->{page}->{namespace} = $c->req->param('namespace');
152         $c->stash->{page}->{name} = $c->req->param('name');
153
154         $c->stash(text => $c->req->param('text'));
155         $c->stash(template => 'wiki/edit.tt2');
156 }
157
158 sub search : Local {
159         my ( $self, $c ) = @_;
160         my $dbh = $c->model;
161
162         if ($c->req->param('search')){
163                 $c->stash(search => $c->req->param('search'));
164                 my $queryfunc = 'plainto_tsquery';
165                 $queryfunc = 'to_tsquery' if $c->req->param('advsearch');
166                 my $posts = $dbh->prepare(q{SELECT wp.wpid,namespace,name
167                         ,(CASE WHEN namespace <> '' THEN namespace || ':' ELSE '' END) || name AS fullname
168                         ,ts_headline(wpr.text,}.$queryfunc.q{($2)) AS headline
169                         ,ts_rank_cd(textsearch, }.$queryfunc.q{($2),32) AS rank
170                         FROM wiki_pages wp
171                                 JOIN wiki_page_revisions wpr USING (wprev)
172                         WHERE (namespace IN (SELECT namespace FROM wiki_namespace_access WHERE gid IN (SELECT groups($1)))
173                                         OR wp.wpid IN (SELECT wpid FROM wiki_page_access WHERE uid = $1))
174                                 AND textsearch @@ }.$queryfunc.q{($2)
175                         ORDER BY rank DESC
176                 });
177                 eval {
178                         $posts->execute($c->stash->{UID},$c->req->param('search'));
179                         my @posts;
180                         while (my $post = $posts->fetchrow_hashref){
181                                 push @posts,$post;
182                         }
183                         $c->stash(searchresults => \@posts);
184                 };
185                 if ($@){
186                         $c->stash( searcherror => $dbh->errstr);
187                 }
188         }
189
190 }
191
192 sub findPage : Private {
193         my ( $self, $c, $p ) = @_;
194         my $dbh = $c->model;
195
196         my @arguments = ($c->stash->{UID});
197         my $where;
198         if ($p){
199                 $where =  q{AND wpid = $2};
200                 push @arguments, $p;
201         }else{
202                 $where = q{AND (namespace = COALESCE($2,'') AND name = $3)};
203                 push @arguments, @{$c->req->captures};
204         }
205
206         my $query = q{SELECT wpid,namespace,name,wprev
207                 ,(CASE WHEN namespace <> '' THEN namespace || ':' ELSE '' END) || name AS fullname
208                 ,bool_or(COALESCE(wpa.edit,wna.edit)) AS edit
209                 ,bool_or(wna.post) AS post
210                 ,bool_or(wpa.moderate OR wna.moderate) AS moderate
211                 ,bool_or(wpa.wpid IS NOT NULL OR wna.namespace IS NOT NULL) AS view
212                 FROM wiki_pages wp
213                         LEFT OUTER JOIN (SELECT * FROM wiki_namespace_access
214                                 WHERE gid IN (SELECT groups($1))) wna USING (namespace)
215                         LEFT OUTER JOIN (SELECT * FROM wiki_page_access
216                                 WHERE uid =  $1) wpa USING (wpid)
217                 WHERE TRUE
218         } . $where . q{ GROUP BY wpid,namespace,name,wprev};
219         $query = $dbh->prepare($query);
220         $query->execute(@arguments);
221
222         my $page = $query->fetchrow_hashref;
223         $c->stash(page => $page);
224 }
225
226 sub loadText : Private {
227         my ( $self, $c, $p ) = @_;
228         my $dbh = $c->model;
229
230         my $text = $dbh->selectrow_array(q{SELECT text
231                 FROM wiki_page_revisions WHERE wprev = $1
232                 },undef,$c->stash->{page}->{wprev});
233         $c->stash(text => $text);
234 }
235
236 sub findNamespaces : Private {
237         my ( $self, $c, $p ) = @_;
238         my $dbh = $c->model;
239
240         my $query = $dbh->prepare(q{SELECT namespace FROM wiki_namespaces
241                 WHERE namespace IN (SELECT namespace FROM wiki_namespace_access WHERE post AND gid IN (SELECT groups($1)))
242                 ORDER BY namespace
243                 });
244         $query->execute($c->stash->{UID});
245         $c->stash(namespaces => $query->fetchall_arrayref({}) );
246 }
247
248
249 =head1 AUTHOR
250
251 Michael Andreen (harv@ruin.nu)
252
253 =head1 LICENSE
254
255 GPL 2.0, or later
256
257 =cut
258
259 1;