2008-09-05 19:57:25 +02:00
|
|
|
#!/usr/bin/perl
|
|
|
|
package IkiWiki::Plugin::editpage;
|
|
|
|
|
|
|
|
use warnings;
|
|
|
|
use strict;
|
|
|
|
use IkiWiki;
|
|
|
|
use open qw{:utf8 :std};
|
|
|
|
|
2008-12-17 21:22:16 +01:00
|
|
|
sub import {
|
2008-09-05 19:57:25 +02:00
|
|
|
hook(type => "getsetup", id => "editpage", call => \&getsetup);
|
2008-09-27 23:04:25 +02:00
|
|
|
hook(type => "refresh", id => "editpage", call => \&refresh);
|
2008-09-05 19:57:25 +02:00
|
|
|
hook(type => "sessioncgi", id => "editpage", call => \&IkiWiki::cgi_editpage);
|
2008-12-17 21:22:16 +01:00
|
|
|
}
|
2008-09-05 19:57:25 +02:00
|
|
|
|
2008-12-17 21:22:16 +01:00
|
|
|
sub getsetup () {
|
2008-09-05 19:57:25 +02:00
|
|
|
return
|
|
|
|
plugin => {
|
|
|
|
safe => 1,
|
|
|
|
rebuild => 1,
|
2010-02-12 04:24:15 +01:00
|
|
|
section => "core",
|
2008-09-05 19:57:25 +02:00
|
|
|
},
|
2008-12-17 21:22:16 +01:00
|
|
|
}
|
2008-09-05 19:57:25 +02:00
|
|
|
|
2008-09-27 23:04:25 +02:00
|
|
|
sub refresh () {
|
|
|
|
if (exists $wikistate{editpage} && exists $wikistate{editpage}{previews}) {
|
|
|
|
# Expire old preview files after one hour.
|
|
|
|
my $expire=time - (60 * 60);
|
|
|
|
|
|
|
|
my @previews;
|
|
|
|
foreach my $file (@{$wikistate{editpage}{previews}}) {
|
|
|
|
my $mtime=(stat("$config{destdir}/$file"))[9];
|
|
|
|
if (defined $mtime && $mtime <= $expire) {
|
2008-09-29 19:25:31 +02:00
|
|
|
# Avoid deleting a preview that was later saved.
|
|
|
|
my $delete=1;
|
|
|
|
foreach my $page (keys %renderedfiles) {
|
|
|
|
if (grep { $_ eq $file } @{$renderedfiles{$page}}) {
|
|
|
|
$delete=0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ($delete) {
|
|
|
|
debug(sprintf(gettext("removing old preview %s"), $file));
|
2012-04-07 18:52:29 +02:00
|
|
|
IkiWiki::prune("$config{destdir}/$file", $config{destdir});
|
2008-09-29 19:25:31 +02:00
|
|
|
}
|
2008-09-27 23:04:25 +02:00
|
|
|
}
|
|
|
|
elsif (defined $mtime) {
|
|
|
|
push @previews, $file;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
$wikistate{editpage}{previews}=\@previews;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-09-05 19:57:25 +02:00
|
|
|
# Back to ikiwiki namespace for the rest, this code is very much
|
|
|
|
# internal to ikiwiki even though it's separated into a plugin,
|
2009-02-12 22:31:05 +01:00
|
|
|
# and other plugins use the function below.
|
2008-09-05 19:57:25 +02:00
|
|
|
package IkiWiki;
|
|
|
|
|
2008-12-17 21:22:16 +01:00
|
|
|
sub cgi_editpage ($$) {
|
2008-09-05 19:57:25 +02:00
|
|
|
my $q=shift;
|
|
|
|
my $session=shift;
|
|
|
|
|
|
|
|
my $do=$q->param('do');
|
|
|
|
return unless $do eq 'create' || $do eq 'edit';
|
|
|
|
|
|
|
|
decode_cgi_utf8($q);
|
|
|
|
|
2012-04-13 20:28:02 +02:00
|
|
|
my @fields=qw(do rcsinfo subpage from page type editcontent
|
|
|
|
editmessage subscribe);
|
2008-09-05 19:57:25 +02:00
|
|
|
my @buttons=("Save Page", "Preview", "Cancel");
|
|
|
|
eval q{use CGI::FormBuilder};
|
|
|
|
error($@) if $@;
|
|
|
|
my $form = CGI::FormBuilder->new(
|
|
|
|
fields => \@fields,
|
|
|
|
charset => "utf-8",
|
|
|
|
method => 'POST',
|
|
|
|
required => [qw{editcontent}],
|
|
|
|
javascript => 0,
|
|
|
|
params => $q,
|
2010-11-23 01:12:17 +01:00
|
|
|
action => IkiWiki::cgiurl(),
|
2008-09-05 19:57:25 +02:00
|
|
|
header => 0,
|
|
|
|
table => 0,
|
2010-04-24 22:11:33 +02:00
|
|
|
template => { template("editpage.tmpl") },
|
2008-09-05 19:57:25 +02:00
|
|
|
);
|
|
|
|
|
|
|
|
decode_form_utf8($form);
|
|
|
|
run_hooks(formbuilder_setup => sub {
|
|
|
|
shift->(form => $form, cgi => $q, session => $session,
|
|
|
|
buttons => \@buttons);
|
|
|
|
});
|
|
|
|
decode_form_utf8($form);
|
|
|
|
|
2008-09-21 04:48:22 +02:00
|
|
|
# This untaint is safe because we check file_pruned and
|
|
|
|
# wiki_file_regexp.
|
|
|
|
my ($page)=$form->field('page')=~/$config{wiki_file_regexp}/;
|
2011-01-23 22:36:27 +01:00
|
|
|
if (! defined $page) {
|
|
|
|
error(gettext("bad page name"));
|
|
|
|
}
|
2011-01-23 15:11:46 +01:00
|
|
|
$page=possibly_foolish_untaint($page);
|
|
|
|
my $absolute=($page =~ s#^/+##); # absolute name used to force location
|
2008-09-05 19:57:25 +02:00
|
|
|
if (! defined $page || ! length $page ||
|
2010-04-18 01:05:40 +02:00
|
|
|
file_pruned($page)) {
|
2008-10-23 22:29:50 +02:00
|
|
|
error(gettext("bad page name"));
|
2008-09-05 19:57:25 +02:00
|
|
|
}
|
|
|
|
|
2010-11-29 20:07:26 +01:00
|
|
|
my $baseurl = urlto($page);
|
2008-09-21 19:22:54 +02:00
|
|
|
|
2008-09-05 19:57:25 +02:00
|
|
|
my $from;
|
|
|
|
if (defined $form->field('from')) {
|
|
|
|
($from)=$form->field('from')=~/$config{wiki_file_regexp}/;
|
|
|
|
}
|
|
|
|
|
|
|
|
my $file;
|
|
|
|
my $type;
|
|
|
|
if (exists $pagesources{$page} && $form->field("do") ne "create") {
|
|
|
|
$file=$pagesources{$page};
|
|
|
|
$type=pagetype($file);
|
|
|
|
if (! defined $type || $type=~/^_/) {
|
|
|
|
error(sprintf(gettext("%s is not an editable page"), $page));
|
|
|
|
}
|
|
|
|
if (! $form->submitted) {
|
|
|
|
$form->field(name => "rcsinfo",
|
|
|
|
value => rcs_prepedit($file), force => 1);
|
|
|
|
}
|
|
|
|
$form->field(name => "editcontent", validate => '/.*/');
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
$type=$form->param('type');
|
|
|
|
if (defined $type && length $type && $hooks{htmlize}{$type}) {
|
|
|
|
$type=possibly_foolish_untaint($type);
|
|
|
|
}
|
|
|
|
elsif (defined $from && exists $pagesources{$from}) {
|
|
|
|
# favor the type of linking page
|
|
|
|
$type=pagetype($pagesources{$from});
|
|
|
|
}
|
2011-02-02 02:01:26 +01:00
|
|
|
$type=$config{default_pageext}
|
|
|
|
if ! defined $type || $type=~/^_/; # not internal type
|
2008-09-30 00:52:42 +02:00
|
|
|
$file=newpagefile($page, $type);
|
2008-09-05 19:57:25 +02:00
|
|
|
if (! $form->submitted) {
|
|
|
|
$form->field(name => "rcsinfo", value => "", force => 1);
|
|
|
|
}
|
|
|
|
$form->field(name => "editcontent", validate => '/.+/');
|
|
|
|
}
|
|
|
|
|
|
|
|
$form->field(name => "do", type => 'hidden');
|
|
|
|
$form->field(name => "sid", type => "hidden", value => $session->id,
|
|
|
|
force => 1);
|
|
|
|
$form->field(name => "from", type => 'hidden');
|
|
|
|
$form->field(name => "rcsinfo", type => 'hidden');
|
|
|
|
$form->field(name => "subpage", type => 'hidden');
|
|
|
|
$form->field(name => "page", value => $page, force => 1);
|
|
|
|
$form->field(name => "type", value => $type, force => 1);
|
2010-06-13 00:10:33 +02:00
|
|
|
$form->field(name => "editmessage", type => "text", size => 80);
|
2008-09-05 19:57:25 +02:00
|
|
|
$form->field(name => "editcontent", type => "textarea", rows => 20,
|
|
|
|
cols => 80);
|
|
|
|
$form->tmpl_param("can_commit", $config{rcs});
|
|
|
|
$form->tmpl_param("helponformattinglink",
|
|
|
|
htmllink($page, $page, "ikiwiki/formatting",
|
|
|
|
noimageinline => 1,
|
|
|
|
linktext => "FormattingHelp"));
|
|
|
|
|
2012-04-13 20:28:02 +02:00
|
|
|
my $cansubscribe=IkiWiki::Plugin::notifyemail->can("subscribe")
|
|
|
|
&& IkiWiki::Plugin::comments->can("import")
|
|
|
|
&& defined $session->param('name');
|
|
|
|
if ($cansubscribe) {
|
|
|
|
$form->field(name => "subscribe", type => "checkbox",
|
|
|
|
options => [gettext("email comments to me")]);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
$form->field(name => "subscribe", type => 'hidden');
|
|
|
|
}
|
|
|
|
|
2010-06-09 22:59:17 +02:00
|
|
|
my $previewing=0;
|
2008-09-05 19:57:25 +02:00
|
|
|
if ($form->submitted eq "Cancel") {
|
|
|
|
if ($form->field("do") eq "create" && defined $from) {
|
2010-11-29 20:07:26 +01:00
|
|
|
redirect($q, urlto($from));
|
2008-09-05 19:57:25 +02:00
|
|
|
}
|
|
|
|
elsif ($form->field("do") eq "create") {
|
2010-11-23 01:00:11 +01:00
|
|
|
redirect($q, baseurl(undef));
|
2008-09-05 19:57:25 +02:00
|
|
|
}
|
|
|
|
else {
|
2010-11-29 20:07:26 +01:00
|
|
|
redirect($q, $baseurl);
|
2008-09-05 19:57:25 +02:00
|
|
|
}
|
|
|
|
exit;
|
|
|
|
}
|
|
|
|
elsif ($form->submitted eq "Preview") {
|
2010-06-09 22:59:17 +02:00
|
|
|
$previewing=1;
|
|
|
|
|
2008-09-05 19:57:25 +02:00
|
|
|
my $new=not exists $pagesources{$page};
|
2010-06-09 23:44:40 +02:00
|
|
|
# temporarily record its type
|
|
|
|
$pagesources{$page}=$page.".".$type if $new;
|
2008-09-27 23:04:25 +02:00
|
|
|
my %wasrendered=map { $_ => 1 } @{$renderedfiles{$page}};
|
2008-09-05 19:57:25 +02:00
|
|
|
|
|
|
|
my $content=$form->field('editcontent');
|
|
|
|
|
|
|
|
run_hooks(editcontent => sub {
|
|
|
|
$content=shift->(
|
|
|
|
content => $content,
|
|
|
|
page => $page,
|
|
|
|
cgi => $q,
|
|
|
|
session => $session,
|
|
|
|
);
|
|
|
|
});
|
|
|
|
my $preview=htmlize($page, $page, $type,
|
|
|
|
linkify($page, $page,
|
|
|
|
preprocess($page, $page,
|
|
|
|
filter($page, $page, $content), 0, 1)));
|
|
|
|
run_hooks(format => sub {
|
|
|
|
$preview=shift->(
|
|
|
|
page => $page,
|
|
|
|
content => $preview,
|
|
|
|
);
|
|
|
|
});
|
|
|
|
$form->tmpl_param("page_preview", $preview);
|
2008-09-27 23:04:25 +02:00
|
|
|
|
|
|
|
# Previewing may have created files on disk.
|
|
|
|
# Keep a list of these to be deleted later.
|
|
|
|
my %previews = map { $_ => 1 } @{$wikistate{editpage}{previews}};
|
2008-09-30 00:19:44 +02:00
|
|
|
foreach my $f (@{$renderedfiles{$page}}) {
|
|
|
|
$previews{$f}=1 unless $wasrendered{$f};
|
2008-09-27 23:04:25 +02:00
|
|
|
}
|
2010-06-09 23:44:40 +02:00
|
|
|
|
|
|
|
# Throw out any other state changes made during previewing,
|
|
|
|
# and save the previews list.
|
|
|
|
loadindex();
|
2008-09-27 23:04:25 +02:00
|
|
|
@{$wikistate{editpage}{previews}} = keys %previews;
|
2008-09-05 19:57:25 +02:00
|
|
|
saveindex();
|
|
|
|
}
|
|
|
|
elsif ($form->submitted eq "Save Page") {
|
|
|
|
$form->tmpl_param("page_preview", "");
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($form->submitted ne "Save Page" || ! $form->validate) {
|
|
|
|
if ($form->field("do") eq "create") {
|
|
|
|
my @page_locs;
|
|
|
|
my $best_loc;
|
|
|
|
if (! defined $from || ! length $from ||
|
|
|
|
$from ne $form->field('from') ||
|
2010-04-18 01:05:40 +02:00
|
|
|
file_pruned($from) ||
|
2008-09-05 19:57:25 +02:00
|
|
|
$absolute ||
|
2008-10-02 18:42:46 +02:00
|
|
|
$form->submitted) {
|
2008-09-05 19:57:25 +02:00
|
|
|
@page_locs=$best_loc=$page;
|
2011-06-29 22:38:32 +02:00
|
|
|
unshift @page_locs, lc($page)
|
|
|
|
if ! $form->submitted && lc($page) ne $page;
|
2008-09-05 19:57:25 +02:00
|
|
|
}
|
2011-11-06 21:14:04 +01:00
|
|
|
elsif (lc $page eq lc $config{discussionpage}) {
|
2011-11-27 18:19:19 +01:00
|
|
|
@page_locs=$best_loc="$from/".lc($page);
|
2011-11-06 21:14:04 +01:00
|
|
|
}
|
2008-09-05 19:57:25 +02:00
|
|
|
else {
|
|
|
|
my $dir=$from."/";
|
|
|
|
$dir=~s![^/]+/+$!!;
|
|
|
|
|
2009-08-14 03:41:33 +02:00
|
|
|
if ((defined $form->field('subpage') &&
|
2011-11-06 21:14:04 +01:00
|
|
|
length $form->field('subpage'))) {
|
2008-09-05 19:57:25 +02:00
|
|
|
$best_loc="$from/$page";
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
$best_loc=$dir.$page;
|
|
|
|
}
|
|
|
|
|
2011-06-29 22:38:32 +02:00
|
|
|
my $mixedcase=lc($page) ne $page;
|
|
|
|
|
|
|
|
push @page_locs, $dir.lc($page) if $mixedcase;
|
2008-09-05 19:57:25 +02:00
|
|
|
push @page_locs, $dir.$page;
|
2011-06-29 22:38:32 +02:00
|
|
|
push @page_locs, $from."/".lc($page) if $mixedcase;
|
|
|
|
push @page_locs, $from."/".$page;
|
2008-09-05 19:57:25 +02:00
|
|
|
while (length $dir) {
|
|
|
|
$dir=~s![^/]+/+$!!;
|
2011-06-29 22:38:32 +02:00
|
|
|
push @page_locs, $dir.lc($page) if $mixedcase;
|
2008-09-05 19:57:25 +02:00
|
|
|
push @page_locs, $dir.$page;
|
|
|
|
}
|
2011-06-29 22:38:32 +02:00
|
|
|
|
2010-02-05 00:24:15 +01:00
|
|
|
my $userpage=IkiWiki::userpage($page);
|
|
|
|
push @page_locs, $userpage
|
|
|
|
if ! grep { $_ eq $userpage } @page_locs;
|
2008-09-05 19:57:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@page_locs = grep {
|
|
|
|
! exists $pagecase{lc $_}
|
|
|
|
} @page_locs;
|
|
|
|
if (! @page_locs) {
|
|
|
|
# hmm, someone else made the page in the
|
|
|
|
# meantime?
|
2010-06-09 22:59:17 +02:00
|
|
|
if ($previewing) {
|
2008-09-05 19:57:25 +02:00
|
|
|
# let them go ahead with the edit
|
|
|
|
# and resolve the conflict at save
|
|
|
|
# time
|
|
|
|
@page_locs=$page;
|
|
|
|
}
|
|
|
|
else {
|
2010-11-29 20:07:26 +01:00
|
|
|
redirect($q, $baseurl);
|
2008-09-05 19:57:25 +02:00
|
|
|
exit;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
my @editable_locs = grep {
|
|
|
|
check_canedit($_, $q, $session, 1)
|
|
|
|
} @page_locs;
|
|
|
|
if (! @editable_locs) {
|
reorder canedit checks during page creation to have best_loc first
When creating a page, multiple locations are tested to see if they can be
edited. If all fail, one of the failure subs is called, to log the user in
to allow them to proceed with the edit. So far so good.
But, what if some pages fail for one reason, and some for another? This
occurs when httpauth_pagespec is used in conjunction with signinedit (and
openid or something). When the user is not signed in at all
The former will fail to edit a page because the user was not httpauthed.
The latter will fail to edit a different page, because the user was not
signed in. One of their failure methods gets to run first.
The page creation code always ran the failure method corresponding to the
topmost page location. So, when editing a foo/Discussion page, and with
httpauth_pagespec => "*!/Discussion", it ran the httpauth failure method,
which was exactly the wrong thing to do.
I fixed this by making it instead run the failure method for the *best*
page location. In the above example, that's foo/Discussion, so signinedit
runs, as desired, and we get the signin page.
This seems like it will be the right choice, or at least an acceptable
choice. If a user wants to use httpauth they can always choose it on the
signin page.
2010-02-12 02:13:30 +01:00
|
|
|
# now let it throw an error, or prompt for
|
|
|
|
# login
|
|
|
|
map { check_canedit($_, $q, $session) }
|
|
|
|
($best_loc, @page_locs);
|
2008-09-05 19:57:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
my @page_types;
|
|
|
|
if (exists $hooks{htmlize}) {
|
2009-05-16 14:56:25 +02:00
|
|
|
foreach my $key (grep { !/^_/ } keys %{$hooks{htmlize}}) {
|
2016-03-08 20:31:15 +01:00
|
|
|
push @page_types, [$key, $hooks{htmlize}{$key}{longname} || $key]
|
|
|
|
unless $hooks{htmlize}{$key}{nocreate};
|
2009-05-16 14:56:25 +02:00
|
|
|
}
|
2008-09-05 19:57:25 +02:00
|
|
|
}
|
2009-05-21 21:50:25 +02:00
|
|
|
@page_types=sort @page_types;
|
2008-09-05 19:57:25 +02:00
|
|
|
|
|
|
|
$form->tmpl_param("page_select", 1);
|
|
|
|
$form->field(name => "page", type => 'select',
|
|
|
|
options => [ map { [ $_, pagetitle($_, 1) ] } @editable_locs ],
|
|
|
|
value => $best_loc);
|
|
|
|
$form->field(name => "type", type => 'select',
|
|
|
|
options => \@page_types);
|
2010-12-25 18:38:26 +01:00
|
|
|
$form->title(sprintf(gettext("creating %s"), pagetitle(basename($page))));
|
2008-09-05 19:57:25 +02:00
|
|
|
|
|
|
|
}
|
|
|
|
elsif ($form->field("do") eq "edit") {
|
|
|
|
check_canedit($page, $q, $session);
|
|
|
|
if (! defined $form->field('editcontent') ||
|
|
|
|
! length $form->field('editcontent')) {
|
|
|
|
my $content="";
|
|
|
|
if (exists $pagesources{$page}) {
|
|
|
|
$content=readfile(srcfile($pagesources{$page}));
|
|
|
|
$content=~s/\n/\r\n/g;
|
|
|
|
}
|
|
|
|
$form->field(name => "editcontent", value => $content,
|
|
|
|
force => 1);
|
|
|
|
}
|
|
|
|
$form->tmpl_param("page_select", 0);
|
|
|
|
$form->field(name => "page", type => 'hidden');
|
|
|
|
$form->field(name => "type", type => 'hidden');
|
2010-12-25 18:38:26 +01:00
|
|
|
$form->title(sprintf(gettext("editing %s"), pagetitle(basename($page))));
|
2008-09-05 19:57:25 +02:00
|
|
|
}
|
|
|
|
|
2011-01-05 21:58:27 +01:00
|
|
|
showform($form, \@buttons, $session, $q, page => $page);
|
2008-09-05 19:57:25 +02:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
# save page
|
|
|
|
check_canedit($page, $q, $session);
|
2014-10-11 10:28:02 +02:00
|
|
|
checksessionexpiry($q, $session);
|
2008-09-05 19:57:25 +02:00
|
|
|
|
|
|
|
my $exists=-e "$config{srcdir}/$file";
|
|
|
|
|
|
|
|
if ($form->field("do") ne "create" && ! $exists &&
|
|
|
|
! defined srcfile($file, 1)) {
|
|
|
|
$form->tmpl_param("message", template("editpagegone.tmpl")->output);
|
|
|
|
$form->field(name => "do", value => "create", force => 1);
|
|
|
|
$form->tmpl_param("page_select", 0);
|
|
|
|
$form->field(name => "page", type => 'hidden');
|
|
|
|
$form->field(name => "type", type => 'hidden');
|
|
|
|
$form->title(sprintf(gettext("editing %s"), $page));
|
2011-01-05 21:58:27 +01:00
|
|
|
showform($form, \@buttons, $session, $q,
|
2011-01-05 18:49:04 +01:00
|
|
|
page => $page);
|
2008-09-05 19:57:25 +02:00
|
|
|
exit;
|
|
|
|
}
|
|
|
|
elsif ($form->field("do") eq "create" && $exists) {
|
|
|
|
$form->tmpl_param("message", template("editcreationconflict.tmpl")->output);
|
|
|
|
$form->field(name => "do", value => "edit", force => 1);
|
|
|
|
$form->tmpl_param("page_select", 0);
|
|
|
|
$form->field(name => "page", type => 'hidden');
|
|
|
|
$form->field(name => "type", type => 'hidden');
|
|
|
|
$form->title(sprintf(gettext("editing %s"), $page));
|
|
|
|
$form->field("editcontent",
|
|
|
|
value => readfile("$config{srcdir}/$file").
|
|
|
|
"\n\n\n".$form->field("editcontent"),
|
|
|
|
force => 1);
|
2011-01-05 21:58:27 +01:00
|
|
|
showform($form, \@buttons, $session, $q,
|
2011-01-05 18:49:04 +01:00
|
|
|
page => $page);
|
2008-09-05 19:57:25 +02:00
|
|
|
exit;
|
|
|
|
}
|
2009-01-17 02:46:55 +01:00
|
|
|
|
|
|
|
my $message="";
|
2010-06-13 00:10:33 +02:00
|
|
|
if (defined $form->field('editmessage') &&
|
|
|
|
length $form->field('editmessage')) {
|
|
|
|
$message=$form->field('editmessage');
|
2009-01-17 02:46:55 +01:00
|
|
|
}
|
2008-09-05 19:57:25 +02:00
|
|
|
|
|
|
|
my $content=$form->field('editcontent');
|
2009-01-17 02:46:55 +01:00
|
|
|
check_content(content => $content, page => $page,
|
|
|
|
cgi => $q, session => $session,
|
|
|
|
subject => $message);
|
2008-09-05 19:57:25 +02:00
|
|
|
run_hooks(editcontent => sub {
|
|
|
|
$content=shift->(
|
|
|
|
content => $content,
|
|
|
|
page => $page,
|
|
|
|
cgi => $q,
|
|
|
|
session => $session,
|
|
|
|
);
|
|
|
|
});
|
|
|
|
$content=~s/\r\n/\n/g;
|
|
|
|
$content=~s/\r/\n/g;
|
|
|
|
$content.="\n" if $content !~ /\n$/;
|
|
|
|
|
|
|
|
$config{cgi}=0; # avoid cgi error message
|
|
|
|
eval { writefile($file, $config{srcdir}, $content) };
|
|
|
|
$config{cgi}=1;
|
|
|
|
if ($@) {
|
protect $@ whenever a block using $@ is non-trivial
As noted in the Try::Tiny man page, eval/$@ can be quite awkward in
corner cases, because $@ has the same properties and problems as C's
errno. While writing a regression test for definetemplate
in which it couldn't find an appropriate template, I received
<span class="error">Error: failed to process template
<span class="createlink">deftmpl</span> </span>
instead of the intended
<span class="error">Error: failed to process template
<span class="createlink">deftmpl</span> template deftmpl not
found</span>
which turned out to be because the "catch"-analogous block called
gettext before it used $@, and gettext can call define_gettext,
which uses eval.
This commit alters all current "catch"-like blocks that use $@, except
those that just do trivial things with $@ (string interpolation, string
concatenation) and call a function (die, error, print, etc.)
2014-02-21 18:06:36 +01:00
|
|
|
# save $@ in case a called function clobbers it
|
|
|
|
my $error = $@;
|
2008-09-05 19:57:25 +02:00
|
|
|
$form->field(name => "rcsinfo", value => rcs_prepedit($file),
|
|
|
|
force => 1);
|
|
|
|
my $mtemplate=template("editfailedsave.tmpl");
|
protect $@ whenever a block using $@ is non-trivial
As noted in the Try::Tiny man page, eval/$@ can be quite awkward in
corner cases, because $@ has the same properties and problems as C's
errno. While writing a regression test for definetemplate
in which it couldn't find an appropriate template, I received
<span class="error">Error: failed to process template
<span class="createlink">deftmpl</span> </span>
instead of the intended
<span class="error">Error: failed to process template
<span class="createlink">deftmpl</span> template deftmpl not
found</span>
which turned out to be because the "catch"-analogous block called
gettext before it used $@, and gettext can call define_gettext,
which uses eval.
This commit alters all current "catch"-like blocks that use $@, except
those that just do trivial things with $@ (string interpolation, string
concatenation) and call a function (die, error, print, etc.)
2014-02-21 18:06:36 +01:00
|
|
|
$mtemplate->param(error_message => $error);
|
2008-09-05 19:57:25 +02:00
|
|
|
$form->tmpl_param("message", $mtemplate->output);
|
|
|
|
$form->field("editcontent", value => $content, force => 1);
|
|
|
|
$form->tmpl_param("page_select", 0);
|
|
|
|
$form->field(name => "page", type => 'hidden');
|
|
|
|
$form->field(name => "type", type => 'hidden');
|
|
|
|
$form->title(sprintf(gettext("editing %s"), $page));
|
2011-01-05 21:58:27 +01:00
|
|
|
showform($form, \@buttons, $session, $q,
|
2011-01-05 18:49:04 +01:00
|
|
|
page => $page);
|
2008-09-05 19:57:25 +02:00
|
|
|
exit;
|
|
|
|
}
|
|
|
|
|
|
|
|
my $conflict;
|
|
|
|
if ($config{rcs}) {
|
|
|
|
if (! $exists) {
|
|
|
|
rcs_add($file);
|
|
|
|
}
|
|
|
|
|
|
|
|
# Prevent deadlock with post-commit hook by
|
|
|
|
# signaling to it that it should not try to
|
|
|
|
# do anything.
|
|
|
|
disable_commit_hook();
|
2010-06-23 23:35:21 +02:00
|
|
|
$conflict=rcs_commit(
|
|
|
|
file => $file,
|
|
|
|
message => $message,
|
2016-12-24 16:03:51 +01:00
|
|
|
token => scalar $form->field("rcsinfo"),
|
2010-06-23 23:35:21 +02:00
|
|
|
session => $session,
|
|
|
|
);
|
2008-09-05 19:57:25 +02:00
|
|
|
enable_commit_hook();
|
|
|
|
rcs_update();
|
|
|
|
}
|
|
|
|
|
|
|
|
# Refresh even if there was a conflict, since other changes
|
|
|
|
# may have been committed while the post-commit hook was
|
|
|
|
# disabled.
|
|
|
|
require IkiWiki::Render;
|
|
|
|
refresh();
|
|
|
|
saveindex();
|
|
|
|
|
|
|
|
if (defined $conflict) {
|
|
|
|
$form->field(name => "rcsinfo", value => rcs_prepedit($file),
|
|
|
|
force => 1);
|
|
|
|
$form->tmpl_param("message", template("editconflict.tmpl")->output);
|
|
|
|
$form->field("editcontent", value => $conflict, force => 1);
|
|
|
|
$form->field("do", "edit", force => 1);
|
|
|
|
$form->tmpl_param("page_select", 0);
|
|
|
|
$form->field(name => "page", type => 'hidden');
|
|
|
|
$form->field(name => "type", type => 'hidden');
|
|
|
|
$form->title(sprintf(gettext("editing %s"), $page));
|
2011-01-05 21:58:27 +01:00
|
|
|
showform($form, \@buttons, $session, $q,
|
2011-01-05 18:49:04 +01:00
|
|
|
page => $page);
|
2008-09-05 19:57:25 +02:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
# The trailing question mark tries to avoid broken
|
|
|
|
# caches and get the most recent version of the page.
|
2010-11-29 20:07:26 +01:00
|
|
|
redirect($q, $baseurl."?updated");
|
2008-09-05 19:57:25 +02:00
|
|
|
}
|
2012-04-13 20:28:02 +02:00
|
|
|
|
|
|
|
if ($cansubscribe && length $form->field("subscribe")) {
|
|
|
|
my $subspec="comment($page)";
|
|
|
|
IkiWiki::Plugin::notifyemail::subscribe(
|
|
|
|
$session->param('name'), $subspec);
|
|
|
|
}
|
2008-09-05 19:57:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
exit;
|
2008-12-17 21:22:16 +01:00
|
|
|
}
|
2008-09-05 19:57:25 +02:00
|
|
|
|
|
|
|
1
|