add &base CGI and form support
[ikiwiki/events.git] / newevent.pm
1 #!/usr/bin/perl
2 package IkiWiki::Plugin::newevent;
3
4 use strict;
5 use warnings;
6 use IkiWiki 3.00;
7 use Time::Local;
8 use DateTime;
9 use CGI::FormBuilder;
10 use Data::Dumper;
11
12 sub import {
13 #hook(type => "formbuilder", id => "newevent", call => \&formbuilder);
14 #hook(type => "formbuilder_setup", id => "newevent", call => \&formbuilder_setup);
15 hook(type => "getsetup", id => "newevent", call => \&getsetup);
16 #hook(type => "preprocess", id => "newevent", call => \&preprocess);
17 #hook(type => "refresh", id => "newevent", call => \&refresh);
18 hook(type => "sessioncgi", id => "newevent", call => \&sessioncgi);
19 }
20
21 my @days = ('01'..'31');
22 my @hours = ('00'..'23');
23 my @minutes = ('00'..'59');
24
25 sub getsetup () {
26 return
27 ( plugin =>
28 { safe => 1
29 , rebuild => undef
30 , section => "misc"
31 }
32 , newevent_base =>
33 { type => "string"
34 , example => "Agenda"
35 , description => "prefix of the agenda hierarchy"
36 , safe => 1
37 , rebuild => 1
38 }
39 );
40 }
41 sub date_of_form ($$;%) {
42 my ($form, $prefix, %default) = @_;
43 %default =
44 ( year => 0
45 , month => 1
46 , day => 1
47 , hour => 0
48 , minute => 0
49 , %default
50 );
51 my $date;
52 eval { $date = DateTime->new
53 ( year => ($form->field($prefix.'_year') ne '' ? $form->field($prefix.'_year') : $default{year})
54 , month => ($form->field($prefix.'_month') ne '' ? substr($form->field($prefix.'_month'), 0, 2) : $default{month})
55 , day => ($form->field($prefix.'_day') ne '' ? $form->field($prefix.'_day') : $default{day})
56 , hour => ($form->field($prefix.'_hour') ne '' ? $form->field($prefix.'_hour') : $default{hour})
57 , minute => ($form->field($prefix.'_minute') ne '' ? $form->field($prefix.'_minute') : $default{minute})
58 , second => 0
59 , nanosecond => 0
60 , time_zone => 'local'
61 , locale => $config{locale}
62 )->set_time_zone('floating') };
63 return $date;
64 };
65 sub duration_of_form ($$) {
66 my ($form, $prefix) = @_;
67 my $dur;
68 eval { $dur = DateTime::Duration->new
69 ( years => $form->field($prefix.'_year')
70 , months => $form->field($prefix.'_month')
71 , days => $form->field($prefix.'_day')
72 , weeks => $form->field($prefix.'_week')
73 , hours => $form->field($prefix.'_hour')
74 , minutes => $form->field($prefix.'_minute')
75 , seconds => 0
76 , nanoseconds => 0
77 , end_of_month => 'limit'
78 ) };
79 return $dur;
80 };
81 sub page_of_event ($$$$$) {
82 my ($form, $from_date, $to_date, $name, $newevent_base) = @_;
83 my $time = '';
84 if ($form->field('from_hour') ne '' or $form->field('from_minute') ne '') {
85 if ($from_date->hour() == $to_date->hour()
86 and $from_date->minute() == $to_date->minute()) {
87 $time = sprintf('%02dh%02d', $from_date->hour(), $from_date->minute());
88 }
89 else {
90 $time = sprintf('%02dh%02d-%02dh%02d'
91 , $from_date->hour(), $from_date->minute()
92 , $to_date->hour(), $to_date->minute());
93 }
94 }
95 return
96 ( $newevent_base
97 . ($newevent_base?'/':'').$from_date->year()
98 . '/'.sprintf('%02d', $from_date->month())
99 . '/'.sprintf('%02d', $from_date->day())
100 . '/'. ($time ne '' ? $time . '/' : '')
101 . $name
102 );
103 }
104 sub check_cannewevent ($$$$) {
105 my $dest=shift;
106 my $destfile=shift;
107 my $cgi=shift;
108 my $session=shift;
109
110 # Must be a legal filename.
111 if (IkiWiki::file_pruned($destfile)) {
112 error(sprintf(gettext("illegal name")));
113 }
114 # Must not be a known source file.
115 if (exists $pagesources{$dest}) {
116 error(sprintf(gettext("%s already exists"),
117 htmllink("", "", $dest
118 , linktext => $dest
119 , noimageinline => 1)));
120 }
121 # Must not exist on disk already.
122 if (-l "$config{srcdir}/$destfile" || -e _) {
123 error(sprintf(gettext("%s already exists on disk"), $destfile));
124 }
125
126 # Must be editable.
127 IkiWiki::check_canedit($dest, $cgi, $session);
128
129 my $can_newevent;
130 IkiWiki::run_hooks(can_newevent => sub {
131 return if defined $can_newevent;
132 my $ret=shift->(cgi => $cgi, session => $session, dest => $dest, destfile => $destfile);
133 if (defined $ret) {
134 if ($ret eq "") {
135 $can_newevent=1;
136 }
137 elsif (ref $ret eq 'CODE') {
138 $ret->();
139 $can_newevent=0;
140 }
141 elsif (defined $ret) {
142 error($ret);
143 $can_newevent=0;
144 }
145 }
146 });
147 return defined $can_newevent ? $can_newevent : 1;
148 }
149 sub post_newevent ($$$) {
150 my $cgi=shift;
151 my $session=shift;
152 my $dest=shift;
153
154 IkiWiki::redirect($cgi, urlto($dest));
155 exit;
156 }
157 sub preprocess (@) {
158 #my %params =
159 # ( base => ($config{newevent_base} ? $config{newevent_base} : gettext('Agenda'))
160 # , @_ );
161 #($form, $buttons) = newevent_form()
162 # if not defined $form;
163 #my $ret = $form->render();
164 return "<div class='newevent'></div>";
165 }
166 sub sessioncgi ($$) {
167 my ($cgi, $session) = @_;
168 if (defined $cgi->param('do') && $cgi->param('do') eq "newevent") {
169 # TOTRY: decode_cgi_utf8($cgi);
170
171 my $now_date = DateTime->now
172 ( time_zone => 'local'
173 , locale => $config{locale}
174 )->set_time_zone('floating');
175 my %dows = map { ($_ => $now_date->{locale}->day_format_wide->[ $_ ]) } (0..6);
176 my %months = map { ($_ => $now_date->{locale}->month_format_wide->[ $_ - 1 ]) } (1..12);
177 my $cgi_date;
178 eval { $cgi_date = DateTime->new
179 ( year => defined $cgi->param("year") ? $cgi->param("year") : $now_date->year()
180 , month => defined $cgi->param("month") ? $cgi->param("month") : $now_date->month()
181 , day => defined $cgi->param("day") ? $cgi->param("day") : $now_date->day()
182 , hour => defined $cgi->param("hour") ? $cgi->param("hour") : $now_date->hour()
183 , minute => defined $cgi->param("minute") ? $cgi->param("minute") : $now_date->minute()
184 , second => 0
185 , nanosecond => 0
186 , time_zone => 'local'
187 , locale => $config{locale}
188 )->set_time_zone('floating') };
189 error(sprintf(gettext("illegal date")))
190 unless $cgi_date;
191
192 my @years = ($cgi_date->year() .. $cgi_date->year()+5);
193 my $week_start_day
194 = (defined $config{week_start_day} and $config{week_start_day} >= 0 and $config{week_start_day} <= 6)
195 ? $config{week_start_day}
196 : 1;
197 my @dow_order = ($week_start_day .. 6, 0 .. $week_start_day-1);
198
199 my $page = Encode::decode_utf8(URI::Escape::uri_unescape(IkiWiki::possibly_foolish_untaint($cgi->param('page'))));
200 my $newevent_base = Encode::decode_utf8(URI::Escape::uri_unescape(IkiWiki::possibly_foolish_untaint($cgi->param('base'))));
201 my $tags = $typedlinks{$page}{tag};
202 my $buttons = [qw{Preview Create}];
203 my ($from_date, $to_date, $end_date, $inc_dur);
204 my $form = CGI::FormBuilder->new
205 ( action => IkiWiki::cgiurl()
206 , charset => "utf-8"
207 , fields => [qw{
208 do base
209 from_date from_year from_month from_day from_hour from_minute
210 to_date to_year to_month to_day to_hour to_minute
211 inc_dur inc_year inc_month inc_week inc_day inc_hour inc_minute
212 end_times end_date end_year end_month end_day end_hour end_minute
213 dom name content
214 }]
215 , header => 0
216 , javascript => 0
217 , messages =>
218 {
219 # form_required_text => 'form_required_text'
220 # , form_invalid_text => 'form_invalid_text'
221 # , form_invalid_file => 'form_invalid_file'
222 # , form_invalid_input => gettext('allowed characters: ').$config{wiki_file_chars}
223 form_invalid_select => gettext('invalid selection')
224 }
225 , method => 'POST'
226 , name => "newevent"
227 , stylesheet => 1
228 , params => $cgi
229 , required => [qw{do base year month day name from_date to_date end_date inc_dur}]
230 , submit => [qw{Preview Create}]
231 , title => gettext("newevent")
232 , template => { template("newevent.tmpl") }
233 , validate =>
234 { from_date => { perl => sub {
235 my (undef, $form) = @_;
236 $from_date = date_of_form($form, 'from')
237 unless defined $from_date;
238 defined $from_date
239 } }
240 , to_date => { perl => sub {
241 my (undef, $form) = @_;
242 $from_date = date_of_form($form, 'from')
243 unless defined $from_date;
244 if (defined $from_date) {
245 $to_date = date_of_form($form, 'to'
246 , year => $from_date->year()
247 , month => $from_date->month()
248 , day => $from_date->day()
249 , hour => $from_date->hour()
250 , minute => $from_date->minute());
251 defined $to_date
252 and (DateTime->compare($from_date, $to_date) <= 0)
253 }
254 else {return 0;}
255 } }
256 , end_date => { perl => sub {
257 my (undef, $form) = @_;
258 if ( $form->field('end_year') ne ''
259 or $form->field('end_month') ne ''
260 or $form->field('end_day') ne '' ) {
261 $from_date = date_of_form($form, 'from')
262 unless defined $from_date;
263 if (defined $from_date) {
264 $end_date = date_of_form($form, 'end'
265 , year => $from_date->year()
266 , month => $from_date->month()
267 , day => $from_date->day()
268 , hour => $from_date->hour()
269 , minute => $from_date->minute());
270 (defined $from_date and defined $end_date
271 and DateTime->compare($from_date, $end_date) <= 0)
272 }
273 else {return 0;}
274 }
275 else {
276 1;
277 }
278 } }
279 , name => '/^.+$/'
280 , base => '/^.*$/'
281 , end_times => sub { $_[0] =~ m/^\d+$/ and $_[0] >= 0 }
282 , inc_year => sub { $_[0] =~ m/^\d+$/ and $_[0] >= 0 }
283 , inc_month => sub { $_[0] =~ m/^\d+$/ and $_[0] >= 0 }
284 , inc_week => sub { $_[0] =~ m/^\d+$/ and $_[0] >= 0 }
285 , inc_day => sub { $_[0] =~ m/^\d+$/ and $_[0] >= 0 }
286 , inc_hour => sub { $_[0] =~ m/^\d+$/ and $_[0] >= 0 }
287 , inc_minute => sub { $_[0] =~ m/^\d+$/ and $_[0] >= 0 }
288 , inc_dur => sub {
289 my (undef, $form) = @_;
290 $inc_dur = duration_of_form($form, 'inc');
291 defined $inc_dur
292 and ($inc_dur->is_positive() or $inc_dur->is_zero());
293 }
294 }
295 );
296 $form->title(sprintf(gettext("creating new events"), pagetitle(IkiWiki::basename($page))));
297 $form->field(name => "do", type => "hidden", value => 'newevent', force => 1);
298 $form->field(name => "base", type => "hidden", force => 1
299 , value => ($form->field('base') ? $form->field('base') : $newevent_base));
300 $form->field(name => "from_date", type => "hidden", value => '1', force => 1);
301 $form->field(name => "to_date", type => "hidden", value => '1', force => 1);
302 $form->field(name => "end_date", type => "hidden", value => '1', force => 1);
303 $form->field(name => "inc_dur", type => "hidden", value => '1', force => 1);
304 $form->field(name => "from_year", type => 'select', value => $cgi_date->year(), options => \@years);
305 $form->field(name => "from_month", type => 'select'
306 , value => sprintf("%02d", $cgi_date->month()).' - '.$months{$cgi_date->month()}
307 , options => [map { sprintf("%02d", $_).' - '.$months{$_} } (1..12)]);
308 $form->field(name => "from_day", type => 'select'
309 , value => sprintf("%02d", $cgi_date->day())
310 , options => \@days);
311 $form->field(name => "from_hour", type => 'select', value => '', options => \@hours);
312 $form->field(name => "from_minute", type => 'select', value => '', options => \@minutes);
313 $form->field(name => "name", type => 'text', size => 60, value => gettext('New event'));
314 $form->field(name => "to_year", type => 'select', value => '', options => \@years);
315 $form->field(name => "to_month", type => 'select'
316 , value => ''
317 , options => [map { sprintf("%02d", $_).' - '.$months{$_} } (1..12)]);
318 $form->field(name => "to_day", type => 'select'
319 , value => ''
320 , options => \@days);
321 $form->field(name => "to_hour", type => 'select', value => '', options => \@hours);
322 $form->field(name => "to_minute", type => 'select', value => '', options => \@minutes);
323 $form->field(name => "end_year", type => 'select', value => '', options => \@years);
324 $form->field(name => "end_month", type => 'select', value => ''
325 , options => [map { sprintf("%02d", $_).' - '.$months{$_} } (1..12)]);
326 $form->field(name => "end_day", type => 'select', value => '', options => \@days);
327 $form->field(name => "end_hour", type => 'select', value => '', options => \@hours);
328 $form->field(name => "end_minute", type => 'select', value => '', options => \@minutes);
329 $form->field(name => "end_times", type => 'text', value => '0', size => 2);
330 $form->field(name => "inc_year", type => 'text', value => '0', size => 2);
331 $form->field(name => "inc_month", type => 'text', value => '0', size => 2);
332 $form->field(name => "inc_week", type => 'text', value => '0', size => 2);
333 $form->field(name => "inc_day", type => 'text', value => '0', size => 2);
334 $form->field(name => "inc_hour", type => 'text', value => '0', size => 2);
335 $form->field(name => "inc_minute", type => 'text', value => '0', size => 2);
336 my $tmpl_neweventcontent = template("neweventcontent.tmpl");
337 $tmpl_neweventcontent->param(title => gettext('Title of the event'));
338 $tmpl_neweventcontent->param(tags => [map {{name => $_}} (sort keys %$tags)]);
339 $form->field(name => "content", type => "textarea", size => 30, rows => 20, cols => 80
340 , value => $tmpl_neweventcontent->output());
341 $form->field(name => "dom", type => 'select', multiple => 1, size => 35
342 , options => [map { my $n = $_; map {($n.' '.$dows{$_})} (0..6)} ('1°', '2°', '3°', '4°', '5°')]);
343
344 IkiWiki::decode_form_utf8($form);
345 IkiWiki::run_hooks(formbuilder_setup => sub {
346 shift->(form => $form, cgi => $cgi, session => $session, buttons => $buttons);
347 });
348 IkiWiki::decode_form_utf8($form);
349
350 if (($form->submitted eq 'Create' || $form->submitted eq 'Preview') && $form->validate) {
351 #IkiWiki::checksessionexpiry($cgi, $session, $cgi->param('sid'));
352 $newevent_base
353 = $form->field('base')
354 ? $form->field('base')
355 : (defined $config{newevent_base} ? $config{newevent_base} : gettext('Agenda'));
356 my $end_times
357 = $form->field('end_times') == 0
358 ? undef : $form->field('end_times');
359 my $dom;
360 foreach ($form->field('dom')) {
361 $dom = {} if not defined $dom;
362 $dom->{$_} = 1;
363 }
364 my $name = $form->field('name');
365 $name = IkiWiki::possibly_foolish_untaint(IkiWiki::titlepage($name));
366 # NOTE: these untaints are safe because of the checks
367 # performed in check_cannewevent later.
368 my $content = $form->field('content');
369 $content =~ s/\r\n/\n/gs;
370 $content =~ s/\n$//s;
371
372 # Queue of event creations to perfom.
373 my @events = ();
374 my $events_try = 0;
375 my $events_max
376 = defined $config{newevent_max_per_commit}
377 ? $config{newevent_max_per_commit} : (2 * 365) ;
378 my $pageext = $config{default_pageext};
379 while (++$events_try <= $events_max
380 and (not defined $end_times or --$end_times >= 0)
381 and (not defined $end_date or DateTime->compare($from_date, $end_date) <= 0)) {
382 my $dest = page_of_event($form, $from_date, $to_date, $name, $newevent_base);
383 my $week = $from_date->weekday_of_month();
384 my $day = $now_date->{locale}->day_format_wide->[$from_date->day_of_week()-1];
385 if (not defined $dom or exists $dom->{"$week° $day"}) {
386 push @events,
387 { page => $dest
388 , file => IkiWiki::newpagefile($dest, $pageext)
389 , from => $from_date
390 , to => $to_date
391 , name => $name
392 };
393 }
394 last unless defined $inc_dur and $inc_dur->is_positive();
395 $from_date = $from_date->clone->add_duration($inc_dur);
396 $to_date = $to_date->clone->add_duration($inc_dur);
397 }
398 error("events try per commit overflow: $events_max")
399 unless $events_try <= $events_max;
400 my $tmpl_neweventpage = template("neweventpage.tmpl");
401 my $i = 0;
402 foreach (@events) {
403 $tmpl_neweventpage->clear_params();
404 $tmpl_neweventpage->param(content => $content);
405 $tmpl_neweventpage->param(page => $_->{page});
406 $tmpl_neweventpage->param(event => $i);
407 $tmpl_neweventpage->param("event_first" => 1)
408 if $i == 0;
409 $tmpl_neweventpage->param("event_last" => 1)
410 if $i == @events - 1;
411 $tmpl_neweventpage->param(events => \@events);
412 $tmpl_neweventpage->param(from_date => "$_->{from}");
413 $tmpl_neweventpage->param(name => $_->{name});
414 $tmpl_neweventpage->param(to_date => "$_->{to}");
415 $_->{content} = $tmpl_neweventpage->output();
416 $i++;
417 }
418 if ($form->submitted eq 'Create') {
419 @events = newevent_hook
420 ( cgi => $cgi
421 , done => {}
422 , events => \@events
423 , session => $session
424 );
425 require IkiWiki::Render;
426 if ($config{rcs}) {
427 IkiWiki::disable_commit_hook()
428 }
429 foreach my $event (@events) {
430 create($event, $cgi, $session, \%months, $newevent_base);
431 }
432 if ($config{rcs}) {
433 IkiWiki::rcs_commit_staged
434 ( message => sprintf(gettext("new event"))
435 , session => $session );
436 IkiWiki::enable_commit_hook();
437 IkiWiki::rcs_update();
438 }
439 IkiWiki::refresh();
440 IkiWiki::saveindex();
441
442 post_newevent($cgi, $session, (defined $events[0] ? $events[0]->{page} : ''));
443 }
444 elsif ($form->submitted eq 'Preview') {
445 preview($cgi, $session, $form, \@events, \%months);
446 IkiWiki::showform($form, $buttons, $session, $cgi);
447 }
448 }
449 else {
450 IkiWiki::showform($form, $buttons, $session, $cgi);
451 }
452
453 exit 0;
454 }
455 }
456 sub preview($$$$) {
457 my ($cgi, $session, $form, $events, $months) = @_;
458 $form->tmpl_param(year => gettext("year"));
459 $form->tmpl_param(month => gettext("month"));
460 $form->tmpl_param(day => gettext("day"));
461 $form->tmpl_param(hour => gettext("hour"));
462 $form->tmpl_param(min => gettext("min"));
463 $form->tmpl_param(dow => gettext("day of week"));
464 $form->tmpl_param(page => gettext("page"));
465 $form->tmpl_param(events => [
466 map {
467 { from_year => $_->{from}->year()
468 , from_month => sprintf('%02d', $_->{from}->month())
469 , from_monthname => $months->{$_->{from}->month()}
470 , from_day => sprintf('%02d', $_->{from}->day())
471 , from_hour => sprintf('%02d', $_->{from}->hour())
472 , from_minute => sprintf('%02d', $_->{from}->minute())
473 , from_dow => $_->{from}->dow()
474 , from_downame => $_->{from}->day_name()
475 , to_year => $_->{to}->year()
476 , to_month => sprintf('%02d', $_->{to}->month())
477 , to_monthname => $months->{$_->{to}->month()}
478 , to_day => sprintf('%02d', $_->{to}->day())
479 , to_hour => sprintf('%02d', $_->{to}->hour())
480 , to_minute => sprintf('%02d', $_->{to}->minute())
481 , to_dow => $_->{to}->dow()
482 , page =>
483 htmllink("", "", $_->{page}
484 , linktext => $_->{page}
485 , noimageinline => 1)
486 }
487 } @$events
488 ]);
489 if (@$events > 0) {
490 my $page = @$events[0];
491 # FROM: editpage.pm
492 my $new = not exists $pagesources{$page};
493 # temporarily record its type
494 my $type = $config{default_pageext};
495 $pagesources{$page} = $page.".".$type if $new;
496 my %wasrendered = map { $_ => 1 } @{$renderedfiles{$page}};
497 my $content = @$events[0]->{content};
498
499 IkiWiki::run_hooks(editcontent => sub {
500 $content = shift->
501 ( cgi => $cgi
502 , content => $content
503 , page => $page
504 , session => $session
505 );
506 });
507 my $preview = IkiWiki::htmlize($page, $page, $type,
508 IkiWiki::linkify($page, $page,
509 IkiWiki::preprocess($page, $page,
510 IkiWiki::filter($page, $page, $content), 0, 1)));
511 IkiWiki::run_hooks(format => sub {
512 $preview = shift->
513 ( content => $preview
514 , page => $page
515 );
516 });
517 $form->tmpl_param("preview", $preview);
518
519 # Previewing may have created files on disk.
520 # Keep a list of these to be deleted later.
521 my %previews = map { $_ => 1 } @{$wikistate{editpage}{previews}};
522 foreach my $f (@{$renderedfiles{$page}}) {
523 $previews{$f} = 1 unless $wasrendered{$f};
524 }
525
526 # Throw out any other state changes made during previewing,
527 # and save the previews list.
528 IkiWiki::loadindex();
529 @{$wikistate{editpage}{previews}} = keys %previews;
530 IkiWiki::saveindex();
531 }
532 else {
533 $form->tmpl_param("preview", gettext("No event"));
534 }
535 }
536 sub create ($$$$$) {
537 my ($event, $cgi, $session, $months, $newevent_base) = @_;
538 check_cannewevent
539 ( $event->{page}
540 , $event->{file}
541 , $cgi
542 , $session
543 );
544 my $pageext = $config{default_pageext};
545
546 $config{cgi} = 0; # NOTE: avoid CGI error message
547 eval { writefile($event->{file}, $config{srcdir}, $event->{content}) };
548 if ($config{rcs}) {
549 IkiWiki::rcs_add($event->{file});
550 }
551 # month page
552 my $monthpage =
553 ( $newevent_base
554 . ($newevent_base?'/':'').$event->{from}->year()
555 . '/'.sprintf('%02d', $event->{from}->month())
556 );
557 my $monthfile = IkiWiki::newpagefile($monthpage, $pageext);
558 if (not exists $pagesources{$monthpage}
559 and not -l $config{srcdir}.'/'.$monthfile
560 and not -e _) {
561 my $tmpl_neweventmonth = template("neweventmonth.tmpl");
562 $tmpl_neweventmonth->param(base => $newevent_base);
563 $tmpl_neweventmonth->param(year => $event->{from}->year());
564 $tmpl_neweventmonth->param(month => sprintf('%02d', $event->{from}->month()));
565 $tmpl_neweventmonth->param(monthname => $months->{$event->{from}->month()});
566 my $content = $tmpl_neweventmonth->output();
567 eval { writefile($monthfile, $config{srcdir}, $content) };
568 if ($config{rcs}) {
569 IkiWiki::rcs_add($monthfile);
570 }
571 }
572 # day page
573 my $daypage =
574 ( $monthpage
575 . '/'.sprintf('%02d', $event->{from}->day())
576 );
577 my $dayfile = IkiWiki::newpagefile($daypage, $pageext);
578 if (not exists $pagesources{$daypage}
579 and not -l $config{srcdir}.'/'.$dayfile
580 and not -e _) {
581 my $tmpl_neweventday = template("neweventday.tmpl");
582 $tmpl_neweventday->param(base => $newevent_base);
583 $tmpl_neweventday->param(year => $event->{from}->year());
584 $tmpl_neweventday->param(month => sprintf('%02d', $event->{from}->month()));
585 $tmpl_neweventday->param(monthname => $months->{$event->{from}->month()});
586 $tmpl_neweventday->param(day => sprintf('%02d', $event->{from}->day()));
587 $tmpl_neweventday->param(dayname => $event->{from}->day_name());
588 my $content = $tmpl_neweventday->output();
589 eval { writefile($dayfile, $config{srcdir}, $content) };
590 if ($config{rcs}) {
591 IkiWiki::rcs_add($dayfile);
592 }
593 }
594 $config{cgi} = 1;
595 }
596 sub newevent_hook {
597 my %params = @_;
598 my @events = @{$params{events}};
599 my %done = %{$params{done}};
600 my $cgi = $params{cgi};
601 my $session = $params{session};
602 return ()
603 unless @events;
604 my @next;
605 foreach my $event (@events) {
606 unless (exists $done{$event->{page}} && $done{$event->{file}}) {
607 IkiWiki::run_hooks(newevent => sub {
608 push @next, shift->
609 ( cgi => $cgi
610 , event => $event
611 , session => $session
612 );
613 });
614 $done{$event->{page}} = 1;
615 }
616 }
617 push @events, newevent_hook
618 ( cgi => $cgi
619 , done => \%done
620 , events => \@next
621 , session => $session
622 );
623 my %seen; # NOTE: insure unicity
624 return grep { ! $seen{$_->{page}}++ } @events;
625 }
626
627 1;