use check_canattach
[ikiwiki] / IkiWiki / Plugin / remove.pm
1 #!/usr/bin/perl
2 package IkiWiki::Plugin::remove;
3
4 use warnings;
5 use strict;
6 use IkiWiki 2.00;
7
8 sub import { #{{{
9         hook(type => "formbuilder_setup", id => "remove", call => \&formbuilder_setup);
10         hook(type => "formbuilder", id => "remove", call => \&formbuilder);
11         hook(type => "sessioncgi", id => "remove", call => \&sessioncgi);
12
13 } # }}}
14
15 sub formbuilder_setup (@) { #{{{
16         my %params=@_;
17         my $form=$params{form};
18         my $q=$params{cgi};
19
20         if (defined $form->field("do") && $form->field("do") eq "edit") {
21                 # Removal button for the page, and also for attachments.
22                 push @{$params{buttons}}, "Remove";
23                 $form->tmpl_param("field-remove" => '<input name="_submit" type="submit" value="Remove Attachments" />');
24         }
25 } #}}}
26
27 sub confirmation_form ($$) { #{{{ 
28         my $q=shift;
29         my $session=shift;
30
31         eval q{use CGI::FormBuilder};
32         error($@) if $@;
33         my $f = CGI::FormBuilder->new(
34                 name => "remove",
35                 header => 0,
36                 charset => "utf-8",
37                 method => 'POST',
38                 javascript => 0,
39                 params => $q,
40                 action => $config{cgiurl},
41                 stylesheet => IkiWiki::baseurl()."style.css",
42                 fields => [qw{do page}],
43         );
44         
45         $f->field(name => "do", type => "hidden", value => "remove", force => 1);
46
47         return $f, ["Remove", "Cancel"];
48 } #}}}
49
50 sub removal_confirm ($$@) {
51         my $q=shift;
52         my $session=shift;
53         my $attachment=shift;
54         my @pages=@_;
55
56         # Save current form state to allow returning to it later
57         # without losing any edits.
58         # (But don't save what button was submitted, to avoid
59         # looping back to here.)
60         # Note: "_submit" is CGI::FormBuilder internals.
61         $q->param(-name => "_submit", -value => "");
62         $session->param(postremove => scalar $q->Vars);
63         IkiWiki::cgi_savesession($session);
64         
65         my ($f, $buttons)=confirmation_form($q, $session);
66         $f->title(sprintf(gettext("confirm removal of %s"),
67                 join(", ", map { IkiWiki::pagetitle($_) } @pages)));
68         $f->field(name => "page", type => "hidden", value => \@pages, force => 1);
69         if (defined $attachment) {
70                 $f->field(name => "attachment", type => "hidden",
71                         value => $attachment, force => 1);
72         }
73
74         IkiWiki::showform($f, $buttons, $session, $q);
75         exit 0;
76 }
77
78 sub postremove ($) {
79         my $session=shift;
80
81         # Load saved form state and return to edit form.
82         my $postremove=CGI->new($session->param("postremove"));
83         $session->clear("postremove");
84         IkiWiki::cgi_savesession($session);
85         IkiWiki::cgi($postremove, $session);
86 }
87
88 sub formbuilder (@) { #{{{
89         my %params=@_;
90         my $form=$params{form};
91
92         if (defined $form->field("do") && $form->field("do") eq "edit") {
93                 my $q=$params{cgi};
94                 my $session=$params{session};
95
96                 if ($form->submitted eq "Remove") {
97                         removal_confirm($q, $session, 0, $form->field("page"));
98                 }
99                 elsif ($form->submitted eq "Remove Attachments") {
100                         my @selected=$q->param("attachment_select");
101                         if (! @selected) {
102                                 error(gettext("Please select the attachments to remove."));
103                         }
104                         removal_confirm($q, $session, 1, @selected);
105                 }
106         }
107 } #}}}
108
109 sub sessioncgi ($$) { #{{{
110         my $q=shift;
111
112         if ($q->param("do") eq 'remove') {
113                 my $session=shift;
114                 my ($form, $buttons)=confirmation_form($q, $session);
115                 IkiWiki::decode_form_utf8($form);
116
117                 if ($form->submitted eq 'Cancel') {
118                         postremove($session);
119                 }
120                 elsif ($form->submitted eq 'Remove' && $form->validate) {
121                         my @pages=$q->param("page");
122         
123                         # Validate removal by checking that the page exists,
124                         # and that the user is allowed to edit(/remove) it.
125                         my @files;
126                         foreach my $page (@pages) {
127                                 # Must be a known source file.
128                                 if (! exists $pagesources{$page}) {
129                                         error(sprintf(gettext("%s does not exist"),
130                                         htmllink("", "", $page, noimageinline => 1)));
131                                 }
132
133                                 # Must exist on disk, and be a regular file.
134                                 my $file=$pagesources{$page};
135                                 if (! -e "$config{srcdir}/$file") {
136                                         error(sprintf(gettext("%s is not in the srcdir, so it cannot be deleted"), $file));
137                                 }
138                                 elsif (-l "$config{srcdir}/$file" && ! -f _) {
139                                         error(sprintf(gettext("%s is not a file"), $file));
140                                 }
141                                 
142                                 # Must be editiable.
143                                 IkiWiki::check_canedit($page, $q, $session);
144
145                                 # This is sorta overkill, but better safe
146                                 # than sorry. If a user can't upload an
147                                 # attachment, don't let them delete it.
148                                 if ($q->param("attachment")) {
149                                         IkiWiki::Plugin::attachment::check_canattach($session, $page, $file);
150                                 }
151
152                                 push @files, IkiWiki::possibly_foolish_untaint($file);
153                         }
154
155                         # Do removal, and update the wiki.
156                         require IkiWiki::Render;
157                         if ($config{rcs}) {
158                                 IkiWiki::disable_commit_hook();
159                                 foreach my $file (@files) {
160                                         my $token=IkiWiki::rcs_prepedit($file);
161                                         IkiWiki::rcs_remove($file);
162                                         IkiWiki::rcs_commit($file, gettext("removed"),
163                                                 $token, $session->param("name"), $ENV{REMOTE_ADDR});
164                                 }
165                                 IkiWiki::enable_commit_hook();
166                                 IkiWiki::rcs_update();
167                         }
168                         else {
169                                 foreach my $file (@files) {
170                                         IkiWiki::prune("$config{srcdir}/$file");
171                                 }
172                         }
173                         IkiWiki::refresh();
174                         IkiWiki::saveindex();
175
176                         if ($q->param("attachment")) {
177                                 # Attachments were deleted, so redirect
178                                 # back to the edit form.
179                                 postremove($session);
180                         }
181                         else {
182                                 # The page is gone, so redirect to parent
183                                 # of the page.
184                                 my $parent=IkiWiki::dirname($pages[0]);
185                                 if (! exists $pagesources{$parent}) {
186                                         $parent="index";
187                                 }
188                                 IkiWiki::redirect($q, $config{url}."/".htmlpage($parent));
189                         }
190                 }
191                 else {
192                         IkiWiki::showform($form, $buttons, $session, $q);
193                 }
194
195                 exit 0;
196         }
197 }
198
199 1