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