source: trunk/lib/OpenGuides.pm @ 678

Last change on this file since 678 was 678, checked in by Earle Martin, 16 years ago

Change the behaviour of the "redirected" message to link to a rendered version of the old page, not the editing view.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 32.5 KB
Line 
1package OpenGuides;
2use strict;
3
4use Carp "croak";
5use CGI;
6use CGI::Wiki::Plugin::Diff;
7use CGI::Wiki::Plugin::Locator::Grid;
8use OpenGuides::CGI;
9use OpenGuides::Template;
10use OpenGuides::Utils;
11use Time::Piece;
12use URI::Escape;
13
14use vars qw( $VERSION );
15
16$VERSION = '0.50';
17
18=head1 NAME
19
20OpenGuides - A complete web application for managing a collaboratively-written guide to a city or town.
21
22=head1 DESCRIPTION
23
24The OpenGuides software provides the framework for a collaboratively-written
25city guide.  It is similar to a wiki but provides somewhat more structured
26data storage allowing you to annotate wiki pages with information such as
27category, location, and much more.  It provides searching facilities
28including "find me everything within a certain distance of this place".
29Every page includes a link to a machine-readable (RDF) version of the page.
30
31=head1 METHODS
32
33=over
34
35=item B<new>
36
37  my $config = OpenGuides::Config->new( file => "wiki.conf" );
38  my $guide = OpenGuides->new( config => $config );
39
40=cut
41
42sub new {
43    my ($class, %args) = @_;
44    my $self = {};
45    bless $self, $class;
46    my $wiki = OpenGuides::Utils->make_wiki_object( config => $args{config} );
47    $self->{wiki} = $wiki;
48    $self->{config} = $args{config};
49    my $geo_handler = $self->config->geo_handler;
50    my $locator;
51    if ( $geo_handler == 1 ) {
52        $locator = CGI::Wiki::Plugin::Locator::Grid->new(
53                                             x => "os_x",    y => "os_y" );
54    } elsif ( $geo_handler == 2 ) {
55        $locator = CGI::Wiki::Plugin::Locator::Grid->new(
56                                             x => "osie_x",  y => "osie_y" );
57    } else {
58        $locator = CGI::Wiki::Plugin::Locator::Grid->new(
59                                             x => "easting", y => "northing" );
60    }
61    $wiki->register_plugin( plugin => $locator );
62    $self->{locator} = $locator;
63    my $differ = CGI::Wiki::Plugin::Diff->new;
64    $wiki->register_plugin( plugin => $differ );
65    $self->{differ} = $differ;
66    return $self;
67}
68
69=item B<wiki>
70
71An accessor, returns the underlying L<CGI::Wiki> object.
72
73=cut
74
75sub wiki {
76    my $self = shift;
77    return $self->{wiki};
78}
79
80=item B<config>
81
82An accessor, returns the underlying L<OpenGuides::Config> object.
83
84=cut
85
86sub config {
87    my $self = shift;
88    return $self->{config};
89}
90
91=item B<locator>
92
93An accessor, returns the underlying L<CGI::Wiki::Plugin::Locator::UK> object.
94
95=cut
96
97sub locator {
98    my $self = shift;
99    return $self->{locator};
100}
101
102=item B<differ>
103
104An accessor, returns the underlying L<CGI::Wiki::Plugin::Diff> object.
105
106=cut
107
108sub differ {
109    my $self = shift;
110    return $self->{differ};
111}
112
113=item B<display_node>
114
115  # Print node to STDOUT.
116  $guide->display_node(
117                        id      => "Calthorpe Arms",
118                        version => 2,
119                      );
120
121  # Or return output as a string (useful for writing tests).
122  $guide->display_node(
123                        id            => "Calthorpe Arms",
124                        return_output => 1,
125                      );
126
127  # Or return the hash of variables that will be passed to the template
128  # (not including those set additionally by OpenGuides::Template).
129  $guide->display_node(
130                        id             => "Calthorpe Arms",
131                        return_tt_vars => 1,
132                      );
133
134If C<version> is omitted then the latest version will be displayed.
135
136=cut
137
138sub display_node {
139    my ($self, %args) = @_;
140    my $return_output = $args{return_output} || 0;
141    my $version = $args{version};
142    my $id = $args{id} || $self->config->home_name;
143    my $wiki = $self->wiki;
144    my $config = $self->config;
145    my $oldid = $args{oldid} || '';
146    my $do_redirect = $args{redirect} || 1;
147
148    my %tt_vars;
149
150    if ( $id =~ /^(Category|Locale) (.*)$/ ) {
151        my $type = $1;
152        $tt_vars{is_indexable_node} = 1;
153        $tt_vars{index_type} = lc($type);
154        $tt_vars{index_value} = $2;
155        $tt_vars{"rss_".lc($type)."_url"} =
156                           $config->script_name . "?action=rss;"
157                           . lc($type) . "=" . lc(CGI->escape($2));
158    }
159
160    my %current_data = $wiki->retrieve_node( $id );
161    my $current_version = $current_data{version};
162    undef $version if ($version && $version == $current_version);
163    my %criteria = ( name => $id );
164    $criteria{version} = $version if $version; # retrieve_node default is current
165
166    my %node_data = $wiki->retrieve_node( %criteria );
167
168    my $raw        = $node_data{content};
169    my $content    = $wiki->format($raw);
170    my $modified   = $node_data{last_modified};
171    my %metadata   = %{$node_data{metadata}};
172
173    my %metadata_vars = OpenGuides::Template->extract_metadata_vars(
174                            wiki     => $wiki,
175                            config   => $config,
176                            metadata => $node_data{metadata} );
177
178    %tt_vars = (
179                 %tt_vars,
180                 %metadata_vars,
181                 content       => $content,
182                 last_modified => $modified,
183                 version       => $node_data{version},
184                 node          => $id,
185                 language      => $config->default_language,
186                 oldid         => $oldid,
187               );
188
189    if ( $raw =~ /^#REDIRECT\s+(.+?)\s*$/ ) {
190        my $redirect = $1;
191        # Strip off enclosing [[ ]] in case this is an extended link.
192        $redirect =~ s/^\[\[//;
193        $redirect =~ s/\]\]\s*$//;
194
195        # Don't redirect if the parameter "redirect" is given as 0.
196        if ($do_redirect == 0) {
197            return %tt_vars if $args{return_tt_vars};
198            $tt_vars{current} = 1;
199            my $output = $self->process_template(
200                                                  id            => $id,
201                                                  template      => "node.tt",
202                                                  tt_vars       => \%tt_vars,
203                                                );
204            return $output if $return_output;
205            print $output;
206        } elsif ( $wiki->node_exists($redirect) && $redirect ne $id && $redirect ne $oldid ) {
207            # Avoid loops by not generating redirects to the same node or the previous node.
208            my $output = $self->redirect_to_node($redirect, $id);
209            return $output if $return_output;
210            print $output;
211            exit 0;
212        }
213    }
214
215    # We've undef'ed $version above if this is the current version.
216    $tt_vars{current} = 1 unless $version;
217
218    if ($id eq "RecentChanges") {
219        my $minor_edits = $self->get_cookie( "show_minor_edits_in_rc" );
220        my %recent_changes;
221        my $q = CGI->new;
222        my $since = $q->param("since");
223        if ( $since ) {
224            $tt_vars{since} = $since;
225            my $t = localtime($since); # overloaded by Time::Piece
226            $tt_vars{since_string} = $t->strftime;
227            my %criteria = ( since => $since );
228            $criteria{metadata_was} = { edit_type => "Normal edit" }
229              unless $minor_edits;
230            my @rc = $self->{wiki}->list_recent_changes( %criteria );
231
232            @rc = map {
233                {
234                  name        => CGI->escapeHTML($_->{name}),
235                  last_modified => CGI->escapeHTML($_->{last_modified}),
236                  version     => CGI->escapeHTML($_->{version}),
237                  comment     => CGI->escapeHTML($_->{metadata}{comment}[0]),
238                  username    => CGI->escapeHTML($_->{metadata}{username}[0]),
239                  host        => CGI->escapeHTML($_->{metadata}{host}[0]),
240                  username_param => CGI->escape($_->{metadata}{username}[0]),
241                  edit_type   => CGI->escapeHTML($_->{metadata}{edit_type}[0]),
242                  url         => $config->script_name . "?"
243          . CGI->escape($wiki->formatter->node_name_to_node_param($_->{name})),
244            }
245                       } @rc;
246            if ( scalar @rc ) {
247                $recent_changes{since} = \@rc;
248            }
249        } else {
250            for my $days ( [0, 1], [1, 7], [7, 14], [14, 30] ) {
251                my %criteria = ( between_days => $days );
252                $criteria{metadata_was} = { edit_type => "Normal edit" }
253                  unless $minor_edits;
254                my @rc = $self->{wiki}->list_recent_changes( %criteria );
255
256                @rc = map {
257                {
258                  name        => CGI->escapeHTML($_->{name}),
259                  last_modified => CGI->escapeHTML($_->{last_modified}),
260                  version     => CGI->escapeHTML($_->{version}),
261                  comment     => CGI->escapeHTML($_->{metadata}{comment}[0]),
262                  username    => CGI->escapeHTML($_->{metadata}{username}[0]),
263                  host        => CGI->escapeHTML($_->{metadata}{host}[0]),
264                  username_param => CGI->escape($_->{metadata}{username}[0]),
265                  edit_type   => CGI->escapeHTML($_->{metadata}{edit_type}[0]),
266                  url         => $config->script_name . "?"
267          . CGI->escape($wiki->formatter->node_name_to_node_param($_->{name})),
268            }
269                           } @rc;
270                if ( scalar @rc ) {
271                    $recent_changes{$days->[1]} = \@rc;
272            }
273            }
274        }
275        $tt_vars{recent_changes} = \%recent_changes;
276        my %processing_args = (
277                                id            => $id,
278                                template      => "recent_changes.tt",
279                                tt_vars       => \%tt_vars,
280                               );
281        if ( !$since && $self->get_cookie("track_recent_changes_views") ) {
282        my $cookie =
283               OpenGuides::CGI->make_recent_changes_cookie(config => $config );
284            $processing_args{cookies} = $cookie;
285            $tt_vars{last_viewed} = OpenGuides::CGI->get_last_recent_changes_visit_from_cookie( config => $config );
286        }
287        return %tt_vars if $args{return_tt_vars};
288        my $output = $self->process_template( %processing_args );
289        return $output if $return_output;
290        print $output;
291    } elsif ( $id eq $self->config->home_name ) {
292        my @recent = $wiki->list_recent_changes(
293            last_n_changes => 10,
294            metadata_was   => { edit_type => "Normal edit" },
295        );
296        @recent = map { {name          => CGI->escapeHTML($_->{name}),
297                         last_modified => CGI->escapeHTML($_->{last_modified}),
298                         version       => CGI->escapeHTML($_->{version}),
299                         comment       => CGI->escapeHTML($_->{metadata}{comment}[0]),
300                         username      => CGI->escapeHTML($_->{metadata}{username}[0]),
301                         url           => $config->script_name . "?"
302          . CGI->escape($wiki->formatter->node_name_to_node_param($_->{name})) }
303                       } @recent;
304        $tt_vars{recent_changes} = \@recent;
305        return %tt_vars if $args{return_tt_vars};
306        my $output = $self->process_template(
307                                              id            => $id,
308                                              template      => "home_node.tt",
309                                              tt_vars       => \%tt_vars,
310                                            );
311        return $output if $return_output;
312        print $output;
313    } else {
314        return %tt_vars if $args{return_tt_vars};
315        my $output = $self->process_template(
316                                              id            => $id,
317                                              template      => "node.tt",
318                                              tt_vars       => \%tt_vars,
319                                            );
320        return $output if $return_output;
321        print $output;
322    }
323}
324
325=item B<display_diffs>
326
327  $guide->display_diffs(
328                         id            => "Home Page",
329                         version       => 6,
330                         other_version => 5,
331                       );
332
333  # Or return output as a string (useful for writing tests).
334  my $output = $guide->display_diffs(
335                                      id            => "Home Page",
336                                      version       => 6,
337                                      other_version => 5,
338                                      return_output => 1,
339                                    );
340
341  # Or return the hash of variables that will be passed to the template
342  # (not including those set additionally by OpenGuides::Template).
343  my %vars = $guide->display_diffs(
344                                    id             => "Home Page",
345                                    version        => 6,
346                                    other_version  => 5,
347                                    return_tt_vars => 1,
348                                  );
349
350=cut
351
352sub display_diffs {
353    my ($self, %args) = @_;
354    my %diff_vars = $self->differ->differences(
355                                        node          => $args{id},
356                                        left_version  => $args{version},
357                                   right_version => $args{other_version},
358                                              );
359    $diff_vars{not_deletable} = 1;
360    $diff_vars{not_editable} = 1;
361    $diff_vars{deter_robots} = 1;
362    return %diff_vars if $args{return_tt_vars};
363    my $output = $self->process_template(
364                                          id       => $args{id},
365                                          template => "differences.tt",
366                                          tt_vars  => \%diff_vars
367                                        );
368    return $output if $args{return_output};
369    print $output;
370}
371
372=item B<find_within_distance>
373
374  $guide->find_within_distance(
375                                id => $node,
376                                metres => $q->param("distance_in_metres")
377                              );
378
379=cut
380
381sub find_within_distance {
382    my ($self, %args) = @_;
383    my $node = $args{id};
384    my $metres = $args{metres};
385    my %data = $self->wiki->retrieve_node( $node );
386    my $lat = $data{metadata}{latitude}[0];
387    my $long = $data{metadata}{longitude}[0];
388    my $script_url = $self->config->script_url;
389    print CGI->redirect( $script_url . "supersearch.cgi?lat=$lat;long=$long;distance_in_metres=$metres" );
390}
391
392=item B<show_backlinks>
393
394  $guide->show_backlinks( id => "Calthorpe Arms" );
395
396As with other methods, parameters C<return_tt_vars> and
397C<return_output> can be used to return these things instead of
398printing the output to STDOUT.
399
400=cut
401
402sub show_backlinks {
403    my ($self, %args) = @_;
404    my $wiki = $self->wiki;
405    my $formatter = $wiki->formatter;
406
407    my @backlinks = $wiki->list_backlinks( node => $args{id} );
408    my @results = map {
409        { url   => CGI->escape($formatter->node_name_to_node_param($_)),
410      title => CGI->escapeHTML($_)
411        }             } sort @backlinks;
412    my %tt_vars = ( results       => \@results,
413                    num_results   => scalar @results,
414                    not_deletable => 1,
415                    deter_robots  => 1,
416                    not_editable  => 1 );
417    return %tt_vars if $args{return_tt_vars};
418    my $output = OpenGuides::Template->output(
419                                               node    => $args{id},
420                                               wiki    => $wiki,
421                                               config  => $self->config,
422                                               template=>"backlink_results.tt",
423                                               vars    => \%tt_vars,
424                                             );
425    return $output if $args{return_output};
426    print $output;
427}
428
429=item B<show_index>
430
431  $guide->show_index(
432                      type   => "category",
433                      value  => "pubs",
434                    );
435
436  # RDF version.
437  $guide->show_index(
438                      type   => "locale",
439                      value  => "Holborn",
440                      format => "rdf",
441                    );
442
443  # Or return output as a string (useful for writing tests).
444  $guide->show_index(
445                      type          => "category",
446                      value         => "pubs",
447                      return_output => 1,
448                    );
449
450=cut
451
452sub show_index {
453    my ($self, %args) = @_;
454    my $wiki = $self->wiki;
455    my $formatter = $wiki->formatter;
456    my %tt_vars;
457    my @selnodes;
458
459    if ( $args{type} and $args{value} ) {
460        if ( $args{type} eq "fuzzy_title_match" ) {
461            my %finds = $wiki->fuzzy_title_match( $args{value} );
462            @selnodes = sort { $finds{$a} <=> $finds{$b} } keys %finds;
463            $tt_vars{criterion} = {
464                type  => $args{type},  # for RDF version
465                value => $args{value}, # for RDF version
466                name  => CGI->escapeHTML("Fuzzy Title Match on '$args{value}'")
467        };
468        $tt_vars{not_editable} = 1;
469        } else {
470            @selnodes = $wiki->list_nodes_by_metadata(
471                metadata_type  => $args{type},
472            metadata_value => $args{value},
473                ignore_case    => 1
474            );
475            my $name = ucfirst($args{type}) . " $args{value}" ;
476            my $url = $self->config->script_name
477                      . "?"
478                      . ucfirst( $args{type} )
479                      . "_"
480                      . uri_escape(
481                              $formatter->node_name_to_node_param($args{value})
482                                  );
483            $tt_vars{criterion} = {
484                type  => $args{type},
485                value => $args{value}, # for RDF version
486                name  => CGI->escapeHTML( $name ),
487            url   => $url
488            };
489        $tt_vars{not_editable} = 1;
490        }
491    } else {
492        @selnodes = $wiki->list_all_nodes();
493    }
494
495    my @nodes = map { { name      => $_,
496                        node_data => { $wiki->retrieve_node( name => $_ ) },
497            param     => $formatter->node_name_to_node_param($_) }
498            } sort @selnodes;
499
500    $tt_vars{nodes} = \@nodes;
501
502    my ($template, %conf);
503
504    if ( $args{format} )
505    {
506      if ( $args{format} eq "rdf" )
507      {
508    $template = "rdf_index.tt";
509        $conf{content_type} = "text/plain";
510      }
511      elsif ( $args{format} eq "plain" )
512      {
513        $template = "plain_index.tt";
514        $conf{content_type} = "text/plain";
515      }
516    }
517    else
518    {
519      $template = "site_index.tt";
520    }
521
522    %conf = (
523              %conf,
524              node        => "$args{type} index", # KLUDGE
525              template    => $template,
526              tt_vars     => \%tt_vars,
527    );
528
529    my $output = $self->process_template( %conf );
530    return $output if $args{return_output};
531    print $output;
532}
533
534=item B<list_all_versions>
535
536  $guide->list_all_versions ( id => "Home Page" );
537
538  # Or return output as a string (useful for writing tests).
539  $guide->list_all_versions (
540                              id            => "Home Page",
541                              return_output => 1,
542                            );
543
544  # Or return the hash of variables that will be passed to the template
545  # (not including those set additionally by OpenGuides::Template).
546  $guide->list_all_versions (
547                              id             => "Home Page",
548                              return_tt_vars => 1,
549                            );
550
551=cut
552
553sub list_all_versions {
554    my ($self, %args) = @_;
555    my $return_output = $args{return_output} || 0;
556    my $node = $args{id};
557    my %curr_data = $self->wiki->retrieve_node($node);
558    my $curr_version = $curr_data{version};
559    my @history;
560    for my $version ( 1 .. $curr_version ) {
561        my %node_data = $self->wiki->retrieve_node( name    => $node,
562                                  version => $version );
563        # $node_data{version} will be zero if this version was deleted.
564    push @history, {
565            version  => CGI->escapeHTML( $version ),
566        modified => CGI->escapeHTML( $node_data{last_modified} ),
567            username => CGI->escapeHTML( $node_data{metadata}{username}[0] ),
568            comment  => CGI->escapeHTML( $node_data{metadata}{comment}[0] ),
569                       } if $node_data{version};
570    }
571    @history = reverse @history;
572    my %tt_vars = ( node          => $node,
573            version       => $curr_version,
574                    not_deletable => 1,
575                    not_editable  => 1,
576                    deter_robots  => 1,
577            history       => \@history );
578    return %tt_vars if $args{return_tt_vars};
579    my $output = $self->process_template(
580                                          id       => $node,
581                                          template => "node_history.tt",
582                                          tt_vars  => \%tt_vars,
583                                        );
584    return $output if $return_output;
585    print $output;
586}
587
588=item B<display_rss>
589
590  # Last ten non-minor edits to Hammersmith pages.
591  $guide->display_rss(
592                       items              => 10,
593                       ignore_minor_edits => 1,
594                       locale             => "Hammersmith",
595                     );
596
597  # All edits bob has made to pub pages in the last week.
598  $guide->display_rss(
599                       days     => 7,
600                       username => "bob",
601                       category => "Pubs",
602                     );
603
604As with other methods, the C<return_output> parameter can be used to
605return the output instead of printing it to STDOUT.
606
607=cut
608
609sub display_rss {
610    my ($self, %args) = @_;
611
612    my $return_output = $args{return_output} ? 1 : 0;
613
614    my $items = $args{items} || "";
615    my $days  = $args{days}  || "";
616    my $ignore_minor_edits = $args{ignore_minor_edits} ? 1 : 0;
617    my $username = $args{username} || "";
618    my $category = $args{category} || "";
619    my $locale   = $args{locale}   || "";
620    my %criteria = (
621                     items              => $items,
622                     days               => $days,
623                     ignore_minor_edits => $ignore_minor_edits,
624                   );
625    my %filter;
626    $filter{username} = $username if $username;
627    $filter{category} = $category if $category;
628    $filter{locale}   = $locale   if $locale;
629    if ( scalar keys %filter ) {
630        $criteria{filter_on_metadata} = \%filter;
631    }
632
633    my $rdf_writer = OpenGuides::RDF->new( wiki   => $self->wiki,
634                       config => $self->config );
635    my $output = "Content-Type: text/plain\n";
636    $output .= "Last-Modified: " . $rdf_writer->rss_timestamp( %criteria ) . "\n\n";
637    $output .= $rdf_writer->make_recentchanges_rss( %criteria );
638    return $output if $return_output;
639    print $output;
640}
641
642=item B<commit_node>
643
644  $guide->commit_node(
645                       id      => $node,
646                       cgi_obj => $q,
647                     );
648
649As with other methods, parameters C<return_tt_vars> and
650C<return_output> can be used to return these things instead of
651printing the output to STDOUT.
652
653The geographical data that you should provide in the L<CGI> object
654depends on the handler you chose in C<wiki.conf>.
655
656=over
657
658=item *
659
660B<British National Grid> - provide either C<os_x> and C<os_y> or
661C<latitude> and C<longitude>; whichever set of data you give, it will
662be converted to the other and both sets will be stored.
663
664=item *
665
666B<Irish National Grid> - provide either C<osie_x> and C<osie_y> or
667C<latitude> and C<longitude>; whichever set of data you give, it will
668be converted to the other and both sets will be stored.
669
670=item *
671
672B<UTM ellipsoid> - provide C<latitude> and C<longitude>; these will be
673converted to easting and northing and both sets of data will be stored.
674
675=back
676
677=cut
678
679sub commit_node {
680    my ($self, %args) = @_;
681    my $node = $args{id};
682    my $q = $args{cgi_obj};
683    my $return_output = $args{return_output};
684    my $wiki = $self->wiki;
685    my $config = $self->config;
686
687    my $content  = $q->param("content");
688    $content =~ s/\r\n/\n/gs;
689    my $checksum = $q->param("checksum");
690
691    my %metadata = OpenGuides::Template->extract_metadata_vars(
692        wiki    => $wiki,
693        config  => $config,
694    cgi_obj => $q
695    );
696
697    $metadata{opening_hours_text} = $q->param("hours_text") || "";
698
699    # Pick out the unmunged versions of lat/long if they're set.
700    # (If they're not, it means they weren't munged in the first place.)
701    $metadata{latitude} = delete $metadata{latitude_unmunged}
702        if $metadata{latitude_unmunged};
703    $metadata{longitude} = delete $metadata{longitude_unmunged}
704        if $metadata{longitude_unmunged};
705
706    # Check to make sure all the indexable nodes are created
707    foreach my $type (qw(Category Locale)) {
708        my $lctype = lc($type);
709        foreach my $index (@{$metadata{$lctype}}) {
710        $index =~ s/(.*)/\u$1/;
711        my $node = $type . " " . $index;
712        # Uppercase the node name before checking for existence
713        $node =~ s/ (\S+)/ \u$1/g;
714        unless ( $wiki->node_exists($node) ) {
715            my $category = $type eq "Category" ? "Category" : "Locales";
716        $wiki->write_node( $node,
717                           "\@INDEX_LINK [[$node]]",
718                   undef,
719                   { username => "Auto Create",
720                     comment  => "Auto created $lctype stub page",
721                     category => $category
722                   }
723        );
724        }
725    }
726    }
727   
728    foreach my $var ( qw( username comment edit_type ) ) {
729        $metadata{$var} = $q->param($var) || "";
730    }
731    $metadata{host} = $ENV{REMOTE_ADDR};
732
733    # CGI::Wiki::Plugin::RSS::ModWiki wants "major_change" to be set.
734    $metadata{major_change} = ( $metadata{edit_type} eq "Normal edit" )
735                            ? 1
736                            : 0;
737
738    my $written = $wiki->write_node($node, $content, $checksum, \%metadata );
739
740    if ($written) {
741        my $output = $self->redirect_to_node($node);
742        return $output if $return_output;
743        print $output;
744    } else {
745        my %node_data = $wiki->retrieve_node($node);
746        my %tt_vars = ( checksum       => $node_data{checksum},
747                        new_content    => $content,
748                        stored_content => $node_data{content} );
749        foreach my $mdvar ( keys %metadata ) {
750            if ($mdvar eq "locales") {
751                $tt_vars{"stored_$mdvar"} = $node_data{metadata}{locale};
752                $tt_vars{"new_$mdvar"}    = $metadata{locale};
753            } elsif ($mdvar eq "categories") {
754                $tt_vars{"stored_$mdvar"} = $node_data{metadata}{category};
755                $tt_vars{"new_$mdvar"}    = $metadata{category};
756            } elsif ($mdvar eq "username" or $mdvar eq "comment"
757                      or $mdvar eq "edit_type" ) {
758                $tt_vars{$mdvar} = $metadata{$mdvar};
759            } else {
760                $tt_vars{"stored_$mdvar"} = $node_data{metadata}{$mdvar}[0];
761                $tt_vars{"new_$mdvar"}    = $metadata{$mdvar};
762            }
763        }
764        return %tt_vars if $args{return_tt_vars};
765        my $output = $self->process_template(
766                                              id       => $node,
767                                              template => "edit_conflict.tt",
768                                              tt_vars  => \%tt_vars,
769                                            );
770        return $output if $args{return_output};
771        print $output;
772    }
773}
774
775
776=item B<delete_node>
777
778  $guide->delete_node(
779                       id       => "FAQ",
780                       version  => 15,
781                       password => "beer",
782                     );
783
784C<version> is optional - if it isn't supplied then all versions of the
785node will be deleted; in other words the node will be entirely
786removed.
787
788If C<password> is not supplied then a form for entering the password
789will be displayed.
790
791As with other methods, parameters C<return_tt_vars> and
792C<return_output> can be used to return these things instead of
793printing the output to STDOUT.
794
795=cut
796
797sub delete_node {
798    my ($self, %args) = @_;
799    my $node = $args{id} or croak "No node ID supplied for deletion";
800    my $return_tt_vars = $args{return_tt_vars} || 0;
801    my $return_output = $args{return_output} || 0;
802
803    my %tt_vars = (
804                    not_editable  => 1,
805                    not_deletable => 1,
806                    deter_robots  => 1,
807                  );
808    $tt_vars{delete_version} = $args{version} || "";
809
810    my $password = $args{password};
811
812    if ($password) {
813        if ($password ne $self->config->admin_pass) {
814            return %tt_vars if $return_tt_vars;
815            my $output = $self->process_template(
816                                     id       => $node,
817                                     template => "delete_password_wrong.tt",
818                                     tt_vars  => \%tt_vars,
819                                   );
820            return $output if $return_output;
821            print $output;
822        } else {
823            $self->wiki->delete_node(
824                                      name    => $node,
825                                      version => $args{version},
826                                    );
827            # Check whether any versions of this node remain.
828            my %check = $self->wiki->retrieve_node( name => $node );
829            $tt_vars{other_versions_remain} = 1 if $check{version};
830            return %tt_vars if $return_tt_vars;
831            my $output = $self->process_template(
832                                     id       => $node,
833                                     template => "delete_done.tt",
834                                     tt_vars  => \%tt_vars,
835                                   );
836            return $output if $return_output;
837            print $output;
838        }
839    } else {
840        return %tt_vars if $return_tt_vars;
841        my $output = $self->process_template(
842                                 id       => $node,
843                                 template => "delete_confirm.tt",
844                                 tt_vars  => \%tt_vars,
845                               );
846        return $output if $return_output;
847        print $output;
848    }
849}
850
851sub process_template {
852    my ($self, %args) = @_;
853    my %output_conf = (
854            wiki     => $self->wiki,
855            config   => $self->config,
856            node     => $args{id},
857            template => $args{template},
858            vars     => $args{tt_vars},
859            cookies  => $args{cookies},
860    );
861    if ( $args{content_type} ) {
862        $output_conf{content_type} = "";
863        my $output = "Content-Type: $args{content_type}\n\n"
864                     . OpenGuides::Template->output( %output_conf );
865    } else {
866        return OpenGuides::Template->output( %output_conf );
867    }
868}
869
870sub redirect_to_node {
871    my ($self, $node, $redirected_from) = @_;
872   
873    my $script_url = $self->config->script_url;
874    my $script_name = $self->config->script_name;
875    my $formatter = $self->wiki->formatter;
876
877    my $id = $formatter->node_name_to_node_param( $node );
878    my $oldid;
879    $oldid = $formatter->node_name_to_node_param( $redirected_from ) if $redirected_from;
880
881    my $redir_param = "$script_url$script_name?";
882    $redir_param .= 'id=' if $oldid;
883    $redir_param .= $id;
884    $redir_param .= ";oldid=$oldid" if $oldid;
885
886    return CGI->redirect( $redir_param );
887}
888
889sub get_cookie {
890    my $self = shift;
891    my $config = $self->config;
892    my $pref_name = shift or return "";
893    my %cookie_data = OpenGuides::CGI->get_prefs_from_cookie(config=>$config);
894    return $cookie_data{$pref_name};
895}
896
897
898=back
899
900=head1 BUGS AND CAVEATS
901
902UTF8 data are currently not handled correctly throughout.
903
904Other bugs are documented at
905L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=OpenGuides>
906
907=head1 SEE ALSO
908
909=over 4
910
911=item * L<http://london.openguides.org/|The Open Guide to London>, the first and biggest OpenGuides site.
912
913=item * L<http://openguides.org/|The OpenGuides website>, with a list of all live OpenGuides installs.
914
915=item * L<CGI::Wiki>, the Wiki toolkit which does the heavy lifting for OpenGuides
916
917=back
918
919=head1 FEEDBACK
920
921If you have a question, a bug report, or a patch, or you're interested
922in joining the development team, please contact openguides-dev@openguides.org
923(moderated mailing list, will reach all current developers but you'll have
924to wait for your post to be approved) or file a bug report at
925L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=OpenGuides>
926
927=head1 AUTHOR
928
929The OpenGuides Project (openguides-dev@openguides.org)
930
931=head1 COPYRIGHT
932
933     Copyright (C) 2003-2005 The OpenGuides Project.  All Rights Reserved.
934
935The OpenGuides distribution is free software; you can redistribute it
936and/or modify it under the same terms as Perl itself.
937
938=head1 CREDITS
939
940Programming by Dominic Hargreaves, Earle Martin, Kake Pugh, and Ivor
941Williams.  Testing and bug reporting by Billy Abbott, Jody Belka,
942Kerry Bosworth, Simon Cozens, Cal Henderson, Steve Jolly, and Bob
943Walker (among others).  Much of the Module::Build stuff copied from
944the Siesta project L<http://siesta.unixbeard.net/>
945
946=cut
947
9481;
Note: See TracBrowser for help on using the repository browser.