X-Git-Url: https://git.cyclocoop.org/%7B%7B%20url_for%28?a=blobdiff_plain;f=poll.pm;h=411f3bd39b8979071caefd75f1b0d9d8ac6001c8;hb=7764e02283b706857fc3318af2b6d15c695de426;hp=612b49d1fb2bc4505cf349207517fe7dea494851;hpb=d5fce9d5efc06ee69f7abce3fe64b7c144c9b6c3;p=ikiwiki%2Fpoll.git
diff --git a/poll.pm b/poll.pm
index 612b49d..411f3bd 100644
--- a/poll.pm
+++ b/poll.pm
@@ -22,6 +22,22 @@ sub getsetup () {
, section => "widget"
};
}
+my $params_re
+ = qr{
+ (?>
+ (?>(?:[^\[\]]|\[[^\[]|\][^\]])+)
+ |
+ (?'loop'
+ \[\[
+ (?>
+ (?>(?:[^\[\]]|\[[^\[]|\][^\]])+)
+ |
+ (?&loop)
+ )*
+ \]\]
+ )
+ )*
+ }x;
sub scan (@) {
my %params = @_;
my $page = $params{page};
@@ -30,7 +46,7 @@ sub scan (@) {
my $type = IkiWiki::pagetype($pagesources{$page});
if (defined $type and $type eq "mdwn") {
my %polls = ();
- while ($content =~ m{(\\?)\[\[\Q$prefix\E(\s+id="([^"]*)")?\s+(.+?)\s*\]\]}gs) {
+ while ($content =~ m{(\\?)\[\[\Q$prefix\E(\s+id="([^"]*)")?\s+($params_re)\s*\]\]}gs) {
my ($escape, $poll, $directive) = ($1, $3, $4);
next if $escape;
$poll = '' unless defined $poll;
@@ -119,10 +135,11 @@ sub preprocess (@) {
if $choices{$choice}{unknown_votes};
}
if ($open && exists $config{cgiurl}) {
+ my $choice_escaped = URI::Escape::uri_escape_utf8($choice, '^A-Za-z0-9\ \-\._~/');
$ret.="\n";
$ret.="\n";
$ret.="\n";
- $ret.="\n";
+ $ret.="\n";
$ret.="\n";
}
$ret.="$choice";
@@ -156,7 +173,8 @@ sub sessioncgi ($$) {
my $cgi=shift;
my $session=shift;
if (defined $cgi->param('do') && $cgi->param('do') eq "poll") {
- my $choice=decode_utf8($cgi->param('choice'));
+ my $choice = Encode::decode_utf8(URI::Escape::uri_unescape(IkiWiki::possibly_foolish_untaint($cgi->param('choice'))));
+
if (! defined $choice || not length $choice) {
error("no choice specified");
}
@@ -169,6 +187,7 @@ sub sessioncgi ($$) {
use Data::Dumper;
error("bad page name");
}
+ &IkiWiki::check_canedit($page, $cgi, $session);
# Did they vote before? If so, let them change their vote,
# and check for dups.
@@ -239,7 +258,25 @@ sub sessioncgi ($$) {
return "$params";
};
my $id='';
- $content =~ s{(\\?)\[\[\Q$prefix\E(\s+id="([^"]*)")?(\s+)(.+?)(\s*)\]\]}{$id=$3;$1.'[['.$prefix.$2.$4.$edit->($1, $5).$6.']]'}gse;
+ $content =~
+ s{
+ (?\\?)
+ \[\[\Q$prefix\E
+ (?:(?\s+)id="(?[^"]*)")?
+ (?\s+)
+ (?$params_re)
+ (?\s*)
+ \]\]
+ }
+ {$id=$+{id};
+ $+{escape}
+ .'[['.$prefix
+ .($+{id} eq ''?'':$+{id_space}.'id="'.$+{id}.'"')
+ .$+{params_space}
+ .$edit->($+{escape}, $+{params})
+ .$+{end_space}
+ .']]'
+ }egsx;
# Store their vote, update the page, and redirect to it.
writefile($pagesources{$page}, $config{srcdir}, $content);
@@ -282,9 +319,13 @@ package IkiWiki::PageSpec;
my ($page, $match, %params) = @_;
my $polls = $IkiWiki::pagestate{$page}{poll};
if (defined $polls and %$polls) {
- my ($match_poll, $match_user, $match_choice) = $match =~ m/^id=(.*?) user=(.*?) choice=(.*?)$/;
- if (exists $polls->{$match_poll}) {
- my %poll = %{$polls->{$match_poll}};
+ my ($match_id, $match_user, $match_choice) = $match =~ m/^id=(.*?) user=(.*?) choice=(.*?)$/;
+ my $match_id_re = IkiWiki::glob2re($match_id?$match_id:'*');
+ my @polls = grep {$_ =~ $match_id_re} (keys %$polls);
+ return IkiWiki::FailReason->new("no poll match id=`$match_id'", $page => $IkiWiki::DEPEND_CONTENT)
+ unless @polls > 0;
+ foreach my $poll (@polls) {
+ my %poll = %{$polls->{$poll}};
my $match_user_re = IkiWiki::glob2re($match_user?$match_user:'*');
my $match_choice_re = IkiWiki::glob2re($match_choice?$match_choice:'*');
while (my ($choice, $data) = each %poll) {
@@ -304,11 +345,8 @@ package IkiWiki::PageSpec;
}
}
}
- return IkiWiki::FailReason->new("no user=`$match_user' has voted for choice=`$match_choice'", $page => $IkiWiki::DEPEND_CONTENT);
- }
- else {
- return IkiWiki::FailReason->new("no poll id=`$match_poll'", $page => $IkiWiki::DEPEND_CONTENT);
}
+ return IkiWiki::FailReason->new("no user=`$match_user' has voted for choice=`$match_choice'", $page => $IkiWiki::DEPEND_CONTENT);
}
else {
return IkiWiki::FailReason->new("no poll", $page => $IkiWiki::DEPEND_CONTENT);