Merge branch 'tova'
commit
c987aee47a
|
@ -88,6 +88,7 @@ sub defaultconfig () { #{{{
|
|||
account_creation_password => "",
|
||||
prefix_directives => 0,
|
||||
hardlink => 0,
|
||||
cgi_disable_uploads => 1,
|
||||
} #}}}
|
||||
|
||||
sub checkconfig () { #{{{
|
||||
|
|
|
@ -281,7 +281,6 @@ sub cgi_editpage ($$) { #{{{
|
|||
eval q{use CGI::FormBuilder};
|
||||
error($@) if $@;
|
||||
my $form = CGI::FormBuilder->new(
|
||||
title => "editpage",
|
||||
fields => \@fields,
|
||||
charset => "utf-8",
|
||||
method => 'POST',
|
||||
|
@ -304,7 +303,7 @@ sub cgi_editpage ($$) { #{{{
|
|||
|
||||
# This untaint is safe because titlepage removes any problematic
|
||||
# characters.
|
||||
my ($page)=$form->field('page');
|
||||
my $page=$form->field('page');
|
||||
$page=titlepage(possibly_foolish_untaint($page));
|
||||
if (! defined $page || ! length $page ||
|
||||
file_pruned($page, $config{srcdir}) || $page=~/^\//) {
|
||||
|
@ -667,10 +666,11 @@ sub cgi (;$$) { #{{{
|
|||
my $q=shift;
|
||||
my $session=shift;
|
||||
|
||||
eval q{use CGI};
|
||||
error($@) if $@;
|
||||
$CGI::DISABLE_UPLOADS=$config{cgi_disable_uploads};
|
||||
|
||||
if (! $q) {
|
||||
eval q{use CGI};
|
||||
error($@) if $@;
|
||||
|
||||
binmode(STDIN);
|
||||
$q=CGI->new;
|
||||
binmode(STDIN, ":utf8");
|
||||
|
|
|
@ -0,0 +1,346 @@
|
|||
#!/usr/bin/perl
|
||||
package IkiWiki::Plugin::attachment;
|
||||
|
||||
use warnings;
|
||||
use strict;
|
||||
use IkiWiki 2.00;
|
||||
|
||||
sub import { #{{{
|
||||
hook(type => "checkconfig", id => "attachment", call => \&checkconfig);
|
||||
hook(type => "formbuilder_setup", id => "attachment", call => \&formbuilder_setup);
|
||||
hook(type => "formbuilder", id => "attachment", call => \&formbuilder);
|
||||
} # }}}
|
||||
|
||||
sub checkconfig () { #{{{
|
||||
$config{cgi_disable_uploads}=0;
|
||||
} #}}}
|
||||
|
||||
sub formbuilder_setup (@) { #{{{
|
||||
my %params=@_;
|
||||
my $form=$params{form};
|
||||
my $q=$params{cgi};
|
||||
|
||||
if ($form->field("do") eq "edit") {
|
||||
$form->field(name => 'attachment', type => 'file');
|
||||
# These buttons are not put in the usual place, so
|
||||
# are not added to the normal formbuilder button list.
|
||||
$form->tmpl_param("field-upload" => '<input name="_submit" type="submit" value="Upload Attachment" />');
|
||||
$form->tmpl_param("field-link" => '<input name="_submit" type="submit" value="Insert Links" />');
|
||||
|
||||
# Add the javascript from the toggle plugin;
|
||||
# the attachments interface uses it to toggle visibility.
|
||||
require IkiWiki::Plugin::toggle;
|
||||
$form->tmpl_param("javascript" => $IkiWiki::Plugin::toggle::javascript);
|
||||
# Start with the attachments interface toggled invisible,
|
||||
# but if it was used, keep it open.
|
||||
if ($form->submitted ne "Upload Attachment" &&
|
||||
! length $q->param("attachment_select")) {
|
||||
$form->tmpl_param("attachments-class" => "toggleable");
|
||||
}
|
||||
else {
|
||||
$form->tmpl_param("attachments-class" => "toggleable-open");
|
||||
}
|
||||
}
|
||||
elsif ($form->title eq "preferences") {
|
||||
my $session=$params{session};
|
||||
my $user_name=$session->param("name");
|
||||
|
||||
$form->field(name => "allowed_attachments", size => 50,
|
||||
fieldset => "admin",
|
||||
comment => "(".htmllink("", "", "ikiwiki/PageSpec", noimageinline => 1).")");
|
||||
if (! IkiWiki::is_admin($user_name)) {
|
||||
$form->field(name => "allowed_attachments", type => "hidden");
|
||||
}
|
||||
if (! $form->submitted) {
|
||||
$form->field(name => "allowed_attachments", force => 1,
|
||||
value => IkiWiki::userinfo_get($user_name, "allowed_attachments"));
|
||||
}
|
||||
if ($form->submitted && $form->submitted eq 'Save Preferences') {
|
||||
if (defined $form->field("allowed_attachments")) {
|
||||
IkiWiki::userinfo_set($user_name, "allowed_attachments",
|
||||
$form->field("allowed_attachments")) ||
|
||||
error("failed to set allowed_attachments");
|
||||
}
|
||||
}
|
||||
}
|
||||
} #}}}
|
||||
|
||||
sub formbuilder (@) { #{{{
|
||||
my %params=@_;
|
||||
my $form=$params{form};
|
||||
my $q=$params{cgi};
|
||||
|
||||
return if $form->field("do") ne "edit";
|
||||
|
||||
my $filename=$q->param('attachment');
|
||||
if (defined $filename && length $filename &&
|
||||
($form->submitted eq "Upload Attachment" || $form->submitted eq "Save Page")) {
|
||||
my $session=$params{session};
|
||||
|
||||
# This is an (apparently undocumented) way to get the name
|
||||
# of the temp file that CGI writes the upload to.
|
||||
my $tempfile=$q->tmpFileName($filename);
|
||||
|
||||
$filename=IkiWiki::titlepage(
|
||||
IkiWiki::possibly_foolish_untaint(
|
||||
attachment_location($form->field('page')).
|
||||
IkiWiki::basename($filename)));
|
||||
if (IkiWiki::file_pruned($filename, $config{srcdir})) {
|
||||
error(gettext("bad attachment filename"));
|
||||
}
|
||||
|
||||
# Check that the user is allowed to edit a page with the
|
||||
# name of the attachment.
|
||||
IkiWiki::check_canedit($filename, $q, $session, 1);
|
||||
|
||||
# Use a special pagespec to test that the attachment is valid.
|
||||
my $allowed=1;
|
||||
foreach my $admin (@{$config{adminuser}}) {
|
||||
my $allowed_attachments=IkiWiki::userinfo_get($admin, "allowed_attachments");
|
||||
if (defined $allowed_attachments &&
|
||||
length $allowed_attachments) {
|
||||
$allowed=pagespec_match($filename,
|
||||
$allowed_attachments,
|
||||
file => $tempfile,
|
||||
user => $session->param("name"),
|
||||
ip => $ENV{REMOTE_ADDR},
|
||||
);
|
||||
last if $allowed;
|
||||
}
|
||||
}
|
||||
if (! $allowed) {
|
||||
error(gettext("attachment rejected")." ($allowed)");
|
||||
}
|
||||
|
||||
# Needed for fast_file_copy and for rendering below.
|
||||
require IkiWiki::Render;
|
||||
|
||||
# Move the attachment into place.
|
||||
# Try to use a fast rename; fall back to copying.
|
||||
IkiWiki::prep_writefile($filename, $config{srcdir});
|
||||
unlink($config{srcdir}."/".$filename);
|
||||
if (rename($tempfile, $config{srcdir}."/".$filename)) {
|
||||
# The temp file has tight permissions; loosen up.
|
||||
chmod(0666 & ~umask, $config{srcdir}."/".$filename);
|
||||
}
|
||||
else {
|
||||
my $fh=$q->upload('attachment');
|
||||
if (! defined $fh || ! ref $fh) {
|
||||
error("failed to get filehandle");
|
||||
}
|
||||
binmode($fh);
|
||||
writefile($filename, $config{srcdir}, undef, 1, sub {
|
||||
IkiWiki::fast_file_copy($tempfile, $filename, $fh, @_);
|
||||
});
|
||||
}
|
||||
|
||||
# Check the attachment in and trigger a wiki refresh.
|
||||
if ($config{rcs}) {
|
||||
IkiWiki::rcs_add($filename);
|
||||
IkiWiki::disable_commit_hook();
|
||||
IkiWiki::rcs_commit($filename, gettext("attachment upload"),
|
||||
IkiWiki::rcs_prepedit($filename),
|
||||
$session->param("name"), $ENV{REMOTE_ADDR});
|
||||
IkiWiki::enable_commit_hook();
|
||||
IkiWiki::rcs_update();
|
||||
}
|
||||
IkiWiki::refresh();
|
||||
IkiWiki::saveindex();
|
||||
}
|
||||
elsif ($form->submitted eq "Insert Links") {
|
||||
my $add="";
|
||||
foreach my $f ($q->param("attachment_select")) {
|
||||
$add.="[[$f]]\n";
|
||||
}
|
||||
$form->field(name => 'editcontent',
|
||||
value => $form->field('editcontent')."\n\n".$add,
|
||||
force => 1) if length $add;
|
||||
}
|
||||
|
||||
# Generate the attachment list only after having added any new
|
||||
# attachments.
|
||||
$form->tmpl_param("attachment_list" => [attachment_list($form->field('page'))]);
|
||||
} # }}}
|
||||
|
||||
sub attachment_location ($) {
|
||||
my $page=shift;
|
||||
|
||||
# Put the attachment in a subdir of the page it's attached
|
||||
# to, unless that page is an "index" page.
|
||||
$page=~s/(^|\/)index//;
|
||||
$page.="/" if length $page;
|
||||
|
||||
return $page;
|
||||
}
|
||||
|
||||
sub attachment_list ($) {
|
||||
my $page=shift;
|
||||
my $loc=attachment_location($page);
|
||||
|
||||
my @ret;
|
||||
foreach my $f (values %pagesources) {
|
||||
if (! defined IkiWiki::pagetype($f) &&
|
||||
$f=~m/^\Q$loc\E[^\/]+$/ &&
|
||||
-e "$config{srcdir}/$f") {
|
||||
push @ret, {
|
||||
"field-select" => '<input type="checkbox" name="attachment_select" value="'.$f.'" />',
|
||||
link => htmllink($page, $page, $f, noimageinline => 1),
|
||||
size => humansize((stat(_))[7]),
|
||||
mtime => displaytime($IkiWiki::pagemtime{$f}),
|
||||
mtime_raw => $IkiWiki::pagemtime{$f},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
# Sort newer attachments to the top of the list, so a newly-added
|
||||
# attachment appears just before the form used to add it.
|
||||
return sort { $b->{mtime_raw} <=> $a->{mtime_raw} || $a->{link} cmp $b->{link} } @ret;
|
||||
}
|
||||
|
||||
my %units=( # size in bytes
|
||||
B => 1,
|
||||
byte => 1,
|
||||
KB => 2 ** 10,
|
||||
kilobyte => 2 ** 10,
|
||||
K => 2 ** 10,
|
||||
KB => 2 ** 10,
|
||||
kilobyte => 2 ** 10,
|
||||
M => 2 ** 20,
|
||||
MB => 2 ** 20,
|
||||
megabyte => 2 ** 20,
|
||||
G => 2 ** 30,
|
||||
GB => 2 ** 30,
|
||||
gigabyte => 2 ** 30,
|
||||
T => 2 ** 40,
|
||||
TB => 2 ** 40,
|
||||
terabyte => 2 ** 40,
|
||||
P => 2 ** 50,
|
||||
PB => 2 ** 50,
|
||||
petabyte => 2 ** 50,
|
||||
E => 2 ** 60,
|
||||
EB => 2 ** 60,
|
||||
exabyte => 2 ** 60,
|
||||
Z => 2 ** 70,
|
||||
ZB => 2 ** 70,
|
||||
zettabyte => 2 ** 70,
|
||||
Y => 2 ** 80,
|
||||
YB => 2 ** 80,
|
||||
yottabyte => 2 ** 80,
|
||||
# ikiwiki, if you find you need larger data quantities, either modify
|
||||
# yourself to add them, or travel back in time to 2008 and kill me.
|
||||
# -- Joey
|
||||
);
|
||||
|
||||
sub parsesize ($) { #{{{
|
||||
my $size=shift;
|
||||
|
||||
no warnings;
|
||||
my $base=$size+0; # force to number
|
||||
use warnings;
|
||||
foreach my $unit (sort keys %units) {
|
||||
if ($size=~/[0-9\s]\Q$unit\E$/i) {
|
||||
return $base * $units{$unit};
|
||||
}
|
||||
}
|
||||
return $base;
|
||||
} #}}}
|
||||
|
||||
sub humansize ($) { #{{{
|
||||
my $size=shift;
|
||||
|
||||
foreach my $unit (reverse sort { $units{$a} <=> $units{$b} || $b cmp $a } keys %units) {
|
||||
if ($size / $units{$unit} > 0.25) {
|
||||
return (int($size / $units{$unit} * 10)/10).$unit;
|
||||
}
|
||||
}
|
||||
return $size; # near zero, or negative
|
||||
} #}}}
|
||||
|
||||
package IkiWiki::PageSpec;
|
||||
|
||||
sub match_maxsize ($$;@) { #{{{
|
||||
shift;
|
||||
my $maxsize=eval{IkiWiki::Plugin::attachment::parsesize(shift)};
|
||||
if ($@) {
|
||||
return IkiWiki::FailReason->new("unable to parse maxsize (or number too large)");
|
||||
}
|
||||
|
||||
my %params=@_;
|
||||
if (! exists $params{file}) {
|
||||
return IkiWiki::FailReason->new("no file specified");
|
||||
}
|
||||
|
||||
if (-s $params{file} > $maxsize) {
|
||||
return IkiWiki::FailReason->new("file too large (".(-s $params{file})." > $maxsize)");
|
||||
}
|
||||
else {
|
||||
return IkiWiki::SuccessReason->new("file not too large");
|
||||
}
|
||||
} #}}}
|
||||
|
||||
sub match_minsize ($$;@) { #{{{
|
||||
shift;
|
||||
my $minsize=eval{IkiWiki::Plugin::attachment::parsesize(shift)};
|
||||
if ($@) {
|
||||
return IkiWiki::FailReason->new("unable to parse minsize (or number too large)");
|
||||
}
|
||||
|
||||
my %params=@_;
|
||||
if (! exists $params{file}) {
|
||||
return IkiWiki::FailReason->new("no file specified");
|
||||
}
|
||||
|
||||
if (-s $params{file} < $minsize) {
|
||||
return IkiWiki::FailReason->new("file too small");
|
||||
}
|
||||
else {
|
||||
return IkiWiki::SuccessReason->new("file not too small");
|
||||
}
|
||||
} #}}}
|
||||
|
||||
sub match_ispage ($$;@) { #{{{
|
||||
my $filename=shift;
|
||||
|
||||
if (defined IkiWiki::pagetype($filename)) {
|
||||
return IkiWiki::SuccessReason->new("file is a wiki page");
|
||||
}
|
||||
else {
|
||||
return IkiWiki::FailReason->new("file is not a wiki page");
|
||||
}
|
||||
} #}}}
|
||||
|
||||
sub match_user ($$;@) { #{{{
|
||||
shift;
|
||||
my $user=shift;
|
||||
my %params=@_;
|
||||
|
||||
if (! exists $params{user}) {
|
||||
return IkiWiki::FailReason->new("no user specified");
|
||||
}
|
||||
|
||||
if (defined $params{user} && lc $params{user} eq lc $user) {
|
||||
return IkiWiki::SuccessReason->new("user is $user");
|
||||
}
|
||||
else {
|
||||
return IkiWiki::FailReason->new("user is $params{user}, not $user");
|
||||
}
|
||||
} #}}}
|
||||
|
||||
sub match_ip ($$;@) { #{{{
|
||||
shift;
|
||||
my $ip=shift;
|
||||
my %params=@_;
|
||||
|
||||
if (! exists $params{ip}) {
|
||||
return IkiWiki::FailReason->new("no IP specified");
|
||||
}
|
||||
|
||||
if (defined $params{ip} && lc $params{ip} eq lc $ip) {
|
||||
return IkiWiki::SuccessReason->new("IP is $ip");
|
||||
}
|
||||
else {
|
||||
return IkiWiki::FailReason->new("IP is $params{ip}, not $ip");
|
||||
}
|
||||
} #}}}
|
||||
|
||||
1
|
|
@ -48,8 +48,7 @@ sub formbuilder_setup { #{{{
|
|||
my $form=$params{form};
|
||||
my $page=$form->field("page");
|
||||
|
||||
return if $form->title ne "editpage"
|
||||
|| $form->field("do") ne "edit";
|
||||
return if $form->field("do") ne "edit";
|
||||
|
||||
$page = IkiWiki::titlepage(IkiWiki::possibly_foolish_untaint($page));
|
||||
return unless exists $pagesources{$page};
|
||||
|
|
|
@ -40,11 +40,11 @@ sub formbuilder_setup (@) { #{{{
|
|||
my %params=@_;
|
||||
|
||||
my $form=$params{form};
|
||||
my $session=$params{session};
|
||||
my $cgi=$params{cgi};
|
||||
my $user_name=$session->param("name");
|
||||
|
||||
if ($form->title eq "preferences") {
|
||||
my $session=$params{session};
|
||||
my $cgi=$params{cgi};
|
||||
my $user_name=$session->param("name");
|
||||
|
||||
$form->field(name => "locked_pages", size => 50,
|
||||
fieldset => "admin",
|
||||
comment => "(".htmllink("", "", "ikiwiki/PageSpec", noimageinline => 1).")");
|
||||
|
|
|
@ -9,7 +9,7 @@ use IkiWiki 2.00;
|
|||
# of css to hide toggleables, to avoid any flashing on page load. The css
|
||||
# is only emitted after the javascript tests that it's going to be able to
|
||||
# show the toggleables.
|
||||
my $javascript=<<'EOF';
|
||||
our $javascript=<<'EOF';
|
||||
<script type="text/javascript">
|
||||
<!--
|
||||
if (document.getElementById && document.getElementsByTagName && document.createTextNode) {
|
||||
|
@ -21,7 +21,8 @@ function inittoggle() {
|
|||
var as = getElementsByClass('toggle');
|
||||
for (var i = 0; i < as.length; i++) {
|
||||
var id = as[i].href.match(/#(\w.+)/)[1];
|
||||
document.getElementById(id).style.display="none";
|
||||
if (document.getElementById(id).className == "toggleable")
|
||||
document.getElementById(id).style.display="none";
|
||||
as[i].onclick = function() {
|
||||
toggle(this);
|
||||
return false;
|
||||
|
@ -80,17 +81,11 @@ sub preprocess_toggle (@) { #{{{
|
|||
my %params=(id => "default", text => "more", @_);
|
||||
|
||||
my $id=genid($params{page}, $params{id});
|
||||
if (! $params{preview}) {
|
||||
return "<a class=\"toggle\" href=\"#$id\">$params{text}</a>";
|
||||
}
|
||||
else {
|
||||
return "$params{text} ".
|
||||
gettext("(not toggleable in preview mode)");
|
||||
}
|
||||
return "<a class=\"toggle\" href=\"#$id\">$params{text}</a>";
|
||||
} # }}}
|
||||
|
||||
sub preprocess_toggleable (@) { #{{{
|
||||
my %params=(id => "default", text => "", @_);
|
||||
my %params=(id => "default", text => "", open => "no", @_);
|
||||
|
||||
# Preprocess the text to expand any preprocessor directives
|
||||
# embedded inside it.
|
||||
|
@ -98,23 +93,24 @@ sub preprocess_toggleable (@) { #{{{
|
|||
IkiWiki::filter($params{page}, $params{destpage}, $params{text}));
|
||||
|
||||
my $id=genid($params{page}, $params{id});
|
||||
my $class=(lc($params{open}) ne "yes") ? "toggleable" : "toggleable-open";
|
||||
|
||||
# Should really be a postprocessor directive, oh well. Work around
|
||||
# markdown's dislike of markdown inside a <div> with various funky
|
||||
# whitespace.
|
||||
my ($indent)=$params{text}=~/( +)$/;
|
||||
$indent="" unless defined $indent;
|
||||
return "<div class=\"toggleable\" id=\"$id\"></div>\n\n$params{text}\n$indent<div class=\"toggleableend\"></div>";
|
||||
return "<div class=\"$class\" id=\"$id\"></div>\n\n$params{text}\n$indent<div class=\"toggleableend\"></div>";
|
||||
} # }}}
|
||||
|
||||
sub format (@) { #{{{
|
||||
my %params=@_;
|
||||
|
||||
if ($params{content}=~s!(<div class="toggleable" id="[^"]+">)</div>!$1!g) {
|
||||
if ($params{content}=~s!(<div class="toggleable(?:-open)?" id="[^"]+">)</div>!$1!g) {
|
||||
$params{content}=~s/<div class="toggleableend">//g;
|
||||
if (! ($params{content}=~s!^<\/body>!$javascript</body>!m)) {
|
||||
if (! ($params{content}=~s!^<body>!<body>$javascript!m)) {
|
||||
# no </body> tag, probably in preview mode
|
||||
$params{content}.=$javascript;
|
||||
$params{content}=$javascript.$params{content};
|
||||
}
|
||||
}
|
||||
return $params{content};
|
||||
|
|
|
@ -180,6 +180,30 @@ sub scan ($) { #{{{
|
|||
}
|
||||
} #}}}
|
||||
|
||||
sub fast_file_copy (@) { #{{{
|
||||
my $srcfile=shift;
|
||||
my $destfile=shift;
|
||||
my $srcfd=shift;
|
||||
my $destfd=shift;
|
||||
my $cleanup=shift;
|
||||
|
||||
my $blksize = 16384;
|
||||
my ($len, $buf, $written);
|
||||
while ($len = sysread $srcfd, $buf, $blksize) {
|
||||
if (! defined $len) {
|
||||
next if $! =~ /^Interrupted/;
|
||||
error("failed to read $srcfile: $!", $cleanup);
|
||||
}
|
||||
my $offset = 0;
|
||||
while ($len) {
|
||||
defined($written = syswrite $destfd, $buf, $len, $offset)
|
||||
or error("failed to write $destfile: $!", $cleanup);
|
||||
$len -= $written;
|
||||
$offset += $written;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub render ($) { #{{{
|
||||
my $file=shift;
|
||||
|
||||
|
@ -215,24 +239,7 @@ sub render ($) { #{{{
|
|||
|
||||
my $srcfd=readfile($srcfile, 1, 1);
|
||||
writefile($file, $config{destdir}, undef, 1, sub {
|
||||
my $destfd=shift;
|
||||
my $cleanup=shift;
|
||||
|
||||
my $blksize = 16384;
|
||||
my ($len, $buf, $written);
|
||||
while ($len = sysread $srcfd, $buf, $blksize) {
|
||||
if (! defined $len) {
|
||||
next if $! =~ /^Interrupted/;
|
||||
error("failed to read $srcfile: $!", $cleanup);
|
||||
}
|
||||
my $offset = 0;
|
||||
while ($len) {
|
||||
defined($written = syswrite $destfd, $buf, $len, $offset)
|
||||
or error("failed to write $file: $!", $cleanup);
|
||||
$len -= $written;
|
||||
$offset += $written;
|
||||
}
|
||||
}
|
||||
fast_file_copy($srcfile, $file, $srcfd, @_);
|
||||
});
|
||||
}
|
||||
} #}}}
|
||||
|
|
|
@ -1,3 +1,16 @@
|
|||
ikiwiki (2.52) UNRELEASED; urgency=low
|
||||
|
||||
* attachment: New plugin for uploading and managing attachments.
|
||||
(Sponsored by The TOVA Company.)
|
||||
* If attachments are not enabled, configure CGI.pm to disable file
|
||||
uploads by default. (An anti-DOS measure.)
|
||||
* toggle: Add support for toggles that are open by default.
|
||||
* toggle: Fix to work in preview mode.
|
||||
* toggle: Add javascript to top of page, not to end. This avoids flicker
|
||||
since closed toggles will not be displayed as the page is loading.
|
||||
|
||||
-- Joey Hess <joeyh@debian.org> Mon, 30 Jun 2008 19:56:28 -0400
|
||||
|
||||
ikiwiki (2.51) unstable; urgency=low
|
||||
|
||||
* Improve toplevel parentlink to link directly to index.html when usedirs is
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
[[template id=plugin name=conditional core=1 author="[[Joey]]"]]
|
||||
[[tag type/useful]]
|
||||
|
||||
This plugin allows files to be uploaded to the wiki over the web.
|
||||
|
||||
For each page `foo`, files in the subdirectory `foo/` are treated as
|
||||
attachments of that page. Attachments can be uploaded and managed as
|
||||
part of the interface for editing a page.
|
||||
|
||||
Warning: Do not enable this plugin on publically editable wikis, unless you
|
||||
take care to lock down the types and sizes of files that can be uploaded.
|
||||
Bear in mind that if you let anyone upload a particular kind of file
|
||||
("*.mp3" files, say), then someone can abuse your wiki in at least three ways:
|
||||
|
||||
1. By uploading many mp3 files, wasting your disk space.
|
||||
2. By uploading mp3 files that attempt to exploit security holes
|
||||
in web browsers or other players.
|
||||
3. By uploading files that claim to be mp3 files, but are really some
|
||||
other kind of file. Some web browsers may display a `foo.mp3` that
|
||||
contains html as a web page; including running any malicious javascript
|
||||
embedded in that page.
|
||||
|
||||
To provide a way to combat these abuses, the wiki admin can specify a
|
||||
[[ikiwiki/PageSpec]] on their preferences page, to control what types of
|
||||
attachments can be uploaded, and by whom. The regular [[ikiwiki/PageSpec]]
|
||||
syntax is expanded with additional tests.
|
||||
|
||||
For example, to limit arbitrary files to 50 kilobytes, but allow
|
||||
larger mp3 files to be uploaded by joey, a test like this could be
|
||||
used:
|
||||
|
||||
(user(joey) and *.mp3 and maxsize(15mb)) or (!ispage() and maxsize(50kb))
|
||||
|
||||
The following additional tests are available:
|
||||
|
||||
* maxsize(size)
|
||||
|
||||
Tests whether the attachment is no larger than the specified size.
|
||||
The size defaults to being in bytes, but "kb", "mb", "gb" etc can be
|
||||
used to specify the units.
|
||||
|
||||
* minsize(size)
|
||||
|
||||
Tests whether the attachment is no smaller than the specified size.
|
||||
|
||||
* ispage()
|
||||
|
||||
Tests whether the attachment will be treated by ikiwiki as a wiki page.
|
||||
(Ie, if it has an extension of ".mdwn", or of any other enabled page
|
||||
format).
|
||||
|
||||
So, if you don't want to allow wiki pages to be uploaded as attachments,
|
||||
use `!ispage()` ; if you only want to allow wiki pages to be uploaded
|
||||
as attachments, use `ispage()`.
|
||||
|
||||
* user(username)
|
||||
|
||||
Tests whether the attachment is being uploaded by a user with the
|
||||
specified username. If openid is enabled, an openid can also be put here.
|
||||
|
||||
* ip(address)
|
||||
|
||||
Tests whether the attacment is being uploaded from the specified IP
|
||||
address.
|
|
@ -0,0 +1,18 @@
|
|||
I found this posted to todo list, moved here: --[[Joey]]
|
||||
|
||||
> First pass at an attachments plugin. See [[plugins/contrib/attach]] for
|
||||
> details/docs. Here's the [diff](http://pastebin.com/f4d889b65), and
|
||||
> here's some [technical notes](http://pastebin.com/f584b9d9d). There are
|
||||
> still various things I want to fix and tweak, but it works reasonably for
|
||||
> me as is.
|
||||
|
||||
I guess I missed this when the plugin page was posted last September, and
|
||||
since the [[soc]] stuff wasn't updated, I didn't realize this was Ben's soc
|
||||
work. Which is more or less why I didn't look at it.
|
||||
|
||||
This plugin would need quite a lot of work to finish up, I do think it was
|
||||
taking the right approach, sorry I never followed up on it.
|
||||
|
||||
In the meantime, I've written an attachment plugin that does most of the
|
||||
same stuff, and behaves closer to how I originally sketched [[todo/fileupload]]
|
||||
as working.
|
|
@ -28,3 +28,6 @@ each other, but can be located anywhere on the page. There can also be
|
|||
mutiple toggles that all toggle a single togglable.
|
||||
|
||||
The id has a default value of "default", so can be omitted in simple cases.
|
||||
|
||||
If you'd like a toggleable to be displayed by default, and toggle to
|
||||
hidden, then pass a parameter "open=true" when setting up the toggleable.
|
||||
|
|
|
@ -11,7 +11,7 @@ accepted, and the following projects were worked on:
|
|||
(See [[todo/latex]])
|
||||
* Implement File Upload Functionality and Image Gallery Creation
|
||||
by Ben Coffey
|
||||
(See [[todo/fileupload/soc-proposal]])
|
||||
(See [[todo/fileupload/soc-proposal]] and [[plugins/contrib/attach]])
|
||||
* Wiki WYSIWYG Editor
|
||||
by [[TaylorKillian]]
|
||||
(See [[todo/wikiwyg]])
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
Stuff the [[plugins/attachment]] plugin is currently missing, that might be
|
||||
nice to add:
|
||||
|
||||
* `mimetype()` pagespecs. (Using a mime type sniffer.)
|
||||
* Virus scanning.
|
||||
* Add a progress bar for attachment uploads (needs AJAX stuff..)
|
||||
* Maybe optimise the "Insert Links" button with javascript, so, if
|
||||
javascript is available, the link is inserted at the current cursor
|
||||
position in the page edit form, without actually reposting the form.
|
||||
(Falling back to the current reposting of the form if javascript is not
|
||||
available of course.)
|
||||
* Set `$CGI::POST_MAX` to some sane value (ie, larger than the largest
|
||||
configured `maxsize()` in the pagespec, or if none is configured,
|
||||
something reasonable. Just as a belt-and-suspenders DOS prevention.
|
||||
* Only allow attachments to be added to a given list of pages.
|
||||
Maybe a pagespec like `parent(patches/*)`
|
|
@ -1 +0,0 @@
|
|||
First pass at an attachments plugin. See [[plugins/contrib/attach]] for details/docs. Here's the [diff](http://pastebin.com/f4d889b65), and here's some [technical notes](http://pastebin.com/f584b9d9d). There are still various things I want to fix and tweak, but it works reasonably for me as is.
|
|
@ -60,4 +60,4 @@ pagespec lock like the above prevents an edit or upload from happening,
|
|||
ikiwiki could display a reasonable message to the user, indicating what
|
||||
they've done wrong.)
|
||||
|
||||
[[tag soc]]
|
||||
[[tag soc done]]
|
||||
|
|
|
@ -2,3 +2,5 @@ It would be nice if one could set the initial state of the toggleable area.
|
|||
--[[[rdennis]]
|
||||
|
||||
[[tag plugins/toggle]]
|
||||
|
||||
[[done]]
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
<TMPL_VAR JAVASCRIPT>
|
||||
<TMPL_IF NAME="PAGE_CONFLICT">
|
||||
<p>
|
||||
<b>Your changes conflict with other changes made to the page.</b>
|
||||
|
@ -60,6 +61,20 @@ Optional comment about this change:<br />
|
|||
</TMPL_IF>
|
||||
<TMPL_VAR FORM-SUBMIT>
|
||||
<TMPL_VAR HELPONFORMATTINGLINK>
|
||||
<a class="toggle" href="#attachments">Attachments</a>
|
||||
<TMPL_IF NAME="FIELD-ATTACHMENT">
|
||||
<div class="<TMPL_VAR ATTACHMENTS-CLASS>" id="attachments">
|
||||
<table>
|
||||
<tr><td colspan="5"><TMPL_VAR FIELD-ATTACHMENT><TMPL_VAR FIELD-UPLOAD></td></tr>
|
||||
<TMPL_LOOP NAME="ATTACHMENT_LIST">
|
||||
<tr><td><TMPL_VAR FIELD-SELECT><TMPL_VAR LINK></td><td><TMPL_VAR SIZE></td><td><TMPL_VAR MTIME></td></tr>
|
||||
</TMPL_LOOP>
|
||||
<TMPL_IF NAME="ATTACHMENT_LIST">
|
||||
<tr><td colspan="2"><TMPL_VAR FIELD-LINK><TMPL_VAR FIELD-DELETE><TMPL_VAR FIELD-RENAME></td></tr>
|
||||
</TMPL_IF>
|
||||
</table>
|
||||
</div>
|
||||
</TMPL_IF>
|
||||
<TMPL_VAR FORM-END>
|
||||
|
||||
<TMPL_IF NAME="PAGE_PREVIEW">
|
||||
|
|
Loading…
Reference in New Issue