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